]>
Commit | Line | Data |
---|---|---|
d2e6a577 FG |
1 | import errno |
2 | import os | |
3 | import pwd | |
4 | import platform | |
3efd9988 | 5 | import tempfile |
d2e6a577 FG |
6 | import uuid |
7 | from ceph_volume import process | |
8 | from . import as_string | |
9 | ||
10 | ||
11 | # TODO: get these out of here and into a common area for others to consume | |
12 | if platform.system() == 'FreeBSD': | |
13 | FREEBSD = True | |
14 | DEFAULT_FS_TYPE = 'zfs' | |
15 | PROCDIR = '/compat/linux/proc' | |
16 | # FreeBSD does not have blockdevices any more | |
17 | BLOCKDIR = '/dev' | |
18 | ROOTGROUP = 'wheel' | |
19 | else: | |
20 | FREEBSD = False | |
21 | DEFAULT_FS_TYPE = 'xfs' | |
22 | PROCDIR = '/proc' | |
23 | BLOCKDIR = '/sys/block' | |
24 | ROOTGROUP = 'root' | |
25 | ||
26 | ||
27 | def generate_uuid(): | |
28 | return str(uuid.uuid4()) | |
29 | ||
30 | ||
31 | def get_ceph_user_ids(): | |
32 | """ | |
33 | Return the id and gid of the ceph user | |
34 | """ | |
35 | try: | |
36 | user = pwd.getpwnam('ceph') | |
37 | except KeyError: | |
38 | # is this even possible? | |
39 | raise RuntimeError('"ceph" user is not available in the current system') | |
40 | return user[2], user[3] | |
41 | ||
42 | ||
43 | def mkdir_p(path, chown=True): | |
44 | """ | |
45 | A `mkdir -p` that defaults to chown the path to the ceph user | |
46 | """ | |
47 | try: | |
48 | os.mkdir(path) | |
49 | except OSError as e: | |
50 | if e.errno == errno.EEXIST: | |
51 | pass | |
52 | else: | |
53 | raise | |
54 | if chown: | |
55 | uid, gid = get_ceph_user_ids() | |
56 | os.chown(path, uid, gid) | |
57 | ||
58 | ||
59 | def chown(path, recursive=True): | |
60 | """ | |
61 | ``chown`` a path to the ceph user (uid and guid fetched at runtime) | |
62 | """ | |
63 | uid, gid = get_ceph_user_ids() | |
64 | if os.path.islink(path): | |
65 | path = os.path.realpath(path) | |
66 | if recursive: | |
67 | process.run(['chown', '-R', 'ceph:ceph', path]) | |
68 | else: | |
69 | os.chown(path, uid, gid) | |
70 | ||
71 | ||
3efd9988 | 72 | def is_binary(path): |
d2e6a577 | 73 | """ |
3efd9988 FG |
74 | Detect if a file path is a binary or not. Will falsely report as binary |
75 | when utf-16 encoded. In the ceph universe there is no such risk (yet) | |
76 | """ | |
77 | with open(path, 'rb') as fp: | |
78 | contents = fp.read(8192) | |
79 | if b'\x00' in contents: # a null byte may signal binary | |
80 | return True | |
81 | return False | |
82 | ||
83 | ||
84 | class tmp_mount(object): | |
85 | """ | |
86 | Temporarily mount a device on a temporary directory, | |
87 | and unmount it upon exit | |
88 | """ | |
89 | ||
90 | def __init__(self, device): | |
91 | self.device = device | |
92 | self.path = None | |
93 | ||
94 | def __enter__(self): | |
95 | self.path = tempfile.mkdtemp() | |
96 | process.run([ | |
97 | 'sudo', | |
98 | 'mount', | |
99 | '-v', | |
100 | self.device, | |
101 | self.path | |
102 | ]) | |
103 | return self.path | |
104 | ||
105 | def __exit__(self, exc_type, exc_val, exc_tb): | |
106 | process.run([ | |
107 | 'sudo', | |
108 | 'umount', | |
109 | '-v', | |
110 | self.path | |
111 | ]) | |
112 | ||
113 | ||
114 | def path_is_mounted(path, destination=None): | |
115 | """ | |
116 | Check if the given path is mounted | |
117 | """ | |
118 | mounts = get_mounts(paths=True) | |
119 | realpath = os.path.realpath(path) | |
120 | mounted_locations = mounts.get(realpath, []) | |
121 | ||
122 | if destination: | |
123 | if destination.startswith('/'): | |
124 | destination = os.path.realpath(destination) | |
125 | return destination in mounted_locations | |
126 | return mounted_locations != [] | |
127 | ||
d2e6a577 | 128 | |
3efd9988 FG |
129 | def device_is_mounted(dev, destination=None): |
130 | """ | |
131 | Check if the given device is mounted, optionally validating that a | |
132 | destination exists | |
133 | """ | |
134 | mounts = get_mounts(devices=True) | |
135 | realpath = os.path.realpath(dev) if dev.startswith('/') else dev | |
136 | destination = os.path.realpath(destination) if destination else None | |
137 | mounted_locations = mounts.get(realpath, []) | |
138 | ||
139 | if destination: | |
140 | return destination in mounted_locations | |
141 | return mounted_locations != [] | |
142 | ||
143 | ||
144 | def get_mounts(devices=False, paths=False): | |
145 | """ | |
146 | Create a mapping of all available system mounts so that other helpers can | |
147 | detect nicely what path or device is mounted | |
d2e6a577 | 148 | |
3efd9988 FG |
149 | It ignores (most of) non existing devices, but since some setups might need |
150 | some extra device information, it will make an exception for: | |
d2e6a577 | 151 | |
3efd9988 FG |
152 | - tmpfs |
153 | - devtmpfs | |
d2e6a577 | 154 | |
3efd9988 FG |
155 | If ``devices`` is set to ``True`` the mapping will be a device-to-path(s), |
156 | if ``paths`` is set to ``True`` then the mapping will be | |
157 | a path-to-device(s) | |
d2e6a577 | 158 | """ |
3efd9988 FG |
159 | devices_mounted = {} |
160 | paths_mounted = {} | |
161 | do_not_skip = ['tmpfs', 'devtmpfs'] | |
162 | default_to_devices = devices is False and paths is False | |
163 | ||
164 | with open(PROCDIR + '/mounts', 'rb') as mounts: | |
165 | proc_mounts = mounts.readlines() | |
166 | ||
167 | for line in proc_mounts: | |
168 | fields = [as_string(f) for f in line.split()] | |
169 | if len(fields) < 3: | |
170 | continue | |
171 | device = os.path.realpath(fields[0]) if fields[0].startswith('/') else fields[0] | |
172 | path = os.path.realpath(fields[1]) | |
173 | # only care about actual existing devices | |
174 | if not os.path.exists(device) or not device.startswith('/'): | |
175 | if device not in do_not_skip: | |
d2e6a577 | 176 | continue |
3efd9988 FG |
177 | if device in devices_mounted.keys(): |
178 | devices_mounted[device].append(path) | |
179 | else: | |
180 | devices_mounted[device] = [path] | |
181 | if path in paths_mounted.keys(): | |
182 | paths_mounted[path].append(device) | |
183 | else: | |
184 | paths_mounted[path] = [device] | |
185 | ||
186 | # Default to returning information for devices if | |
187 | if devices is True or default_to_devices: | |
188 | return devices_mounted | |
189 | else: | |
190 | return paths_mounted |