2
2
# -*- coding: utf-8 -*-
3
3
4
4
# Copyright: (c) 2012, Red Hat, inc
5
- # Written by Seth Vidal
6
- # based on the mount modules from salt and puppet
5
+ # Copyright: (c) 2021, quidame <[email protected] >
6
+ # Written by Seth Vidal, based on the mount modules from salt and puppet
7
+ # Enhanced by quidame (swapon/swapoff support)
7
8
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
8
9
9
10
from __future__ import absolute_import , division , print_function
15
16
module: mount
16
17
short_description: Control active and configured mount points
17
18
description:
18
- - This module controls active and configured mount points in C(/etc/fstab).
19
+ - This module controls active and configured mount points in C(/etc/fstab),
20
+ as well as active and configured swap spaces.
19
21
author:
20
22
- Ansible Core Team
21
23
- Seth Vidal (@skvidal)
24
+ - quidame (@quidame)
22
25
version_added: "1.0.0"
23
26
options:
24
27
path:
25
28
description:
26
- - Path to the mount point (e.g. C(/mnt/files)).
29
+ - Path to the mount point (e.g. C(/mnt/files)). Must be C(none) for swap spaces.
27
30
- Before Ansible 2.3 this option was only usable as I(dest), I(destfile) and I(name).
28
31
type: path
29
32
required: true
30
33
aliases: [ name ]
31
34
src:
32
35
description:
33
36
- Device (or NFS volume, or something else) to be mounted on I(path).
34
- - Required when I(state) set to C(present) or C(mounted).
37
+ - Required when I(state) set to C(present) or C(mounted), or when I(fstype=swap) .
35
38
type: path
36
39
fstype:
37
40
description:
38
41
- Filesystem type.
39
- - Required when I(state) is C(present) or C(mounted).
42
+ - Required when I(state) is C(present) or C(mounted). Also required for
43
+ any I(state) to properly handle swap spaces (and then set to c(swap)).
40
44
type: str
41
45
opts:
42
46
description:
43
- - Mount options (see fstab(5), or vfstab(4) on Solaris).
47
+ - Mount options (see fstab(5), or vfstab(4) on Solaris) for mountable
48
+ filesystems, or swapon(8) options for C(swap) filesystems.
44
49
type: str
45
50
dump:
46
51
description:
64
69
description:
65
70
- If C(mounted), the device will be actively mounted and appropriately
66
71
configured in I(fstab). If the mount point is not present, the mount
67
- point will be created.
72
+ point will be created (unless I(path=none), as expected for C(swap)
73
+ filesystems).
68
74
- If C(unmounted), the device will be unmounted without changing I(fstab).
69
75
- C(present) only specifies that the device is to be configured in
70
76
I(fstab) and does not trigger or require a mount.
84
90
fstab:
85
91
description:
86
92
- File to use instead of C(/etc/fstab).
93
+ - The filename must not start with a dot, and must end with C(.fstab),
94
+ otherwise it is silently ignored. It is also ignored by mount helpers
95
+ (for filesystems not natively supported by the C(mount) command).
87
96
- You should not use this option unless you really know what you are doing.
88
97
- This might be useful if you need to configure mountpoints in a chroot environment.
89
98
- OpenBSD does not allow specifying alternate fstab files with mount so do not
108
117
- Using C(remounted) with I(opts) set may create unexpected results based on
109
118
the existing options already defined on mount, so care should be taken to
110
119
ensure that conflicting options are not present before hand.
120
+ - Support for swap spaces activation/deactivation as been added in version
121
+ 1.2.0 of C(ansible.posix).
122
+ - Strictly speaking, swap filesystems can't be C(mounted), C(unmounted) or
123
+ C(remounted). The module internally calls C(swapon) and C(swapoff) commands
124
+ to enable or disable such filesystems and make them usable by the kernel.
111
125
'''
112
126
113
127
EXAMPLES = r'''
169
183
opts: rw,sync,hard,intr
170
184
state: mounted
171
185
fstype: nfs
186
+
187
+ - name: Enable swap device with priority=1
188
+ ansible.posix.mount:
189
+ src: /dev/mapper/vg0-swap
190
+ fstype: swap
191
+ path: none
192
+ opts: pri=1
193
+ state: mounted
194
+
195
+ - name: Disable swap file and keep its record in fstab
196
+ ansible.posix.mount:
197
+ src: /var/swapfile
198
+ fstype: swap
199
+ path: none
200
+ state: unmounted
172
201
'''
173
202
174
203
175
204
import errno
176
205
import os
206
+ import re
177
207
import platform
178
208
179
209
from ansible .module_utils .basic import AnsibleModule
@@ -546,10 +576,10 @@ def is_bind_mounted(module, linux_mounts, dest, src=None, fstype=None):
546
576
else :
547
577
bin_path = module .get_bin_path ('mount' , required = True )
548
578
cmd = '%s -l' % bin_path
549
- rc , out , err = module .run_command (cmd )
579
+ _ , out , _ = module .run_command (cmd )
550
580
mounts = []
551
581
552
- if len (out ):
582
+ if len (out ) > 0 :
553
583
mounts = to_native (out ).strip ().split ('\n ' )
554
584
555
585
for mnt in mounts :
@@ -639,6 +669,78 @@ def get_linux_mounts(module, mntinfo_file="/proc/self/mountinfo"):
639
669
return mounts
640
670
641
671
672
+ def is_swap (module , args ):
673
+ """Return True if the device/file is an active swap space, False otherwise."""
674
+
675
+ if module .params ['fstype' ] != 'swap' or args ['name' ] != 'none' :
676
+ return False
677
+
678
+ swapon_bin = module .get_bin_path ('swapon' , required = True )
679
+ cmd = [swapon_bin , '--noheadings' , '--show=name' ]
680
+ dev = os .path .realpath (args ['src' ])
681
+
682
+ rc , out , err = module .run_command (cmd )
683
+
684
+ if rc != 0 :
685
+ module .fail_json (msg = "Error while querying active swaps: %s" % err )
686
+
687
+ return bool (dev in out .splitlines ())
688
+
689
+
690
+ def swapon (module , args ):
691
+ """Activate a swap device/file with the proper options."""
692
+
693
+ swapon_bin = module .get_bin_path ('swapon' , required = True )
694
+ cmd = [swapon_bin ]
695
+
696
+ # Only 'swapon -a' applies options from fstab, otherwise they are ignored
697
+ # unless provided on command line with '-o opts'. But not all versions of
698
+ # swapon accept -o or --options. So we don't use it here, but at least we
699
+ # keep the 'priority' and 'discard' options.
700
+ if args ['opts' ] is not None :
701
+ for opt in args ['opts' ].split (',' ):
702
+ if re .match ('pri=[0-9]' , opt ):
703
+ cmd += ['-p' , opt .split ('=' )[1 ]]
704
+ if re .match ('discard=' , opt ):
705
+ cmd += ['-d' , opt .split ('=' )[1 ]]
706
+
707
+ # src such as UUID=some_uuid and LABEL=some_label work as is.
708
+ cmd += [args ['src' ]]
709
+
710
+ rc , out , err = module .run_command (cmd )
711
+
712
+ if rc :
713
+ return rc , out + err
714
+ return 0 , ''
715
+
716
+
717
+ def swapoff (module , args ):
718
+ """Deactivate a swap device/file."""
719
+
720
+ swapoff_bin = module .get_bin_path ('swapoff' , required = True )
721
+ cmd = [swapoff_bin , args ['src' ]]
722
+
723
+ rc , out , err = module .run_command (cmd )
724
+
725
+ if rc :
726
+ return rc , out + err
727
+ return 0 , ''
728
+
729
+
730
+ def reswap (module , args ):
731
+ """Deactivate a swap device/file and reactivate it with new options."""
732
+
733
+ if is_swap (module , args ):
734
+ rc , msg = swapoff (module , args )
735
+ if rc :
736
+ return rc , msg
737
+
738
+ rc , msg = swapon (module , args )
739
+ if rc :
740
+ return rc , msg
741
+ return 0 , ''
742
+
743
+
642
744
def main ():
643
745
module = AnsibleModule (
644
746
argument_spec = dict (
@@ -651,12 +753,14 @@ def main():
651
753
passno = dict (type = 'str' , no_log = False ),
652
754
src = dict (type = 'path' ),
653
755
backup = dict (type = 'bool' , default = False ),
654
- state = dict (type = 'str' , required = True , choices = ['absent' , 'mounted' , 'present' , 'unmounted' , 'remounted' ]),
756
+ state = dict (type = 'str' , required = True ,
757
+ choices = ['absent' , 'mounted' , 'present' , 'unmounted' , 'remounted' ]),
655
758
),
656
759
supports_check_mode = True ,
657
760
required_if = (
658
761
['state' , 'mounted' , ['src' , 'fstype' ]],
659
762
['state' , 'present' , ['src' , 'fstype' ]],
763
+ ['fstype' , 'swap' , ['src' ]],
660
764
),
661
765
)
662
766
@@ -744,6 +848,12 @@ def main():
744
848
if res :
745
849
module .fail_json (
746
850
msg = "Error unmounting %s: %s" % (name , msg ))
851
+ elif is_swap (module , args ):
852
+ res , msg = swapoff (module , args )
853
+
854
+ if res :
855
+ module .fail_json (
856
+ msg = "Error disabling swap space %s: %s" % (args ['src' ], msg ))
747
857
748
858
if os .path .exists (name ):
749
859
try :
@@ -759,10 +869,19 @@ def main():
759
869
module .fail_json (
760
870
msg = "Error unmounting %s: %s" % (name , msg ))
761
871
872
+ changed = True
873
+ elif is_swap (module , args ):
874
+ if not module .check_mode :
875
+ res , msg = swapoff (module , args )
876
+
877
+ if res :
878
+ module .fail_json (
879
+ msg = "Error disabling swap space %s: %s" % (args ['src' ], msg ))
880
+
762
881
changed = True
763
882
elif state == 'mounted' :
764
883
dirs_created = []
765
- if not os .path .exists (name ) and not module .check_mode :
884
+ if name != 'none' and not os .path .exists (name ) and not module .check_mode :
766
885
try :
767
886
# Something like mkdir -p but with the possibility to undo.
768
887
# Based on some copy-paste from the "file" module.
@@ -798,11 +917,18 @@ def main():
798
917
if changed and not module .check_mode :
799
918
res , msg = remount (module , args )
800
919
changed = True
920
+ elif is_swap (module , args ):
921
+ if changed and not module .check_mode :
922
+ res , msg = reswap (module , args )
923
+ changed = True
801
924
else :
802
925
changed = True
803
926
804
927
if not module .check_mode :
805
- res , msg = mount (module , args )
928
+ if args ['fstype' ] == 'swap' and name == 'none' :
929
+ res , msg = swapon (module , args )
930
+ else :
931
+ res , msg = mount (module , args )
806
932
807
933
if res :
808
934
# Not restoring fstab after a failed mount was reported as a bug,
@@ -820,15 +946,26 @@ def main():
820
946
except Exception :
821
947
pass
822
948
823
- module .fail_json (msg = "Error mounting %s: %s" % (name , msg ))
949
+ if args ['fstype' ] == 'swap' and name == 'none' :
950
+ error_msg = "Error enabling swap space %s: %s" % (args ['src' ], msg )
951
+ else :
952
+ error_msg = "Error mounting %s: %s" % (name , msg )
953
+
954
+ module .fail_json (msg = error_msg )
824
955
elif state == 'present' :
825
956
name , changed = set_mount (module , args )
826
957
elif state == 'remounted' :
827
958
if not module .check_mode :
828
- res , msg = remount (module , args )
959
+ if module .params ['fstype' ] == 'swap' and name == 'none' :
960
+ res , msg = reswap (module , args )
961
+
962
+ if res :
963
+ module .fail_json (msg = "Error re-enabling swap space %s: %s" % (args ['src' ], msg ))
964
+ else :
965
+ res , msg = remount (module , args )
829
966
830
- if res :
831
- module .fail_json (msg = "Error remounting %s: %s" % (name , msg ))
967
+ if res :
968
+ module .fail_json (msg = "Error remounting %s: %s" % (name , msg ))
832
969
833
970
changed = True
834
971
else :
0 commit comments