swift 2.23.2__py3-none-any.whl → 2.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- swift/__init__.py +29 -50
- swift/account/auditor.py +21 -118
- swift/account/backend.py +33 -28
- swift/account/reaper.py +37 -28
- swift/account/replicator.py +22 -0
- swift/account/server.py +60 -26
- swift/account/utils.py +28 -11
- swift-2.23.2.data/scripts/swift-account-audit → swift/cli/account_audit.py +23 -13
- swift-2.23.2.data/scripts/swift-config → swift/cli/config.py +2 -2
- swift/cli/container_deleter.py +5 -11
- swift-2.23.2.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +8 -7
- swift/cli/dispersion_report.py +10 -9
- swift-2.23.2.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +63 -21
- swift/cli/form_signature.py +3 -7
- swift-2.23.2.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +8 -2
- swift/cli/info.py +183 -29
- swift/cli/manage_shard_ranges.py +708 -37
- swift-2.23.2.data/scripts/swift-oldies → swift/cli/oldies.py +25 -14
- swift-2.23.2.data/scripts/swift-orphans → swift/cli/orphans.py +7 -3
- swift/cli/recon.py +196 -67
- swift-2.23.2.data/scripts/swift-recon-cron → swift/cli/recon_cron.py +17 -20
- swift-2.23.2.data/scripts/swift-reconciler-enqueue → swift/cli/reconciler_enqueue.py +2 -3
- swift/cli/relinker.py +807 -126
- swift/cli/reload.py +135 -0
- swift/cli/ringbuilder.py +217 -20
- swift/cli/ringcomposer.py +0 -1
- swift/cli/shard-info.py +4 -3
- swift/common/base_storage_server.py +9 -20
- swift/common/bufferedhttp.py +48 -74
- swift/common/constraints.py +20 -15
- swift/common/container_sync_realms.py +9 -11
- swift/common/daemon.py +25 -8
- swift/common/db.py +198 -127
- swift/common/db_auditor.py +168 -0
- swift/common/db_replicator.py +95 -55
- swift/common/digest.py +141 -0
- swift/common/direct_client.py +144 -33
- swift/common/error_limiter.py +93 -0
- swift/common/exceptions.py +25 -1
- swift/common/header_key_dict.py +2 -9
- swift/common/http_protocol.py +373 -0
- swift/common/internal_client.py +129 -59
- swift/common/linkat.py +3 -4
- swift/common/manager.py +284 -67
- swift/common/memcached.py +396 -147
- swift/common/middleware/__init__.py +4 -0
- swift/common/middleware/account_quotas.py +211 -46
- swift/common/middleware/acl.py +3 -8
- swift/common/middleware/backend_ratelimit.py +230 -0
- swift/common/middleware/bulk.py +22 -34
- swift/common/middleware/catch_errors.py +1 -3
- swift/common/middleware/cname_lookup.py +6 -11
- swift/common/middleware/container_quotas.py +1 -1
- swift/common/middleware/container_sync.py +39 -17
- swift/common/middleware/copy.py +12 -0
- swift/common/middleware/crossdomain.py +22 -9
- swift/common/middleware/crypto/__init__.py +2 -1
- swift/common/middleware/crypto/crypto_utils.py +11 -15
- swift/common/middleware/crypto/decrypter.py +28 -11
- swift/common/middleware/crypto/encrypter.py +12 -17
- swift/common/middleware/crypto/keymaster.py +8 -15
- swift/common/middleware/crypto/kms_keymaster.py +2 -1
- swift/common/middleware/dlo.py +15 -11
- swift/common/middleware/domain_remap.py +5 -4
- swift/common/middleware/etag_quoter.py +128 -0
- swift/common/middleware/formpost.py +73 -70
- swift/common/middleware/gatekeeper.py +8 -1
- swift/common/middleware/keystoneauth.py +33 -3
- swift/common/middleware/list_endpoints.py +4 -4
- swift/common/middleware/listing_formats.py +85 -49
- swift/common/middleware/memcache.py +4 -81
- swift/common/middleware/name_check.py +3 -2
- swift/common/middleware/proxy_logging.py +160 -92
- swift/common/middleware/ratelimit.py +17 -10
- swift/common/middleware/read_only.py +6 -4
- swift/common/middleware/recon.py +59 -22
- swift/common/middleware/s3api/acl_handlers.py +25 -3
- swift/common/middleware/s3api/acl_utils.py +6 -1
- swift/common/middleware/s3api/controllers/__init__.py +6 -0
- swift/common/middleware/s3api/controllers/acl.py +3 -2
- swift/common/middleware/s3api/controllers/bucket.py +242 -137
- swift/common/middleware/s3api/controllers/logging.py +2 -2
- swift/common/middleware/s3api/controllers/multi_delete.py +43 -20
- swift/common/middleware/s3api/controllers/multi_upload.py +219 -133
- swift/common/middleware/s3api/controllers/obj.py +112 -8
- swift/common/middleware/s3api/controllers/object_lock.py +44 -0
- swift/common/middleware/s3api/controllers/s3_acl.py +2 -2
- swift/common/middleware/s3api/controllers/tagging.py +57 -0
- swift/common/middleware/s3api/controllers/versioning.py +36 -7
- swift/common/middleware/s3api/etree.py +22 -9
- swift/common/middleware/s3api/exception.py +0 -4
- swift/common/middleware/s3api/s3api.py +113 -41
- swift/common/middleware/s3api/s3request.py +384 -218
- swift/common/middleware/s3api/s3response.py +126 -23
- swift/common/middleware/s3api/s3token.py +16 -17
- swift/common/middleware/s3api/schema/delete.rng +1 -1
- swift/common/middleware/s3api/subresource.py +7 -10
- swift/common/middleware/s3api/utils.py +27 -10
- swift/common/middleware/slo.py +665 -358
- swift/common/middleware/staticweb.py +64 -37
- swift/common/middleware/symlink.py +52 -19
- swift/common/middleware/tempauth.py +76 -58
- swift/common/middleware/tempurl.py +192 -174
- swift/common/middleware/versioned_writes/__init__.py +51 -0
- swift/common/middleware/{versioned_writes.py → versioned_writes/legacy.py} +27 -26
- swift/common/middleware/versioned_writes/object_versioning.py +1482 -0
- swift/common/middleware/x_profile/exceptions.py +1 -4
- swift/common/middleware/x_profile/html_viewer.py +18 -19
- swift/common/middleware/x_profile/profile_model.py +1 -2
- swift/common/middleware/xprofile.py +10 -10
- swift-2.23.2.data/scripts/swift-container-server → swift/common/recon.py +13 -8
- swift/common/registry.py +147 -0
- swift/common/request_helpers.py +324 -57
- swift/common/ring/builder.py +67 -25
- swift/common/ring/composite_builder.py +1 -1
- swift/common/ring/ring.py +177 -51
- swift/common/ring/utils.py +1 -1
- swift/common/splice.py +10 -6
- swift/common/statsd_client.py +205 -0
- swift/common/storage_policy.py +49 -44
- swift/common/swob.py +86 -102
- swift/common/{utils.py → utils/__init__.py} +2191 -2762
- swift/common/utils/base.py +131 -0
- swift/common/utils/config.py +433 -0
- swift/common/utils/ipaddrs.py +256 -0
- swift/common/utils/libc.py +345 -0
- swift/common/utils/logs.py +859 -0
- swift/common/utils/timestamp.py +412 -0
- swift/common/wsgi.py +555 -536
- swift/container/auditor.py +14 -100
- swift/container/backend.py +552 -227
- swift/container/reconciler.py +126 -37
- swift/container/replicator.py +96 -22
- swift/container/server.py +397 -176
- swift/container/sharder.py +1580 -639
- swift/container/sync.py +94 -88
- swift/container/updater.py +53 -32
- swift/obj/auditor.py +153 -35
- swift/obj/diskfile.py +466 -217
- swift/obj/expirer.py +406 -124
- swift/obj/mem_diskfile.py +7 -4
- swift/obj/mem_server.py +1 -0
- swift/obj/reconstructor.py +523 -262
- swift/obj/replicator.py +249 -188
- swift/obj/server.py +213 -122
- swift/obj/ssync_receiver.py +145 -85
- swift/obj/ssync_sender.py +113 -54
- swift/obj/updater.py +653 -139
- swift/obj/watchers/__init__.py +0 -0
- swift/obj/watchers/dark_data.py +213 -0
- swift/proxy/controllers/account.py +11 -11
- swift/proxy/controllers/base.py +848 -604
- swift/proxy/controllers/container.py +452 -86
- swift/proxy/controllers/info.py +3 -2
- swift/proxy/controllers/obj.py +1009 -490
- swift/proxy/server.py +185 -112
- swift-2.35.0.dist-info/AUTHORS +501 -0
- swift-2.35.0.dist-info/LICENSE +202 -0
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/METADATA +52 -61
- swift-2.35.0.dist-info/RECORD +201 -0
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/WHEEL +1 -1
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/entry_points.txt +43 -0
- swift-2.35.0.dist-info/pbr.json +1 -0
- swift/locale/de/LC_MESSAGES/swift.po +0 -1216
- swift/locale/en_GB/LC_MESSAGES/swift.po +0 -1207
- swift/locale/es/LC_MESSAGES/swift.po +0 -1085
- swift/locale/fr/LC_MESSAGES/swift.po +0 -909
- swift/locale/it/LC_MESSAGES/swift.po +0 -894
- swift/locale/ja/LC_MESSAGES/swift.po +0 -965
- swift/locale/ko_KR/LC_MESSAGES/swift.po +0 -964
- swift/locale/pt_BR/LC_MESSAGES/swift.po +0 -881
- swift/locale/ru/LC_MESSAGES/swift.po +0 -891
- swift/locale/tr_TR/LC_MESSAGES/swift.po +0 -832
- swift/locale/zh_CN/LC_MESSAGES/swift.po +0 -833
- swift/locale/zh_TW/LC_MESSAGES/swift.po +0 -838
- swift-2.23.2.data/scripts/swift-account-auditor +0 -23
- swift-2.23.2.data/scripts/swift-account-info +0 -51
- swift-2.23.2.data/scripts/swift-account-reaper +0 -23
- swift-2.23.2.data/scripts/swift-account-replicator +0 -34
- swift-2.23.2.data/scripts/swift-account-server +0 -23
- swift-2.23.2.data/scripts/swift-container-auditor +0 -23
- swift-2.23.2.data/scripts/swift-container-info +0 -51
- swift-2.23.2.data/scripts/swift-container-reconciler +0 -21
- swift-2.23.2.data/scripts/swift-container-replicator +0 -34
- swift-2.23.2.data/scripts/swift-container-sharder +0 -33
- swift-2.23.2.data/scripts/swift-container-sync +0 -23
- swift-2.23.2.data/scripts/swift-container-updater +0 -23
- swift-2.23.2.data/scripts/swift-dispersion-report +0 -24
- swift-2.23.2.data/scripts/swift-form-signature +0 -20
- swift-2.23.2.data/scripts/swift-init +0 -119
- swift-2.23.2.data/scripts/swift-object-auditor +0 -29
- swift-2.23.2.data/scripts/swift-object-expirer +0 -33
- swift-2.23.2.data/scripts/swift-object-info +0 -60
- swift-2.23.2.data/scripts/swift-object-reconstructor +0 -33
- swift-2.23.2.data/scripts/swift-object-relinker +0 -41
- swift-2.23.2.data/scripts/swift-object-replicator +0 -37
- swift-2.23.2.data/scripts/swift-object-server +0 -27
- swift-2.23.2.data/scripts/swift-object-updater +0 -23
- swift-2.23.2.data/scripts/swift-proxy-server +0 -23
- swift-2.23.2.data/scripts/swift-recon +0 -24
- swift-2.23.2.data/scripts/swift-ring-builder +0 -24
- swift-2.23.2.data/scripts/swift-ring-builder-analyzer +0 -22
- swift-2.23.2.data/scripts/swift-ring-composer +0 -22
- swift-2.23.2.dist-info/DESCRIPTION.rst +0 -166
- swift-2.23.2.dist-info/RECORD +0 -220
- swift-2.23.2.dist-info/metadata.json +0 -1
- swift-2.23.2.dist-info/pbr.json +0 -1
- {swift-2.23.2.dist-info → swift-2.35.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,256 @@
|
|
1
|
+
# Copyright (c) 2010-2012 OpenStack Foundation
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
12
|
+
# implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
import ctypes
|
17
|
+
import ctypes.util
|
18
|
+
import os
|
19
|
+
import platform
|
20
|
+
import re
|
21
|
+
import socket
|
22
|
+
import warnings
|
23
|
+
|
24
|
+
|
25
|
+
# Used by the parse_socket_string() function to validate IPv6 addresses
|
26
|
+
IPV6_RE = re.compile(r"^\[(?P<address>.*)\](:(?P<port>[0-9]+))?$")
|
27
|
+
|
28
|
+
|
29
|
+
def is_valid_ip(ip):
|
30
|
+
"""
|
31
|
+
Return True if the provided ip is a valid IP-address
|
32
|
+
"""
|
33
|
+
return is_valid_ipv4(ip) or is_valid_ipv6(ip)
|
34
|
+
|
35
|
+
|
36
|
+
def is_valid_ipv4(ip):
|
37
|
+
"""
|
38
|
+
Return True if the provided ip is a valid IPv4-address
|
39
|
+
"""
|
40
|
+
try:
|
41
|
+
socket.inet_pton(socket.AF_INET, ip)
|
42
|
+
except socket.error: # not a valid IPv4 address
|
43
|
+
return False
|
44
|
+
return True
|
45
|
+
|
46
|
+
|
47
|
+
def is_valid_ipv6(ip):
|
48
|
+
"""
|
49
|
+
Returns True if the provided ip is a valid IPv6-address
|
50
|
+
"""
|
51
|
+
try:
|
52
|
+
socket.inet_pton(socket.AF_INET6, ip)
|
53
|
+
except socket.error: # not a valid IPv6 address
|
54
|
+
return False
|
55
|
+
return True
|
56
|
+
|
57
|
+
|
58
|
+
def expand_ipv6(address):
|
59
|
+
"""
|
60
|
+
Expand ipv6 address.
|
61
|
+
:param address: a string indicating valid ipv6 address
|
62
|
+
:returns: a string indicating fully expanded ipv6 address
|
63
|
+
|
64
|
+
"""
|
65
|
+
packed_ip = socket.inet_pton(socket.AF_INET6, address)
|
66
|
+
return socket.inet_ntop(socket.AF_INET6, packed_ip)
|
67
|
+
|
68
|
+
|
69
|
+
libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
|
70
|
+
try:
|
71
|
+
getifaddrs = libc.getifaddrs
|
72
|
+
freeifaddrs = libc.freeifaddrs
|
73
|
+
netifaces = None # for patching
|
74
|
+
except AttributeError:
|
75
|
+
getifaddrs = None
|
76
|
+
freeifaddrs = None
|
77
|
+
try:
|
78
|
+
import netifaces
|
79
|
+
except ImportError:
|
80
|
+
raise ImportError('C function getifaddrs not available, '
|
81
|
+
'and netifaces not installed')
|
82
|
+
else:
|
83
|
+
warnings.warn('getifaddrs is not available; falling back to the '
|
84
|
+
'archived and no longer maintained netifaces project. '
|
85
|
+
'This fallback will be removed in a future release; '
|
86
|
+
'see https://bugs.launchpad.net/swift/+bug/2019233 for '
|
87
|
+
'more information.', FutureWarning)
|
88
|
+
else:
|
89
|
+
class sockaddr_in4(ctypes.Structure):
|
90
|
+
if platform.system() == 'Linux':
|
91
|
+
_fields_ = [
|
92
|
+
("sin_family", ctypes.c_uint16),
|
93
|
+
("sin_port", ctypes.c_uint16),
|
94
|
+
("sin_addr", ctypes.c_ubyte * 4),
|
95
|
+
]
|
96
|
+
else:
|
97
|
+
# Assume BSD / OS X
|
98
|
+
_fields_ = [
|
99
|
+
("sin_len", ctypes.c_uint8),
|
100
|
+
("sin_family", ctypes.c_uint8),
|
101
|
+
("sin_port", ctypes.c_uint16),
|
102
|
+
("sin_addr", ctypes.c_ubyte * 4),
|
103
|
+
]
|
104
|
+
|
105
|
+
class sockaddr_in6(ctypes.Structure):
|
106
|
+
if platform.system() == 'Linux':
|
107
|
+
_fields_ = [
|
108
|
+
("sin6_family", ctypes.c_uint16),
|
109
|
+
("sin6_port", ctypes.c_uint16),
|
110
|
+
("sin6_flowinfo", ctypes.c_uint32),
|
111
|
+
("sin6_addr", ctypes.c_ubyte * 16),
|
112
|
+
]
|
113
|
+
else:
|
114
|
+
# Assume BSD / OS X
|
115
|
+
_fields_ = [
|
116
|
+
("sin6_len", ctypes.c_uint8),
|
117
|
+
("sin6_family", ctypes.c_uint8),
|
118
|
+
("sin6_port", ctypes.c_uint16),
|
119
|
+
("sin6_flowinfo", ctypes.c_uint32),
|
120
|
+
("sin6_addr", ctypes.c_ubyte * 16),
|
121
|
+
]
|
122
|
+
|
123
|
+
class ifaddrs(ctypes.Structure):
|
124
|
+
pass
|
125
|
+
|
126
|
+
# Have to do this a little later so we can self-reference
|
127
|
+
ifaddrs._fields_ = [
|
128
|
+
("ifa_next", ctypes.POINTER(ifaddrs)),
|
129
|
+
("ifa_name", ctypes.c_char_p),
|
130
|
+
("ifa_flags", ctypes.c_int),
|
131
|
+
# Use the smaller of the two to start, can cast later
|
132
|
+
# when we *know* we're looking at INET6
|
133
|
+
("ifa_addr", ctypes.POINTER(sockaddr_in4)),
|
134
|
+
# Don't care about the rest of the fields
|
135
|
+
]
|
136
|
+
|
137
|
+
def errcheck(result, func, arguments):
|
138
|
+
if result != 0:
|
139
|
+
errno = ctypes.set_errno(0)
|
140
|
+
raise OSError(errno, "getifaddrs: %s" % os.strerror(errno))
|
141
|
+
return result
|
142
|
+
|
143
|
+
getifaddrs.errcheck = errcheck
|
144
|
+
|
145
|
+
|
146
|
+
def whataremyips(ring_ip=None):
|
147
|
+
"""
|
148
|
+
Get "our" IP addresses ("us" being the set of services configured by
|
149
|
+
one `*.conf` file). If our REST listens on a specific address, return it.
|
150
|
+
Otherwise, if listen on '0.0.0.0' or '::' return all addresses, including
|
151
|
+
the loopback.
|
152
|
+
|
153
|
+
:param str ring_ip: Optional ring_ip/bind_ip from a config file; may be
|
154
|
+
IP address or hostname.
|
155
|
+
:returns: list of Strings of ip addresses
|
156
|
+
"""
|
157
|
+
if ring_ip:
|
158
|
+
# See if bind_ip is '0.0.0.0'/'::'
|
159
|
+
try:
|
160
|
+
_, _, _, _, sockaddr = socket.getaddrinfo(
|
161
|
+
ring_ip, None, 0, socket.SOCK_STREAM, 0,
|
162
|
+
socket.AI_NUMERICHOST)[0]
|
163
|
+
if sockaddr[0] not in ('0.0.0.0', '::'):
|
164
|
+
return [ring_ip]
|
165
|
+
except socket.gaierror:
|
166
|
+
pass
|
167
|
+
|
168
|
+
addresses = []
|
169
|
+
|
170
|
+
if getifaddrs:
|
171
|
+
addrs = ctypes.POINTER(ifaddrs)()
|
172
|
+
getifaddrs(ctypes.byref(addrs))
|
173
|
+
try:
|
174
|
+
cur = addrs
|
175
|
+
while cur:
|
176
|
+
if not cur.contents.ifa_addr:
|
177
|
+
# Not all interfaces will have addresses; move on
|
178
|
+
cur = cur.contents.ifa_next
|
179
|
+
continue
|
180
|
+
sa_family = cur.contents.ifa_addr.contents.sin_family
|
181
|
+
if sa_family == socket.AF_INET:
|
182
|
+
addresses.append(
|
183
|
+
socket.inet_ntop(
|
184
|
+
socket.AF_INET,
|
185
|
+
cur.contents.ifa_addr.contents.sin_addr,
|
186
|
+
)
|
187
|
+
)
|
188
|
+
elif sa_family == socket.AF_INET6:
|
189
|
+
addr = ctypes.cast(cur.contents.ifa_addr,
|
190
|
+
ctypes.POINTER(sockaddr_in6))
|
191
|
+
addresses.append(
|
192
|
+
socket.inet_ntop(
|
193
|
+
socket.AF_INET6,
|
194
|
+
addr.contents.sin6_addr,
|
195
|
+
)
|
196
|
+
)
|
197
|
+
cur = cur.contents.ifa_next
|
198
|
+
finally:
|
199
|
+
freeifaddrs(addrs)
|
200
|
+
return addresses
|
201
|
+
|
202
|
+
# getifaddrs not available; try netifaces
|
203
|
+
for interface in netifaces.interfaces():
|
204
|
+
try:
|
205
|
+
iface_data = netifaces.ifaddresses(interface)
|
206
|
+
for family in iface_data:
|
207
|
+
if family not in (netifaces.AF_INET, netifaces.AF_INET6):
|
208
|
+
continue
|
209
|
+
for address in iface_data[family]:
|
210
|
+
addr = address['addr']
|
211
|
+
|
212
|
+
# If we have an ipv6 address remove the
|
213
|
+
# %ether_interface at the end
|
214
|
+
if family == netifaces.AF_INET6:
|
215
|
+
addr = expand_ipv6(addr.split('%')[0])
|
216
|
+
addresses.append(addr)
|
217
|
+
except ValueError:
|
218
|
+
pass
|
219
|
+
return addresses
|
220
|
+
|
221
|
+
|
222
|
+
def parse_socket_string(socket_string, default_port):
|
223
|
+
"""
|
224
|
+
Given a string representing a socket, returns a tuple of (host, port).
|
225
|
+
Valid strings are DNS names, IPv4 addresses, or IPv6 addresses, with an
|
226
|
+
optional port. If an IPv6 address is specified it **must** be enclosed in
|
227
|
+
[], like *[::1]* or *[::1]:11211*. This follows the accepted prescription
|
228
|
+
for `IPv6 host literals`_.
|
229
|
+
|
230
|
+
Examples::
|
231
|
+
|
232
|
+
server.org
|
233
|
+
server.org:1337
|
234
|
+
127.0.0.1:1337
|
235
|
+
[::1]:1337
|
236
|
+
[::1]
|
237
|
+
|
238
|
+
.. _IPv6 host literals: https://tools.ietf.org/html/rfc3986#section-3.2.2
|
239
|
+
"""
|
240
|
+
port = default_port
|
241
|
+
# IPv6 addresses must be between '[]'
|
242
|
+
if socket_string.startswith('['):
|
243
|
+
match = IPV6_RE.match(socket_string)
|
244
|
+
if not match:
|
245
|
+
raise ValueError("Invalid IPv6 address: %s" % socket_string)
|
246
|
+
host = match.group('address')
|
247
|
+
port = match.group('port') or port
|
248
|
+
else:
|
249
|
+
if ':' in socket_string:
|
250
|
+
tokens = socket_string.split(':')
|
251
|
+
if len(tokens) > 2:
|
252
|
+
raise ValueError("IPv6 addresses must be between '[]'")
|
253
|
+
host, port = tokens
|
254
|
+
else:
|
255
|
+
host = socket_string
|
256
|
+
return (host, port)
|
@@ -0,0 +1,345 @@
|
|
1
|
+
# Copyright (c) 2010-2023 OpenStack Foundation
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
12
|
+
# implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
"""Functions Swift uses to interact with libc and other low-level APIs."""
|
17
|
+
|
18
|
+
import ctypes
|
19
|
+
import ctypes.util
|
20
|
+
import fcntl
|
21
|
+
import logging
|
22
|
+
import os
|
23
|
+
import platform
|
24
|
+
import socket
|
25
|
+
|
26
|
+
|
27
|
+
# These are lazily pulled from libc elsewhere
|
28
|
+
_posix_fadvise = None
|
29
|
+
_libc_socket = None
|
30
|
+
_libc_bind = None
|
31
|
+
_libc_accept = None
|
32
|
+
# see man -s 2 setpriority
|
33
|
+
_libc_setpriority = None
|
34
|
+
# see man -s 2 syscall
|
35
|
+
_posix_syscall = None
|
36
|
+
|
37
|
+
# from /usr/src/linux-headers-*/include/uapi/linux/resource.h
|
38
|
+
PRIO_PROCESS = 0
|
39
|
+
|
40
|
+
|
41
|
+
# /usr/include/x86_64-linux-gnu/asm/unistd_64.h defines syscalls there
|
42
|
+
# are many like it, but this one is mine, see man -s 2 ioprio_set
|
43
|
+
def NR_ioprio_set():
|
44
|
+
"""Give __NR_ioprio_set value for your system."""
|
45
|
+
architecture = os.uname()[4]
|
46
|
+
arch_bits = platform.architecture()[0]
|
47
|
+
# check if supported system, now support x86_64 and AArch64
|
48
|
+
if architecture == 'x86_64' and arch_bits == '64bit':
|
49
|
+
return 251
|
50
|
+
elif architecture == 'aarch64' and arch_bits == '64bit':
|
51
|
+
return 30
|
52
|
+
raise OSError("Swift doesn't support ionice priority for %s %s" %
|
53
|
+
(architecture, arch_bits))
|
54
|
+
|
55
|
+
|
56
|
+
# this syscall integer probably only works on x86_64 linux systems, you
|
57
|
+
# can check if it's correct on yours with something like this:
|
58
|
+
"""
|
59
|
+
#include <stdio.h>
|
60
|
+
#include <sys/syscall.h>
|
61
|
+
|
62
|
+
int main(int argc, const char* argv[]) {
|
63
|
+
printf("%d\n", __NR_ioprio_set);
|
64
|
+
return 0;
|
65
|
+
}
|
66
|
+
"""
|
67
|
+
|
68
|
+
# this is the value for "which" that says our who value will be a pid
|
69
|
+
# pulled out of /usr/src/linux-headers-*/include/linux/ioprio.h
|
70
|
+
IOPRIO_WHO_PROCESS = 1
|
71
|
+
|
72
|
+
|
73
|
+
IO_CLASS_ENUM = {
|
74
|
+
'IOPRIO_CLASS_RT': 1,
|
75
|
+
'IOPRIO_CLASS_BE': 2,
|
76
|
+
'IOPRIO_CLASS_IDLE': 3,
|
77
|
+
}
|
78
|
+
|
79
|
+
# the IOPRIO_PRIO_VALUE "macro" is also pulled from
|
80
|
+
# /usr/src/linux-headers-*/include/linux/ioprio.h
|
81
|
+
IOPRIO_CLASS_SHIFT = 13
|
82
|
+
|
83
|
+
|
84
|
+
def IOPRIO_PRIO_VALUE(class_, data):
|
85
|
+
return (((class_) << IOPRIO_CLASS_SHIFT) | data)
|
86
|
+
|
87
|
+
|
88
|
+
# These constants are Linux-specific, and Python doesn't seem to know
|
89
|
+
# about them. We ask anyway just in case that ever gets fixed.
|
90
|
+
#
|
91
|
+
# The values were copied from the Linux 3.x kernel headers.
|
92
|
+
AF_ALG = getattr(socket, 'AF_ALG', 38)
|
93
|
+
F_SETPIPE_SZ = getattr(fcntl, 'F_SETPIPE_SZ', 1031)
|
94
|
+
|
95
|
+
|
96
|
+
def noop_libc_function(*args):
|
97
|
+
return 0
|
98
|
+
|
99
|
+
|
100
|
+
def load_libc_function(func_name, log_error=True,
|
101
|
+
fail_if_missing=False, errcheck=False):
|
102
|
+
"""
|
103
|
+
Attempt to find the function in libc, otherwise return a no-op func.
|
104
|
+
|
105
|
+
:param func_name: name of the function to pull from libc.
|
106
|
+
:param log_error: log an error when a function can't be found
|
107
|
+
:param fail_if_missing: raise an exception when a function can't be found.
|
108
|
+
Default behavior is to return a no-op function.
|
109
|
+
:param errcheck: boolean, if true install a wrapper on the function
|
110
|
+
to check for a return values of -1 and call
|
111
|
+
ctype.get_errno and raise an OSError
|
112
|
+
"""
|
113
|
+
try:
|
114
|
+
libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
|
115
|
+
func = getattr(libc, func_name)
|
116
|
+
except AttributeError:
|
117
|
+
if fail_if_missing:
|
118
|
+
raise
|
119
|
+
if log_error:
|
120
|
+
logging.warning("Unable to locate %s in libc. Leaving as a "
|
121
|
+
"no-op.", func_name)
|
122
|
+
return noop_libc_function
|
123
|
+
if errcheck:
|
124
|
+
def _errcheck(result, f, args):
|
125
|
+
if result == -1:
|
126
|
+
errcode = ctypes.get_errno()
|
127
|
+
raise OSError(errcode, os.strerror(errcode))
|
128
|
+
return result
|
129
|
+
func.errcheck = _errcheck
|
130
|
+
return func
|
131
|
+
|
132
|
+
|
133
|
+
class _LibcWrapper(object):
|
134
|
+
"""
|
135
|
+
A callable object that forwards its calls to a C function from libc.
|
136
|
+
|
137
|
+
These objects are lazy. libc will not be checked until someone tries to
|
138
|
+
either call the function or check its availability.
|
139
|
+
|
140
|
+
_LibcWrapper objects have an "available" property; if true, then libc
|
141
|
+
has the function of that name. If false, then calls will fail with a
|
142
|
+
NotImplementedError.
|
143
|
+
"""
|
144
|
+
|
145
|
+
def __init__(self, func_name):
|
146
|
+
self._func_name = func_name
|
147
|
+
self._func_handle = None
|
148
|
+
self._loaded = False
|
149
|
+
|
150
|
+
def _ensure_loaded(self):
|
151
|
+
if not self._loaded:
|
152
|
+
func_name = self._func_name
|
153
|
+
try:
|
154
|
+
# Keep everything in this try-block in local variables so
|
155
|
+
# that a typo in self.some_attribute_name doesn't raise a
|
156
|
+
# spurious AttributeError.
|
157
|
+
func_handle = load_libc_function(
|
158
|
+
func_name, fail_if_missing=True)
|
159
|
+
self._func_handle = func_handle
|
160
|
+
except AttributeError:
|
161
|
+
# We pass fail_if_missing=True to load_libc_function and
|
162
|
+
# then ignore the error. It's weird, but otherwise we have
|
163
|
+
# to check if self._func_handle is noop_libc_function, and
|
164
|
+
# that's even weirder.
|
165
|
+
pass
|
166
|
+
self._loaded = True
|
167
|
+
|
168
|
+
@property
|
169
|
+
def available(self):
|
170
|
+
self._ensure_loaded()
|
171
|
+
return bool(self._func_handle)
|
172
|
+
|
173
|
+
def __call__(self, *args):
|
174
|
+
if self.available:
|
175
|
+
return self._func_handle(*args)
|
176
|
+
else:
|
177
|
+
raise NotImplementedError(
|
178
|
+
"No function %r found in libc" % self._func_name)
|
179
|
+
|
180
|
+
|
181
|
+
def drop_buffer_cache(fd, offset, length):
|
182
|
+
"""
|
183
|
+
Drop 'buffer' cache for the given range of the given file.
|
184
|
+
|
185
|
+
:param fd: file descriptor
|
186
|
+
:param offset: start offset
|
187
|
+
:param length: length
|
188
|
+
"""
|
189
|
+
global _posix_fadvise
|
190
|
+
if _posix_fadvise is None:
|
191
|
+
_posix_fadvise = load_libc_function('posix_fadvise64')
|
192
|
+
# 4 means "POSIX_FADV_DONTNEED"
|
193
|
+
ret = _posix_fadvise(fd, ctypes.c_uint64(offset),
|
194
|
+
ctypes.c_uint64(length), 4)
|
195
|
+
if ret != 0:
|
196
|
+
logging.warning("posix_fadvise64(%(fd)s, %(offset)s, %(length)s, 4) "
|
197
|
+
"-> %(ret)s", {'fd': fd, 'offset': offset,
|
198
|
+
'length': length, 'ret': ret})
|
199
|
+
|
200
|
+
|
201
|
+
class sockaddr_alg(ctypes.Structure):
|
202
|
+
_fields_ = [("salg_family", ctypes.c_ushort),
|
203
|
+
("salg_type", ctypes.c_ubyte * 14),
|
204
|
+
("salg_feat", ctypes.c_uint),
|
205
|
+
("salg_mask", ctypes.c_uint),
|
206
|
+
("salg_name", ctypes.c_ubyte * 64)]
|
207
|
+
|
208
|
+
|
209
|
+
_bound_md5_sockfd = None
|
210
|
+
|
211
|
+
|
212
|
+
def get_md5_socket():
|
213
|
+
"""
|
214
|
+
Get an MD5 socket file descriptor. One can MD5 data with it by writing it
|
215
|
+
to the socket with os.write, then os.read the 16 bytes of the checksum out
|
216
|
+
later.
|
217
|
+
|
218
|
+
NOTE: It is the caller's responsibility to ensure that os.close() is
|
219
|
+
called on the returned file descriptor. This is a bare file descriptor,
|
220
|
+
not a Python object. It doesn't close itself.
|
221
|
+
"""
|
222
|
+
|
223
|
+
# Linux's AF_ALG sockets work like this:
|
224
|
+
#
|
225
|
+
# First, initialize a socket with socket() and bind(). This tells the
|
226
|
+
# socket what algorithm to use, as well as setting up any necessary bits
|
227
|
+
# like crypto keys. Of course, MD5 doesn't need any keys, so it's just the
|
228
|
+
# algorithm name.
|
229
|
+
#
|
230
|
+
# Second, to hash some data, get a second socket by calling accept() on
|
231
|
+
# the first socket. Write data to the socket, then when finished, read the
|
232
|
+
# checksum from the socket and close it. This lets you checksum multiple
|
233
|
+
# things without repeating all the setup code each time.
|
234
|
+
#
|
235
|
+
# Since we only need to bind() one socket, we do that here and save it for
|
236
|
+
# future re-use. That way, we only use one file descriptor to get an MD5
|
237
|
+
# socket instead of two, and we also get to save some syscalls.
|
238
|
+
|
239
|
+
global _bound_md5_sockfd
|
240
|
+
global _libc_socket
|
241
|
+
global _libc_bind
|
242
|
+
global _libc_accept
|
243
|
+
|
244
|
+
if _libc_accept is None:
|
245
|
+
_libc_accept = load_libc_function('accept', fail_if_missing=True)
|
246
|
+
if _libc_socket is None:
|
247
|
+
_libc_socket = load_libc_function('socket', fail_if_missing=True)
|
248
|
+
if _libc_bind is None:
|
249
|
+
_libc_bind = load_libc_function('bind', fail_if_missing=True)
|
250
|
+
|
251
|
+
# Do this at first call rather than at import time so that we don't use a
|
252
|
+
# file descriptor on systems that aren't using any MD5 sockets.
|
253
|
+
if _bound_md5_sockfd is None:
|
254
|
+
sockaddr_setup = sockaddr_alg(
|
255
|
+
AF_ALG,
|
256
|
+
(ord('h'), ord('a'), ord('s'), ord('h'), 0),
|
257
|
+
0, 0,
|
258
|
+
(ord('m'), ord('d'), ord('5'), 0))
|
259
|
+
hash_sockfd = _libc_socket(ctypes.c_int(AF_ALG),
|
260
|
+
ctypes.c_int(socket.SOCK_SEQPACKET),
|
261
|
+
ctypes.c_int(0))
|
262
|
+
if hash_sockfd < 0:
|
263
|
+
raise IOError(ctypes.get_errno(),
|
264
|
+
"Failed to initialize MD5 socket")
|
265
|
+
|
266
|
+
bind_result = _libc_bind(ctypes.c_int(hash_sockfd),
|
267
|
+
ctypes.pointer(sockaddr_setup),
|
268
|
+
ctypes.c_int(ctypes.sizeof(sockaddr_alg)))
|
269
|
+
if bind_result < 0:
|
270
|
+
os.close(hash_sockfd)
|
271
|
+
raise IOError(ctypes.get_errno(), "Failed to bind MD5 socket")
|
272
|
+
|
273
|
+
_bound_md5_sockfd = hash_sockfd
|
274
|
+
|
275
|
+
md5_sockfd = _libc_accept(ctypes.c_int(_bound_md5_sockfd), None, 0)
|
276
|
+
if md5_sockfd < 0:
|
277
|
+
raise IOError(ctypes.get_errno(), "Failed to accept MD5 socket")
|
278
|
+
|
279
|
+
return md5_sockfd
|
280
|
+
|
281
|
+
|
282
|
+
def modify_priority(conf, logger):
|
283
|
+
"""
|
284
|
+
Modify priority by nice and ionice.
|
285
|
+
"""
|
286
|
+
|
287
|
+
global _libc_setpriority
|
288
|
+
if _libc_setpriority is None:
|
289
|
+
_libc_setpriority = load_libc_function('setpriority',
|
290
|
+
errcheck=True)
|
291
|
+
|
292
|
+
def _setpriority(nice_priority):
|
293
|
+
"""
|
294
|
+
setpriority for this pid
|
295
|
+
|
296
|
+
:param nice_priority: valid values are -19 to 20
|
297
|
+
"""
|
298
|
+
try:
|
299
|
+
_libc_setpriority(PRIO_PROCESS, os.getpid(),
|
300
|
+
int(nice_priority))
|
301
|
+
except (ValueError, OSError):
|
302
|
+
print("WARNING: Unable to modify scheduling priority of process."
|
303
|
+
" Keeping unchanged! Check logs for more info. ")
|
304
|
+
logger.exception('Unable to modify nice priority')
|
305
|
+
else:
|
306
|
+
logger.debug('set nice priority to %s' % nice_priority)
|
307
|
+
|
308
|
+
nice_priority = conf.get('nice_priority')
|
309
|
+
if nice_priority is not None:
|
310
|
+
_setpriority(nice_priority)
|
311
|
+
|
312
|
+
global _posix_syscall
|
313
|
+
if _posix_syscall is None:
|
314
|
+
_posix_syscall = load_libc_function('syscall', errcheck=True)
|
315
|
+
|
316
|
+
def _ioprio_set(io_class, io_priority):
|
317
|
+
"""
|
318
|
+
ioprio_set for this process
|
319
|
+
|
320
|
+
:param io_class: the I/O class component, can be
|
321
|
+
IOPRIO_CLASS_RT, IOPRIO_CLASS_BE,
|
322
|
+
or IOPRIO_CLASS_IDLE
|
323
|
+
:param io_priority: priority value in the I/O class
|
324
|
+
"""
|
325
|
+
try:
|
326
|
+
io_class = IO_CLASS_ENUM[io_class]
|
327
|
+
io_priority = int(io_priority)
|
328
|
+
_posix_syscall(NR_ioprio_set(),
|
329
|
+
IOPRIO_WHO_PROCESS,
|
330
|
+
os.getpid(),
|
331
|
+
IOPRIO_PRIO_VALUE(io_class, io_priority))
|
332
|
+
except (KeyError, ValueError, OSError):
|
333
|
+
print("WARNING: Unable to modify I/O scheduling class "
|
334
|
+
"and priority of process. Keeping unchanged! "
|
335
|
+
"Check logs for more info.")
|
336
|
+
logger.exception("Unable to modify ionice priority")
|
337
|
+
else:
|
338
|
+
logger.debug('set ionice class %s priority %s',
|
339
|
+
io_class, io_priority)
|
340
|
+
|
341
|
+
io_class = conf.get("ionice_class")
|
342
|
+
if io_class is None:
|
343
|
+
return
|
344
|
+
io_priority = conf.get("ionice_priority", 0)
|
345
|
+
_ioprio_set(io_class, io_priority)
|