Commit 49012c08 authored by Yuan Gao's avatar Yuan Gao
Browse files

Support mounting to specific AZ mount target

parent 8d8187dc
...@@ -171,6 +171,12 @@ To mount file system within a given network namespace, run: ...@@ -171,6 +171,12 @@ To mount file system within a given network namespace, run:
$ sudo mount -t efs -o netns=netns-path file-system-id efs-mount-point/ $ sudo mount -t efs -o netns=netns-path file-system-id efs-mount-point/
``` ```
To mount file system to the mount target in specific availability zone (e.g. us-east-1a), run:
```
$ sudo mount -t efs -o az=az-name file-system-id efs-mount-point/
```
To mount over TLS, simply add the `tls` option: To mount over TLS, simply add the `tls` option:
``` ```
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
%endif %endif
Name : amazon-efs-utils Name : amazon-efs-utils
Version : 1.29.1 Version : 1.30.1
Release : 1%{platform} Release : 1%{platform}
Summary : This package provides utilities for simplifying the use of EFS file systems Summary : This package provides utilities for simplifying the use of EFS file systems
...@@ -131,6 +131,10 @@ fi ...@@ -131,6 +131,10 @@ fi
%clean %clean
%changelog %changelog
* Mon Mar 22 2021 Yuan Gao <ygaochn@amazon.com> - 1.30.1
- Support new option: az, enable mount file system to specific availability zone mount target
- Merge PR #84 on Github. Fix to use regional AWS STS endpoints instead of the global endpoint to reduce latency
* Mon Jan 25 2021 Yuan Gao <ygaochn@amazon.com> - 1.29.1 * Mon Jan 25 2021 Yuan Gao <ygaochn@amazon.com> - 1.29.1
- Update the python dependency to python3 - Update the python dependency to python3
- Support SLES and OpenSUSE - Support SLES and OpenSUSE
......
...@@ -11,7 +11,7 @@ set -ex ...@@ -11,7 +11,7 @@ set -ex
BASE_DIR=$(pwd) BASE_DIR=$(pwd)
BUILD_ROOT=${BASE_DIR}/build/debbuild BUILD_ROOT=${BASE_DIR}/build/debbuild
VERSION=1.29.1 VERSION=1.30.1
RELEASE=1 RELEASE=1
DEB_SYSTEM_RELEASE_PATH=/etc/os-release DEB_SYSTEM_RELEASE_PATH=/etc/os-release
......
...@@ -7,5 +7,5 @@ ...@@ -7,5 +7,5 @@
# #
[global] [global]
version=1.29.1 version=1.30.1
release=1 release=1
Package: amazon-efs-utils Package: amazon-efs-utils
Architecture: all Architecture: all
Version: 1.29.1 Version: 1.30.1
Section: utils Section: utils
Depends: python3, nfs-common, stunnel4 (>= 4.56), openssl (>= 1.0.2), util-linux Depends: python3, nfs-common, stunnel4 (>= 4.56), openssl (>= 1.0.2), util-linux
Priority: optional Priority: optional
......
...@@ -14,7 +14,7 @@ logging_file_count = 10 ...@@ -14,7 +14,7 @@ logging_file_count = 10
state_file_dir_mode = 750 state_file_dir_mode = 750
[mount] [mount]
dns_name_format = {fs_id}.efs.{region}.{dns_name_suffix} dns_name_format = {az}.{fs_id}.efs.{region}.{dns_name_suffix}
dns_name_suffix = amazonaws.com dns_name_suffix = amazonaws.com
#The region of the file system when mounting from on-premises or cross region. #The region of the file system when mounting from on-premises or cross region.
#region = us-east-1 #region = us-east-1
...@@ -36,14 +36,18 @@ port_range_upper_bound = 20449 ...@@ -36,14 +36,18 @@ port_range_upper_bound = 20449
[mount.cn-north-1] [mount.cn-north-1]
dns_name_suffix = amazonaws.com.cn dns_name_suffix = amazonaws.com.cn
[mount.cn-northwest-1] [mount.cn-northwest-1]
dns_name_suffix = amazonaws.com.cn dns_name_suffix = amazonaws.com.cn
[mount.us-iso-east-1] [mount.us-iso-east-1]
dns_name_suffix = c2s.ic.gov dns_name_suffix = c2s.ic.gov
stunnel_cafile = /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
[mount.us-isob-east-1] [mount.us-isob-east-1]
dns_name_suffix = sc2s.sgov.gov dns_name_suffix = sc2s.sgov.gov
stunnel_cafile = /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
[mount-watchdog] [mount-watchdog]
enabled = true enabled = true
......
...@@ -99,7 +99,19 @@ Use the named profile used to lookup IAM credentials in the AWS CLI credentials ...@@ -99,7 +99,19 @@ Use the named profile used to lookup IAM credentials in the AWS CLI credentials
(~/.aws/credentials) or AWS CLI config file (~/.aws/config). If "awsprofile" is not \ (~/.aws/credentials) or AWS CLI config file (~/.aws/config). If "awsprofile" is not \
specified, the "default" profile is used\&. specified, the "default" profile is used\&.
.TP .TP
mountport \fBawscredsuri\fR
Use the relative uri to lookup IAM credentials from ecs task metadata endpoint\&.
.TP
\fBcafile\fR
Use the cafile as the stunnel certificate authority file.\&.
.TP
\fBnetns\fR
Mount the EFS file system to the specified network namespace\&.
.TP
\fBaz\fR
Mount the EFS file system to the specified availability zone mount target\&.
.TP
\fBmountport\fR
Use the port 2049 to bypass portmapper daemon on EC2 Mac instances running macOS Big Sur\&. Use the port 2049 to bypass portmapper daemon on EC2 Mac instances running macOS Big Sur\&.
.if n \{\ .if n \{\
.RE .RE
...@@ -115,6 +127,10 @@ Mount an EFS file system with file system ID "fs-abcd1234" at mount point \ ...@@ -115,6 +127,10 @@ Mount an EFS file system with file system ID "fs-abcd1234" at mount point \
"/mnt/efs" without encryption of data in transit in given network namespace \ "/mnt/efs" without encryption of data in transit in given network namespace \
'/proc/1/net/ns' '/proc/1/net/ns'
.TP .TP
sudo mount -t efs -o az=us-east-1a fs-abcd1234 /mnt/efs
Mount an EFS file system with file system ID "fs-abcd1234" at mount point \
"/mnt/efs" to the mount target in availability zone us-east-1a
.TP
sudo mount -t efs fs-abcd1234:/child /mnt/efs sudo mount -t efs fs-abcd1234:/child /mnt/efs
Mount a non-root directory of an EFS file system with file system ID \ Mount a non-root directory of an EFS file system with file system ID \
"fs-abcd1234" at mount point "/mnt/efs" without encryption of data in transit\&. "fs-abcd1234" at mount point "/mnt/efs" without encryption of data in transit\&.
......
...@@ -78,7 +78,7 @@ except ImportError: ...@@ -78,7 +78,7 @@ except ImportError:
BOTOCORE_PRESENT = False BOTOCORE_PRESENT = False
VERSION = '1.29.1' VERSION = '1.30.1'
SERVICE = 'elasticfilesystem' SERVICE = 'elasticfilesystem'
CLONE_NEWNET = 0x40000000 CLONE_NEWNET = 0x40000000
...@@ -154,7 +154,8 @@ SIGNED_HEADERS = ';'.join(CANONICAL_HEADERS_DICT.keys()) ...@@ -154,7 +154,8 @@ SIGNED_HEADERS = ';'.join(CANONICAL_HEADERS_DICT.keys())
REQUEST_PAYLOAD = '' REQUEST_PAYLOAD = ''
FS_ID_RE = re.compile('^(?P<fs_id>fs-[0-9a-f]+)$') FS_ID_RE = re.compile('^(?P<fs_id>fs-[0-9a-f]+)$')
EFS_FQDN_RE = re.compile(r'^(?P<fs_id>fs-[0-9a-f]+)\.efs\.(?P<region>[a-z0-9-]+)\.(?P<dns_name_suffix>[a-z0-9.]+)$') EFS_FQDN_RE = re.compile(r'^((?P<az>[a-z0-9-]+)\.)?(?P<fs_id>fs-[0-9a-f]+)\.efs\.'
r'(?P<region>[a-z0-9-]+)\.(?P<dns_name_suffix>[a-z0-9.]+)$')
AP_ID_RE = re.compile('^fsap-[0-9a-f]{17}$') AP_ID_RE = re.compile('^fsap-[0-9a-f]{17}$')
CREDENTIALS_KEYS = ['AccessKeyId', 'SecretAccessKey', 'Token'] CREDENTIALS_KEYS = ['AccessKeyId', 'SecretAccessKey', 'Token']
...@@ -180,6 +181,7 @@ EFS_ONLY_OPTIONS = [ ...@@ -180,6 +181,7 @@ EFS_ONLY_OPTIONS = [
'accesspoint', 'accesspoint',
'awscredsuri', 'awscredsuri',
'awsprofile', 'awsprofile',
'az',
'cafile', 'cafile',
'iam', 'iam',
'netns', 'netns',
...@@ -696,12 +698,14 @@ def serialize_stunnel_config(config, header=None): ...@@ -696,12 +698,14 @@ def serialize_stunnel_config(config, header=None):
return lines return lines
def add_stunnel_ca_options(efs_config, config, options): def add_stunnel_ca_options(efs_config, config, options, region):
if 'cafile' in options: if 'cafile' in options:
stunnel_cafile = options['cafile'] stunnel_cafile = options['cafile']
else: else:
try: try:
stunnel_cafile = config.get(CONFIG_SECTION, 'stunnel_cafile') config_section = get_config_section(config, region)
stunnel_cafile = config.get(config_section, 'stunnel_cafile')
logging.debug("Using stunnel_cafile %s in config section [%s]", stunnel_cafile, config_section)
except NoOptionError: except NoOptionError:
logging.debug('No CA file configured, using default CA file %s', DEFAULT_STUNNEL_CAFILE) logging.debug('No CA file configured, using default CA file %s', DEFAULT_STUNNEL_CAFILE)
stunnel_cafile = DEFAULT_STUNNEL_CAFILE stunnel_cafile = DEFAULT_STUNNEL_CAFILE
...@@ -713,6 +717,15 @@ def add_stunnel_ca_options(efs_config, config, options): ...@@ -713,6 +717,15 @@ def add_stunnel_ca_options(efs_config, config, options):
efs_config['CAfile'] = stunnel_cafile efs_config['CAfile'] = stunnel_cafile
def get_config_section(config, region):
region_specific_config_section = '%s.%s' % (CONFIG_SECTION, region)
if config.has_section(region_specific_config_section):
config_section = region_specific_config_section
else:
config_section = CONFIG_SECTION
return config_section
def is_stunnel_option_supported(stunnel_output, stunnel_option_name): def is_stunnel_option_supported(stunnel_output, stunnel_option_name):
supported = False supported = False
for line in stunnel_output: for line in stunnel_output:
...@@ -779,7 +792,7 @@ def get_system_release_version(): ...@@ -779,7 +792,7 @@ def get_system_release_version():
def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_port, dns_name, verify_level, ocsp_enabled, def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_port, dns_name, verify_level, ocsp_enabled,
options, log_dir=LOG_DIR, cert_details=None): options, region, log_dir=LOG_DIR, cert_details=None):
""" """
Serializes stunnel configuration to a file. Unfortunately this does not conform to Python's config file format, so we have to Serializes stunnel configuration to a file. Unfortunately this does not conform to Python's config file format, so we have to
hand-serialize it. hand-serialize it.
...@@ -805,7 +818,7 @@ def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_por ...@@ -805,7 +818,7 @@ def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_por
efs_config['connect'] = efs_config['connect'] % dns_name efs_config['connect'] = efs_config['connect'] % dns_name
efs_config['verify'] = verify_level efs_config['verify'] = verify_level
if verify_level > 0: if verify_level > 0:
add_stunnel_ca_options(efs_config, config, options) add_stunnel_ca_options(efs_config, config, options, region)
if cert_details: if cert_details:
efs_config['cert'] = cert_details['certificate'] efs_config['cert'] = cert_details['certificate']
...@@ -819,7 +832,10 @@ def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_por ...@@ -819,7 +832,10 @@ def write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_por
if config.getboolean(CONFIG_SECTION, 'stunnel_check_cert_hostname'): if config.getboolean(CONFIG_SECTION, 'stunnel_check_cert_hostname'):
if check_host_supported: if check_host_supported:
efs_config['checkHost'] = dns_name # Stunnel checkHost option checks if the specified DNS host name or wildcard matches any of the provider in peer
# certificate's CN fields, after introducing the AZ field in dns name, the host name in the stunnel config file
# is not valid, remove the az info there
efs_config['checkHost'] = dns_name[dns_name.index(fs_id):]
else: else:
fatal_error(tls_controls_message % 'stunnel_check_cert_hostname') fatal_error(tls_controls_message % 'stunnel_check_cert_hostname')
...@@ -1011,6 +1027,7 @@ def bootstrap_tls(config, init_system, dns_name, fs_id, mountpoint, options, sta ...@@ -1011,6 +1027,7 @@ def bootstrap_tls(config, init_system, dns_name, fs_id, mountpoint, options, sta
cert_details['mountStateDir'] = get_mount_specific_filename(fs_id, mountpoint, tls_port) + '+' cert_details['mountStateDir'] = get_mount_specific_filename(fs_id, mountpoint, tls_port) + '+'
# common name for certificate signing request is max 64 characters # common name for certificate signing request is max 64 characters
cert_details['commonName'] = socket.gethostname()[0:64] cert_details['commonName'] = socket.gethostname()[0:64]
region = get_target_region(config)
cert_details['region'] = region cert_details['region'] = region
cert_details['certificateCreationTime'] = create_certificate(config, cert_details['mountStateDir'], cert_details['certificateCreationTime'] = create_certificate(config, cert_details['mountStateDir'],
cert_details['commonName'], cert_details['region'], fs_id, cert_details['commonName'], cert_details['region'], fs_id,
...@@ -1029,7 +1046,7 @@ def bootstrap_tls(config, init_system, dns_name, fs_id, mountpoint, options, sta ...@@ -1029,7 +1046,7 @@ def bootstrap_tls(config, init_system, dns_name, fs_id, mountpoint, options, sta
ocsp_enabled = is_ocsp_enabled(config, options) ocsp_enabled = is_ocsp_enabled(config, options)
stunnel_config_file = write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_port, dns_name, verify_level, stunnel_config_file = write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_port, dns_name, verify_level,
ocsp_enabled, options, cert_details=cert_details) ocsp_enabled, options, region, cert_details=cert_details)
tunnel_args = [_stunnel_bin(), stunnel_config_file] tunnel_args = [_stunnel_bin(), stunnel_config_file]
if 'netns' in options: if 'netns' in options:
tunnel_args = ['nsenter', '--net=' + options['netns']] + tunnel_args tunnel_args = ['nsenter', '--net=' + options['netns']] + tunnel_args
...@@ -1186,9 +1203,11 @@ def parse_arguments(config, args=None): ...@@ -1186,9 +1203,11 @@ def parse_arguments(config, args=None):
if not fsname or not mountpoint: if not fsname or not mountpoint:
usage(out=sys.stderr) usage(out=sys.stderr)
fs_id, path = match_device(config, fsname) # We treat az as an option when customer is using dns name of az mount target to mount,
# even if they don't provide az with option, we update the options with that info
fs_id, path, az = match_device(config, fsname, options)
return fs_id, path, mountpoint, options return fs_id, path, mountpoint, add_field_in_options(options, 'az', az)
def get_client_info(config): def get_client_info(config):
...@@ -1453,7 +1472,7 @@ def bootstrap_logging(config, log_dir=LOG_DIR): ...@@ -1453,7 +1472,7 @@ def bootstrap_logging(config, log_dir=LOG_DIR):
logging.error('Malformed logging level "%s", setting logging level to %s', raw_level, level) logging.error('Malformed logging level "%s", setting logging level to %s', raw_level, level)
def get_dns_name(config, fs_id): def get_dns_name(config, fs_id, options):
def _validate_replacement_field_count(format_str, expected_ct): def _validate_replacement_field_count(format_str, expected_ct):
if format_str.count('{') != expected_ct or format_str.count('}') != expected_ct: if format_str.count('{') != expected_ct or format_str.count('}') != expected_ct:
raise ValueError('DNS name format has an incorrect number of replacement fields') raise ValueError('DNS name format has an incorrect number of replacement fields')
...@@ -1467,6 +1486,14 @@ def get_dns_name(config, fs_id): ...@@ -1467,6 +1486,14 @@ def get_dns_name(config, fs_id):
expected_replacement_field_ct = 1 expected_replacement_field_ct = 1
if '{az}' in dns_name_format:
az = options.get('az')
if az:
expected_replacement_field_ct += 1
format_args['az'] = az
else:
dns_name_format = dns_name_format.replace('{az}.', '')
if '{region}' in dns_name_format: if '{region}' in dns_name_format:
expected_replacement_field_ct += 1 expected_replacement_field_ct += 1
format_args['region'] = get_target_region(config) format_args['region'] = get_target_region(config)
...@@ -1477,9 +1504,7 @@ def get_dns_name(config, fs_id): ...@@ -1477,9 +1504,7 @@ def get_dns_name(config, fs_id):
region = format_args.get('region') region = format_args.get('region')
if region: if region:
region_specific_config_section = '%s.%s' % (CONFIG_SECTION, region) config_section = get_config_section(config, region)
if config.has_section(region_specific_config_section):
config_section = region_specific_config_section
format_args['dns_name_suffix'] = config.get(config_section, 'dns_name_suffix') format_args['dns_name_suffix'] = config.get(config_section, 'dns_name_suffix')
...@@ -1650,8 +1675,8 @@ def get_credential_scope(date, region): ...@@ -1650,8 +1675,8 @@ def get_credential_scope(date, region):
return '/'.join([date.strftime(DATE_ONLY_FORMAT), region, SERVICE, AWS4_REQUEST]) return '/'.join([date.strftime(DATE_ONLY_FORMAT), region, SERVICE, AWS4_REQUEST])
def match_device(config, device): def match_device(config, device, options):
"""Return the EFS id and the remote path to mount""" """Return the EFS id, the remote path, and the az to mount"""
try: try:
remote, path = device.split(':', 1) remote, path = device.split(':', 1)
...@@ -1660,7 +1685,7 @@ def match_device(config, device): ...@@ -1660,7 +1685,7 @@ def match_device(config, device):
path = '/' path = '/'
if FS_ID_RE.match(remote): if FS_ID_RE.match(remote):
return remote, path return remote, path, None
try: try:
primary, secondaries, _ = socket.gethostbyname_ex(remote) primary, secondaries, _ = socket.gethostbyname_ex(remote)
...@@ -1683,12 +1708,19 @@ def match_device(config, device): ...@@ -1683,12 +1708,19 @@ def match_device(config, device):
efs_fqdn_match = EFS_FQDN_RE.match(hostname) efs_fqdn_match = EFS_FQDN_RE.match(hostname)
if efs_fqdn_match: if efs_fqdn_match:
az = efs_fqdn_match.group('az')
fs_id = efs_fqdn_match.group('fs_id') fs_id = efs_fqdn_match.group('fs_id')
expected_dns_name = get_dns_name(config, fs_id)
if az and 'az' in options and az != options['az']:
fatal_error(
'The hostname "%s" resolved by the specified domain name "%s" does not match the az provided in the '
'mount options, expected = %s, given = %s' % (hostname, remote, options['az'], az))
expected_dns_name = get_dns_name(config, fs_id, add_field_in_options(options, 'az', az))
# check that the DNS name of the mount target matches exactly the DNS name the CNAME resolves to # check that the DNS name of the mount target matches exactly the DNS name the CNAME resolves to
if hostname == expected_dns_name: if hostname == expected_dns_name:
return fs_id, path return fs_id, path, az
else: else:
create_default_cloudwatchlog_agent_if_not_exist(config) create_default_cloudwatchlog_agent_if_not_exist(config)
fatal_error('The specified CNAME "%s" did not resolve to a valid DNS name for an EFS mount target. ' fatal_error('The specified CNAME "%s" did not resolve to a valid DNS name for an EFS mount target. '
...@@ -1696,6 +1728,12 @@ def match_device(config, device): ...@@ -1696,6 +1728,12 @@ def match_device(config, device):
% (remote, 'https://docs.aws.amazon.com/efs/latest/ug/mounting-fs-mount-cmd-dns-name.html')) % (remote, 'https://docs.aws.amazon.com/efs/latest/ug/mounting-fs-mount-cmd-dns-name.html'))
def add_field_in_options(options, field_key, field_value):
if field_value and field_key not in options:
options[field_key] = field_value
return options
def is_nfs_mount(mountpoint): def is_nfs_mount(mountpoint):
if not check_if_platform_is_mac(): if not check_if_platform_is_mac():
cmd = ['stat', '-f', '-L', '-c', '%T', mountpoint] cmd = ['stat', '-f', '-L', '-c', '%T', mountpoint]
...@@ -2150,7 +2188,7 @@ def main(): ...@@ -2150,7 +2188,7 @@ def main():
init_system = get_init_system() init_system = get_init_system()
check_network_status(fs_id, init_system) check_network_status(fs_id, init_system)
dns_name = get_dns_name(config, fs_id) dns_name = get_dns_name(config, fs_id, options)
if 'tls' in options: if 'tls' in options:
mount_tls(config, init_system, dns_name, path, fs_id, mountpoint, options) mount_tls(config, init_system, dns_name, path, fs_id, mountpoint, options)
......
...@@ -48,7 +48,7 @@ except ImportError: ...@@ -48,7 +48,7 @@ except ImportError:
from urllib import urlencode from urllib import urlencode
VERSION = '1.29.1' VERSION = '1.30.1'
SERVICE = 'elasticfilesystem' SERVICE = 'elasticfilesystem'
CONFIG_FILE = '/etc/amazon/efs/efs-utils.conf' CONFIG_FILE = '/etc/amazon/efs/efs-utils.conf'
......
...@@ -18,6 +18,9 @@ except ImportError: ...@@ -18,6 +18,9 @@ except ImportError:
CAPATH = '/capath' CAPATH = '/capath'
CAFILE = '/cafile.crt' CAFILE = '/cafile.crt'
DEFAULT_REGION = 'us-east-1'
ISOLATED_REGION = 'us-iso-east-1'
ISOLATED_REGION_STUNNEL_CAFILE = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem'
def _get_config(): def _get_config():
...@@ -39,7 +42,7 @@ def test_use_existing_cafile(tmpdir): ...@@ -39,7 +42,7 @@ def test_use_existing_cafile(tmpdir):
options = {'cafile': str(_create_temp_file(tmpdir))} options = {'cafile': str(_create_temp_file(tmpdir))}
efs_config = {} efs_config = {}
mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options) mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options, DEFAULT_REGION)
assert options['cafile'] == efs_config.get('CAfile') assert options['cafile'] == efs_config.get('CAfile')
assert 'CApath' not in efs_config assert 'CApath' not in efs_config
...@@ -50,7 +53,7 @@ def test_use_missing_cafile(capsys): ...@@ -50,7 +53,7 @@ def test_use_missing_cafile(capsys):
efs_config = {} efs_config = {}
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex:
mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options) mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options, DEFAULT_REGION)
assert 0 != ex.value.code assert 0 != ex.value.code
...@@ -64,7 +67,7 @@ def test_stunnel_cafile_configuration_in_option(mocker): ...@@ -64,7 +67,7 @@ def test_stunnel_cafile_configuration_in_option(mocker):
mocker.patch('os.path.exists', return_value=True) mocker.patch('os.path.exists', return_value=True)
mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options) mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options, DEFAULT_REGION)
assert CAFILE == efs_config.get('CAfile') assert CAFILE == efs_config.get('CAfile')
...@@ -78,7 +81,7 @@ def test_stunnel_cafile_configuration_in_config(mocker): ...@@ -78,7 +81,7 @@ def test_stunnel_cafile_configuration_in_config(mocker):
mocker.patch('os.path.exists', return_value=True) mocker.patch('os.path.exists', return_value=True)
mount_efs.add_stunnel_ca_options(efs_config, config, options) mount_efs.add_stunnel_ca_options(efs_config, config, options, DEFAULT_REGION)
assert CAFILE == efs_config.get('CAfile') assert CAFILE == efs_config.get('CAfile')
...@@ -89,6 +92,23 @@ def test_stunnel_cafile_not_configured(mocker): ...@@ -89,6 +92,23 @@ def test_stunnel_cafile_not_configured(mocker):
mocker.patch('os.path.exists', return_value=True) mocker.patch('os.path.exists', return_value=True)
mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options) mount_efs.add_stunnel_ca_options(efs_config, _get_config(), options, DEFAULT_REGION)
assert mount_efs.DEFAULT_STUNNEL_CAFILE == efs_config.get('CAfile') assert mount_efs.DEFAULT_STUNNEL_CAFILE == efs_config.get('CAfile')
def test_stunnel_cafile_configured_in_mount_region_section(mocker):
options = {}
efs_config = {}
config = _get_config()
config.set(mount_efs.CONFIG_SECTION, 'stunnel_cafile', CAFILE)
config_section = '%s.%s' % (mount_efs.CONFIG_SECTION, ISOLATED_REGION)
config.add_section(config_section)
config.set(config_section, 'stunnel_cafile', ISOLATED_REGION_STUNNEL_CAFILE)
mocker.patch('os.path.exists', return_value=True)
mount_efs.add_stunnel_ca_options(efs_config, config, options, ISOLATED_REGION)
assert ISOLATED_REGION_STUNNEL_CAFILE == efs_config.get('CAfile')
\ No newline at end of file
...@@ -17,6 +17,7 @@ from .. import utils ...@@ -17,6 +17,7 @@ from .. import utils
FS_ID = 'fs-deadbeef' FS_ID = 'fs-deadbeef'
DEFAULT_REGION = 'us-east-1' DEFAULT_REGION = 'us-east-1'
DEFAULT_AZ = 'us-east-1a'
SPECIAL_REGION_DNS_DICT = { SPECIAL_REGION_DNS_DICT = {
"cn-north-1": "amazonaws.com.cn", "cn-north-1": "amazonaws.com.cn",
"cn-northwest-1": "amazonaws.com.cn", "cn-northwest-1": "amazonaws.com.cn",
...@@ -24,6 +25,8 @@ SPECIAL_REGION_DNS_DICT = { ...@@ -24,6 +25,8 @@ SPECIAL_REGION_DNS_DICT = {
"us-isob-east-1": "sc2s.sgov.gov" "us-isob-east-1": "sc2s.sgov.gov"
} }
SPECIAL_REGIONS = ["cn-north-1", "cn-northwest-1", "us-iso-east-1", "us-isob-east-1"] SPECIAL_REGIONS = ["cn-north-1", "cn-northwest-1", "us-iso-east-1", "us-isob-east-1"]
DEFAULT_NFS_OPTIONS = {}
OPTIONS_WITH_AZ = {'az': DEFAULT_AZ}
@pytest.fixture(autouse=True)