Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Neil Hanlon
Efs Utils
Commits
49012c08
Commit
49012c08
authored
Mar 31, 2021
by
Yuan Gao
Browse files
Support mounting to specific AZ mount target
parent
8d8187dc
Changes
15
Show whitespace changes
Inline
Side-by-side
README.md
View file @
49012c08
...
...
@@ -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/
```
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:
```
...
...
amazon-efs-utils.spec
View file @
49012c08
...
...
@@ -31,7 +31,7 @@
%endif
Name : amazon-efs-utils
Version : 1.
29
.1
Version : 1.
30
.1
Release : 1%{platform}
Summary : This package provides utilities for simplifying the use of EFS file systems
...
...
@@ -131,6 +131,10 @@ fi
%clean
%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
- Update the python dependency to python3
- Support SLES and OpenSUSE
...
...
build-deb.sh
View file @
49012c08
...
...
@@ -11,7 +11,7 @@ set -ex
BASE_DIR
=
$(
pwd
)
BUILD_ROOT
=
${
BASE_DIR
}
/build/debbuild
VERSION
=
1.
29
.1
VERSION
=
1.
30
.1
RELEASE
=
1
DEB_SYSTEM_RELEASE_PATH
=
/etc/os-release
...
...
config.ini
View file @
49012c08
...
...
@@ -7,5 +7,5 @@
#
[global]
version
=
1.
29
.1
version
=
1.
30
.1
release
=
1
dist/amazon-efs-utils.control
View file @
49012c08
Package: amazon-efs-utils
Architecture: all
Version: 1.
29
.1
Version: 1.
30
.1
Section: utils
Depends: python3, nfs-common, stunnel4 (>= 4.56), openssl (>= 1.0.2), util-linux
Priority: optional
...
...
dist/efs-utils.conf
View file @
49012c08
...
...
@@ -14,7 +14,7 @@ logging_file_count = 10
state_file_dir_mode
=
750
[
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
#The region of the file system when mounting from on-premises or cross region.
#region = us-east-1
...
...
@@ -36,14 +36,18 @@ port_range_upper_bound = 20449
[
mount
.
cn
-
north
-
1
]
dns_name_suffix
=
amazonaws
.
com
.
cn
[
mount
.
cn
-
northwest
-
1
]
dns_name_suffix
=
amazonaws
.
com
.
cn
[
mount
.
us
-
iso
-
east
-
1
]
dns_name_suffix
=
c2s
.
ic
.
gov
stunnel_cafile
= /
etc
/
pki
/
ca
-
trust
/
extracted
/
pem
/
tls
-
ca
-
bundle
.
pem
[
mount
.
us
-
isob
-
east
-
1
]
dns_name_suffix
=
sc2s
.
sgov
.
gov
stunnel_cafile
= /
etc
/
pki
/
ca
-
trust
/
extracted
/
pem
/
tls
-
ca
-
bundle
.
pem
[
mount
-
watchdog
]
enabled
=
true
...
...
man/mount.efs.8
View file @
49012c08
...
...
@@ -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 \
specified, the "default" profile is used\&.
.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\&.
.if n \{\
.RE
...
...
@@ -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 \
'/proc/1/net/ns'
.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
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\&.
...
...
src/mount_efs/__init__.py
View file @
49012c08
...
...
@@ -78,7 +78,7 @@ except ImportError:
BOTOCORE_PRESENT
=
False
VERSION
=
'1.
29
.1'
VERSION
=
'1.
30
.1'
SERVICE
=
'elasticfilesystem'
CLONE_NEWNET
=
0x40000000
...
...
@@ -154,7 +154,8 @@ SIGNED_HEADERS = ';'.join(CANONICAL_HEADERS_DICT.keys())
REQUEST_PAYLOAD
=
''
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}$'
)
CREDENTIALS_KEYS
=
[
'AccessKeyId'
,
'SecretAccessKey'
,
'Token'
]
...
...
@@ -180,6 +181,7 @@ EFS_ONLY_OPTIONS = [
'accesspoint'
,
'awscredsuri'
,
'awsprofile'
,
'az'
,
'cafile'
,
'iam'
,
'netns'
,
...
...
@@ -696,12 +698,14 @@ def serialize_stunnel_config(config, header=None):
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
:
stunnel_cafile
=
options
[
'cafile'
]
else
:
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
:
logging
.
debug
(
'No CA file configured, using default CA file %s'
,
DEFAULT_STUNNEL_CAFILE
)
stunnel_cafile
=
DEFAULT_STUNNEL_CAFILE
...
...
@@ -713,6 +717,15 @@ def add_stunnel_ca_options(efs_config, config, options):
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
):
supported
=
False
for
line
in
stunnel_output
:
...
...
@@ -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
,
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
hand-serialize it.
...
...
@@ -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
[
'verify'
]
=
verify_level
if
verify_level
>
0
:
add_stunnel_ca_options
(
efs_config
,
config
,
options
)
add_stunnel_ca_options
(
efs_config
,
config
,
options
,
region
)
if
cert_details
:
efs_config
[
'cert'
]
=
cert_details
[
'certificate'
]
...
...
@@ -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
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
:
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
cert_details
[
'mountStateDir'
]
=
get_mount_specific_filename
(
fs_id
,
mountpoint
,
tls_port
)
+
'+'
# common name for certificate signing request is max 64 characters
cert_details
[
'commonName'
]
=
socket
.
gethostname
()[
0
:
64
]
region
=
get_target_region
(
config
)
cert_details
[
'region'
]
=
region
cert_details
[
'certificateCreationTime'
]
=
create_certificate
(
config
,
cert_details
[
'mountStateDir'
],
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
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
,
ocsp_enabled
,
options
,
cert_details
=
cert_details
)
ocsp_enabled
,
options
,
region
,
cert_details
=
cert_details
)
tunnel_args
=
[
_stunnel_bin
(),
stunnel_config_file
]
if
'netns'
in
options
:
tunnel_args
=
[
'nsenter'
,
'--net='
+
options
[
'netns'
]]
+
tunnel_args
...
...
@@ -1186,9 +1203,11 @@ def parse_arguments(config, args=None):
if
not
fsname
or
not
mountpoint
:
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
):
...
...
@@ -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
)
def
get_dns_name
(
config
,
fs_id
):
def
get_dns_name
(
config
,
fs_id
,
options
):
def
_validate_replacement_field_count
(
format_str
,
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'
)
...
...
@@ -1467,6 +1486,14 @@ def get_dns_name(config, fs_id):
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
:
expected_replacement_field_ct
+=
1
format_args
[
'region'
]
=
get_target_region
(
config
)
...
...
@@ -1477,9 +1504,7 @@ def get_dns_name(config, fs_id):
region
=
format_args
.
get
(
'region'
)
if
region
:
region_specific_config_section
=
'%s.%s'
%
(
CONFIG_SECTION
,
region
)
if
config
.
has_section
(
region_specific_config_section
):
config_section
=
region_specific_config_section
config_section
=
get_config_section
(
config
,
region
)
format_args
[
'dns_name_suffix'
]
=
config
.
get
(
config_section
,
'dns_name_suffix'
)
...
...
@@ -1650,8 +1675,8 @@ def get_credential_scope(date, region):
return
'/'
.
join
([
date
.
strftime
(
DATE_ONLY_FORMAT
),
region
,
SERVICE
,
AWS4_REQUEST
])
def
match_device
(
config
,
device
):
"""Return the EFS id
and
the remote path to mount"""
def
match_device
(
config
,
device
,
options
):
"""Return the EFS id
,
the remote path
, and the az
to mount"""
try
:
remote
,
path
=
device
.
split
(
':'
,
1
)
...
...
@@ -1660,7 +1685,7 @@ def match_device(config, device):
path
=
'/'
if
FS_ID_RE
.
match
(
remote
):
return
remote
,
path
return
remote
,
path
,
None
try
:
primary
,
secondaries
,
_
=
socket
.
gethostbyname_ex
(
remote
)
...
...
@@ -1683,12 +1708,19 @@ def match_device(config, device):
efs_fqdn_match
=
EFS_FQDN_RE
.
match
(
hostname
)
if
efs_fqdn_match
:
az
=
efs_fqdn_match
.
group
(
'az'
)
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
if
hostname
==
expected_dns_name
:
return
fs_id
,
path
return
fs_id
,
path
,
az
else
:
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. '
...
...
@@ -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'
))
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
):
if
not
check_if_platform_is_mac
():
cmd
=
[
'stat'
,
'-f'
,
'-L'
,
'-c'
,
'%T'
,
mountpoint
]
...
...
@@ -2150,7 +2188,7 @@ def main():
init_system
=
get_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
:
mount_tls
(
config
,
init_system
,
dns_name
,
path
,
fs_id
,
mountpoint
,
options
)
...
...
src/watchdog/__init__.py
View file @
49012c08
...
...
@@ -48,7 +48,7 @@ except ImportError:
from
urllib
import
urlencode
VERSION
=
'1.
29
.1'
VERSION
=
'1.
30
.1'
SERVICE
=
'elasticfilesystem'
CONFIG_FILE
=
'/etc/amazon/efs/efs-utils.conf'
...
...
test/mount_efs_test/test_add_stunnel_ca_options.py
View file @
49012c08
...
...
@@ -18,6 +18,9 @@ except ImportError:
CAPATH
=
'/capath'
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
():
...
...
@@ -39,7 +42,7 @@ def test_use_existing_cafile(tmpdir):
options
=
{
'cafile'
:
str
(
_create_temp_file
(
tmpdir
))}
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
'CApath'
not
in
efs_config
...
...
@@ -50,7 +53,7 @@ def test_use_missing_cafile(capsys):
efs_config
=
{}
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
...
...
@@ -64,7 +67,7 @@ def test_stunnel_cafile_configuration_in_option(mocker):
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'
)
...
...
@@ -78,7 +81,7 @@ def test_stunnel_cafile_configuration_in_config(mocker):
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'
)
...
...
@@ -89,6 +92,23 @@ def test_stunnel_cafile_not_configured(mocker):
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'
)
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
test/mount_efs_test/test_get_dns_name.py
View file @
49012c08
...
...
@@ -17,6 +17,7 @@ from .. import utils
FS_ID
=
'fs-deadbeef'
DEFAULT_REGION
=
'us-east-1'
DEFAULT_AZ
=
'us-east-1a'
SPECIAL_REGION_DNS_DICT
=
{
"cn-north-1"
:
"amazonaws.com.cn"
,
"cn-northwest-1"
:
"amazonaws.com.cn"
,
...
...
@@ -24,6 +25,8 @@ SPECIAL_REGION_DNS_DICT = {
"us-isob-east-1"
:
"sc2s.sgov.gov"
}
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
)
...
...
@@ -32,7 +35,7 @@ def setup(mocker):
mocker
.
patch
(
'socket.gethostbyname'
)
def
_get_mock_config
(
dns_name_format
=
'{fs_id}.efs.{region}.{dns_name_suffix}'
,
dns_name_suffix
=
'amazonaws.com'
,
def
_get_mock_config
(
dns_name_format
=
'{
az}.{
fs_id}.efs.{region}.{dns_name_suffix}'
,
dns_name_suffix
=
'amazonaws.com'
,
config_section
=
'mount'
):
def
config_get_side_effect
(
section
,
field
):
if
section
==
mount_efs
.
CONFIG_SECTION
and
field
==
'dns_name_format'
:
...
...
@@ -51,25 +54,41 @@ def _get_mock_config(dns_name_format='{fs_id}.efs.{region}.{dns_name_suffix}', d
def
test_get_dns_name
(
mocker
):
config
=
_get_mock_config
()
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
'%s.efs.%s.amazonaws.com'
%
(
FS_ID
,
DEFAULT_REGION
)
==
dns_name
def
test_get_dns_name_with_az_in_options
(
mocker
):
config
=
_get_mock_config
(
'{az}.{fs_id}.efs.{region}.amazonaws.com'
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
OPTIONS_WITH_AZ
)
assert
'%s.%s.efs.%s.amazonaws.com'
%
(
DEFAULT_AZ
,
FS_ID
,
DEFAULT_REGION
)
==
dns_name
def
test_get_dns_name_without_az_in_options
(
mocker
):
config
=
_get_mock_config
(
'{az}.{fs_id}.efs.{region}.amazonaws.com'
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
'%s.efs.%s.amazonaws.com'
%
(
FS_ID
,
DEFAULT_REGION
)
==
dns_name
def
test_get_dns_name_suffix_hardcoded
(
mocker
):
config
=
_get_mock_config
(
'{fs_id}.e
lastic-file-system
.{region}.amazonaws.com'
)
config
=
_get_mock_config
(
'{
az}.{
fs_id}.e
fs
.{region}.amazonaws.com'
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
'%s.e
lastic-file-system
.%s.amazonaws.com'
%
(
FS_ID
,
DEFAULT_REGION
)
==
dns_name
assert
'%s.e
fs
.%s.amazonaws.com'
%
(
FS_ID
,
DEFAULT_REGION
)
==
dns_name
def
test_get_dns_name_region_hardcoded
(
mocker
):
get_target_region_mock
=
mocker
.
patch
(
'mount_efs.get_target_region'
)
config
=
_get_mock_config
(
'{fs_id}.efs.%s.{dns_name_suffix}'
%
DEFAULT_REGION
)
config
=
_get_mock_config
(
'{
az}.{
fs_id}.efs.%s.{dns_name_suffix}'
%
DEFAULT_REGION
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
utils
.
assert_not_called
(
get_target_region_mock
)
...
...
@@ -79,20 +98,20 @@ def test_get_dns_name_region_hardcoded(mocker):
def
test_get_dns_name_region_and_suffix_hardcoded
(
mocker
):
get_target_region_mock
=
mocker
.
patch
(
'mount_efs.get_target_region'
)
config
=
_get_mock_config
(
'{fs_id}.e
lastic-file-system
.us-west-2.amazonaws.com'
)
config
=
_get_mock_config
(
'{
az}.{
fs_id}.e
fs
.us-west-2.amazonaws.com'
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
utils
.
assert_not_called
(
get_target_region_mock
)
assert
'%s.e
lastic-file-system
.us-west-2.amazonaws.com'
%
FS_ID
==
dns_name
assert
'%s.e
fs
.us-west-2.amazonaws.com'
%
FS_ID
==
dns_name
def
test_get_dns_name_bad_format_wrong_specifiers
(
mocker
):
config
=
_get_mock_config
(
'{foo}.efs.{bar}'
)
with
pytest
.
raises
(
ValueError
)
as
ex
:
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
'must include'
in
str
(
ex
.
value
)
...
...
@@ -101,7 +120,7 @@ def test_get_dns_name_bad_format_too_many_specifiers_1(mocker):
config
=
_get_mock_config
(
'{fs_id}.efs.{foo}'
)
with
pytest
.
raises
(
ValueError
)
as
ex
:
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
'incorrect number'
in
str
(
ex
.
value
)
...
...
@@ -110,7 +129,7 @@ def test_get_dns_name_bad_format_too_many_specifiers_2(mocker):
config
=
_get_mock_config
(
'{fs_id}.efs.{region}.{foo}'
)
with
pytest
.
raises
(
ValueError
)
as
ex
:
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
'incorrect number'
in
str
(
ex
.
value
)
...
...
@@ -121,7 +140,7 @@ def test_get_dns_name_unresolvable(mocker, capsys):
mocker
.
patch
(
'socket.gethostbyname'
,
side_effect
=
socket
.
gaierror
)
with
pytest
.
raises
(
SystemExit
)
as
ex
:
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
0
!=
ex
.
value
.
code
...
...
@@ -139,7 +158,7 @@ def test_get_dns_name_special_region(mocker):
config
=
_get_mock_config
(
dns_name_suffix
=
special_dns_name_suffix
,
config_section
=
config_section
)
config
.
has_section
.
return_value
=
True
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
assert
'%s.efs.%s.%s'
%
(
FS_ID
,
special_region
,
special_dns_name_suffix
)
==
dns_name
...
...
@@ -153,9 +172,8 @@ def test_get_dns_name_region_in_suffix(mocker):
config
=
_get_mock_config
(
'{fs_id}.efs.{dns_name_suffix}'
,
dns_name_suffix
=
dns_name_suffix
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
)
dns_name
=
mount_efs
.
get_dns_name
(
config
,
FS_ID
,
DEFAULT_NFS_OPTIONS
)
utils
.
assert_not_called
(
get_target_region_mock
)
assert
'%s.efs.%s.%s'
%
(
FS_ID
,
special_region
,
special_dns_name_suffix
)
==
dns_name
test/mount_efs_test/test_get_target_region.py
View file @
49012c08
...
...
@@ -79,7 +79,7 @@ def get_config(dns_name_format, region=None):
def
get_target_region_helper
():
config
=
get_config
(
'{fs_id}.efs.{region}.{dns_name_suffix}'
)
config
=
get_config
(
'{
az}.{
fs_id}.efs.{region}.{dns_name_suffix}'
)
return
mount_efs
.
get_target_region
(
config
)
...
...
@@ -184,7 +184,7 @@ def test_get_target_region_missing_region(mocker, capsys):
Get target region from configuration file
"""
def
test_get_target_region_from_config_variable
(
mocker
):
config
=
get_config
(
'{fs_id}.efs.us-east-2.{dns_name_suffix}'
,
TARGET_REGION
)
config
=
get_config
(
'{
az}.{
fs_id}.efs.us-east-2.{dns_name_suffix}'
,
TARGET_REGION
)
assert
TARGET_REGION
==
mount_efs
.
get_target_region
(
config
)
...
...
@@ -195,11 +195,11 @@ def _test_get_target_region_from_dns_format(mocker, config):
def
test_get_target_region_from_legacy_dns_name_format
(
mocker
):
config
=
get_config
(
'{fs_id}.efs.us-east-1.amazonaws.com'
)
config
=
get_config
(
'{
az}.{
fs_id}.efs.us-east-1.amazonaws.com'
)
_test_get_target_region_from_dns_format
(
mocker
,
config
)
def
test_get_target_region_from_suffixed_dns_name_format
(
mocker
):
config
=
get_config
(
'{fs_id}.efs.us-east-1.{dns_name_suffix}'
)
config
=
get_config
(
'{
az}.{
fs_id}.efs.us-east-1.{dns_name_suffix}'
)
config
.
set
(
mount_efs
.
CONFIG_SECTION
,
'dns_name_suffix'
,
DNS_NAME_SUFFIX
)
_test_get_target_region_from_dns_format
(
mocker
,
config
)
\ No newline at end of file
test/mount_efs_test/test_match_device.py
View file @
49012c08
...
...
@@ -14,45 +14,86 @@ import mount_efs
from
..
import
utils
from
mock
import
MagicMock
DEFAULT_AZ
=
'us-east-1a'
CORRECT_DEVICE_DESCRIPTORS_FS_ID
=
[
(
'fs-deadbeef'
,
(
'fs-deadbeef'
,
'/'
)),
(
'fs-deadbeef:/'
,
(
'fs-deadbeef'
,
'/'
)),
(
'fs-deadbeef:/some/subpath'
,
(
'fs-deadbeef'
,
'/some/subpath'
)),
(
'fs-deadbeef:/some/subpath/with:colons'
,
(
'fs-deadbeef'
,
'/some/subpath/with:colons'
)),
(
'fs-deadbeef'
,
(
'fs-deadbeef'
,
'/'
,
None
)),
(
'fs-deadbeef:/'
,
(
'fs-deadbeef'
,
'/'
,
None
)),
(
'fs-deadbeef:/some/subpath'
,
(
'fs-deadbeef'
,
'/some/subpath'
,
None
)),
(
'fs-deadbeef:/some/subpath/with:colons'
,
(
'fs-deadbeef'
,
'/some/subpath/with:colons'
,
None
)),
]
CORRECT_DEVICE_DESCRIPTORS_CNAME_DNS
=
[
(
'custom-cname.example.com'
,
(
'fs-deadbeef'
,
'/'
)),
(
'custom-cname.example.com:/'
,
(
'fs-deadbeef'
,
'/'
)),
(
'custom-cname.example.com:/some/subpath'
,
(
'fs-deadbeef'
,
'/some/subpath'
)),
(
'custom-cname.example.com:/some/subpath/with:colons'
,
(
'fs-deadbeef'
,
'/some/subpath/with:colons'
)),
(
'custom-cname.example.com'
,
(
'fs-deadbeef'
,
'/'
,
None
)),
(
'custom-cname.example.com:/'
,
(
'fs-deadbeef'
,
'/'
,
None
)),
(
'custom-cname.example.com:/some/subpath'
,
(
'fs-deadbeef'
,
'/some/subpath'
,
None
)),
(
'custom-cname.example.com:/some/subpath/with:colons'
,
(
'fs-deadbeef'
,
'/some/subpath/with:colons'
,
None
)),
]
DEFAULT_CLOUDWATCH_DISABLED
=
'false'
CORRECT_DEVICE_DESCRIPTORS_CNAME_DNS_WITH_AZ
=
[
(
'custom-cname.example.com'
,
(
'fs-deadbeef'
,
'/'
,
DEFAULT_AZ
)),
(
'custom-cname.example.com:/'
,
(
'fs-deadbeef'
,
'/'
,
DEFAULT_AZ
)),
(
'custom-cname.example.com:/some/subpath'
,
(