mirror of https://github.com/ceph/ceph-ansible.git
resync ceph-iscsi-gw with old upstream
Taken from https://github.com/pcuzner/ceph-iscsi-ansible/tree/tcmu-fixes Closes: https://bugzilla.redhat.com/show_bug.cgi?id=1454945 and https://bugzilla.redhat.com/show_bug.cgi?id=1484083 Signed-off-by: Sébastien Han <seb@redhat.com>pull/1747/head
parent
358b3b588d
commit
aa364264cd
|
@ -57,7 +57,7 @@ ansible_provision = proc do |ansible|
|
||||||
'nfss' => (0..NNFSS - 1).map { |j| "#{LABEL_PREFIX}nfs#{j}" },
|
'nfss' => (0..NNFSS - 1).map { |j| "#{LABEL_PREFIX}nfs#{j}" },
|
||||||
'rbd_mirrors' => (0..NRBD_MIRRORS - 1).map { |j| "#{LABEL_PREFIX}rbd_mirror#{j}" },
|
'rbd_mirrors' => (0..NRBD_MIRRORS - 1).map { |j| "#{LABEL_PREFIX}rbd_mirror#{j}" },
|
||||||
'clients' => (0..CLIENTS - 1).map { |j| "#{LABEL_PREFIX}client#{j}" },
|
'clients' => (0..CLIENTS - 1).map { |j| "#{LABEL_PREFIX}client#{j}" },
|
||||||
'iscsi_gw' => (0..NISCSI_GWS - 1).map { |j| "#{LABEL_PREFIX}iscsi_gw#{j}" },
|
'iscsi_gws' => (0..NISCSI_GWS - 1).map { |j| "#{LABEL_PREFIX}iscsi_gw#{j}" },
|
||||||
'mgrs' => (0..MGRS - 1).map { |j| "#{LABEL_PREFIX}mgr#{j}" }
|
'mgrs' => (0..MGRS - 1).map { |j| "#{LABEL_PREFIX}mgr#{j}" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +397,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
end
|
end
|
||||||
|
|
||||||
(0..NISCSI_GWS - 1).each do |i|
|
(0..NISCSI_GWS - 1).each do |i|
|
||||||
config.vm.define "#{LABEL_PREFIX}iscsi_gw#{i}" do |iscsi_gw|
|
config.vm.define "#{LABEL_PREFIX}iscsi-gw#{i}" do |iscsi_gw|
|
||||||
iscsi_gw.vm.hostname = "#{LABEL_PREFIX}iscsi-gw#{i}"
|
iscsi_gw.vm.hostname = "#{LABEL_PREFIX}iscsi-gw#{i}"
|
||||||
if ASSIGN_STATIC_IP
|
if ASSIGN_STATIC_IP
|
||||||
iscsi_gw.vm.network :private_network,
|
iscsi_gw.vm.network :private_network,
|
||||||
|
@ -420,7 +420,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
end
|
end
|
||||||
# Parallels
|
# Parallels
|
||||||
iscsi_gw.vm.provider "parallels" do |prl|
|
iscsi_gw.vm.provider "parallels" do |prl|
|
||||||
prl.name = "ceph-iscsi-gw#{i}"
|
prl.name = "iscsi-gw#{i}"
|
||||||
prl.memory = "#{MEMORY}"
|
prl.memory = "#{MEMORY}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -46,13 +46,6 @@ pushd %{buildroot}%{_datarootdir}/ceph-ansible
|
||||||
rm -r infrastructure-playbooks/untested-by-ci
|
rm -r infrastructure-playbooks/untested-by-ci
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# Strip iscsi files.
|
|
||||||
# These are just placeholders until ceph-iscsi-gw can merge into
|
|
||||||
# ceph-ansible. (See https://bugzilla.redhat.com/1454945).
|
|
||||||
pushd %{buildroot}%{_datarootdir}/ceph-ansible
|
|
||||||
rm -r roles/ceph-iscsi-gw
|
|
||||||
popd
|
|
||||||
|
|
||||||
%check
|
%check
|
||||||
# Borrowed from upstream's .travis.yml:
|
# Borrowed from upstream's .travis.yml:
|
||||||
ansible-playbook -i dummy-ansible-hosts test.yml --syntax-check
|
ansible-playbook -i dummy-ansible-hosts test.yml --syntax-check
|
||||||
|
|
|
@ -51,7 +51,7 @@ dummy:
|
||||||
#restapi_group_name: restapis
|
#restapi_group_name: restapis
|
||||||
#rbdmirror_group_name: rbdmirrors
|
#rbdmirror_group_name: rbdmirrors
|
||||||
#client_group_name: clients
|
#client_group_name: clients
|
||||||
#iscsi_group_name: iscsigws
|
#iscsi_gw_group_name: iscsi_gws
|
||||||
#mgr_group_name: mgrs
|
#mgr_group_name: mgrs
|
||||||
|
|
||||||
# If check_firewall is true, then ansible will try to determine if the
|
# If check_firewall is true, then ansible will try to determine if the
|
||||||
|
@ -205,6 +205,8 @@ dummy:
|
||||||
# flavors so far include: ceph_master, ceph_jewel, ceph_kraken, ceph_luminous
|
# flavors so far include: ceph_master, ceph_jewel, ceph_kraken, ceph_luminous
|
||||||
#nfs_ganesha_flavor: "ceph_master"
|
#nfs_ganesha_flavor: "ceph_master"
|
||||||
|
|
||||||
|
#ceph_iscsi_config_dev: true # special repo for deploying iSCSI gateways
|
||||||
|
|
||||||
|
|
||||||
# REPOSITORY: CUSTOM
|
# REPOSITORY: CUSTOM
|
||||||
#
|
#
|
||||||
|
|
|
@ -7,4 +7,45 @@
|
||||||
# file as a good configuration file when no variable in it.
|
# file as a good configuration file when no variable in it.
|
||||||
dummy:
|
dummy:
|
||||||
|
|
||||||
|
# You can override vars by using host or group vars
|
||||||
|
|
||||||
|
# Specify the iqn for ALL gateways. This iqn is shared across the gateways, so an iscsi
|
||||||
|
# client sees the gateway group as a single storage subsystem.
|
||||||
|
#gateway_iqn: "iqn.2003-01.com.redhat.iscsi-gw:ceph-igw"
|
||||||
|
|
||||||
|
# gateway_ip_list provides a list of the IP Addrresses - one per gateway - that will be used
|
||||||
|
# as an iscsi target portal ip. The list must be comma separated - and the order determines
|
||||||
|
# the sequence of TPG's within the iscsi target across each gateway. Once set, additional
|
||||||
|
# gateways can be added, but the order must *not* be changed.
|
||||||
|
#gateway_ip_list: "192.168.122.101,192.168.122.102,192.168.122.103"
|
||||||
|
|
||||||
|
# rbd_devices defines the images that should be created and exported from the iscsi gateways.
|
||||||
|
# If the rbd does not exist, it will be created for you. In addition you may increase the
|
||||||
|
# size of rbd's by changing the size parameter and rerunning the playbook. A size value lower
|
||||||
|
# than the current size of the rbd is ignored.
|
||||||
|
#
|
||||||
|
# the 'host' parameter defines which of the gateway nodes should handle the physical
|
||||||
|
# allocation/expansion or removal of the rbd
|
||||||
|
# to remove an image, simply use a state of 'absent'. This will first check the rbd is not allocated
|
||||||
|
# to any client, and the remove it from LIO and then delete the rbd image
|
||||||
|
#
|
||||||
|
# NB. this variable definition can be commented out to bypass LUN management
|
||||||
|
#rbd_devices:
|
||||||
|
# - { pool: 'rbd', image: 'ansible1', size: '30G', host: 'ceph-1', state: 'present' }
|
||||||
|
# - { pool: 'rbd', image: 'ansible2', size: '15G', host: 'ceph-1', state: 'present' }
|
||||||
|
# - { pool: 'rbd', image: 'ansible3', size: '30G', host: 'ceph-1', state: 'present' }
|
||||||
|
# - { pool: 'rbd', image: 'ansible4', size: '50G', host: 'ceph-1', state: 'present' }
|
||||||
|
|
||||||
|
|
||||||
|
# client_connections defines the client ACL's to restrict client access to specific LUNs
|
||||||
|
# The settings are as follows;
|
||||||
|
# - image_list is a comma separated list of rbd images of the form <pool name>.<rbd_image_name>
|
||||||
|
# - chap supplies the user and password the client will use for authentication of the
|
||||||
|
# form <user>/<password>
|
||||||
|
# - status shows the intended state of this client definition - 'present' or 'absent'
|
||||||
|
#
|
||||||
|
# NB. this definition can be commented out to skip client (nodeACL) management
|
||||||
|
#client_connections:
|
||||||
|
# - { client: 'iqn.1994-05.com.redhat:rh7-iscsi-client', image_list: 'rbd.ansible1,rbd.ansible2', chap: 'rh7-iscsi-client/redhat', status: 'present' }
|
||||||
|
# - { client: 'iqn.1991-05.com.microsoft:w2k12r2', image_list: 'rbd.ansible4', chap: 'w2k12r2/microsoft_w2k12', status: 'absent' }
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ fetch_directory: ~/ceph-ansible-keys
|
||||||
#restapi_group_name: restapis
|
#restapi_group_name: restapis
|
||||||
#rbdmirror_group_name: rbdmirrors
|
#rbdmirror_group_name: rbdmirrors
|
||||||
#client_group_name: clients
|
#client_group_name: clients
|
||||||
#iscsi_group_name: iscsigws
|
#iscsi_gw_group_name: iscsi_gws
|
||||||
#mgr_group_name: mgrs
|
#mgr_group_name: mgrs
|
||||||
|
|
||||||
# If check_firewall is true, then ansible will try to determine if the
|
# If check_firewall is true, then ansible will try to determine if the
|
||||||
|
@ -205,6 +205,8 @@ ceph_repository: rhcs
|
||||||
# flavors so far include: ceph_master, ceph_jewel, ceph_kraken, ceph_luminous
|
# flavors so far include: ceph_master, ceph_jewel, ceph_kraken, ceph_luminous
|
||||||
#nfs_ganesha_flavor: "ceph_master"
|
#nfs_ganesha_flavor: "ceph_master"
|
||||||
|
|
||||||
|
#ceph_iscsi_config_dev: true # special repo for deploying iSCSI gateways
|
||||||
|
|
||||||
|
|
||||||
# REPOSITORY: CUSTOM
|
# REPOSITORY: CUSTOM
|
||||||
#
|
#
|
||||||
|
|
|
@ -426,7 +426,7 @@
|
||||||
hosts:
|
hosts:
|
||||||
- "{{ mon_group_name|default('mons') }}"
|
- "{{ mon_group_name|default('mons') }}"
|
||||||
|
|
||||||
gather_facts: false # Already gathered previously
|
gather_facts: false # already gathered previously
|
||||||
|
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
|
@ -453,6 +453,38 @@
|
||||||
path: /var/lib/ceph/
|
path: /var/lib/ceph/
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
|
- name: purge iscsi gateway(s)
|
||||||
|
|
||||||
|
vars:
|
||||||
|
igw_purge_type: all
|
||||||
|
|
||||||
|
hosts:
|
||||||
|
- "{{ iscsi_gw_group_name|default('iscsi-gw') }}"
|
||||||
|
|
||||||
|
gather_facts: false # already gathered previously
|
||||||
|
|
||||||
|
become: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: igw_purge | purging the gateway configuration
|
||||||
|
igw_purge:
|
||||||
|
mode: "gateway"
|
||||||
|
|
||||||
|
- name: igw_purge | deleting configured rbd devices
|
||||||
|
igw_purge:
|
||||||
|
mode: "disks"
|
||||||
|
when:
|
||||||
|
- igw_purge_type == 'all'
|
||||||
|
|
||||||
|
- name: restart rbd-target-gw daemons
|
||||||
|
service:
|
||||||
|
name: rbd-target-gw
|
||||||
|
state: restarted
|
||||||
|
when:
|
||||||
|
- ansible_service_mgr == 'systemd'
|
||||||
|
|
||||||
|
|
||||||
- name: final cleanup - check any running ceph, purge ceph packages, purge config and remove data
|
- name: final cleanup - check any running ceph, purge ceph packages, purge config and remove data
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_client
|
||||||
|
short_description: Manage iscsi gateway client definitions
|
||||||
|
description:
|
||||||
|
- This module calls the 'client' configuration management module installed
|
||||||
|
on the iscsi gateway node to handle the definition of iscsi clients on the
|
||||||
|
gateway(s). This definition will setup iscsi authentication (e.g. chap),
|
||||||
|
and mask the required rbd images to the client.
|
||||||
|
|
||||||
|
The 'client' configuration module is provided by ceph-iscsi-config
|
||||||
|
rpm which is installed on the gateway nodes.
|
||||||
|
|
||||||
|
To support module debugging, this module logs to
|
||||||
|
/var/log/ansible-module-igw_config.log on the target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
client_iqn:
|
||||||
|
description:
|
||||||
|
- iqn of the client machine which should be connected or removed from the
|
||||||
|
iscsi gateway environment
|
||||||
|
required: true
|
||||||
|
|
||||||
|
image_list:
|
||||||
|
description:
|
||||||
|
- comma separated string providing the rbd images that this
|
||||||
|
client definition should have. The rbd images provided must use the
|
||||||
|
following format <pool_name>.<rbd_image_name>
|
||||||
|
e.g. rbd.disk1,rbd.disk2
|
||||||
|
required: true
|
||||||
|
|
||||||
|
chap:
|
||||||
|
description:
|
||||||
|
- chap credentials for the client to authenticate to the gateways
|
||||||
|
to gain access to the exported rbds (LUNs). The credentials is a string
|
||||||
|
value of the form 'username/password'. The iscsi client must then use
|
||||||
|
these settings to gain access to any LUN resources.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- desired state for this client - absent or present
|
||||||
|
required: true
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
from ceph_iscsi_config.client import GWClient
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
|
||||||
|
# the main function is called ansible_main to allow the call stack
|
||||||
|
# to be checked to determine whether the call to the ceph_iscsi_config
|
||||||
|
# modules is from ansible or not
|
||||||
|
def ansible_main():
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
"client_iqn": {"required": True, "type": "str"},
|
||||||
|
"image_list": {"required": True, "type": "str"},
|
||||||
|
"chap": {"required": True, "type": "str"},
|
||||||
|
"state": {
|
||||||
|
"required": True,
|
||||||
|
"choices": ['present', 'absent'],
|
||||||
|
"type": "str"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
client_iqn = module.params['client_iqn']
|
||||||
|
|
||||||
|
if module.params['image_list']:
|
||||||
|
image_list = module.params['image_list'].split(',')
|
||||||
|
else:
|
||||||
|
image_list = []
|
||||||
|
|
||||||
|
chap = module.params['chap']
|
||||||
|
desired_state = module.params['state']
|
||||||
|
|
||||||
|
logger.info("START - Client configuration started : {}".format(client_iqn))
|
||||||
|
|
||||||
|
# The client is defined using the GWClient class. This class handles
|
||||||
|
# client attribute updates, rados configuration object updates and LIO
|
||||||
|
# settings. Since the logic is external to this custom module, clients
|
||||||
|
# can be created/deleted by other methods in the same manner.
|
||||||
|
client = GWClient(logger, client_iqn, image_list, chap)
|
||||||
|
if client.error:
|
||||||
|
module.fail_json(msg=client.error_msg)
|
||||||
|
|
||||||
|
client.manage(desired_state)
|
||||||
|
if client.error:
|
||||||
|
module.fail_json(msg=client.error_msg)
|
||||||
|
|
||||||
|
logger.info("END - Client configuration complete - {} "
|
||||||
|
"changes made".format(client.change_count))
|
||||||
|
|
||||||
|
changes_made = True if client.change_count > 0 else False
|
||||||
|
|
||||||
|
module.exit_json(changed=changes_made,
|
||||||
|
meta={"msg": "Client definition completed {} "
|
||||||
|
"changes made".format(client.change_count)})
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# initialise global variables used by all called modules
|
||||||
|
# e.g. ceph conffile, keyring etc
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_gateway
|
||||||
|
short_description: Manage the iscsi gateway definition
|
||||||
|
description:
|
||||||
|
- This module calls the 'gateway' configuration management module installed
|
||||||
|
on the iscsi gateway node(s) to handle the definition of iscsi gateways.
|
||||||
|
The module will configure;
|
||||||
|
* the iscsi target and target portal group (TPG)
|
||||||
|
* rbd maps to the gateway and registration of those rbds as LUNs to the
|
||||||
|
kernels LIO subsystem
|
||||||
|
|
||||||
|
The actual configuration modules are provided by ceph-iscsi-config rpm
|
||||||
|
which is installed on the gateway nodes.
|
||||||
|
|
||||||
|
To support module debugging, this module logs to
|
||||||
|
/var/log/ansible-module-igw_config.log on the target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
gateway_iqn:
|
||||||
|
description:
|
||||||
|
- iqn that all gateway nodes will use to present a common system image
|
||||||
|
name to iscsi clients
|
||||||
|
required: true
|
||||||
|
|
||||||
|
gateway_ip_list:
|
||||||
|
description:
|
||||||
|
- comma separated string providing the IP addresses that will be used
|
||||||
|
as iSCSI portal IPs to accept iscsi client connections. Each IP address
|
||||||
|
should equate to an IP on a gateway node - typically dedicated to iscsi
|
||||||
|
traffic. The order of the IP addresses determines the TPG sequence
|
||||||
|
within the target definition - so once defined, new gateways can be
|
||||||
|
added but *must* be added to the end of this list to preserve the tpg
|
||||||
|
sequence
|
||||||
|
|
||||||
|
e.g. 192.168.122.101,192.168.122.103
|
||||||
|
required: true
|
||||||
|
|
||||||
|
mode:
|
||||||
|
description:
|
||||||
|
- mode in which to run the gateway module. Two modes are supported
|
||||||
|
target ... define the iscsi target iqn, tpg's and portals
|
||||||
|
map ...... map luns to the tpg's, and also define the ALUA path setting
|
||||||
|
for each LUN (activeOptimized/activenonoptimized)
|
||||||
|
required: true
|
||||||
|
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
|
||||||
|
from ceph_iscsi_config.gateway import GWTarget
|
||||||
|
from ceph_iscsi_config.utils import valid_ip
|
||||||
|
|
||||||
|
|
||||||
|
# the main function is called ansible_main to allow the call stack
|
||||||
|
# to be checked to determine whether the call to the ceph_iscsi_config
|
||||||
|
# modules is from ansible or not
|
||||||
|
def ansible_main():
|
||||||
|
# Configures the gateway on the host. All images defined are added to
|
||||||
|
# the default tpg for later allocation to clients
|
||||||
|
fields = {"gateway_iqn": {"required": True, "type": "str"},
|
||||||
|
"gateway_ip_list": {"required": True}, # "type": "list"},
|
||||||
|
"mode": {
|
||||||
|
"required": True,
|
||||||
|
"choices": ['target', 'map']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
gateway_iqn = module.params['gateway_iqn']
|
||||||
|
gateway_ip_list = module.params['gateway_ip_list'].split(',')
|
||||||
|
mode = module.params['mode']
|
||||||
|
|
||||||
|
if not valid_ip(gateway_ip_list):
|
||||||
|
module.fail_json(msg="Invalid gateway IP address(es) provided - port "
|
||||||
|
"22 check failed ({})".format(gateway_ip_list))
|
||||||
|
|
||||||
|
logger.info("START - GATEWAY configuration started - mode {}".format(mode))
|
||||||
|
|
||||||
|
gateway = GWTarget(logger, gateway_iqn, gateway_ip_list)
|
||||||
|
if gateway.error:
|
||||||
|
logger.critical("(ansible_main) Gateway init failed - "
|
||||||
|
"{}".format(gateway.error_msg))
|
||||||
|
module.fail_json(msg="iSCSI gateway initialisation failed "
|
||||||
|
"({})".format(gateway.error_msg))
|
||||||
|
|
||||||
|
gateway.manage(mode)
|
||||||
|
|
||||||
|
if gateway.error:
|
||||||
|
logger.critical("(main) Gateway creation or load failed, "
|
||||||
|
"unable to continue")
|
||||||
|
module.fail_json(msg="iSCSI gateway creation/load failure "
|
||||||
|
"({})".format(gateway.error_msg))
|
||||||
|
|
||||||
|
|
||||||
|
logger.info("END - GATEWAY configuration complete")
|
||||||
|
module.exit_json(changed=gateway.changes_made,
|
||||||
|
meta={"msg": "Gateway setup complete"})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# initialise global variables used by all called modules
|
||||||
|
# e.g. ceph conffile, keyring etc
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -0,0 +1,166 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_lun
|
||||||
|
short_description: Manage ceph rbd images to present as iscsi LUNs to clients
|
||||||
|
description:
|
||||||
|
- This module calls the 'lun' configuration management module installed
|
||||||
|
on the iscsi gateway node(s). The lun module handles the creation and resize
|
||||||
|
of rbd images, and then maps these rbd devices to the gateway node(s) to be
|
||||||
|
exposed through the kernel's LIO target.
|
||||||
|
|
||||||
|
To support module debugging, this module logs to /var/log/ansible-module-igw_config.log
|
||||||
|
on the target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
pool:
|
||||||
|
description:
|
||||||
|
- The ceph pool where the image should exist or be created in.
|
||||||
|
|
||||||
|
NOTE - The pool *must* exist prior to the Ansible run.
|
||||||
|
|
||||||
|
required: true
|
||||||
|
|
||||||
|
image:
|
||||||
|
description:
|
||||||
|
- this is the rbd image name to create/resize - if the rbd does not exist it
|
||||||
|
is created for you with the settings optimised for exporting over iscsi.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
size:
|
||||||
|
description:
|
||||||
|
- The size of the rbd image to create/resize. The size is numeric suffixed by
|
||||||
|
G or T (GB or TB). Increasing the size of a LUN is supported, but if a size
|
||||||
|
is provided that is smaller that the current size, the request is simply ignored.
|
||||||
|
|
||||||
|
e.g. 100G
|
||||||
|
required: true
|
||||||
|
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- the host variable defines the name of the gateway node that will be
|
||||||
|
the allocation host for this rbd image. RBD creation and resize can
|
||||||
|
only be performed by one gateway, the other gateways in the
|
||||||
|
configuration will wait for the operation to complete.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
features:
|
||||||
|
description:
|
||||||
|
- placeholder to potentially allow different rbd features to be set at
|
||||||
|
allocation time by Ansible. NOT CURRENTLY USED
|
||||||
|
required: false
|
||||||
|
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- desired state for this LUN - absent or present. For a state='absent'
|
||||||
|
request, the lun module will verify that the rbd image is not allocated to
|
||||||
|
a client. As long as the rbd image is not in use, the LUN definition will be
|
||||||
|
removed from LIO, unmapped from all gateways AND DELETED.
|
||||||
|
|
||||||
|
USE WITH CARE!
|
||||||
|
required: true
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
from ceph_iscsi_config.lun import LUN
|
||||||
|
from ceph_iscsi_config.utils import valid_size
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
|
||||||
|
# the main function is called ansible_main to allow the call stack
|
||||||
|
# to be checked to determine whether the call to the ceph_iscsi_config
|
||||||
|
# modules is from ansible or not
|
||||||
|
def ansible_main():
|
||||||
|
|
||||||
|
# Define the fields needs to create/map rbd's the the host(s)
|
||||||
|
# NB. features and state are reserved/unused
|
||||||
|
fields = {
|
||||||
|
"pool": {"required": False, "default": "rbd", "type": "str"},
|
||||||
|
"image": {"required": True, "type": "str"},
|
||||||
|
"size": {"required": True, "type": "str"},
|
||||||
|
"host": {"required": True, "type": "str"},
|
||||||
|
"features": {"required": False, "type": "str"},
|
||||||
|
"state": {
|
||||||
|
"required": False,
|
||||||
|
"default": "present",
|
||||||
|
"choices": ['present', 'absent'],
|
||||||
|
"type": "str"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# not supporting check mode currently
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
pool = module.params["pool"]
|
||||||
|
image = module.params['image']
|
||||||
|
size = module.params['size']
|
||||||
|
allocating_host = module.params['host']
|
||||||
|
desired_state = module.params['state']
|
||||||
|
|
||||||
|
################################################
|
||||||
|
# Validate the parameters passed from Ansible #
|
||||||
|
################################################
|
||||||
|
if not valid_size(size):
|
||||||
|
logger.critical("image '{}' has an invalid size specification '{}' "
|
||||||
|
"in the ansible configuration".format(image,
|
||||||
|
size))
|
||||||
|
module.fail_json(msg="(main) Unable to use the size parameter '{}' "
|
||||||
|
"for image '{}' from the playbook - "
|
||||||
|
"must be a number suffixed by M,G "
|
||||||
|
"or T".format(size,
|
||||||
|
image))
|
||||||
|
|
||||||
|
# define a lun object and perform some initial parameter validation
|
||||||
|
lun = LUN(logger, pool, image, size, allocating_host)
|
||||||
|
if lun.error:
|
||||||
|
module.fail_json(msg=lun.error_msg)
|
||||||
|
|
||||||
|
logger.info("START - LUN configuration started for {}/{}".format(pool,
|
||||||
|
image))
|
||||||
|
|
||||||
|
# attempt to create/allocate the LUN for LIO
|
||||||
|
lun.manage(desired_state)
|
||||||
|
if lun.error:
|
||||||
|
module.fail_json(msg=lun.error_msg)
|
||||||
|
|
||||||
|
if lun.num_changes == 0:
|
||||||
|
logger.info("END - No changes needed")
|
||||||
|
else:
|
||||||
|
logger.info("END - {} configuration changes "
|
||||||
|
"made".format(lun.num_changes))
|
||||||
|
|
||||||
|
module.exit_json(changed=(lun.num_changes > 0),
|
||||||
|
meta={"msg": "Configuration updated"})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# initialise global variables used by all called modules
|
||||||
|
# e.g. ceph conffile, keyring etc
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -0,0 +1,212 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_purge
|
||||||
|
short_description: Provide a purge capability to remove an iSCSI gateway
|
||||||
|
environment
|
||||||
|
description:
|
||||||
|
- This module handles the removal of a gateway configuration from a ceph
|
||||||
|
environment.
|
||||||
|
The playbook that calls this module prompts the user for the type of purge
|
||||||
|
to perform.
|
||||||
|
The purge options are;
|
||||||
|
all ... purge all LIO configuration *and* delete all defined rbd images
|
||||||
|
lio ... purge only the LIO configuration (rbd's are left intact)
|
||||||
|
|
||||||
|
USE WITH CAUTION
|
||||||
|
|
||||||
|
To support module debugging, this module logs to
|
||||||
|
/var/log/ansible-module-igw_config.log on each target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
mode:
|
||||||
|
description:
|
||||||
|
- the mode defines the type of purge requested
|
||||||
|
gateway ... remove the LIO configuration only
|
||||||
|
disks ... remove the rbd disks defined to the gateway
|
||||||
|
required: true
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config', 'python-rtslib']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import socket
|
||||||
|
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
from ceph_iscsi_config.common import Config
|
||||||
|
from ceph_iscsi_config.lio import LIO, Gateway
|
||||||
|
from ceph_iscsi_config.utils import ipv4_addresses, get_ip
|
||||||
|
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
|
||||||
|
def delete_group(module, image_list, cfg):
|
||||||
|
|
||||||
|
logger.debug("RBD Images to delete are : {}".format(','.join(image_list)))
|
||||||
|
pending_list = list(image_list)
|
||||||
|
|
||||||
|
for rbd_path in image_list:
|
||||||
|
if delete_rbd(module, rbd_path):
|
||||||
|
disk_key = rbd_path.replace('/', '.', 1)
|
||||||
|
cfg.del_item('disks', disk_key)
|
||||||
|
pending_list.remove(rbd_path)
|
||||||
|
cfg.changed = True
|
||||||
|
|
||||||
|
if cfg.changed:
|
||||||
|
cfg.commit()
|
||||||
|
|
||||||
|
return pending_list
|
||||||
|
|
||||||
|
|
||||||
|
def delete_rbd(module, rbd_path):
|
||||||
|
|
||||||
|
logger.debug("issuing delete for {}".format(rbd_path))
|
||||||
|
rm_cmd = 'rbd --no-progress rm {}'.format(rbd_path)
|
||||||
|
rc, rm_out, err = module.run_command(rm_cmd, use_unsafe_shell=True)
|
||||||
|
logger.debug("delete RC = {}, {}".format(rc, rm_out, err))
|
||||||
|
|
||||||
|
return True if rc == 0 else False
|
||||||
|
|
||||||
|
|
||||||
|
def is_cleanup_host(config):
|
||||||
|
"""
|
||||||
|
decide which gateway host should be responsible for any non-specific
|
||||||
|
updates to the config object
|
||||||
|
:param config: configuration dict from the rados pool
|
||||||
|
:return: boolean indicating whether the addition cleanup should be
|
||||||
|
performed by the running host
|
||||||
|
"""
|
||||||
|
cleanup = False
|
||||||
|
|
||||||
|
if 'ip_list' in config.config["gateways"]:
|
||||||
|
|
||||||
|
gw_1 = config.config["gateways"]["ip_list"][0]
|
||||||
|
|
||||||
|
usable_ip = get_ip(gw_1)
|
||||||
|
if usable_ip != '0.0.0.0':
|
||||||
|
if usable_ip in ipv4_addresses():
|
||||||
|
cleanup = True
|
||||||
|
|
||||||
|
return cleanup
|
||||||
|
|
||||||
|
|
||||||
|
def ansible_main():
|
||||||
|
|
||||||
|
fields = {"mode": {"required": True,
|
||||||
|
"type": "str",
|
||||||
|
"choices": ["gateway", "disks"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
run_mode = module.params['mode']
|
||||||
|
changes_made = False
|
||||||
|
|
||||||
|
logger.info("START - GATEWAY configuration PURGE started, run mode "
|
||||||
|
"is {}".format(run_mode))
|
||||||
|
cfg = Config(logger)
|
||||||
|
this_host = socket.gethostname().split('.')[0]
|
||||||
|
perform_cleanup_tasks = is_cleanup_host(cfg)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Purge gateway configuration, if the config has gateways
|
||||||
|
if run_mode == 'gateway' and len(cfg.config['gateways'].keys()) > 0:
|
||||||
|
|
||||||
|
lio = LIO()
|
||||||
|
gateway = Gateway(cfg)
|
||||||
|
|
||||||
|
if gateway.session_count() > 0:
|
||||||
|
module.fail_json(msg="Unable to purge - gateway still has active "
|
||||||
|
"sessions")
|
||||||
|
|
||||||
|
gateway.drop_target(this_host)
|
||||||
|
if gateway.error:
|
||||||
|
module.fail_json(msg=gateway.error_msg)
|
||||||
|
|
||||||
|
lio.drop_lun_maps(cfg, perform_cleanup_tasks)
|
||||||
|
if lio.error:
|
||||||
|
module.fail_json(msg=lio.error_msg)
|
||||||
|
|
||||||
|
if gateway.changed or lio.changed:
|
||||||
|
|
||||||
|
# each gateway removes it's own entry from the config
|
||||||
|
cfg.del_item("gateways", this_host)
|
||||||
|
|
||||||
|
if perform_cleanup_tasks:
|
||||||
|
cfg.reset = True
|
||||||
|
|
||||||
|
# drop all client definitions from the configuration object
|
||||||
|
client_names = cfg.config["clients"].keys()
|
||||||
|
for client in client_names:
|
||||||
|
cfg.del_item("clients", client)
|
||||||
|
|
||||||
|
cfg.del_item("gateways", "iqn")
|
||||||
|
cfg.del_item("gateways", "created")
|
||||||
|
cfg.del_item("gateways", "ip_list")
|
||||||
|
|
||||||
|
cfg.commit()
|
||||||
|
|
||||||
|
changes_made = True
|
||||||
|
|
||||||
|
elif run_mode == 'disks' and len(cfg.config['disks'].keys()) > 0:
|
||||||
|
#
|
||||||
|
# Remove the disks on this host, that have been registered in the
|
||||||
|
# config object
|
||||||
|
#
|
||||||
|
# if the owner field for a disk is set to this host, this host can
|
||||||
|
# safely delete it
|
||||||
|
# nb. owner gets set at rbd allocation and mapping time
|
||||||
|
images_left = []
|
||||||
|
|
||||||
|
# delete_list will contain a list of pool/image names where the owner
|
||||||
|
# is this host
|
||||||
|
delete_list = [key.replace('.', '/', 1) for key in cfg.config['disks']
|
||||||
|
if cfg.config['disks'][key]['owner'] == this_host]
|
||||||
|
|
||||||
|
if delete_list:
|
||||||
|
images_left = delete_group(module, delete_list, cfg)
|
||||||
|
|
||||||
|
# if the delete list still has entries we had problems deleting the
|
||||||
|
# images
|
||||||
|
if images_left:
|
||||||
|
module.fail_json(msg="Problems deleting the following rbd's : "
|
||||||
|
"{}".format(','.join(images_left)))
|
||||||
|
|
||||||
|
changes_made = cfg.changed
|
||||||
|
|
||||||
|
logger.debug("ending lock state variable {}".format(cfg.config_locked))
|
||||||
|
|
||||||
|
logger.info("END - GATEWAY configuration PURGE complete")
|
||||||
|
|
||||||
|
module.exit_json(changed=changes_made,
|
||||||
|
meta={"msg": "Purge of iSCSI settings ({}) "
|
||||||
|
"complete".format(run_mode)})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -66,3 +66,18 @@
|
||||||
fail:
|
fail:
|
||||||
msg: "Systemd must be present"
|
msg: "Systemd must be present"
|
||||||
when: ansible_service_mgr != 'systemd'
|
when: ansible_service_mgr != 'systemd'
|
||||||
|
|
||||||
|
- name: fail on unsupported distribution for iscsi gateways
|
||||||
|
fail:
|
||||||
|
msg: "iSCSI gateways can only be deployed on Red Hat Enterprise Linux or CentOS"
|
||||||
|
when:
|
||||||
|
- ansible_distribution not in ['Red Hat Enterprise Linux', 'CentOS']
|
||||||
|
- iscsi_gw_group_name in group_names
|
||||||
|
|
||||||
|
- name: fail on unsupported distribution version for iscsi gateways
|
||||||
|
fail:
|
||||||
|
msg: "iSCSI gateways can only be deployed on Red Hat Enterprise Linux or CentOS >= 7.4"
|
||||||
|
when:
|
||||||
|
- ansible_distribution == 'Red Hat Enterprise Linux' or ansible_distribution == 'CentOS'
|
||||||
|
- ansible_distribution_version < '7.4'
|
||||||
|
- iscsi_gw_group_name in group_names
|
||||||
|
|
|
@ -97,3 +97,15 @@
|
||||||
when:
|
when:
|
||||||
- mgr_group_name in group_names
|
- mgr_group_name in group_names
|
||||||
- ceph_release_num.{{ ceph_release }} > ceph_release_num.jewel
|
- ceph_release_num.{{ ceph_release }} > ceph_release_num.jewel
|
||||||
|
|
||||||
|
- name: install redhat ceph iscsi package
|
||||||
|
package:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: "{{ (upgrade_ceph_packages|bool) | ternary('latest','present') }}"
|
||||||
|
with_items:
|
||||||
|
- tcmu-runner
|
||||||
|
- ceph-iscsi-config
|
||||||
|
- targetcli
|
||||||
|
when:
|
||||||
|
- iscsi_gw_group_name in group_names
|
||||||
|
- ceph_release_num.{{ ceph_release }} >= ceph_release_num.luminous
|
||||||
|
|
|
@ -33,3 +33,22 @@
|
||||||
- nfs_group_name in group_names
|
- nfs_group_name in group_names
|
||||||
- nfs_ganesha_dev
|
- nfs_ganesha_dev
|
||||||
|
|
||||||
|
- name: fetch ceph-iscsi-config red hat development repository
|
||||||
|
uri:
|
||||||
|
url: https://shaman.ceph.com/api/repos/ceph-iscsi-config/{{ ceph_dev_branch }}/{{ ceph_dev_sha1 }}/{{ ansible_distribution | lower }}/{{ ansible_distribution_major_version }}/repo
|
||||||
|
return_content: yes
|
||||||
|
register: ceph_iscsi_config_dev_yum_repo
|
||||||
|
when:
|
||||||
|
- ceph_iscsi_config_dev
|
||||||
|
- iscsi_gw_group_name in group_names
|
||||||
|
|
||||||
|
- name: configure ceph-iscsi-config red hat development repository
|
||||||
|
copy:
|
||||||
|
content: "{{ ceph_iscsi_config_dev_yum_repo.content }}"
|
||||||
|
dest: /etc/yum.repos.d/ceph-iscsi-config-dev.repo
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
backup: yes
|
||||||
|
when:
|
||||||
|
- ceph_iscsi_config_dev
|
||||||
|
- iscsi_gw_group_name in group_names
|
||||||
|
|
|
@ -43,7 +43,7 @@ nfs_group_name: nfss
|
||||||
restapi_group_name: restapis
|
restapi_group_name: restapis
|
||||||
rbdmirror_group_name: rbdmirrors
|
rbdmirror_group_name: rbdmirrors
|
||||||
client_group_name: clients
|
client_group_name: clients
|
||||||
iscsi_group_name: iscsigws
|
iscsi_gw_group_name: iscsi_gws
|
||||||
mgr_group_name: mgrs
|
mgr_group_name: mgrs
|
||||||
|
|
||||||
# If check_firewall is true, then ansible will try to determine if the
|
# If check_firewall is true, then ansible will try to determine if the
|
||||||
|
@ -197,6 +197,8 @@ nfs_ganesha_dev: false # use development repos for nfs-ganesha
|
||||||
# flavors so far include: ceph_master, ceph_jewel, ceph_kraken, ceph_luminous
|
# flavors so far include: ceph_master, ceph_jewel, ceph_kraken, ceph_luminous
|
||||||
nfs_ganesha_flavor: "ceph_master"
|
nfs_ganesha_flavor: "ceph_master"
|
||||||
|
|
||||||
|
ceph_iscsi_config_dev: true # special repo for deploying iSCSI gateways
|
||||||
|
|
||||||
|
|
||||||
# REPOSITORY: CUSTOM
|
# REPOSITORY: CUSTOM
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2016 Paul Cuzner pcuzner at redhat dot com
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,7 @@
|
||||||
|
This package installs the playbooks/tasks necessary to configure LIO gateways that provide a front-end to a ceph cluster.
|
||||||
|
|
||||||
|
The playbooks use custom modules that are just wrappers calling python modules installed on the gateways nodes. These
|
||||||
|
python modules handle the configuration interaction for;
|
||||||
|
- the iscsi target definition (target iqn, target portal groups and portal IP's)
|
||||||
|
- LUN's including RBD create and resize
|
||||||
|
- client definition
|
|
@ -0,0 +1,70 @@
|
||||||
|
# ceph-iscsi-ansible
|
||||||
|
This project provides a mechanism to deploy iSCSI gateways in front of a ceph cluster using Ansible. The ansible playbooks
|
||||||
|
provided rely upon configuration logic from the "ceph-iscsi-config" project. This separation provides independence to the
|
||||||
|
configuration logic, potentially opening up the possibility for puppet/chef to create/manage ceph/iSCSI gateways in the
|
||||||
|
same way.
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
At a high level, this project provides custom modules which are responsible for calling the configuration logic, together
|
||||||
|
with the relevant playbooks. The project defines a new ceph-ansible role; ceph-iscsi-gw, together with two playbooks;
|
||||||
|
|
||||||
|
- **ceph-iscsi-gw-yml** ... to define our change the gateway configuration based on group_vars/ceph-iscsi-gw.yml
|
||||||
|
- **purge_gateways.yml** .. to destroy the LIO configuration, or the LIO and any associated rbd images.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
The combination of the playbooks and the configuration logic deliver the following features;
|
||||||
|
|
||||||
|
- confirms RHEL7.3 and aborts if necessary
|
||||||
|
- ensures targetcli/device-mapper-multipath is installed (for rtslib support)
|
||||||
|
- configures multipath.conf
|
||||||
|
- creates rbd's if needed - at allocation time, each rbd is assigned an owner, which will become the preferred path
|
||||||
|
- checks the size of the rbds at run time and expands if necessary
|
||||||
|
- maps the rbd's to the host (gateway)
|
||||||
|
- enables the rbdmap service to start on boot, and reconfigures the target service to be dependent on rbdmap
|
||||||
|
- adds the rbd's to the /etc/ceph/rbdmap file ensuring the devices are automatically mapped following a gateway reboot
|
||||||
|
- maps these rbds to LIO
|
||||||
|
- once mapped, the alua preferred path state is set or cleared (supporting an active/passive topology)
|
||||||
|
- creates an iscsi target - common iqn, and multiple tpg's
|
||||||
|
- adds a portal ip based on a the provided IP addresses defined in the group vars to each tpg
|
||||||
|
- enables the local tpg, other gateways are defined as disabled
|
||||||
|
- adds all the mapped luns to ALL tpg's (ready for client assignment)
|
||||||
|
- add clients to the active/enabled tpg, with/without CHAP
|
||||||
|
- images mapped to clients can be added/removed by changing image_list and rerunning the playbook
|
||||||
|
- clients can be removed using the state=absent variable and rerunning the playbook. At this point the entry can be
|
||||||
|
removed from the group variables file
|
||||||
|
- configuration can be wiped with the purge_gateway playbook
|
||||||
|
- current state can be seen by looking at the configuration object (stored in the rbd pool)
|
||||||
|
|
||||||
|
### Why RHEL 7.3?
|
||||||
|
There are several system dependencies that are required to ensure the correct (i.e. don't eat my data!) behaviors when OSD connectivity
|
||||||
|
or gateway nodes fail. RHEL 7.3 delivers the necessary kernel changes, and also provides an updated multipathd, enabling rbd images
|
||||||
|
to be managed by multipathd.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
* a working ceph cluster ( *rbd pool defined* )
|
||||||
|
* a server/host with ceph-ansible installed and working
|
||||||
|
* nodes intended to be gateways should be at least ceph clients, with the ability to create and map rbd images
|
||||||
|
|
||||||
|
|
||||||
|
## Testing So far
|
||||||
|
The solution has been tested on a collocated cluster where the osd/mons and gateways all reside on the same node.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
### Prepare the iSCSI Gateway Nodes
|
||||||
|
1. install the ceph-iscsi-config package on the nodes, intended to be gateways. NB. The playbook includes a check for the presence
|
||||||
|
of this rpm (https://github.com/pcuzner/ceph-iscsi-config)
|
||||||
|
|
||||||
|
### Install the ansible playbooks
|
||||||
|
1. install the ceph-iscsi-ansible rpm from the packages directory on the node where you already have ceph-ansible installed.
|
||||||
|
2. update /etc/ansible/hosts to include a host group (ceph-iscsi-gw) for the nodes that you want to become iscsi gateways
|
||||||
|
3. make a copy of the group_vars/ceph-iscsi-gw.sample file called ceph-iscsi-gw, and update it to define the environment you want
|
||||||
|
4. run the playbook
|
||||||
|
```> ansible-playbook ceph-iscsi-gw.yml```
|
||||||
|
|
||||||
|
## Purging the configuration
|
||||||
|
As mentioned above, the project provides a purge-gateways.yml playbook which can remove the LIO configuration alone, or remove
|
||||||
|
both LIO and all associated rbd images that have been declared in the group_vars/ceph-iscsi-gw file. The purge playbook will
|
||||||
|
check for any active iscsi sessions, and abort if any are found.
|
||||||
|
|
||||||
|
## Known Issues and Considerations
|
||||||
|
1. the ceph cluster name is the default 'ceph', so the corresponding configuration file /etc/ceph/ceph.conf is assumed to be valid
|
|
@ -0,0 +1,109 @@
|
||||||
|
Name: ceph-iscsi-ansible
|
||||||
|
Version: 2.0
|
||||||
|
Release: 1%{?dist}
|
||||||
|
Summary: Ansible playbooks for deploying LIO iscsi gateways in front of a Ceph cluster
|
||||||
|
License: ASL 2.0
|
||||||
|
URL: https://github.com/pcuzner/ceph-iscsi-ansible
|
||||||
|
Source0: https://github.com/pcuzner/ceph-iscsi-ansible/archive/%{version}/%{name}-%{version}.tar.gz
|
||||||
|
BuildArch: noarch
|
||||||
|
|
||||||
|
Requires: ansible >= 1.9
|
||||||
|
Requires: ceph-ansible >= 1.0.5
|
||||||
|
|
||||||
|
%description
|
||||||
|
Ansible playbooks that define nodes as iSCSI gateways (LIO). Once complete, the
|
||||||
|
LIO instance on each node provides an ISCSI endpoint for clients to connect to.
|
||||||
|
The playbook defines the front-end iSCSI environment (target -> tpgN ->
|
||||||
|
NodeACLS/client), as well as the underlying rbd definition for the rbd images
|
||||||
|
to be exported over iSCSI.
|
||||||
|
|
||||||
|
ceph-iscsi-gw.yml ......... defines the LIO configuration(defined by
|
||||||
|
group_vars/ceph-iscsi-gw.yml)
|
||||||
|
purge-iscsi-gateways.yml .. deletes the LIO configuration, and optionally rbd's
|
||||||
|
from the environment
|
||||||
|
|
||||||
|
NB: The playbooks are dependent upon the ceph-iscsi-config package being
|
||||||
|
installed/available to the hosts that will become iSCSI gateways.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q
|
||||||
|
|
||||||
|
%build
|
||||||
|
|
||||||
|
%install
|
||||||
|
mkdir -p %{buildroot}%{_datarootdir}/ceph-ansible
|
||||||
|
|
||||||
|
for f in group_vars library roles ceph-iscsi-gw.yml purge-iscsi-gateways.yml; do
|
||||||
|
cp -a $f %{buildroot}%{_datarootdir}/ceph-ansible
|
||||||
|
done
|
||||||
|
|
||||||
|
%files
|
||||||
|
%doc LICENSE
|
||||||
|
%doc README
|
||||||
|
%{_datarootdir}/ceph-ansible/ceph-iscsi-gw.yml
|
||||||
|
%{_datarootdir}/ceph-ansible/purge-iscsi-gateways.yml
|
||||||
|
%{_datarootdir}/ceph-ansible/group_vars/ceph-iscsi-gw.sample
|
||||||
|
%{_datarootdir}/ceph-ansible/roles/ceph-iscsi-gw
|
||||||
|
%{_datarootdir}/ceph-ansible/library/igw*
|
||||||
|
%exclude %{_datarootdir}/ceph-ansible/library/igw*.pyo
|
||||||
|
%exclude %{_datarootdir}/ceph-ansible/library/igw*.pyc
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Fri Jan 13 2017 Paul Cuzner <pcuzner@redhat.com> - 2.0-1
|
||||||
|
- converted from device-mapper/krbd to TCMU based rbd configurations
|
||||||
|
- renamed iscsi-gateway config file to use .cfg extension
|
||||||
|
- renamed purge playbook to match naming in ceph-ansible
|
||||||
|
|
||||||
|
* Fri Nov 04 2016 Paul Cuzner <pcuzner@redhat.com> - 1.5-1
|
||||||
|
- playbook now seeds the configuration directory on ansible host (rhbz 1390026)
|
||||||
|
- resolve a 1.4 regression affecting the igw_purge module
|
||||||
|
- fail gracefully if bogus client name is given (rhbz 1390023)
|
||||||
|
|
||||||
|
* Thu Oct 27 2016 Paul Cuzner <pcuzner@redhat.com> - 1.4-1
|
||||||
|
- clients can now be added without images or chap defined using null strings
|
||||||
|
- changed parameters for client definition to position for other auth mechanisms
|
||||||
|
- adapt purge module to use revised disk naming scheme within config object
|
||||||
|
- updated group_vars sample to reflect name changes
|
||||||
|
- added state= setting to LUN definitions (enabling disks to be add/removed)
|
||||||
|
- fix syntax issue during ceph.conf seed process
|
||||||
|
- documentation added to the Ansible modules
|
||||||
|
|
||||||
|
* Fri Oct 21 2016 Paul Cuzner <pcuzner@redhat.com> - 1.3-1
|
||||||
|
- removed rsync rpm dependency (BZ 1386090)
|
||||||
|
- ceph.conf pulled from seed monitor, then pushed to gateways using copy task
|
||||||
|
- add a template based config file to each gateway for runtime info
|
||||||
|
- add additional variables allowing non-default ceph cluster names/keyrings (BZ 1386617)
|
||||||
|
|
||||||
|
* Sat Oct 15 2016 Paul Cuzner <pcuzner@redhat.com> - 1.2-1
|
||||||
|
- documented the passwordless ssh requirement for the seed_monitor node
|
||||||
|
- fix BZ 1384505 mask the target service preventing manual start/stop
|
||||||
|
- fix BZ 1384858 when the admin updates ansible hosts but not the gateway_ip_list variable
|
||||||
|
|
||||||
|
* Wed Oct 12 2016 Paul Cuzner <pcuzner@redhat.com> - 1.1-1
|
||||||
|
- updated playbook to modify lvm.conf to exclude the dm devices created for mapped rbds
|
||||||
|
|
||||||
|
* Mon Oct 10 2016 Paul Cuzner <pcuzner@redhat.com> - 1.0-1
|
||||||
|
- fix : allow client_connections and rbd_devices to be be empty to skip those steps
|
||||||
|
- add usage guidelines to the group_vars/ceph-iscsi-gw.sample file
|
||||||
|
- added variable to allow pre-req checks to be bypassed during a run
|
||||||
|
- updated list of rpm pre-req that ansible checks for
|
||||||
|
- add synchronize task to the playbook to copy admin keyring to gateway node(s)
|
||||||
|
- updated igw_purge module to allow for the deletion of the alua port groups
|
||||||
|
|
||||||
|
* Thu Oct 06 2016 Paul Cuzner <pcuzner@redhat.com> - 0.8-1
|
||||||
|
- fix : purge_gateways.yml was missing
|
||||||
|
- removed packages directory to clean up the source archive
|
||||||
|
- spec file updates (dependencies)
|
||||||
|
|
||||||
|
* Wed Oct 05 2016 Paul Cuzner <pcuzner@redhat.com> - 0.7-1
|
||||||
|
- removed service dependencies for rbdmap/target (replaced by rbd-target-gw form ceph-iscsi-config rpm)
|
||||||
|
- removed target overrides files
|
||||||
|
- updated playbook to add skip_partx yes to multipath.conf
|
||||||
|
|
||||||
|
* Mon Oct 03 2016 Paul Cuzner <pcuzner@redhat.com> - 0.6-1
|
||||||
|
- changed the main function to have an ansible prefix to allow the code to know where it is invoked from
|
||||||
|
- updated the purge module to support image names being prefixed by a pool i.e. pool/image
|
||||||
|
|
||||||
|
* Tue Sep 27 2016 Paul Cuzner <pcuzner@redhat.com> - 0.5-1
|
||||||
|
- initial rpm package
|
||||||
|
|
|
@ -1 +1,42 @@
|
||||||
---
|
---
|
||||||
|
# You can override vars by using host or group vars
|
||||||
|
|
||||||
|
# Specify the iqn for ALL gateways. This iqn is shared across the gateways, so an iscsi
|
||||||
|
# client sees the gateway group as a single storage subsystem.
|
||||||
|
gateway_iqn: "iqn.2003-01.com.redhat.iscsi-gw:ceph-igw"
|
||||||
|
|
||||||
|
# gateway_ip_list provides a list of the IP Addrresses - one per gateway - that will be used
|
||||||
|
# as an iscsi target portal ip. The list must be comma separated - and the order determines
|
||||||
|
# the sequence of TPG's within the iscsi target across each gateway. Once set, additional
|
||||||
|
# gateways can be added, but the order must *not* be changed.
|
||||||
|
gateway_ip_list: "192.168.122.101,192.168.122.102,192.168.122.103"
|
||||||
|
|
||||||
|
# rbd_devices defines the images that should be created and exported from the iscsi gateways.
|
||||||
|
# If the rbd does not exist, it will be created for you. In addition you may increase the
|
||||||
|
# size of rbd's by changing the size parameter and rerunning the playbook. A size value lower
|
||||||
|
# than the current size of the rbd is ignored.
|
||||||
|
#
|
||||||
|
# the 'host' parameter defines which of the gateway nodes should handle the physical
|
||||||
|
# allocation/expansion or removal of the rbd
|
||||||
|
# to remove an image, simply use a state of 'absent'. This will first check the rbd is not allocated
|
||||||
|
# to any client, and the remove it from LIO and then delete the rbd image
|
||||||
|
#
|
||||||
|
# NB. this variable definition can be commented out to bypass LUN management
|
||||||
|
rbd_devices:
|
||||||
|
- { pool: 'rbd', image: 'ansible1', size: '30G', host: 'ceph-1', state: 'present' }
|
||||||
|
- { pool: 'rbd', image: 'ansible2', size: '15G', host: 'ceph-1', state: 'present' }
|
||||||
|
- { pool: 'rbd', image: 'ansible3', size: '30G', host: 'ceph-1', state: 'present' }
|
||||||
|
- { pool: 'rbd', image: 'ansible4', size: '50G', host: 'ceph-1', state: 'present' }
|
||||||
|
|
||||||
|
|
||||||
|
# client_connections defines the client ACL's to restrict client access to specific LUNs
|
||||||
|
# The settings are as follows;
|
||||||
|
# - image_list is a comma separated list of rbd images of the form <pool name>.<rbd_image_name>
|
||||||
|
# - chap supplies the user and password the client will use for authentication of the
|
||||||
|
# form <user>/<password>
|
||||||
|
# - status shows the intended state of this client definition - 'present' or 'absent'
|
||||||
|
#
|
||||||
|
# NB. this definition can be commented out to skip client (nodeACL) management
|
||||||
|
client_connections:
|
||||||
|
- { client: 'iqn.1994-05.com.redhat:rh7-iscsi-client', image_list: 'rbd.ansible1,rbd.ansible2', chap: 'rh7-iscsi-client/redhat', status: 'present' }
|
||||||
|
- { client: 'iqn.1991-05.com.microsoft:w2k12r2', image_list: 'rbd.ansible4', chap: 'w2k12r2/microsoft_w2k12', status: 'absent' }
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_client
|
||||||
|
short_description: Manage iscsi gateway client definitions
|
||||||
|
description:
|
||||||
|
- This module calls the 'client' configuration management module installed
|
||||||
|
on the iscsi gateway node to handle the definition of iscsi clients on the
|
||||||
|
gateway(s). This definition will setup iscsi authentication (e.g. chap),
|
||||||
|
and mask the required rbd images to the client.
|
||||||
|
|
||||||
|
The 'client' configuration module is provided by ceph-iscsi-config
|
||||||
|
rpm which is installed on the gateway nodes.
|
||||||
|
|
||||||
|
To support module debugging, this module logs to
|
||||||
|
/var/log/ansible-module-igw_config.log on the target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
client_iqn:
|
||||||
|
description:
|
||||||
|
- iqn of the client machine which should be connected or removed from the
|
||||||
|
iscsi gateway environment
|
||||||
|
required: true
|
||||||
|
|
||||||
|
image_list:
|
||||||
|
description:
|
||||||
|
- comma separated string providing the rbd images that this
|
||||||
|
client definition should have. The rbd images provided must use the
|
||||||
|
following format <pool_name>.<rbd_image_name>
|
||||||
|
e.g. rbd.disk1,rbd.disk2
|
||||||
|
required: true
|
||||||
|
|
||||||
|
chap:
|
||||||
|
description:
|
||||||
|
- chap credentials for the client to authenticate to the gateways
|
||||||
|
to gain access to the exported rbds (LUNs). The credentials is a string
|
||||||
|
value of the form 'username/password'. The iscsi client must then use
|
||||||
|
these settings to gain access to any LUN resources.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- desired state for this client - absent or present
|
||||||
|
required: true
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
from ceph_iscsi_config.client import GWClient
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
|
||||||
|
# the main function is called ansible_main to allow the call stack
|
||||||
|
# to be checked to determine whether the call to the ceph_iscsi_config
|
||||||
|
# modules is from ansible or not
|
||||||
|
def ansible_main():
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
"client_iqn": {"required": True, "type": "str"},
|
||||||
|
"image_list": {"required": True, "type": "str"},
|
||||||
|
"chap": {"required": True, "type": "str"},
|
||||||
|
"state": {
|
||||||
|
"required": True,
|
||||||
|
"choices": ['present', 'absent'],
|
||||||
|
"type": "str"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
client_iqn = module.params['client_iqn']
|
||||||
|
|
||||||
|
if module.params['image_list']:
|
||||||
|
image_list = module.params['image_list'].split(',')
|
||||||
|
else:
|
||||||
|
image_list = []
|
||||||
|
|
||||||
|
chap = module.params['chap']
|
||||||
|
desired_state = module.params['state']
|
||||||
|
|
||||||
|
logger.info("START - Client configuration started : {}".format(client_iqn))
|
||||||
|
|
||||||
|
# The client is defined using the GWClient class. This class handles
|
||||||
|
# client attribute updates, rados configuration object updates and LIO
|
||||||
|
# settings. Since the logic is external to this custom module, clients
|
||||||
|
# can be created/deleted by other methods in the same manner.
|
||||||
|
client = GWClient(logger, client_iqn, image_list, chap)
|
||||||
|
if client.error:
|
||||||
|
module.fail_json(msg=client.error_msg)
|
||||||
|
|
||||||
|
client.manage(desired_state)
|
||||||
|
if client.error:
|
||||||
|
module.fail_json(msg=client.error_msg)
|
||||||
|
|
||||||
|
logger.info("END - Client configuration complete - {} "
|
||||||
|
"changes made".format(client.change_count))
|
||||||
|
|
||||||
|
changes_made = True if client.change_count > 0 else False
|
||||||
|
|
||||||
|
module.exit_json(changed=changes_made,
|
||||||
|
meta={"msg": "Client definition completed {} "
|
||||||
|
"changes made".format(client.change_count)})
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# initialise global variables used by all called modules
|
||||||
|
# e.g. ceph conffile, keyring etc
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_gateway
|
||||||
|
short_description: Manage the iscsi gateway definition
|
||||||
|
description:
|
||||||
|
- This module calls the 'gateway' configuration management module installed
|
||||||
|
on the iscsi gateway node(s) to handle the definition of iscsi gateways.
|
||||||
|
The module will configure;
|
||||||
|
* the iscsi target and target portal group (TPG)
|
||||||
|
* rbd maps to the gateway and registration of those rbds as LUNs to the
|
||||||
|
kernels LIO subsystem
|
||||||
|
|
||||||
|
The actual configuration modules are provided by ceph-iscsi-config rpm
|
||||||
|
which is installed on the gateway nodes.
|
||||||
|
|
||||||
|
To support module debugging, this module logs to
|
||||||
|
/var/log/ansible-module-igw_config.log on the target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
gateway_iqn:
|
||||||
|
description:
|
||||||
|
- iqn that all gateway nodes will use to present a common system image
|
||||||
|
name to iscsi clients
|
||||||
|
required: true
|
||||||
|
|
||||||
|
gateway_ip_list:
|
||||||
|
description:
|
||||||
|
- comma separated string providing the IP addresses that will be used
|
||||||
|
as iSCSI portal IPs to accept iscsi client connections. Each IP address
|
||||||
|
should equate to an IP on a gateway node - typically dedicated to iscsi
|
||||||
|
traffic. The order of the IP addresses determines the TPG sequence
|
||||||
|
within the target definition - so once defined, new gateways can be
|
||||||
|
added but *must* be added to the end of this list to preserve the tpg
|
||||||
|
sequence
|
||||||
|
|
||||||
|
e.g. 192.168.122.101,192.168.122.103
|
||||||
|
required: true
|
||||||
|
|
||||||
|
mode:
|
||||||
|
description:
|
||||||
|
- mode in which to run the gateway module. Two modes are supported
|
||||||
|
target ... define the iscsi target iqn, tpg's and portals
|
||||||
|
map ...... map luns to the tpg's, and also define the ALUA path setting
|
||||||
|
for each LUN (activeOptimized/activenonoptimized)
|
||||||
|
required: true
|
||||||
|
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
|
||||||
|
from ceph_iscsi_config.gateway import GWTarget
|
||||||
|
from ceph_iscsi_config.utils import valid_ip
|
||||||
|
|
||||||
|
|
||||||
|
# the main function is called ansible_main to allow the call stack
|
||||||
|
# to be checked to determine whether the call to the ceph_iscsi_config
|
||||||
|
# modules is from ansible or not
|
||||||
|
def ansible_main():
|
||||||
|
# Configures the gateway on the host. All images defined are added to
|
||||||
|
# the default tpg for later allocation to clients
|
||||||
|
fields = {"gateway_iqn": {"required": True, "type": "str"},
|
||||||
|
"gateway_ip_list": {"required": True}, # "type": "list"},
|
||||||
|
"mode": {
|
||||||
|
"required": True,
|
||||||
|
"choices": ['target', 'map']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
gateway_iqn = module.params['gateway_iqn']
|
||||||
|
gateway_ip_list = module.params['gateway_ip_list'].split(',')
|
||||||
|
mode = module.params['mode']
|
||||||
|
|
||||||
|
if not valid_ip(gateway_ip_list):
|
||||||
|
module.fail_json(msg="Invalid gateway IP address(es) provided - port "
|
||||||
|
"22 check failed ({})".format(gateway_ip_list))
|
||||||
|
|
||||||
|
logger.info("START - GATEWAY configuration started - mode {}".format(mode))
|
||||||
|
|
||||||
|
gateway = GWTarget(logger, gateway_iqn, gateway_ip_list)
|
||||||
|
if gateway.error:
|
||||||
|
logger.critical("(ansible_main) Gateway init failed - "
|
||||||
|
"{}".format(gateway.error_msg))
|
||||||
|
module.fail_json(msg="iSCSI gateway initialisation failed "
|
||||||
|
"({})".format(gateway.error_msg))
|
||||||
|
|
||||||
|
gateway.manage(mode)
|
||||||
|
|
||||||
|
if gateway.error:
|
||||||
|
logger.critical("(main) Gateway creation or load failed, "
|
||||||
|
"unable to continue")
|
||||||
|
module.fail_json(msg="iSCSI gateway creation/load failure "
|
||||||
|
"({})".format(gateway.error_msg))
|
||||||
|
|
||||||
|
|
||||||
|
logger.info("END - GATEWAY configuration complete")
|
||||||
|
module.exit_json(changed=gateway.changes_made,
|
||||||
|
meta={"msg": "Gateway setup complete"})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# initialise global variables used by all called modules
|
||||||
|
# e.g. ceph conffile, keyring etc
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -0,0 +1,166 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_lun
|
||||||
|
short_description: Manage ceph rbd images to present as iscsi LUNs to clients
|
||||||
|
description:
|
||||||
|
- This module calls the 'lun' configuration management module installed
|
||||||
|
on the iscsi gateway node(s). The lun module handles the creation and resize
|
||||||
|
of rbd images, and then maps these rbd devices to the gateway node(s) to be
|
||||||
|
exposed through the kernel's LIO target.
|
||||||
|
|
||||||
|
To support module debugging, this module logs to /var/log/ansible-module-igw_config.log
|
||||||
|
on the target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
pool:
|
||||||
|
description:
|
||||||
|
- The ceph pool where the image should exist or be created in.
|
||||||
|
|
||||||
|
NOTE - The pool *must* exist prior to the Ansible run.
|
||||||
|
|
||||||
|
required: true
|
||||||
|
|
||||||
|
image:
|
||||||
|
description:
|
||||||
|
- this is the rbd image name to create/resize - if the rbd does not exist it
|
||||||
|
is created for you with the settings optimised for exporting over iscsi.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
size:
|
||||||
|
description:
|
||||||
|
- The size of the rbd image to create/resize. The size is numeric suffixed by
|
||||||
|
G or T (GB or TB). Increasing the size of a LUN is supported, but if a size
|
||||||
|
is provided that is smaller that the current size, the request is simply ignored.
|
||||||
|
|
||||||
|
e.g. 100G
|
||||||
|
required: true
|
||||||
|
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- the host variable defines the name of the gateway node that will be
|
||||||
|
the allocation host for this rbd image. RBD creation and resize can
|
||||||
|
only be performed by one gateway, the other gateways in the
|
||||||
|
configuration will wait for the operation to complete.
|
||||||
|
required: true
|
||||||
|
|
||||||
|
features:
|
||||||
|
description:
|
||||||
|
- placeholder to potentially allow different rbd features to be set at
|
||||||
|
allocation time by Ansible. NOT CURRENTLY USED
|
||||||
|
required: false
|
||||||
|
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- desired state for this LUN - absent or present. For a state='absent'
|
||||||
|
request, the lun module will verify that the rbd image is not allocated to
|
||||||
|
a client. As long as the rbd image is not in use, the LUN definition will be
|
||||||
|
removed from LIO, unmapped from all gateways AND DELETED.
|
||||||
|
|
||||||
|
USE WITH CARE!
|
||||||
|
required: true
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
from ceph_iscsi_config.lun import LUN
|
||||||
|
from ceph_iscsi_config.utils import valid_size
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
|
||||||
|
# the main function is called ansible_main to allow the call stack
|
||||||
|
# to be checked to determine whether the call to the ceph_iscsi_config
|
||||||
|
# modules is from ansible or not
|
||||||
|
def ansible_main():
|
||||||
|
|
||||||
|
# Define the fields needs to create/map rbd's the the host(s)
|
||||||
|
# NB. features and state are reserved/unused
|
||||||
|
fields = {
|
||||||
|
"pool": {"required": False, "default": "rbd", "type": "str"},
|
||||||
|
"image": {"required": True, "type": "str"},
|
||||||
|
"size": {"required": True, "type": "str"},
|
||||||
|
"host": {"required": True, "type": "str"},
|
||||||
|
"features": {"required": False, "type": "str"},
|
||||||
|
"state": {
|
||||||
|
"required": False,
|
||||||
|
"default": "present",
|
||||||
|
"choices": ['present', 'absent'],
|
||||||
|
"type": "str"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# not supporting check mode currently
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
pool = module.params["pool"]
|
||||||
|
image = module.params['image']
|
||||||
|
size = module.params['size']
|
||||||
|
allocating_host = module.params['host']
|
||||||
|
desired_state = module.params['state']
|
||||||
|
|
||||||
|
################################################
|
||||||
|
# Validate the parameters passed from Ansible #
|
||||||
|
################################################
|
||||||
|
if not valid_size(size):
|
||||||
|
logger.critical("image '{}' has an invalid size specification '{}' "
|
||||||
|
"in the ansible configuration".format(image,
|
||||||
|
size))
|
||||||
|
module.fail_json(msg="(main) Unable to use the size parameter '{}' "
|
||||||
|
"for image '{}' from the playbook - "
|
||||||
|
"must be a number suffixed by M,G "
|
||||||
|
"or T".format(size,
|
||||||
|
image))
|
||||||
|
|
||||||
|
# define a lun object and perform some initial parameter validation
|
||||||
|
lun = LUN(logger, pool, image, size, allocating_host)
|
||||||
|
if lun.error:
|
||||||
|
module.fail_json(msg=lun.error_msg)
|
||||||
|
|
||||||
|
logger.info("START - LUN configuration started for {}/{}".format(pool,
|
||||||
|
image))
|
||||||
|
|
||||||
|
# attempt to create/allocate the LUN for LIO
|
||||||
|
lun.manage(desired_state)
|
||||||
|
if lun.error:
|
||||||
|
module.fail_json(msg=lun.error_msg)
|
||||||
|
|
||||||
|
if lun.num_changes == 0:
|
||||||
|
logger.info("END - No changes needed")
|
||||||
|
else:
|
||||||
|
logger.info("END - {} configuration changes "
|
||||||
|
"made".format(lun.num_changes))
|
||||||
|
|
||||||
|
module.exit_json(changed=(lun.num_changes > 0),
|
||||||
|
meta={"msg": "Configuration updated"})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# initialise global variables used by all called modules
|
||||||
|
# e.g. ceph conffile, keyring etc
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -0,0 +1,212 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: igw_purge
|
||||||
|
short_description: Provide a purge capability to remove an iSCSI gateway
|
||||||
|
environment
|
||||||
|
description:
|
||||||
|
- This module handles the removal of a gateway configuration from a ceph
|
||||||
|
environment.
|
||||||
|
The playbook that calls this module prompts the user for the type of purge
|
||||||
|
to perform.
|
||||||
|
The purge options are;
|
||||||
|
all ... purge all LIO configuration *and* delete all defined rbd images
|
||||||
|
lio ... purge only the LIO configuration (rbd's are left intact)
|
||||||
|
|
||||||
|
USE WITH CAUTION
|
||||||
|
|
||||||
|
To support module debugging, this module logs to
|
||||||
|
/var/log/ansible-module-igw_config.log on each target machine(s).
|
||||||
|
|
||||||
|
option:
|
||||||
|
mode:
|
||||||
|
description:
|
||||||
|
- the mode defines the type of purge requested
|
||||||
|
gateway ... remove the LIO configuration only
|
||||||
|
disks ... remove the rbd disks defined to the gateway
|
||||||
|
required: true
|
||||||
|
|
||||||
|
requirements: ['ceph-iscsi-config', 'python-rtslib']
|
||||||
|
|
||||||
|
author:
|
||||||
|
- 'Paul Cuzner'
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import socket
|
||||||
|
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from ansible.module_utils.basic import *
|
||||||
|
|
||||||
|
import ceph_iscsi_config.settings as settings
|
||||||
|
from ceph_iscsi_config.common import Config
|
||||||
|
from ceph_iscsi_config.lio import LIO, Gateway
|
||||||
|
from ceph_iscsi_config.utils import ipv4_addresses, get_ip
|
||||||
|
|
||||||
|
__author__ = 'pcuzner@redhat.com'
|
||||||
|
|
||||||
|
|
||||||
|
def delete_group(module, image_list, cfg):
|
||||||
|
|
||||||
|
logger.debug("RBD Images to delete are : {}".format(','.join(image_list)))
|
||||||
|
pending_list = list(image_list)
|
||||||
|
|
||||||
|
for rbd_path in image_list:
|
||||||
|
if delete_rbd(module, rbd_path):
|
||||||
|
disk_key = rbd_path.replace('/', '.', 1)
|
||||||
|
cfg.del_item('disks', disk_key)
|
||||||
|
pending_list.remove(rbd_path)
|
||||||
|
cfg.changed = True
|
||||||
|
|
||||||
|
if cfg.changed:
|
||||||
|
cfg.commit()
|
||||||
|
|
||||||
|
return pending_list
|
||||||
|
|
||||||
|
|
||||||
|
def delete_rbd(module, rbd_path):
|
||||||
|
|
||||||
|
logger.debug("issuing delete for {}".format(rbd_path))
|
||||||
|
rm_cmd = 'rbd --no-progress rm {}'.format(rbd_path)
|
||||||
|
rc, rm_out, err = module.run_command(rm_cmd, use_unsafe_shell=True)
|
||||||
|
logger.debug("delete RC = {}, {}".format(rc, rm_out, err))
|
||||||
|
|
||||||
|
return True if rc == 0 else False
|
||||||
|
|
||||||
|
|
||||||
|
def is_cleanup_host(config):
|
||||||
|
"""
|
||||||
|
decide which gateway host should be responsible for any non-specific
|
||||||
|
updates to the config object
|
||||||
|
:param config: configuration dict from the rados pool
|
||||||
|
:return: boolean indicating whether the addition cleanup should be
|
||||||
|
performed by the running host
|
||||||
|
"""
|
||||||
|
cleanup = False
|
||||||
|
|
||||||
|
if 'ip_list' in config.config["gateways"]:
|
||||||
|
|
||||||
|
gw_1 = config.config["gateways"]["ip_list"][0]
|
||||||
|
|
||||||
|
usable_ip = get_ip(gw_1)
|
||||||
|
if usable_ip != '0.0.0.0':
|
||||||
|
if usable_ip in ipv4_addresses():
|
||||||
|
cleanup = True
|
||||||
|
|
||||||
|
return cleanup
|
||||||
|
|
||||||
|
|
||||||
|
def ansible_main():
|
||||||
|
|
||||||
|
fields = {"mode": {"required": True,
|
||||||
|
"type": "str",
|
||||||
|
"choices": ["gateway", "disks"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec=fields,
|
||||||
|
supports_check_mode=False)
|
||||||
|
|
||||||
|
run_mode = module.params['mode']
|
||||||
|
changes_made = False
|
||||||
|
|
||||||
|
logger.info("START - GATEWAY configuration PURGE started, run mode "
|
||||||
|
"is {}".format(run_mode))
|
||||||
|
cfg = Config(logger)
|
||||||
|
this_host = socket.gethostname().split('.')[0]
|
||||||
|
perform_cleanup_tasks = is_cleanup_host(cfg)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Purge gateway configuration, if the config has gateways
|
||||||
|
if run_mode == 'gateway' and len(cfg.config['gateways'].keys()) > 0:
|
||||||
|
|
||||||
|
lio = LIO()
|
||||||
|
gateway = Gateway(cfg)
|
||||||
|
|
||||||
|
if gateway.session_count() > 0:
|
||||||
|
module.fail_json(msg="Unable to purge - gateway still has active "
|
||||||
|
"sessions")
|
||||||
|
|
||||||
|
gateway.drop_target(this_host)
|
||||||
|
if gateway.error:
|
||||||
|
module.fail_json(msg=gateway.error_msg)
|
||||||
|
|
||||||
|
lio.drop_lun_maps(cfg, perform_cleanup_tasks)
|
||||||
|
if lio.error:
|
||||||
|
module.fail_json(msg=lio.error_msg)
|
||||||
|
|
||||||
|
if gateway.changed or lio.changed:
|
||||||
|
|
||||||
|
# each gateway removes it's own entry from the config
|
||||||
|
cfg.del_item("gateways", this_host)
|
||||||
|
|
||||||
|
if perform_cleanup_tasks:
|
||||||
|
cfg.reset = True
|
||||||
|
|
||||||
|
# drop all client definitions from the configuration object
|
||||||
|
client_names = cfg.config["clients"].keys()
|
||||||
|
for client in client_names:
|
||||||
|
cfg.del_item("clients", client)
|
||||||
|
|
||||||
|
cfg.del_item("gateways", "iqn")
|
||||||
|
cfg.del_item("gateways", "created")
|
||||||
|
cfg.del_item("gateways", "ip_list")
|
||||||
|
|
||||||
|
cfg.commit()
|
||||||
|
|
||||||
|
changes_made = True
|
||||||
|
|
||||||
|
elif run_mode == 'disks' and len(cfg.config['disks'].keys()) > 0:
|
||||||
|
#
|
||||||
|
# Remove the disks on this host, that have been registered in the
|
||||||
|
# config object
|
||||||
|
#
|
||||||
|
# if the owner field for a disk is set to this host, this host can
|
||||||
|
# safely delete it
|
||||||
|
# nb. owner gets set at rbd allocation and mapping time
|
||||||
|
images_left = []
|
||||||
|
|
||||||
|
# delete_list will contain a list of pool/image names where the owner
|
||||||
|
# is this host
|
||||||
|
delete_list = [key.replace('.', '/', 1) for key in cfg.config['disks']
|
||||||
|
if cfg.config['disks'][key]['owner'] == this_host]
|
||||||
|
|
||||||
|
if delete_list:
|
||||||
|
images_left = delete_group(module, delete_list, cfg)
|
||||||
|
|
||||||
|
# if the delete list still has entries we had problems deleting the
|
||||||
|
# images
|
||||||
|
if images_left:
|
||||||
|
module.fail_json(msg="Problems deleting the following rbd's : "
|
||||||
|
"{}".format(','.join(images_left)))
|
||||||
|
|
||||||
|
changes_made = cfg.changed
|
||||||
|
|
||||||
|
logger.debug("ending lock state variable {}".format(cfg.config_locked))
|
||||||
|
|
||||||
|
logger.info("END - GATEWAY configuration PURGE complete")
|
||||||
|
|
||||||
|
module.exit_json(changed=changes_made,
|
||||||
|
meta={"msg": "Purge of iSCSI settings ({}) "
|
||||||
|
"complete".format(run_mode)})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
module_name = os.path.basename(__file__).replace('ansible_module_', '')
|
||||||
|
logger = logging.getLogger(os.path.basename(module_name))
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('/var/log/ansible-module-igw_config.log',
|
||||||
|
maxBytes=5242880,
|
||||||
|
backupCount=7)
|
||||||
|
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s : '
|
||||||
|
'%(message)s')
|
||||||
|
handler.setFormatter(log_fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
settings.init()
|
||||||
|
|
||||||
|
ansible_main()
|
|
@ -1 +1,13 @@
|
||||||
---
|
---
|
||||||
|
galaxy_info:
|
||||||
|
author: Paul Cuzner
|
||||||
|
description: Installs Ceph iSCSI Gateways
|
||||||
|
license: Apache
|
||||||
|
min_ansible_version: 2.3
|
||||||
|
platforms:
|
||||||
|
- name: EL
|
||||||
|
versions:
|
||||||
|
- 7
|
||||||
|
categories:
|
||||||
|
- system
|
||||||
|
dependencies: []
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
- name: igw_gateway (tgt) | configure iscsi target (gateway)
|
||||||
|
igw_gateway:
|
||||||
|
mode: "target"
|
||||||
|
gateway_iqn: "{{ gateway_iqn }}"
|
||||||
|
gateway_ip_list: "{{ gateway_ip_list }}"
|
||||||
|
register: target
|
||||||
|
|
||||||
|
- name: igw_lun | configure luns (create/map rbds and add to lio)
|
||||||
|
igw_lun:
|
||||||
|
pool: "{{ item.pool }}"
|
||||||
|
image: "{{ item.image }}"
|
||||||
|
size: "{{ item.size }}"
|
||||||
|
host: "{{ item.host }}"
|
||||||
|
state: "{{ item.state }}"
|
||||||
|
with_items: "{{ rbd_devices|default([]) }}"
|
||||||
|
register: images
|
||||||
|
|
||||||
|
- name: igw_gateway (map) | map luns to the iscsi target
|
||||||
|
igw_gateway:
|
||||||
|
mode: "map"
|
||||||
|
gateway_iqn: "{{ gateway_iqn }}"
|
||||||
|
gateway_ip_list: "{{ gateway_ip_list }}"
|
||||||
|
register: luns
|
||||||
|
|
||||||
|
- name: igw_client | configure client connectivity
|
||||||
|
igw_client:
|
||||||
|
client_iqn: "{{ item.client }}"
|
||||||
|
image_list: "{{ item.image_list }}"
|
||||||
|
chap: "{{ item.chap }}"
|
||||||
|
state: "{{ item.status }}"
|
||||||
|
with_items: "{{ client_connections|default([]) }}"
|
||||||
|
register: clients
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
- name: set crt path(s)
|
||||||
|
set_fact:
|
||||||
|
crt_files:
|
||||||
|
- "/etc/ceph/iscsi-gateway.crt"
|
||||||
|
- "/etc/ceph/iscsi-gateway.key"
|
||||||
|
- "/etc/ceph/iscsi-gateway.pem"
|
||||||
|
- "/etc/ceph/iscsi-gateway-pub.key"
|
||||||
|
|
||||||
|
- name: stat for crt file(s)
|
||||||
|
local_action: stat path={{ fetch_directory }}/{{ fsid }}/{{ item }}
|
||||||
|
with_items: "{{ crt_files }}"
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
always_run: true
|
||||||
|
register: crt_files_exist
|
||||||
|
|
||||||
|
- name: try to fetch crt file(s)
|
||||||
|
copy:
|
||||||
|
src: "{{ fetch_directory }}/{{ fsid }}/{{ item.0 }}"
|
||||||
|
dest: "{{ item.0 }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0400
|
||||||
|
changed_when: false
|
||||||
|
with_together:
|
||||||
|
- "{{ crt_files }}"
|
||||||
|
- "{{ crt_files_exist.results }}"
|
||||||
|
when: item.1.stat.exists == true
|
||||||
|
|
||||||
|
- include: generate_crt.yml
|
||||||
|
with_together:
|
||||||
|
- "{{ crt_files }}"
|
||||||
|
- "{{ crt_files_exist.results }}"
|
||||||
|
when: item.1.stat.exists == false
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
- name: (local) create ssl crt/key files
|
||||||
|
shell: |
|
||||||
|
openssl req -newkey rsa:2048 -nodes -keyout /etc/ceph/iscsi-gateway.key -x509 -days 365 -out /etc/ceph/iscsi-gateway.crt -subj "/C=US/ST=./L=./O=RedHat/OU=Linux/CN={{ ansible_hostname }}"
|
||||||
|
run_once: True
|
||||||
|
|
||||||
|
- name: (local) create pem
|
||||||
|
shell: |
|
||||||
|
cat /etc/ceph/iscsi-gateway.crt /etc/ceph/iscsi-gateway.key > /etc/ceph/iscsi-gateway.pem
|
||||||
|
run_once: True
|
||||||
|
register: pem
|
||||||
|
|
||||||
|
- name: (local) create public key from pem
|
||||||
|
shell: |
|
||||||
|
openssl x509 -inform pem -in /etc/ceph/iscsi-gateway.pem -pubkey -noout > /etc/ceph/iscsi-gateway-pub.key
|
||||||
|
run_once: True
|
||||||
|
when:
|
||||||
|
- pem.changed
|
||||||
|
|
||||||
|
- name: lock ssl file access to root only
|
||||||
|
file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
mode: 0400
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
with_items: "{{ crt_files }}"
|
||||||
|
|
||||||
|
- name: copy crt(s) to the ansible server
|
||||||
|
fetch:
|
||||||
|
src: "{{ item }}"
|
||||||
|
dest: "{{ fetch_directory }}/{{ fsid }}/{{ item }}"
|
||||||
|
flat: yes
|
||||||
|
with_items: "{{ crt_files }}"
|
|
@ -1 +1,8 @@
|
||||||
---
|
---
|
||||||
|
- include: prerequisites.yml
|
||||||
|
|
||||||
|
# deploy_ssl_keys used the ansible controller to create self-signed crt/key/pub files
|
||||||
|
# and transfers them to /etc/ceph directory on each controller. SSL certs are used by
|
||||||
|
# the API for https support.
|
||||||
|
- include: deploy_ssl_keys.yml
|
||||||
|
- include: configure_iscsi.yml
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
- name: check the status of the target.service override
|
||||||
|
stat:
|
||||||
|
path: /etc/systemd/system/target.service
|
||||||
|
register: target
|
||||||
|
|
||||||
|
- name: mask the target service - preventing manual start
|
||||||
|
systemd:
|
||||||
|
name: target
|
||||||
|
masked: yes
|
||||||
|
enabled: no
|
||||||
|
when:
|
||||||
|
- target.stat.exists == False or (target.stat.exists and target.stat.islnk == False)
|
||||||
|
|
||||||
|
- name: enable the rbd-target-gw service and make sure it is running
|
||||||
|
service:
|
||||||
|
name: rbd-target-gw
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: copy admin key
|
||||||
|
copy:
|
||||||
|
src: "{{ fetch_directory }}/{{ fsid }}/etc/ceph/{{ cluster }}.client.admin.keyring"
|
||||||
|
dest: "/etc/ceph/{{ cluster }}.client.admin.keyring"
|
||||||
|
owner: "ceph"
|
||||||
|
group: "ceph"
|
||||||
|
mode: "0600"
|
||||||
|
when:
|
||||||
|
- cephx
|
||||||
|
|
||||||
|
- name: deploy gateway settings, used by the ceph_iscsi_config modules
|
||||||
|
template:
|
||||||
|
src: "{{ role_path }}/templates/iscsi-gateway.cfg.j2"
|
||||||
|
dest: /etc/ceph/iscsi-gateway.cfg
|
|
@ -0,0 +1,17 @@
|
||||||
|
# This is seed configuration used by the ceph_iscsi_config modules
|
||||||
|
# when handling configuration tasks for iscsi gateway(s)
|
||||||
|
#
|
||||||
|
# {{ ansible_managed }}
|
||||||
|
|
||||||
|
[config]
|
||||||
|
cluster_name = {{ cluster }}
|
||||||
|
gateway_keyring = /etc/ceph/{{ cluster }}.client.admin.keyring
|
||||||
|
|
||||||
|
|
||||||
|
# Optional settings related to the CLI/API service
|
||||||
|
#api_user = admin
|
||||||
|
#api_password = admin
|
||||||
|
#api_port = 5001
|
||||||
|
#api_secure = true
|
||||||
|
#loop_delay = .5
|
||||||
|
#trusted_ip_list = 192.168.122.1
|
|
@ -12,6 +12,7 @@
|
||||||
- rbdmirrors
|
- rbdmirrors
|
||||||
- clients
|
- clients
|
||||||
- mgrs
|
- mgrs
|
||||||
|
- iscsi_gws
|
||||||
|
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
|
|
||||||
|
@ -140,3 +141,13 @@
|
||||||
- { role: ceph-common, when: "ceph_release_num.{{ ceph_stable_release }} > ceph_release_num.jewel" }
|
- { role: ceph-common, when: "ceph_release_num.{{ ceph_stable_release }} > ceph_release_num.jewel" }
|
||||||
- { role: ceph-config, when: "ceph_release_num.{{ ceph_stable_release }} > ceph_release_num.jewel" }
|
- { role: ceph-config, when: "ceph_release_num.{{ ceph_stable_release }} > ceph_release_num.jewel" }
|
||||||
- { role: ceph-mgr, when: "ceph_release_num.{{ ceph_stable_release }} > ceph_release_num.jewel" }
|
- { role: ceph-mgr, when: "ceph_release_num.{{ ceph_stable_release }} > ceph_release_num.jewel" }
|
||||||
|
|
||||||
|
- hosts: iscsi_gws
|
||||||
|
gather_facts: false
|
||||||
|
become: True
|
||||||
|
roles:
|
||||||
|
- { role: ceph-defaults, when: "ceph_release_num.{{ ceph_stable_release }} >= ceph_release_num.luminous" }
|
||||||
|
- { role: ceph-common, when: "ceph_release_num.{{ ceph_stable_release }} >= ceph_release_num.luminous" }
|
||||||
|
- { role: ceph-config, when: "ceph_release_num.{{ ceph_stable_release }} >= ceph_release_num.luminous" }
|
||||||
|
- { role: ceph-iscsi-gw, when: "ceph_release_num.{{ ceph_stable_release }} >= ceph_release_num.luminous" }
|
||||||
|
|
||||||
|
|
|
@ -23,3 +23,6 @@ ceph-nfs0
|
||||||
|
|
||||||
[rbdmirrors]
|
[rbdmirrors]
|
||||||
ceph-rbd-mirror0
|
ceph-rbd-mirror0
|
||||||
|
|
||||||
|
#[iscsi_gws]
|
||||||
|
#ceph-iscsi-gw0 ceph_repository="dev"
|
||||||
|
|
Loading…
Reference in New Issue