From: Daniel Gryniewicz Date: Thu, 5 May 2016 18:20:03 +0000 (-0400) Subject: Add support for Ceph NFS Gateway X-Git-Tag: v1.0.6~77^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4c2a433acb02048b3d1dc2dcab8ebb0c94ef9add;p=ceph-ansible.git Add support for Ceph NFS Gateway Ceph has the ability to export it's filesystem via NFS using Ganesha. Add a ceph-nfs role that will start Ganesha and export the Ceph filesystems. Note that, although support is going in to export RGW via NFS, this is not working yet. Signed-off-by: Daniel Gryniewicz --- diff --git a/Vagrantfile b/Vagrantfile index fd4e17a4e..aa38bc1ff 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -11,6 +11,7 @@ NMONS = settings['mon_vms'] NOSDS = settings['osd_vms'] NMDSS = settings['mds_vms'] NRGWS = settings['rgw_vms'] +NNFSS = settings['nfs_vms'] RESTAPI = settings['restapi'] CLIENTS = settings['client_vms'] SUBNET = settings['subnet'] @@ -49,6 +50,7 @@ ansible_provision = proc do |ansible| 'osds' => (0..NOSDS - 1).map { |j| "#{OSPREFIX}osd#{j}" }, 'mdss' => (0..NMDSS - 1).map { |j| "#{OSPREFIX}mds#{j}" }, 'rgws' => (0..NRGWS - 1).map { |j| "#{OSPREFIX}rgw#{j}" }, + 'nfss' => (0..NNFSS - 1).map { |j| "#{OSPREFIX}nfs#{j}" }, 'clients' => (0..CLIENTS - 1).map { |j| "#{OSPREFIX}client#{j}" } } @@ -64,6 +66,7 @@ ansible_provision = proc do |ansible| osd_containerized_deployment: 'true', mds_containerized_deployment: 'true', rgw_containerized_deployment: 'true', + nfs_containerized_deployment: 'true', restapi_containerized_deployment: 'true', ceph_mon_docker_interface: ETH, ceph_mon_docker_subnet: "#{SUBNET}.0/24", @@ -186,6 +189,36 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| end end + (0..NNFSS - 1).each do |i| + config.vm.define "nfs#{i}" do |nfs| + nfs.vm.hostname = "ceph-nfs#{i}" + if !OSVM + nfs.vm.network :private_network, ip: "#{SUBNET}.6#{i}" + end + + # Virtualbox + nfs.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + nfs.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + nfs.vm.provider :libvirt do |lv| + lv.memory = MEMORY + end + + # Parallels + nfs.vm.provider "parallels" do |prl| + prl.name = "ceph-nfs#{i}" + prl.memory = "#{MEMORY}" + end + end + end + (0..NMDSS - 1).each do |i| config.vm.define "#{OSPREFIX}mds#{i}" do |mds| mds.vm.hostname = "#{OSPREFIX}ceph-mds#{i}" diff --git a/group_vars/all.sample b/group_vars/all.sample index 963b4a128..947ba540c 100644 --- a/group_vars/all.sample +++ b/group_vars/all.sample @@ -24,6 +24,7 @@ dummy: #osd_group_name: osds #rgw_group_name: rgws #mds_group_name: mdss +#nfs_group_name: nfss #restapi_group_name: restapis #rbdmirror_group_name: rbdmirrors #client_group_name: clients diff --git a/group_vars/nfss.sample b/group_vars/nfss.sample new file mode 100644 index 000000000..f2f2353dc --- /dev/null +++ b/group_vars/nfss.sample @@ -0,0 +1,68 @@ +--- +# Variables here are applicable to all host groups NOT roles + +# This sample file generated by generate_group_vars_sample.sh + +# Dummy variable to avoid error because ansible does not recognize the +# file as a good configuration file when no variable in it. +dummy: + +# You can override vars by using host or group vars + +########### +# GENERAL # +########### + +#fetch_directory: fetch/ + +## Ceph options +# +#cephx: true + +####################### +# Access type options # +####################### +# Enable NFS File access +#fsal_ceph: true + +# Enable NFS Object access +#fsal_rgw: false + +###################### +# NFS Ganesha Config # +###################### +#ceph_nfs_export_id: 20134 +#ceph_nfs_pseudo_path: "/ceph" +#ceph_nfs_protocols: "3,4" +#ceph_nfs_access_type: "RW" + + +################### +# CONFIG OVERRIDE # +################### + +# Ganesha configuration file override. +# This allows you to specify more configuration options +# using an INI style format. +# The following sections are supported: [global], [mon], [osd], [mds], [rgw] +# +# Example: +# ceph_conf_overrides: +# global: +# foo: 1234 +# bar: 5678 +# +#ganesha_conf_overrides: {} + +########## +# DOCKER # +########## + +#nfs_containerized_deployment: false +#nfs_containerized_deployment_with_kv: false +#kv_type: etcd +#kv_endpoint: 127.0.0.1 +#ceph_nfs_docker_username: ceph +#ceph_nfs_docker_imagename: ganesha +#ceph_nfs_docker_extra_env: "GANESHA_EPOCH={{ ganesha_epoch }}" # comma separated variables +#ceph_docker_on_openstack: false diff --git a/localrepo-site.yml.sample b/localrepo-site.yml.sample index ce7d6755c..d7fdf8320 100644 --- a/localrepo-site.yml.sample +++ b/localrepo-site.yml.sample @@ -44,6 +44,11 @@ roles: - ceph-rgw +- hosts: nfss + become: True + roles: + - ceph-nfs + - hosts: restapis become: True roles: diff --git a/purge-cluster.yml b/purge-cluster.yml index fe45002f2..37333b344 100644 --- a/purge-cluster.yml +++ b/purge-cluster.yml @@ -36,6 +36,7 @@ - osds - mdss - rgws + - nfss become: yes @@ -44,6 +45,7 @@ mon_group_name: mons rgw_group_name: rgws mds_group_name: mdss + nfs_group_name: nfss rbdmirror_group_name: rbdmirrors # When set to true both groups of packages are purged. @@ -159,6 +161,15 @@ systemd_unit_files.stdout != "0" and rgw_group_name in group_names + - name: stop ceph nfss with systemd + service: + name: nfs-ganesha + state: stopped + when: + ansible_os_family == 'RedHat' and + systemd_unit_files.stdout != "0" and + nfs_group_name in group_names + - name: stop ceph rbd mirror with systemd service: name: ceph-rbd-mirror@admin.service @@ -196,6 +207,12 @@ ansible_os_family == 'RedHat' and rgw_group_name in group_names + - name: stop ceph nfss + shell: "service nfs-ganesha status ; if [ $? == 0 ] ; then service nfs-ganesha stop ; else echo ; fi" + when: + ansible_os_family == 'RedHat' and + nfs_group_name in group_names + # Ubuntu 14.04 - name: stop ceph osds on ubuntu shell: | @@ -229,6 +246,13 @@ ansible_distribution == 'Ubuntu' and rgw_group_name in group_names + - name: stop ceph nfss on ubuntu + command: initctl stop nfs-ganesha + failed_when: false + when: + ansible_distribution == 'Ubuntu' and + nfs_group_name in group_names + - name: stop ceph rbd mirror on ubuntu command: initctl stop ceph-rbd-mirorr cluster={{ cluster }} id=admin failed_when: false diff --git a/roles/ceph-common/defaults/main.yml b/roles/ceph-common/defaults/main.yml index a8d135437..7103d525c 100644 --- a/roles/ceph-common/defaults/main.yml +++ b/roles/ceph-common/defaults/main.yml @@ -16,6 +16,7 @@ mon_group_name: mons osd_group_name: osds rgw_group_name: rgws mds_group_name: mdss +nfs_group_name: nfss restapi_group_name: restapis rbdmirror_group_name: rbdmirrors client_group_name: clients diff --git a/roles/ceph-common/handlers/main.yml b/roles/ceph-common/handlers/main.yml index 895d4af6a..a05397f71 100644 --- a/roles/ceph-common/handlers/main.yml +++ b/roles/ceph-common/handlers/main.yml @@ -139,3 +139,10 @@ when: - ansible_os_family == 'RedHat' - rgw_group_name in group_names + +- name: restart ceph nfss + service: + name: nfs-ganesha + state: restarted + when: + - nfs_group_name in group_names diff --git a/roles/ceph-common/tasks/checks/check_firewall.yml b/roles/ceph-common/tasks/checks/check_firewall.yml index 3880c6a1b..7eb493a1b 100644 --- a/roles/ceph-common/tasks/checks/check_firewall.yml +++ b/roles/ceph-common/tasks/checks/check_firewall.yml @@ -80,3 +80,20 @@ - rgw_group_name in group_names - rgwportstate.rc == 0 - nmapexist.rc == 0 + +- name: check if NFS ports are not filtered + local_action: shell set -o pipefail && nmap -p 111,2049 {{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }} | grep -sqo -e filtered -e '0 hosts up' + changed_when: false + failed_when: false + register: nfsportstate + when: + - nfs_group_name in group_names + - nmapexist.rc == 0 + +- name: fail if NFS ports are filtered + fail: + msg: "Please allow ports 111 and 2049 on your firewall" + when: + - nfs_group_name in group_names + - nfsportstate.rc == 0 + - nmapexist.rc == 0 diff --git a/roles/ceph-common/tasks/installs/install_on_debian.yml b/roles/ceph-common/tasks/installs/install_on_debian.yml index 858a748f5..a15b6ec75 100644 --- a/roles/ceph-common/tasks/installs/install_on_debian.yml +++ b/roles/ceph-common/tasks/installs/install_on_debian.yml @@ -38,3 +38,10 @@ state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" default_release: "{{ ceph_stable_release_uca | default(ansible_distribution_release) }}{{ '-backports' if ceph_origin == 'distro' and ceph_use_distro_backports else ''}}" when: mds_group_name in group_names + +- name: install NFS gateway + apt: + pkg: nfs-ganesha + state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" + update_cache: yes + when: nfs_group_name in group_names diff --git a/roles/ceph-common/tasks/installs/install_on_redhat.yml b/roles/ceph-common/tasks/installs/install_on_redhat.yml index 3e5e91f32..0ec74deae 100644 --- a/roles/ceph-common/tasks/installs/install_on_redhat.yml +++ b/roles/ceph-common/tasks/installs/install_on_redhat.yml @@ -171,3 +171,19 @@ when: - rgw_group_name in group_names - ansible_pkg_mgr == "dnf" + +- name: install NFS gateway + yum: + name: nfs-ganesha-ceph + state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" + when: + - nfs_group_name in group_names + - ansible_pkg_mgr == "yum" + +- name: install NFS gateway + dnf: + name: nfs-ganesha-ceph + state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" + when: + - nfs_group_name in group_names + - ansible_pkg_mgr == "dnf" diff --git a/roles/ceph-common/tasks/installs/install_rh_storage_on_debian.yml b/roles/ceph-common/tasks/installs/install_rh_storage_on_debian.yml index e123f9d46..8bc5452a9 100644 --- a/roles/ceph-common/tasks/installs/install_rh_storage_on_debian.yml +++ b/roles/ceph-common/tasks/installs/install_rh_storage_on_debian.yml @@ -74,3 +74,9 @@ pkg: ceph-common state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" when: client_group_name in group_names + +- name: install red hat storage NFS gateway + apt: + name: nfs-ganesha + state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" + when: nfs_group_name in group_names diff --git a/roles/ceph-common/tasks/installs/install_rh_storage_on_redhat.yml b/roles/ceph-common/tasks/installs/install_rh_storage_on_redhat.yml index 050def2dd..dfdfba574 100644 --- a/roles/ceph-common/tasks/installs/install_rh_storage_on_redhat.yml +++ b/roles/ceph-common/tasks/installs/install_rh_storage_on_redhat.yml @@ -65,3 +65,10 @@ state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" when: - rgw_group_name in group_names + +- name: install NFS gateway + yum: + name: nfs-ganesha-ceph + state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}" + when: + - nfs_group_name in group_names diff --git a/roles/ceph-common/tasks/main.yml b/roles/ceph-common/tasks/main.yml index 0df9ea79c..8bc7c9ca5 100644 --- a/roles/ceph-common/tasks/main.yml +++ b/roles/ceph-common/tasks/main.yml @@ -217,6 +217,7 @@ - restart ceph rgws on ubuntu - restart ceph rgws on red hat - restart ceph rgws with systemd + - restart ceph nfss - name: create rbd client directory file: diff --git a/roles/ceph-common/templates/ganesha.conf.j2 b/roles/ceph-common/templates/ganesha.conf.j2 new file mode 100644 index 000000000..ab64ea6a3 --- /dev/null +++ b/roles/ceph-common/templates/ganesha.conf.j2 @@ -0,0 +1,23 @@ +#jinja2: trim_blocks: "true", lstrip_blocks: "true" +# {{ ansible_managed }} + +EXPORT +{ + Export_ID={{ ceph_nfs_export_id }}; + + Path = "/"; + + Pseudo = {{ ceph_nfs_pseudo_path }}; + + Access_Type = {{ ceph_nfs_access_type }}; + + NFS_Protocols = {{ ceph_nfs_protocols }}; + + Transport_Protocols = TCP; + + Sectype = sys,krb5,krb5i,krb5p; + + FSAL { + Name = CEPH; + } +} diff --git a/roles/ceph-nfs/LICENSE b/roles/ceph-nfs/LICENSE new file mode 100644 index 000000000..4953f91ef --- /dev/null +++ b/roles/ceph-nfs/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2016] [Red Hat, Inc.] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/roles/ceph-nfs/README.md b/roles/ceph-nfs/README.md new file mode 100644 index 000000000..1c7b65300 --- /dev/null +++ b/roles/ceph-nfs/README.md @@ -0,0 +1,46 @@ +# Ansible role: Ceph NFS Gateway + +This role bootstraps Ceph NFS Gateway(s). +It can bootstrap dockerized Ceph NFS Gateway(s). NFS support is provided by +the NFS Ganesha project. + +It can provide one or both of NFS File access (requires at least one ceph-mds +role) or NFS Object access (requires at least one ceph-rgw role). + +# Requirements + +Nothing, it runs out of the box. + +# Role variables + +Have a look at: `defaults/main.yml`. + +## Mandatory variables + +None. + +# Dependencies + +The role `ceph.ceph-common` must be installed. + +# Example Playbook + +``` +- hosts: servers + remote_user: ubuntu + roles: + - { role: ceph.ceph-nfs } +``` + +# Contribution + +**THIS REPOSITORY DOES NOT ACCEPT PULL REQUESTS** +**PULL REQUESTS MUST GO THROUGH [CEPH-ANSIBLE](https://github.com/ceph/ceph-ansible)** + +# License + +Apache + +# Author Information + +This role was created by [Daniel Gryniewicz](http://redhat.com/). diff --git a/roles/ceph-nfs/defaults/main.yml b/roles/ceph-nfs/defaults/main.yml new file mode 100644 index 000000000..1c725c1ec --- /dev/null +++ b/roles/ceph-nfs/defaults/main.yml @@ -0,0 +1,60 @@ +--- +# You can override vars by using host or group vars + +########### +# GENERAL # +########### + +fetch_directory: fetch/ + +## Ceph options +# +cephx: true + +####################### +# Access type options # +####################### +# Enable NFS File access +fsal_ceph: true + +# Enable NFS Object access +fsal_rgw: false + +###################### +# NFS Ganesha Config # +###################### +ceph_nfs_export_id: 20134 +ceph_nfs_pseudo_path: "/ceph" +ceph_nfs_protocols: "3,4" +ceph_nfs_access_type: "RW" + + +################### +# CONFIG OVERRIDE # +################### + +# Ganesha configuration file override. +# This allows you to specify more configuration options +# using an INI style format. +# The following sections are supported: [global], [mon], [osd], [mds], [rgw] +# +# Example: +# ceph_conf_overrides: +# global: +# foo: 1234 +# bar: 5678 +# +ganesha_conf_overrides: {} + +########## +# DOCKER # +########## + +nfs_containerized_deployment: false +nfs_containerized_deployment_with_kv: false +kv_type: etcd +kv_endpoint: 127.0.0.1 +ceph_nfs_docker_username: ceph +ceph_nfs_docker_imagename: ganesha +#ceph_nfs_docker_extra_env: "GANESHA_EPOCH={{ ganesha_epoch }}" # comma separated variables +ceph_docker_on_openstack: false diff --git a/roles/ceph-nfs/meta/main.yml b/roles/ceph-nfs/meta/main.yml new file mode 100644 index 000000000..800a2589a --- /dev/null +++ b/roles/ceph-nfs/meta/main.yml @@ -0,0 +1,14 @@ +--- +galaxy_info: + author: Daniel Gryniewicz + description: Installs Ceph NFS Gateway + license: Apache + min_ansible_version: 1.7 + platforms: + - name: Ubuntu + versions: + - trusty + categories: + - system +dependencies: + - { role: ceph.ceph-common, when: not nfs_containerized_deployment } diff --git a/roles/ceph-nfs/tasks/docker/checks.yml b/roles/ceph-nfs/tasks/docker/checks.yml new file mode 100644 index 000000000..5559e7f4a --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/checks.yml @@ -0,0 +1,25 @@ +--- +- name: set config and keys paths + set_fact: + ceph_config_keys: + - /etc/ceph/ceph.client.admin.keyring + - /etc/ceph/ceph.conf + - /etc/ceph/monmap + - /etc/ceph/ceph.mon.keyring + - /etc/ganesha/ganesha.conf + +- name: stat for ceph config and keys + stat: + path: "{{ item }}" + with_items: ceph_config_keys + changed_when: false + failed_when: false + register: statleftover + +- name: fail if we find existing cluster files + fail: + msg: "looks like no cluster is running but ceph files are present, please remove them" + with_together: + - ceph_config_keys + - statleftover.results + when: item.1.stat.exists == true diff --git a/roles/ceph-nfs/tasks/docker/copy_configs.yml b/roles/ceph-nfs/tasks/docker/copy_configs.yml new file mode 100644 index 000000000..f2ba50e81 --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/copy_configs.yml @@ -0,0 +1,10 @@ +--- +- name: push ceph files to the ansible server + fetch: + src: "{{ item.0 }}" + dest: "{{ fetch_directory }}/docker_mon_files/{{ item.0 }}" + flat: yes + with_together: + - ceph_config_keys + - statconfig.results + when: item.1.stat.exists == false diff --git a/roles/ceph-nfs/tasks/docker/create_configs.yml b/roles/ceph-nfs/tasks/docker/create_configs.yml new file mode 100644 index 000000000..3a9b51ccc --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/create_configs.yml @@ -0,0 +1,19 @@ +--- +- name: create ganesha conf directory + file: + path: /etc/ganesha + state: directory + owner: root + group: root + mode: 0644 + +- name: generate ganesha configuration file + action: config_template + args: + src: "{{ playbook_dir }}/roles/ceph-common/templates/ganesha.conf.j2" + dest: /etc/ganesha/ganesha.conf + owner: "root" + group: "root" + mode: "0644" + config_overrides: "{{ ganesha_conf_overrides }}" + config_type: ini diff --git a/roles/ceph-nfs/tasks/docker/dirs_permissions.yml b/roles/ceph-nfs/tasks/docker/dirs_permissions.yml new file mode 100644 index 000000000..b58687d0a --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/dirs_permissions.yml @@ -0,0 +1,49 @@ +--- +# NOTE (leseb): we can not use docker inspect with 'format filed' because of +# https://github.com/ansible/ansible/issues/10156 +- name: inspect ceph version + shell: docker inspect "{{ ceph_nfs_docker_username }}/{{ ceph_nfs_docker_imagename }}" | awk -F '=' '/CEPH_VERSION/ { gsub ("\",", "", $2); print $2 }' | uniq + changed_when: false + failed_when: false + run_once: true + register: ceph_version + +- set_fact: + after_hammer=True + when: ceph_version.stdout not in ['firefly','giant', 'hammer'] + +- name: create bootstrap directories (for or before hammer) + file: + path: "{{ item }}" + state: directory + owner: root + group: root + mode: "0755" + with_items: + - /etc/ceph/ + - /var/lib/ceph/ + when: not after_hammer + +- name: create bootstrap directories (after hammer) + file: + path: "{{ item }}" + state: directory + owner: "64045" + group: "64045" + mode: "0755" + with_items: + - /etc/ceph/ + - /var/lib/ceph/ + when: after_hammer + +- name: create ganesha directories + file: + path: "{{ item }}" + state: directory + owner: root + group: root + mode: "0755" + with_items: + - /etc/ganesha/ + - /var/lib/nfs/ganesha + - /var/run/ganesha diff --git a/roles/ceph-nfs/tasks/docker/fetch_configs.yml b/roles/ceph-nfs/tasks/docker/fetch_configs.yml new file mode 100644 index 000000000..bd7f746ae --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/fetch_configs.yml @@ -0,0 +1,27 @@ +--- +- name: set config and keys paths + set_fact: + ceph_config_keys: + - /etc/ceph/ceph.conf + - /etc/ganesha/ganesha.conf + +- name: stat for config and keys + local_action: stat path={{ fetch_directory }}/docker_mon_files/{{ item }} + with_items: ceph_config_keys + changed_when: false + become: false + failed_when: false + register: statconfig + +- name: try to fetch config and keys + copy: + src: "{{ fetch_directory }}/docker_mon_files/{{ item.0 }}" + dest: "{{ item.0 }}" + owner: root + group: root + mode: 0644 + changed_when: false + with_together: + - ceph_config_keys + - statconfig.results + when: item.1.stat.exists == true diff --git a/roles/ceph-nfs/tasks/docker/main.yml b/roles/ceph-nfs/tasks/docker/main.yml new file mode 100644 index 000000000..e2e000e10 --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/main.yml @@ -0,0 +1,45 @@ +--- +- name: check if a cluster is already running + shell: "docker ps | grep -sq '{{ceph_nfs_docker_username}}/{{ceph_nfs_docker_imagename}}'" + register: ceph_health + changed_when: false + failed_when: false + +- name: check if it is Atomic host + stat: path=/run/ostree-booted + register: stat_ostree + +- name: set fact for using Atomic host + set_fact: + is_atomic: '{{ stat_ostree.stat.exists }}' + +- include: checks.yml + when: + ceph_health.rc != 0 and + not mon_containerized_deployment_with_kv + +- include: pre_requisite.yml + +- include: "{{ playbook_dir }}/roles/ceph-common/tasks/docker/fetch_image.yml" + vars: + ceph_docker_username: '{{ ceph_nfs_docker_username}}' + ceph_docker_imagename: '{{ ceph_nfs_docker_imagename}}' + +- include: dirs_permissions.yml + +# let the first ganesha create configs and keyrings +- include: create_configs.yml + when: + inventory_hostname == groups.nfss[0] and + mon_containerized_default_ceph_conf_with_kv + +- include: fetch_configs.yml + when: not mon_containerized_deployment_with_kv + +- include: selinux.yml + when: ansible_os_family == 'RedHat' + +- include: start_docker_nfs.yml + +- include: copy_configs.yml + when: not mon_containerized_deployment_with_kv diff --git a/roles/ceph-nfs/tasks/docker/pre_requisite.yml b/roles/ceph-nfs/tasks/docker/pre_requisite.yml new file mode 100644 index 000000000..f2d9ecd70 --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/pre_requisite.yml @@ -0,0 +1,82 @@ +--- +- name: install pip and docker on ubuntu + apt: + name: "{{ item }}" + state: present + update_cache: yes + with_items: + - python-pip + - docker + - docker.io + when: ansible_distribution == 'Ubuntu' + tags: + with_pkg + +- name: install pip and docker on debian + apt: + name: "{{ item }}" + state: present + update_cache: yes + with_items: + - python-pip + - docker-engine + when: ansible_distribution == 'Debian' + tags: + with_pkg + +- name: install pip and docker on redhat + yum: + name: "{{ item }}" + state: present + with_items: + - python-pip + - docker-engine + when: + ansible_os_family == 'RedHat' and + ansible_pkg_mgr == "yum" + tags: + with_pkg + +- name: install pip and docker on redhat + dnf: + name: "{{ item }}" + state: present + with_items: + - python-pip + - docker-engine + when: + ansible_os_family == 'RedHat' and + ansible_pkg_mgr == "dnf" + tags: + with_pkg + +- name: install epel-release on redhat + yum: + name: epel-release + state: present + when: ansible_os_family == 'RedHat' + tags: + with_pkg + +# NOTE (jimcurtis): need at least version 1.9.0 of six or we get: +# re:NameError: global name 'DEFAULT_DOCKER_API_VERSION' is not defined +- name: install six + pip: + name: six + version: 1.9.0 + tags: + with_pkg + +- name: pause after docker install before starting (on openstack vms) + pause: seconds=5 + when: ceph_docker_on_openstack + tags: + with_pkg + +- name: start docker service + service: + name: docker + state: started + enabled: yes + tags: + with_pkg diff --git a/roles/ceph-nfs/tasks/docker/selinux.yml b/roles/ceph-nfs/tasks/docker/selinux.yml new file mode 100644 index 000000000..6d8395832 --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/selinux.yml @@ -0,0 +1,16 @@ +--- +- name: check if selinux is enabled + command: getenforce + register: sestatus + changed_when: false + +- name: set selinux permissions + shell: chcon -Rt svirt_sandbox_file_t {{ item }} + with_items: + - /etc/ceph + - /etc/ganesha + - /var/lib/ceph + - /var/lib/nfs/ganesha + - /var/run/ganesha + changed_when: false + when: sestatus.stdout != 'Disabled' diff --git a/roles/ceph-nfs/tasks/docker/start_docker_nfs.yml b/roles/ceph-nfs/tasks/docker/start_docker_nfs.yml new file mode 100644 index 000000000..78d3f166f --- /dev/null +++ b/roles/ceph-nfs/tasks/docker/start_docker_nfs.yml @@ -0,0 +1,82 @@ +--- +# Use systemd to manage container on Atomic host and CoreOS +- name: generate systemd unit file + become: true + template: + src: "{{ playbook_dir }}/roles/ceph-nfs/templates/ceph-nfs.service.j2" + dest: /var/lib/nfs/ganesha/ceph-nfs@.service + owner: "root" + group: "root" + mode: "0644" + when: + is_atomic or + ansible_os_family == 'CoreOS' + +- name: link systemd unit file for NFS instance + file: + src: /var/lib/nfs/ganesha/ceph-nfs@.service + dest: /etc/systemd/system/multi-user.target.wants/ceph-nfs@{{ ansible_hostname }}.service + state: link + when: + is_atomic or + ansible_os_family == 'CoreOS' + +- name: enable systemd unit file for NFS instance + shell: systemctl enable /etc/systemd/system/multi-user.target.wants/ceph-nfs@{{ ansible_hostname }}.service + failed_when: false + changed_when: false + when: + is_atomic or + ansible_os_family == 'CoreOS' + +- name: reload systemd unit files + shell: systemctl daemon-reload + changed_when: false + failed_when: false + when: + is_atomic or + ansible_os_family == 'CoreOS' + +- name: systemd start NFS container + service: + name: ceph-nfs@{{ ansible_hostname }} + state: started + enabled: yes + changed_when: false + when: + is_atomic or + ansible_os_family == 'CoreOS' + +- name: wait for ceph.conf exists + wait_for: + path: /etc/ceph/ceph.conf + when: is_atomic + +- name: run the ceph NFS docker image + docker: + image: "{{ ceph_nfs_docker_username }}/{{ ceph_nfs_docker_imagename }}" + name: "{{ ansible_hostname }}" + net: "host" + state: "running" + privileged: true + ports: "{{ ceph_nfs_port }}:{{ ceph_nfs_port }},111:111" + env: "CEPH_DAEMON=NFS,CEPH_PUBLIC_NETWORK={{ ceph_nfs_docker_subnet }},{{ ceph_nfs_extra_envs }}" + volumes: "/etc/ceph:/etc/ceph,/etc/ganesha:/etc/ganesha" + when: + not is_atomic and + ansible_os_family != 'CoreOS' and + not mon_containerized_deployment_with_kv + +- name: run the ceph NFS docker image with kv + docker: + image: "{{ ceph_nfs_docker_username }}/{{ ceph_nfs_docker_imagename }}" + name: "{{ ansible_hostname }}" + net: "host" + state: "running" + privileged: true + env: "CEPH_DAEMON=NFS,CEPH_PUBLIC_NETWORK={{ ceph_nfs_docker_subnet }},{{ ceph_nfs_extra_envs }}" + volumes: "/etc/ganesha:/etc/ganesha" + when: + not is_atomic and + ansible_os_family != 'CoreOS' and + mon_containerized_deployment_with_kv diff --git a/roles/ceph-nfs/tasks/main.yml b/roles/ceph-nfs/tasks/main.yml new file mode 100644 index 000000000..7c2539de3 --- /dev/null +++ b/roles/ceph-nfs/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- include: pre_requisite.yml + when: not nfs_containerized_deployment + +- include: ./docker/main.yml + when: nfs_containerized_deployment diff --git a/roles/ceph-nfs/tasks/pre_requisite.yml b/roles/ceph-nfs/tasks/pre_requisite.yml new file mode 100644 index 000000000..6119cd40b --- /dev/null +++ b/roles/ceph-nfs/tasks/pre_requisite.yml @@ -0,0 +1,17 @@ +--- +- name: create NFS gateway directories + file: + path: "{{ item }}" + state: directory + owner: "{{ dir_owner }}" + group: "{{ dir_group }}" + mode: "{{ dir_mode }}" + with_items: + - /var/lib/nfs/ganesha + - /var/run/ganesha + +- name: start NFS gateway service + service: + name: nfs-ganesha + state: started + enabled: yes diff --git a/roles/ceph-nfs/templates/ceph-nfs.service.j2 b/roles/ceph-nfs/templates/ceph-nfs.service.j2 new file mode 100644 index 000000000..1552cad5d --- /dev/null +++ b/roles/ceph-nfs/templates/ceph-nfs.service.j2 @@ -0,0 +1,30 @@ +[Unit] +Description=NFS-Ganesha file server +Documentation=http://github.com/nfs-ganesha/nfs-ganesha/wiki +After=docker.service + +[Service] +EnvironmentFile=-/etc/environment +ExecStartPre=-/usr/bin/docker rm %i +ExecStartPre=/usr/bin/mkdir -p /etc/ceph /etc/ganesha /var/lib/nfs/ganesha +ExecStart=/usr/bin/docker run --rm --name %i --net=host \ + {% if not mon_containerized_deployment_with_kv -%} + -v /etc/ceph:/etc/ceph \ + -v /etc/ganesha:/etc/ganesha \ + {% else -%} + -e KV_TYPE={{kv_type}} \ + -e KV_IP={{kv_endpoint}}\ + {% endif -%} + --privileged \ + -e CEPH_DAEMON=NFS \ + -e CEPH_PUBLIC_NETWORK={{ ceph_mon_docker_subnet }} \ + --name={{ ansible_hostname }} \ + {{ ceph_nfs_docker_username }}/{{ ceph_nfs_docker_imagename }} +ExecStopPost=-/usr/bin/docker stop %i +Restart=always +RestartSec=10s +TimeoutStartSec=120 +TimeoutStopSec=15 + +[Install] +WantedBy=multi-user.target diff --git a/site-docker.yml.sample b/site-docker.yml.sample index 4cba5a799..eeef9391a 100644 --- a/site-docker.yml.sample +++ b/site-docker.yml.sample @@ -22,6 +22,11 @@ roles: - ceph-rgw +- hosts: nfss + become: True + roles: + - ceph-nfs + - hosts: restapis become: True roles: diff --git a/site.yml.sample b/site.yml.sample index 3945ea1ef..e8ab7bdfa 100644 --- a/site.yml.sample +++ b/site.yml.sample @@ -26,6 +26,11 @@ roles: - ceph-rgw +- hosts: nfss + become: True + roles: + - ceph-nfs + - hosts: restapis become: True roles: diff --git a/vagrant_variables.yml.atomic b/vagrant_variables.yml.atomic index eda2b81c4..e0a0e9824 100644 --- a/vagrant_variables.yml.atomic +++ b/vagrant_variables.yml.atomic @@ -7,6 +7,7 @@ mon_vms: 1 osd_vms: 1 mds_vms: 0 rgw_vms: 0 +nfs_vms: 0 client_vms: 0 # Deploy RESTAPI on each of the Monitors diff --git a/vagrant_variables.yml.openstack b/vagrant_variables.yml.openstack index 81c45359c..82eb5e378 100644 --- a/vagrant_variables.yml.openstack +++ b/vagrant_variables.yml.openstack @@ -8,6 +8,7 @@ mon_vms: 1 osd_vms: 1 mds_vms: 0 rgw_vms: 0 +nfs_vms: 0 client_vms: 0 # Deploy RESTAPI on each of the Monitors diff --git a/vagrant_variables.yml.sample b/vagrant_variables.yml.sample index 7232fe940..b971cec0e 100644 --- a/vagrant_variables.yml.sample +++ b/vagrant_variables.yml.sample @@ -8,6 +8,7 @@ mon_vms: 3 osd_vms: 3 mds_vms: 0 rgw_vms: 0 +nfs_vms: 0 client_vms: 0 # Deploy RESTAPI on each of the Monitors