summaryrefslogtreecommitdiff
path: root/swift/obj/vfile_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'swift/obj/vfile_utils.py')
-rw-r--r--swift/obj/vfile_utils.py228
1 files changed, 228 insertions, 0 deletions
diff --git a/swift/obj/vfile_utils.py b/swift/obj/vfile_utils.py
new file mode 100644
index 000000000..8b9036b6c
--- /dev/null
+++ b/swift/obj/vfile_utils.py
@@ -0,0 +1,228 @@
+# Copyright (c) 2010-2012 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import os.path
+import pwd
+import re
+
+from swift.common.storage_policy import split_policy_string
+from swift.obj.fmgr_pb2 import VOLUME_DEFAULT, VOLUME_TOMBSTONE
+
+# regex to extract policy from path (one KV per policy)
+# TODO: use split_policy_string or similar, not re
+policy_re = re.compile(r"^objects(-\d+)?$")
+volume_name_re = re.compile(r"^v\d{7}$")
+losf_name_re = re.compile(r"^losf(-\d+)?$")
+
+
+class VIOError(IOError):
+ """
+ Exceptions are part of the interface, subclass IOError to make it easier
+ to interface with diskfile.py
+ """
+
+
+class VOSError(OSError):
+ """
+ Exceptions are part of the interface, subclass OSError to make it easier
+ to interface with diskfile.py
+ """
+
+
+class VFileException(Exception):
+ pass
+
+
+def get_volume_type(extension):
+ ext_map = {
+ ".ts": VOLUME_TOMBSTONE
+ }
+
+ return ext_map.get(extension, VOLUME_DEFAULT)
+
+
+def valid_volume_name(name):
+ """Returns True if name is a valid volume name, False otherwise"""
+ if volume_name_re.match(name):
+ return True
+ else:
+ return False
+
+
+def valid_losf_name(name):
+ """Returns True if name is a valid losf dir name, False otherwise"""
+ if losf_name_re.match(name):
+ return True
+ else:
+ return False
+
+
+# used by "fsck" to get the socket path from the volume path
+def get_socket_path_from_volume_path(volume_path):
+ volume_path = os.path.normpath(volume_path)
+ volume_dir_path, volume_name = os.path.split(volume_path)
+ losf_path, volume_dir = os.path.split(volume_dir_path)
+ mount_path, losf_dir = os.path.split(losf_path)
+ if volume_dir != "volumes" or not valid_volume_name(volume_name) or \
+ not valid_losf_name(losf_dir):
+ raise ValueError("Invalid volume path")
+
+ socket_path = os.path.join(losf_path, "rpc.socket")
+ return socket_path
+
+
+def get_mountpoint_from_volume_path(volume_path):
+ volume_path = os.path.normpath(volume_path)
+ volume_dir_path, volume_name = os.path.split(volume_path)
+ losf_path, volume_dir = os.path.split(volume_dir_path)
+ mount_path, losf_dir = os.path.split(losf_path)
+ if volume_dir != "volumes" or not valid_volume_name(volume_name) or \
+ not valid_losf_name(losf_dir):
+ raise ValueError("Invalid volume path")
+ return mount_path
+
+
+class SwiftPathInfo(object):
+ def __init__(self, type, socket_path=None, volume_dir=None,
+ policy_idx=None, partition=None, suffix=None, ohash=None,
+ filename=None):
+ self.type = type
+ self.socket_path = socket_path
+ self.volume_dir = volume_dir
+ self.policy_idx = policy_idx
+ self.partition = partition
+ self.suffix = suffix
+ self.ohash = ohash
+ self.filename = filename
+
+ # parses a swift path, returns a SwiftPathInfo instance
+ @classmethod
+ def from_path(cls, path):
+ count_to_type = {
+ 4: "file",
+ 3: "ohash",
+ 2: "suffix",
+ 1: "partition",
+ 0: "partitions" # "objects" directory
+ }
+
+ clean_path = os.path.normpath(path)
+ ldir = clean_path.split(os.sep)
+
+ try:
+ obj_idx = [i for i, elem in enumerate(ldir)
+ if elem.startswith("objects")][0]
+ except IndexError:
+ raise VOSError("cannot parse object directory")
+
+ elements = ldir[(obj_idx + 1):]
+ count = len(elements)
+
+ if count > 4:
+ raise VOSError("cannot parse swift file path")
+
+ _, policy = split_policy_string(ldir[obj_idx])
+ policy_idx = policy.idx
+
+ prefix = os.path.join("/", *ldir[0:obj_idx])
+ m = policy_re.match(ldir[obj_idx])
+ if not m:
+ raise VOSError(
+ "cannot parse object element of directory")
+ if m.group(1):
+ sofsdir = "losf{}".format(m.group(1))
+ else:
+ sofsdir = "losf"
+ socket_path = os.path.join(prefix, sofsdir, "rpc.socket")
+ volume_dir = os.path.join(prefix, sofsdir, "volumes")
+
+ type = count_to_type[count]
+ return cls(type, socket_path, volume_dir, policy_idx, *elements)
+
+
+class SwiftQuarantinedPathInfo(object):
+ def __init__(self, type, socket_path=None, volume_dir=None,
+ policy_idx=None, ohash=None, filename=None):
+ self.type = type
+ self.socket_path = socket_path
+ self.volume_dir = volume_dir
+ self.policy_idx = policy_idx
+ self.ohash = ohash
+ self.filename = filename
+
+ # parses a quarantined path (<device>/quarantined/objects-X or below),
+ # returns a SwiftQuarantinedPathInfo instance
+ @classmethod
+ def from_path(cls, path):
+ count_to_type = {
+ 3: "file",
+ 2: "ohash",
+ 1: "ohashes",
+ }
+
+ clean_path = os.path.normpath(path)
+ ldir = clean_path.split(os.sep)
+
+ try:
+ quar_idx = ldir.index("quarantined")
+ except ValueError:
+ raise VOSError("cannot parse quarantined path %s" %
+ path)
+
+ elements = ldir[(quar_idx + 1):]
+ count = len(elements)
+
+ if count < 1 or count > 3 or "objects" not in elements[0]:
+ raise VOSError("cannot parse quarantined path %s" %
+ path)
+
+ _, policy = split_policy_string(elements[0])
+ policy_idx = policy.idx
+
+ prefix = os.path.join("/", *ldir[:quar_idx])
+ prefix = os.path.join(prefix, elements[0].replace("objects", "losf"))
+ socket_path = os.path.join(prefix, "rpc.socket")
+ volume_dir = os.path.join(prefix, "volumes")
+
+ type = count_to_type[count]
+ return cls(type, socket_path, volume_dir, policy_idx, *elements[1:])
+
+
+def get_volume_index(volume_path):
+ """
+ returns the volume index, either from its basename, or full path
+ """
+ name = os.path.split(volume_path)[1]
+
+ if not valid_volume_name(name):
+ raise ValueError("Invalid volume name")
+
+ index = int(name[1:8])
+ return index
+
+
+# given an offset and alignement, returns the next aligned offset
+def next_aligned_offset(offset, alignment):
+ if offset % alignment != 0:
+ return (offset + (alignment - offset % alignment))
+ else:
+ return offset
+
+
+def change_user(username):
+ pw = pwd.getpwnam(username)
+ uid = pw.pw_uid
+ os.setuid(uid)