]>
git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/util/system.py
8 from ceph_volume
import process
, terminal
9 from . import as_string
11 logger
= logging
.getLogger(__name__
)
12 mlogger
= terminal
.MultiLogger(__name__
)
14 # TODO: get these out of here and into a common area for others to consume
15 if platform
.system() == 'FreeBSD':
17 DEFAULT_FS_TYPE
= 'zfs'
18 PROCDIR
= '/compat/linux/proc'
19 # FreeBSD does not have blockdevices any more
24 DEFAULT_FS_TYPE
= 'xfs'
26 BLOCKDIR
= '/sys/block'
31 return str(uuid
.uuid4())
34 def which(executable
):
35 """find the location of an executable"""
45 for location
in locations
:
46 executable_path
= os
.path
.join(location
, executable
)
47 if os
.path
.exists(executable_path
) and os
.path
.isfile(executable_path
):
48 return executable_path
49 mlogger
.warning('Absolute path not found for executable: %s', executable
)
50 mlogger
.warning('Ensure $PATH environment variable contains common executable locations')
51 # fallback to just returning the argument as-is, to prevent a hard fail,
52 # and hoping that the system might have the executable somewhere custom
56 def get_ceph_user_ids():
58 Return the id and gid of the ceph user
61 user
= pwd
.getpwnam('ceph')
63 # is this even possible?
64 raise RuntimeError('"ceph" user is not available in the current system')
65 return user
[2], user
[3]
68 def get_file_contents(path
, default
=''):
70 if not os
.path
.exists(path
):
73 with
open(path
, 'r') as open_file
:
74 contents
= open_file
.read().strip()
76 logger
.exception('Failed to read contents from: %s' % path
)
81 def mkdir_p(path
, chown
=True):
83 A `mkdir -p` that defaults to chown the path to the ceph user
88 if e
.errno
== errno
.EEXIST
:
93 uid
, gid
= get_ceph_user_ids()
94 os
.chown(path
, uid
, gid
)
97 def chown(path
, recursive
=True):
99 ``chown`` a path to the ceph user (uid and guid fetched at runtime)
101 uid
, gid
= get_ceph_user_ids()
102 if os
.path
.islink(path
):
103 process
.run(['chown', '-h', 'ceph:ceph', path
])
104 path
= os
.path
.realpath(path
)
106 process
.run(['chown', '-R', 'ceph:ceph', path
])
108 os
.chown(path
, uid
, gid
)
113 Detect if a file path is a binary or not. Will falsely report as binary
114 when utf-16 encoded. In the ceph universe there is no such risk (yet)
116 with
open(path
, 'rb') as fp
:
117 contents
= fp
.read(8192)
118 if b
'\x00' in contents
: # a null byte may signal binary
123 class tmp_mount(object):
125 Temporarily mount a device on a temporary directory,
126 and unmount it upon exit
128 When ``encrypted`` is set to ``True``, the exit method will call out to
129 close the device so that it doesn't remain open after mounting. It is
130 assumed that it will be open because otherwise it wouldn't be possible to
131 mount in the first place
134 def __init__(self
, device
, encrypted
=False):
137 self
.encrypted
= encrypted
140 self
.path
= tempfile
.mkdtemp()
149 def __exit__(self
, exc_type
, exc_val
, exc_tb
):
156 # avoid a circular import from the encryption module
157 from ceph_volume
.util
import encryption
158 encryption
.dmcrypt_close(self
.device
)
163 Removes mounts at the given path
172 def path_is_mounted(path
, destination
=None):
174 Check if the given path is mounted
176 mounts
= get_mounts(paths
=True)
177 realpath
= os
.path
.realpath(path
)
178 mounted_locations
= mounts
.get(realpath
, [])
181 return destination
in mounted_locations
182 return mounted_locations
!= []
185 def device_is_mounted(dev
, destination
=None):
187 Check if the given device is mounted, optionally validating that a
190 plain_mounts
= get_mounts(devices
=True)
191 realpath_mounts
= get_mounts(devices
=True, realpath
=True)
192 realpath_dev
= os
.path
.realpath(dev
) if dev
.startswith('/') else dev
193 destination
= os
.path
.realpath(destination
) if destination
else None
195 plain_dev_mounts
= plain_mounts
.get(dev
, [])
196 realpath_dev_mounts
= plain_mounts
.get(realpath_dev
, [])
198 plain_dev_real_mounts
= realpath_mounts
.get(dev
, [])
199 realpath_dev_real_mounts
= realpath_mounts
.get(realpath_dev
, [])
204 plain_dev_real_mounts
,
205 realpath_dev_real_mounts
208 for mounts
in mount_locations
:
209 if mounts
: # we have a matching mount
211 if destination
in mounts
:
213 '%s detected as mounted, exists at destination: %s', dev
, destination
217 logger
.info('%s was found as mounted', dev
)
219 logger
.info('%s was not found as mounted', dev
)
223 def get_mounts(devices
=False, paths
=False, realpath
=False):
225 Create a mapping of all available system mounts so that other helpers can
226 detect nicely what path or device is mounted
228 It ignores (most of) non existing devices, but since some setups might need
229 some extra device information, it will make an exception for:
234 If ``devices`` is set to ``True`` the mapping will be a device-to-path(s),
235 if ``paths`` is set to ``True`` then the mapping will be
238 :param realpath: Resolve devices to use their realpaths. This is useful for
239 paths like LVM where more than one path can point to the same device
243 do_not_skip
= ['tmpfs', 'devtmpfs']
244 default_to_devices
= devices
is False and paths
is False
246 with
open(PROCDIR
+ '/mounts', 'rb') as mounts
:
247 proc_mounts
= mounts
.readlines()
249 for line
in proc_mounts
:
250 fields
= [as_string(f
) for f
in line
.split()]
254 device
= os
.path
.realpath(fields
[0]) if fields
[0].startswith('/') else fields
[0]
257 path
= os
.path
.realpath(fields
[1])
258 # only care about actual existing devices
259 if not os
.path
.exists(device
) or not device
.startswith('/'):
260 if device
not in do_not_skip
:
262 if device
in devices_mounted
.keys():
263 devices_mounted
[device
].append(path
)
265 devices_mounted
[device
] = [path
]
266 if path
in paths_mounted
.keys():
267 paths_mounted
[path
].append(device
)
269 paths_mounted
[path
] = [device
]
271 # Default to returning information for devices if
272 if devices
is True or default_to_devices
:
273 return devices_mounted
278 def set_context(path
, recursive
= False):
279 # restore selinux context to default policy values
280 if which('restorecon').startswith('/'):
282 process
.run(['restorecon', '-R', path
])
284 process
.run(['restorecon', path
])