Middleware¶
账户配额¶
account_quotas 是一个中间件,当给定的账户配额(以字节为单位)被超出时,它会阻止写入请求(PUT、POST),但仍然允许 DELETE 请求。
account_quotas 使用以下元数据条目来存储账户配额
元数据 |
使用 |
|---|---|
X-Account-Meta-Quota-Bytes (已弃用) |
账户下所有容器中存储的总体最大字节数。 |
X-Account-Quota-Bytes |
账户下所有容器中存储的总体最大字节数。 |
X-Account-Quota-Bytes-Policy-<策略名称> |
给定策略下账户下所有容器中存储的总体最大字节数。 |
X-Account-Quota-Count |
账户下的最大对象数。 |
X-Account-Quota-Count-Policy-<策略名称> |
给定策略下账户下的最大对象数。 |
对这些元数据条目的写入请求仅允许转售商进行。如果未设置相应的元数据条目,则没有总体字节数或对象数限制。
此外,可以使用形式为 x-account-<配额类型>-policy-<策略名称> 的元数据为每个存储策略设置配额类型为 quota-bytes 或 quota-count 的账户配额。同样,只有转售商可以更新这些元数据,如果未设置相应的元数据,则特定策略将没有限制。
注意
每个策略的配额不必加起来等于账户的总配额,并且给定策略下所有 容器配额 的总和不必等于账户的策略配额。
account_quotas 中间件应添加到您的 /etc/swift/proxy-server.conf 文件的管道中,紧跟在任何身份验证中间件之后。例如
[pipeline:main]
pipeline = catch_errors cache tempauth account_quotas proxy-server
[filter:account_quotas]
use = egg:swift#account_quotas
设置账户上的配额
swift -A http://127.0.0.1:8080/auth/v1.0 -U account:reseller -K secret post -m quota-bytes:10000
移除配额
swift -A http://127.0.0.1:8080/auth/v1.0 -U account:reseller -K secret post -m quota-bytes:
账户配额的限制与容器配额的限制相同。
例如,在上传没有 content-length 头的对象时,代理服务器不知道当前上传对象的最终大小,如果当前账户大小在配额内,上传将被允许。由于最终一致性,在账户大小更新之前,可能还可以进行进一步的上传。
- class swift.common.middleware.account_quotas.AccountQuotaMiddleware(app, *args, **kwargs)¶
基类:
object账户配额中间件
有关完整描述,请参见上文。
- swift.common.middleware.account_quotas.filter_factory(global_conf, **local_conf)¶
返回一个 WSGI filter app,供 paste.deploy 使用。
AWS S3 API¶
s3api 中间件将在 swift 之上模拟 S3 REST API。
要将此中间件添加到您的配置中,请在身份验证中间件之前添加 s3api 中间件。有关更多详细信息和可配置选项,请参阅 proxy-server.conf-sample。
要设置您的客户端,请确保您使用的是 swift 项目的 tempauth 或 keystone 身份验证系统。当您的 swift 在 SAIO 环境中时,请确保您已在 proxy-server.conf 中设置了 tempauth 中间件配置,并且访问密钥将是账户和用户字符串的连接,看起来应该像 test:tester,秘密访问密钥是账户密码。主机也应该指向 swift 存储主机名。
tempauth 选项示例
[filter:tempauth]
use = egg:swift#tempauth
user_admin_admin = admin .admin .reseller_admin
user_test_tester = testing
以下是使用 python boto 库的 tempauth 的示例客户端
from boto.s3.connection import S3Connection
connection = S3Connection(
aws_access_key_id='test:tester',
aws_secret_access_key='testing',
port=8080,
host='127.0.0.1',
is_secure=False,
calling_format=boto.s3.connection.OrdinaryCallingFormat())
如果您使用 keystone 身份验证,则需要 ec2 凭证,可以从仪表板的 API Endpoints 选项卡下载,或者通过 openstack ec2 命令获取。
这里展示了如何创建 EC2 凭证
# openstack ec2 credentials create
+------------+---------------------------------------------------+
| Field | Value |
+------------+---------------------------------------------------+
| access | c2e30f2cd5204b69a39b3f1130ca8f61 |
| links | {u'self': u'http://controller:5000/v3/......'} |
| project_id | 407731a6c2d0425c86d1e7f12a900488 |
| secret | baab242d192a4cd6b68696863e07ed59 |
| trust_id | None |
| user_id | 00f0ee06afe74f81b410f3fe03d34fbc |
+------------+---------------------------------------------------+
使用 python boto 库的 keystone 身份验证的示例客户端将是
from boto.s3.connection import S3Connection
connection = S3Connection(
aws_access_key_id='c2e30f2cd5204b69a39b3f1130ca8f61',
aws_secret_access_key='baab242d192a4cd6b68696863e07ed59',
port=8080,
host='127.0.0.1',
is_secure=False,
calling_format=boto.s3.connection.OrdinaryCallingFormat())
部署¶
代理服务器设置¶
在 proxy-server.conf 文件中,将 s3api 设置在身份验证之前。要启用当前支持的所有兼容性,您应该确保 bulk、slo 和您的身份验证中间件也包含在您的代理管道设置中。
使用 tempauth,最小示例配置是
[pipeline:main]
pipeline = proxy-logging cache s3api tempauth bulk slo proxy-logging proxy-server
使用 keystone 时,配置将是
[pipeline:main]
pipeline = proxy-logging cache authtoken s3api s3token keystoneauth bulk slo proxy-logging proxy-server
最后,添加 s3api 中间件部分
[filter:s3api]
use = egg:swift#s3api
注意
keystonemiddleware.authtoken 可以位于 s3api 之前/之后,但我们建议将其放在 s3api 之前,因为当 authtoken 在 s3api 之后时,authtoken 和 s3token 都将向 keystone 发出可接受的令牌(即,进行两次身份验证)。在 keystonemiddleware.authtoken 中间件中,您应该将 delay_auth_decision 选项设置为 True。
限制¶
目前,s3api 正在从 https://github.com/openstack/swift3 移植,因此 swift3 中已存在的任何问题仍然存在。请务必在启用选项之前,仔细阅读示例 proxy-server.conf 中的描述以及配置的作用。
支持的 API¶
兼容性将继续在 upstream 中得到改进,您可以通过 SwiftStack 构建的检查工具密切关注兼容性。详细信息请参阅 https://github.com/swiftstack/s3compat。
- class swift.common.middleware.s3api.s3api.S3ApiMiddleware(app, wsgi_conf, *args, **kwargs)¶
基类:
objectS3Api:S3 兼容性中间件
- check_filter_order(pipeline, required_filters)¶
检查必需的过滤器是否按顺序出现在管道中。
- check_pipeline(wsgi_conf)¶
检查 proxy-server.conf 是否具有适合 s3api 的管道。
- swift.common.middleware.s3api.s3api.filter_factory(global_conf, **local_conf)¶
标准 filter factory,用于将中间件与 paste.deploy 一起使用。
S3 令牌中间件¶
s3token 中间件用于使用 s3api + keystone 进行身份验证。此中间件
从 s3api 中间件接收带有 S3 Authorization 访问密钥的请求。
使用 Keystone 验证 s3 令牌。
将账户名转换为 AUTH_%(tenant_name)。
可以选择从 keystone 检索并缓存密钥以在本地验证签名。
注意
如果从 swift3 升级,auth_version 配置选项已被移除,auth_uri 选项现在包含 Keystone API 版本。如果您以前的配置是
[filter:s3token]
use = egg:swift3#s3token
auth_uri = https://keystonehost:35357
auth_version = 3
您现在应该使用
[filter:s3token]
use = egg:swift#s3token
auth_uri = https://keystonehost:35357/v3
- class swift.common.middleware.s3api.s3token.S3Token(app, conf)¶
基类:
object处理 S3 身份验证的中间件。
- swift.common.middleware.s3api.s3token.filter_factory(global_conf, **local_conf)¶
返回一个 WSGI filter app,供 paste.deploy 使用。
- class swift.common.middleware.s3api.s3request.ChecksummingInput(wsgi_input, content_length, checksum_hasher, checksum_key, checksum_source)¶
Bases:
InputProxywsgi.input 包装器,用于在读取输入时计算 X-Amz-Checksum-*。计算出的值将与请求标头或尾部中发送的预期值进行比较。为了允许后者,预期值将在读取输入后惰性获取。
- 参数:
wsgi_input – 要包装的文件类对象。
content_length – 预期读取的字节数。
checksum_hasher – 用于计算读取字节校验和的哈希器。
checksum_key – 将包含预期校验和值的标头或尾部的名称。
checksum_source – 一个字典,其中包含
checksum_key。
- chunk_update(chunk, eof, *args, **kwargs)¶
每次从包装的输入读取一个字节块时调用。
- 参数:
chunk – 已读取的字节块。
eof – 如果没有更多字节可从包装的输入中读取,则为
True,否则为False。如果调用了read(),当chunk的大**小小于请求的大小或请求大小为 None 时,则此值为True。如果调用了readline,当读取了一个不完整的行(即不以b'\n'结尾)且其大**小小于请求的大小或请求大小为 None 时,则此值为True。如果使用请求的大小,该大小精确匹配包装输入中剩余的字节数来调用read()或readline(),则eof将为False。后续使用非零size调用read()或readline()将导致eof为True。或者,可以通过将bytes_received与输入的预期大**小进行比较来推断输入的结束。
- class swift.common.middleware.s3api.s3request.ChunkReader(wsgi_input, chunk_size, validator, chunk_params)¶
Bases:
InputProxywsgi.input 包装器,用于从 aws-chunked 输入中读取单个块并验证其签名。
- 参数:
wsgi_input – wsgi 输入。
chunk_size – 要读取的字节数。
validator – 要调用以验证块内容的函数。
chunk_params – 来自块标头中的参数字符串。
- chunk_update(chunk, eof, *args, **kwargs)¶
每次从包装的输入读取一个字节块时调用。
- 参数:
chunk – 已读取的字节块。
eof – 如果没有更多字节可从包装的输入中读取,则为
True,否则为False。如果调用了read(),当chunk的大**小小于请求的大小或请求大小为 None 时,则此值为True。如果调用了readline,当读取了一个不完整的行(即不以b'\n'结尾)且其大**小小于请求的大小或请求大小为 None 时,则此值为True。如果使用请求的大小,该大小精确匹配包装输入中剩余的字节数来调用read()或readline(),则eof将为False。后续使用非零size调用read()或readline()将导致eof为True。或者,可以通过将bytes_received与输入的预期大**小进行比较来推断输入的结束。
- read(size=None, *args, **kwargs)¶
将读取请求传递给底层文件类对象,并将读取的字节数加到总数中。
- 参数:
size – (可选) 要读取的最大字节数;默认值
None表示不限制。
- readline(size=None, *args, **kwargs)¶
将读取行请求传递给底层文件类对象,并将读取的字节数加到总数中。
- 参数:
size – (可选) 要从当前行读取的最大字节数;默认值
None表示不限制。
- class swift.common.middleware.s3api.s3request.HashingInput(wsgi_input, content_length, expected_hex_hash)¶
Bases:
InputProxywsgi.input 包装器,用于在读取输入时验证 SHA256。
- chunk_update(chunk, eof, *args, **kwargs)¶
每次从包装的输入读取一个字节块时调用。
- 参数:
chunk – 已读取的字节块。
eof – 如果没有更多字节可从包装的输入中读取,则为
True,否则为False。如果调用了read(),当chunk的大**小小于请求的大小或请求大小为 None 时,则此值为True。如果调用了readline,当读取了一个不完整的行(即不以b'\n'结尾)且其大**小小于请求的大小或请求大小为 None 时,则此值为True。如果使用请求的大小,该大小精确匹配包装输入中剩余的字节数来调用read()或readline(),则eof将为False。后续使用非零size调用read()或readline()将导致eof为True。或者,可以通过将bytes_received与输入的预期大**小进行比较来推断输入的结束。
- class swift.common.middleware.s3api.s3request.S3AclRequest(env, app=None, conf=None)¶
Bases:
S3RequestS3Acl 请求对象。
- authenticate(app)¶
authenticate 方法将运行预身份验证请求并检索账户信息。请注意,它目前仅支持 keystone 和 tempauth。(不支持第三方身份验证中间件)
- get_acl_response(app, method=None, container=None, obj=None, headers=None, body=None, query=None)¶
重写 _get_response 方法,以从响应 sysmeta 标头添加 s3 acl 信息。
- get_response(app, method=None, container=None, obj=None, headers=None, body=None, query=None)¶
包装 get_response 调用,以便与 acl 处理方法挂钩。
- to_swift_req(method, container, obj, query=None, body=None, headers=None)¶
基于此请求的环境创建 Swift 请求。
- class swift.common.middleware.s3api.s3request.S3Request(env, app=None, conf=None)¶
Bases:
RequestS3 请求对象。
- property body¶
swob.Request.body 对于恶意输入不够安全。在请求体过大时,它不会进行任何检查就消耗大量内存。请改用 xml()。
- property bucket_acl¶
获取和设置容器 acl 属性。
- check_copy_source(app)¶
check_copy_source 检查 copy source 的存在性,以及在将对象复制到自身时是否存在非法请求参数。
- 返回值:
源 HEAD 响应。
- get_container_info(app)¶
get_container_info 将从后端 Swift 返回 get_container_info 的结果字典。
- 返回值:
来自 swift.controllers.base.get_container_info 的容器信息字典。
- 引发:
当容器不存在时为 NoSuchBucket。
- 引发:
请求失败但不是 404 时为 InternalError。
- get_response(app, method=None, container=None, obj=None, headers=None, body=None, query=None)¶
get_response 是一个供子类扩展的入口点。如果在此时需要执行其他任务来获取 swift 响应,我们可以重写此方法。swift.common.middleware.s3api.s3request.S3Request 需要直接调用 _get_response 来获取纯粹的 swift 响应。
- property object_acl¶
获取和设置对象 acl 属性。
- property timestamp¶
来自 Date 标头的 S3Timestamp。如果指定了 X-Amz-Date 标头,则它将优先于 Date 标头。
:return : S3Timestamp 实例
- to_swift_req(method, container, obj, query=None, body=None, headers=None)¶
基于此请求的环境创建 Swift 请求。
- validate_part_number(parts_count=None, check_max=True)¶
获取 partNumber 参数(如果存在),并检查其是否有效。
要有效,partNumber 必须满足两个条件。首先,它必须是介于 1 和最大允许部分(包括)之间的整数。最大允许部分是配置的
max_upload_part_num和(如果给出)parts_count中的最大值。其次,partNumber 必须小于或等于parts_count(如果给出)。- 参数:
parts_count – 如果给出,则这是现有对象的总部分数。
- 引发:
InvalidPartArgument – 如果 partNumber 参数无效,即小于 1 或大于最大允许的部分。
InvalidPartNumber – 如果 partNumber 参数有效但大于
num_parts。
- 返回值:
如果 partNumber 参数存在,则返回一个整数部分号;否则返回
None。
- xml(max_length)¶
类似于 swob.Request.body,但它在创建 body 字符串之前会检查内容长度。
- class swift.common.middleware.s3api.s3request.SigV4Mixin¶
基类:
object提供 S3 signature v4 功能的请求类 mixin。
- property timestamp¶
根据 auth 类型返回时间戳字符串。与 v2 的区别在于,v4 即使是查询 auth 类型也必须查看 'X-Amz-Date'。
- class swift.common.middleware.s3api.s3request.SigV4Request(env, app=None, conf=None)¶
Bases:
SigV4Mixin,S3Request
- class swift.common.middleware.s3api.s3request.SigV4S3AclRequest(env, app=None, conf=None)¶
Bases:
SigV4Mixin,S3AclRequest
- class swift.common.middleware.s3api.s3request.StreamingInput(input, decoded_content_length, expected_trailers, sig_checker)¶
基类:
objectwsgi.input 包装器,用于读取分块输入,并在读取每个块时进行验证。一旦所有块都已读取,就会读取任何尾部。
- 参数:
input – wsgi 输入。
decoded_content_length – 预期从块中提取的有效负载字节数。
expected_trailers – 预期的尾部名称集。
sig_checker – SigCheckerV4 的一个实例,将调用它来验证每个块的签名。
- swift.common.middleware.s3api.s3request.get_request_class(env, s3_acl)¶
辅助函数,用于从 Map 中查找要使用的请求类。
- exception swift.common.middleware.s3api.s3response.AccessDenied(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.AccountProblem(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.AmbiguousGrantByEmailAddress(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.AuthorizationHeaderMalformed(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.AuthorizationQueryParametersError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.BadDigest(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.BrokenMPU(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.BucketAlreadyExists(bucket, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.BucketAlreadyOwnedByYou(bucket, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.BucketNotEmpty(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.CredentialsNotSupported(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.CrossLocationLoggingProhibited(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.EntityTooLarge(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.EntityTooSmall(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.ErrorResponse(msg=None, reason=None, *args, **kwargs)¶
Bases:
S3ResponseBase,HTTPExceptionS3 错误对象。
有关 S3 错误的参考信息,请访问:http://docs.aws.amazon.com/AmazonS3/2025.2/API/ErrorResponses.html
- property summary¶
提供错误代码和原因的摘要。
- exception swift.common.middleware.s3api.s3response.ExpiredToken(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- class swift.common.middleware.s3api.s3response.HeaderKeyDict(base_headers=None, **kwargs)¶
Bases:
HeaderKeyDict类似于 Swift 的普通 HeaderKeyDict 类,但其键名已被标准化为 S3 客户端的预期。
- exception swift.common.middleware.s3api.s3response.IllegalVersioningConfigurationException(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.IncompleteBody(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.IncorrectNumberOfFilesInPostRequest(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InlineDataTooLarge(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InternalError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidAccessKeyId(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidArgument(name, value, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidBucketName(bucket, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidBucketState(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidChunkSizeError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidDigest(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidLocationConstraint(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidObjectState(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidPart(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidPartArgument(max_parts, value)¶
Bases:
InvalidArgument
- exception swift.common.middleware.s3api.s3response.InvalidPartNumber(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidPartOrder(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidPayer(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidPolicyDocument(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidRange(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidRequest(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidSOAPRequest(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidSecurity(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidStorageClass(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidTargetBucketForLogging(bucket, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidToken(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.InvalidURI(uri, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.KeyTooLongError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MalformedACLError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MalformedPOSTRequest(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MalformedTrailerError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MalformedXML(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MaxMessageLengthExceeded(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MaxPostPreDataLengthExceededError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MetadataTooLarge(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MethodNotAllowed(method, resource_type, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MissingContentLength(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MissingRequestBodyError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MissingSecurityElement(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.MissingSecurityHeader(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NoLoggingStatusForKey(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NoSuchBucket(bucket, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NoSuchKey(key, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NoSuchLifecycleConfiguration(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NoSuchUpload(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NoSuchVersion(key, version_id, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NotSignedUp(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.NotSuchBucketPolicy(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.ObjectLockConfigurationNotFoundError(bucket, msg=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.OperationAborted(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.PermanentRedirect(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.PreconditionFailed(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.Redirect(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.RequestIsNotMultiPartContent(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.RequestTimeTooSkewed(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.RequestTimeout(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.RequestTorrentOfBucketError(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.RestoreAlreadyInProgress(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.S3NotImplemented(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- class swift.common.middleware.s3api.s3response.S3Response(*args, **kwargs)¶
Bases:
S3ResponseBase,ResponseSimilar to the Response class in Swift, but uses our HeaderKeyDict for headers instead of Swift’s HeaderKeyDict. This also translates Swift specific headers to S3 headers.
- classmethod from_swift_resp(sw_resp)¶
Create a new S3 response object based on the given Swift response.
- class swift.common.middleware.s3api.s3response.S3ResponseBase¶
基类:
objectBase class for swift3 responses.
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.SignatureDoesNotMatch(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.SlowDown(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.TemporaryRedirect(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.TokenRefreshRequired(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.TooManyBuckets(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.UnexpectedContent(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.UnresolvableGrantByEmailAddress(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.UserKeyMustBeSpecified(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.s3response.VersionedBucketNotEmpty(msg=None, reason=None, *args, **kwargs)¶
Bases:
BucketNotEmpty
- exception swift.common.middleware.s3api.s3response.XAmzContentSHA256Mismatch(msg=None, reason=None, *args, **kwargs)¶
Bases:
ErrorResponse
- exception swift.common.middleware.s3api.exception.ACLError¶
Bases:
S3Exception
- exception swift.common.middleware.s3api.exception.InvalidSubresource(resource, cause)¶
Bases:
S3Exception
- exception swift.common.middleware.s3api.exception.NotS3Request¶
Bases:
S3Exception
- exception swift.common.middleware.s3api.exception.S3Exception¶
基础:
Exception
- exception swift.common.middleware.s3api.exception.S3InputChecksumMismatch¶
Bases:
S3InputErrorClient provided a X-Amz-Checksum-* header, but it doesn’t match the data.
This should result in a InvalidRequest going back to the client.
- exception swift.common.middleware.s3api.exception.S3InputChecksumTrailerInvalid(trailer_name)¶
Bases:
S3InputErrorClient provided a X-Amz-Checksum-* trailer, but it is not a valid format.
This should result in a InvalidRequest going back to the client.
- exception swift.common.middleware.s3api.exception.S3InputChunkSignatureMismatch¶
Bases:
S3InputErrorClient provided a chunk-signature, but it doesn’t match the data.
This should result in a 403 going back to the client.
- exception swift.common.middleware.s3api.exception.S3InputChunkTooSmall(bad_chunk_size, chunk_number)¶
Bases:
S3InputError
- exception swift.common.middleware.s3api.exception.S3InputError¶
基础:
BaseExceptionThere was an error with the client input detected on read().
Inherit from BaseException (rather than Exception) so it cuts from the proxy-server app (which will presumably be the one reading the input) through all the layers of the pipeline back to s3api. It should never escape the s3api middleware.
- exception swift.common.middleware.s3api.exception.S3InputIncomplete¶
Bases:
S3InputError
- exception swift.common.middleware.s3api.exception.S3InputMalformedTrailer¶
Bases:
S3InputError
- exception swift.common.middleware.s3api.exception.S3InputMissingSecret¶
Bases:
S3InputErrorClient provided per-chunk signatures, but we have no secret with which to verify them.
This happens if the auth middleware responsible for the user never called the provided
check_signaturecallback.
- exception swift.common.middleware.s3api.exception.S3InputSHA256Mismatch(expected, computed)¶
Bases:
S3InputErrorClient provided a X-Amz-Content-SHA256, but it doesn’t match the data.
This should result in a BadDigest going back to the client.
- exception swift.common.middleware.s3api.exception.S3InputSizeError(expected, provided)¶
Bases:
S3InputError
- class swift.common.middleware.s3api.etree._Element(*args, **kwargs)¶
Bases:
ElementBaseWrapper Element class of lxml.etree.Element to support a utf-8 encoded non-ascii string as a text.
Why we need this?: Original lxml.etree.Element supports only unicode for the text. It declines maintainability because we have to call a lot of encode/decode methods to apply account/container/object name (i.e. PATH_INFO) to each Element instance. When using this class, we can remove such a redundant codes from swift.common.middleware.s3api middleware.
- property text¶
utf-8 wrapper property of lxml.etree.Element.text
- class swift.common.middleware.s3api.utils.Config(base=None)¶
基础:
dict- update([E, ]**F) None. Update D from dict/iterable E and F.¶
如果存在 E 并且具有 .keys() 方法,则执行:for k in E: D[k] = E[k] 如果存在 E 并且缺少 .keys() 方法,则执行:for k, v in E: D[k] = v 在任何一种情况下,之后都会执行:for k in F: D[k] = F[k]
- class swift.common.middleware.s3api.utils.S3Timestamp(timestamp, offset=0, delta=0, check_bounds=True)¶
Bases:
Timestamp- property amz_date_format¶
this format should be like ‘YYYYMMDDThhmmssZ’
- swift.common.middleware.s3api.utils.mktime(timestamp_str, time_format='%Y-%m-%dT%H:%M:%S')¶
mktime creates a float instance in epoch time really like as time.mktime
the difference from time.mktime is allowing to 2 formats string for the argument for the S3 testing usage. TODO: support
- 参数:
timestamp_str – a string of timestamp formatted as (a) RFC2822 (e.g. date header) (b) %Y-%m-%dT%H:%M:%S (e.g. copy result)
time_format – a string of format to parse in (b) process
- 返回值:
a float instance in epoch time
- swift.common.middleware.s3api.utils.sysmeta_header(resource, name)¶
Returns the system metadata header for given resource type and name.
- swift.common.middleware.s3api.utils.sysmeta_prefix(resource)¶
Returns the system metadata prefix for given resource type.
- swift.common.middleware.s3api.utils.validate_bucket_name(name, dns_compliant_bucket_names)¶
Validates the name of the bucket against S3 criteria, http://docs.amazonwebservices.com/AmazonS3/2025.2/BucketRestrictions.html True is valid, False is invalid.
s3api’s ACLs implementation¶
s3api uses a different implementation approach to achieve S3 ACLs.
First, we should understand what we have to design to achieve real S3 ACLs. Current s3api(real S3)’s ACLs Model is as follows
AccessControlPolicy:
Owner:
AccessControlList:
Grant[n]:
(Grantee, Permission)
Each bucket or object has its own acl consisting of Owner and AcessControlList. AccessControlList can contain some Grants. By default, AccessControlList has only one Grant to allow FULL CONTROLL to owner. Each Grant includes single pair with Grantee, Permission. Grantee is the user (or user group) allowed the given permission.
This module defines the groups and the relation tree.
If you wanna get more information about S3’s ACLs model in detail, please see official documentation here,
http://docs.aws.amazon.com/AmazonS3/2025.2/dev/acl-overview.html
- class swift.common.middleware.s3api.subresource.ACL(owner, grants=None, s3_acl=False, allow_no_owner=False)¶
基类:
objectS3 ACL class.
- Refs (S3 API - acl-overview
http://docs.aws.amazon.com/AmazonS3/2025.2/dev/acl-overview.html):
The sample ACL includes an Owner element identifying the owner via the AWS account’s canonical user ID. The Grant element identifies the grantee (either an AWS account or a predefined group), and the permission granted. This default ACL has one Grant element for the owner. You grant permissions by adding Grant elements, each grant identifying the grantee and the permission.
- check_owner(user_id)¶
Check that the user is an owner.
- check_permission(user_id, permission)¶
Check that the user has a permission.
- elem()¶
Decode the value to an ACL instance.
- classmethod from_elem(elem, s3_acl=False, allow_no_owner=False)¶
Convert an ElementTree to an ACL instance
- classmethod from_headers(headers, bucket_owner, object_owner=None, as_private=True)¶
将 HTTP 头部转换为 ACL 实例。
- class swift.common.middleware.s3api.subresource.AllUsers¶
Bases:
Group对该组的访问权限允许任何人访问资源。请求可以是签名的(已认证)或未签名的(匿名的)。未签名的请求省略请求中的 Authentication 头部。
注意:s3api 将未签名请求视为 Swift API 访问,并将其绕过到 Swift。因此,AllUsers 的行为与 AuthenticatedUsers 完全相同。
- class swift.common.middleware.s3api.subresource.AuthenticatedUsers¶
Bases:
Group此组代表所有 AWS 账户。对该组的访问权限允许任何 AWS 账户访问资源。但是,所有请求都必须经过签名(已认证)。
- class swift.common.middleware.s3api.subresource.CannedACL¶
基类:
object一个类似字典的对象,返回预设 ACL。
- class swift.common.middleware.s3api.subresource.Grant(grantee, permission)¶
基类:
objectGrant 类,包含 Grantee 和 Permission
- elem()¶
创建一个 etree 元素。
- classmethod from_elem(elem)¶
Convert an ElementTree to an ACL instance
- class swift.common.middleware.s3api.subresource.Grantee¶
基类:
objectGrantee 的基类。
方法
init: 创建一个 Grantee 实例
elem: 从自身创建一个 ElementTree
静态方法
- from_header: 将 HTTP 头部中的 grantee字符串
转换为 Grantee 实例。
from_elem: 将 ElementTree 转换为 Grantee 实例。
- elem()¶
获取此实例的 etree 元素。
- static from_header(grantee)¶
将 HTTP 头部中的 grantee字符串转换为 Grantee 实例。
- class swift.common.middleware.s3api.subresource.Group¶
Bases:
GranteeAmazon S3 预定义组的基类
- elem()¶
获取此实例的 etree 元素。
- class swift.common.middleware.s3api.subresource.LogDelivery¶
Bases:
Group对存储桶的 WRITE 和 READ_ACP 权限使此组能够将服务器访问日志写入存储桶。
- class swift.common.middleware.s3api.subresource.Owner(id, name)¶
基类:
objectS3 账户的 Owner 类
- class swift.common.middleware.s3api.subresource.User(name)¶
Bases:
GranteeS3 账户的规范化用户类。
- elem()¶
获取此实例的 etree 元素。
- swift.common.middleware.s3api.subresource.canned_acl_grantees(bucket_owner, object_owner=None)¶
AWS S3 支持的预定义权限集。
- swift.common.middleware.s3api.subresource.decode_acl(resource, headers, allow_no_owner)¶
将 Swift 元数据解码为 ACL 实例。
给定资源类型和 HTTP 头部,此方法返回一个 ACL 实例。
- swift.common.middleware.s3api.subresource.encode_acl(resource, acl)¶
将 ACL 实例编码为 Swift 元数据。
给定资源类型和 ACL 实例,此方法返回 HTTP 头部,可用于 Swift 元数据。
- swift.common.middleware.s3api.subresource.get_group_subclass_from_uri(uri)¶
将 URI 转换为预定义组之一。
ACL 处理程序¶
为什么需要它¶
为了保持控制器类的整洁,我们需要这些处理程序。它对于为每个控制器定制 acl 检查算法非常有用。
基本信息¶
BaseAclHandler 包装了基本的 ACL 处理。(例如,它将使用 HEAD 从 ACL_MAP 检查 acl)。
如何扩展¶
创建一个以控制器命名的处理程序。(例如,BucketAclHandler 用于 BucketController)。它包含实际 S3 方法在控制器上的方法,如下所示。
示例
class BucketAclHandler(BaseAclHandler):
def PUT:
<< put acl handling algorithms here for PUT bucket >>
注意
如果方法不需要在 acl 检查之外调用 _get_response,则该方法必须在方法末尾返回它所需响应。
- class swift.common.middleware.s3api.acl_handlers.BaseAclHandler(req, logger, container=None, obj=None, headers=None)¶
基类:
objectBaseAclHandler:处理映射到 ACL_MAP 的基本请求的 ACL
- get_acl(headers, body, bucket_owner, object_owner=None)¶
从 S3(例如 x-amz-grant)头部或 S3 acl xml 请求体获取 ACL 实例。
- class swift.common.middleware.s3api.acl_handlers.BucketAclHandler(req, logger, container=None, obj=None, headers=None)¶
Bases:
BaseAclHandlerBucketAclHandler:BucketController 的处理程序
- class swift.common.middleware.s3api.acl_handlers.MultiObjectDeleteAclHandler(req, logger, container=None, obj=None, headers=None)¶
Bases:
BaseAclHandlerMultiObjectDeleteAclHandler:MultiObjectDeleteController 的处理程序
- class swift.common.middleware.s3api.acl_handlers.MultiUploadAclHandler(req, logger, **kwargs)¶
Bases:
BaseAclHandlerMultiUpload 相关操作只需要为 BASE 容器检查一次 ACL,因此 MultiUploadAclHandler 继承自 BaseAclHandler,以便仅在定义了动词时才检查 ACL。我们应该将动词定义为传入请求中后端 Swift 请求的第一步。
- 基本规则
BASE 容器名称始终不包含 ‘MULTIUPLOAD_SUFFIX’
任何检查时机都可以,但我们应该尽快检查。
控制器
动词
CheckResource
权限
分块
PUT
容器
WRITE
上传
GET
容器
READ
上传
POST
容器
WRITE
上传
GET
容器
READ
上传
DELETE
容器
WRITE
上传
POST
容器
WRITE
- class swift.common.middleware.s3api.acl_handlers.ObjectAclHandler(req, logger, container=None, obj=None, headers=None)¶
Bases:
BaseAclHandlerObjectAclHandler:ObjectController 的处理程序
- class swift.common.middleware.s3api.acl_handlers.PartAclHandler(req, logger, **kwargs)¶
Bases:
MultiUploadAclHandlerPartAclHandler:PartController 的处理程序
- class swift.common.middleware.s3api.acl_handlers.S3AclHandler(req, logger, container=None, obj=None, headers=None)¶
Bases:
BaseAclHandlerS3AclHandler:S3AclController 的处理程序
- class swift.common.middleware.s3api.acl_handlers.UploadAclHandler(req, logger, **kwargs)¶
Bases:
MultiUploadAclHandlerUploadAclHandler:UploadController 的处理程序
- class swift.common.middleware.s3api.acl_handlers.UploadsAclHandler(req, logger, **kwargs)¶
Bases:
MultiUploadAclHandlerUploadsAclHandler:UploadsController 的处理程序
- swift.common.middleware.s3api.acl_utils.handle_acl_header(req)¶
处理 x-amz-acl 头部。注意,此头部目前仅用于普通 ACL(未实现),在 s3acl 中。TODO:添加转换为 Swift ACL,例如 x-container-read 到 s3acl
- swift.common.middleware.s3api.acl_utils.swift_acl_translate(acl, group='', user='', xml=False)¶
接受 S3 样式的 ACL,并返回一个头部/值对列表,该列表在 Swift 中实现该 ACL,如果尚无实现方式,则返回“NotImplemented”。
- class swift.common.middleware.s3api.controllers.base.Controller(app, conf, logger, **kwargs)¶
基类:
object中间件的基类 WSGI 控制器
- classmethod resource_type()¶
返回此控制器的目标资源类型。
- class swift.common.middleware.s3api.controllers.base.UnsupportedController(app, conf, logger, **kwargs)¶
Bases:
Controller处理不受支持的请求。
- swift.common.middleware.s3api.controllers.base.bucket_operation(func=None, err_resp=None, err_msg=None)¶
一个装饰器,确保请求是存储桶操作。如果目标资源是对象,此装饰器默认会更新请求,以便控制器将其作为存储桶操作进行处理。如果指定了“err_resp”,则在出错时将引发它。
- swift.common.middleware.s3api.controllers.base.check_container_existence(func)¶
一个装饰器,用于确保存储桶存在。
- swift.common.middleware.s3api.controllers.base.object_operation(func)¶
一个装饰器,用于确保请求是对象操作。如果目标资源不是对象,则会引发错误响应。
- class swift.common.middleware.s3api.controllers.service.ServiceController(app, conf, logger, **kwargs)¶
Bases:
Controller处理账户级别的请求。
- GET(req)¶
处理 GET Service 请求
- class swift.common.middleware.s3api.controllers.bucket.BucketController(app, conf, logger, **kwargs)¶
Bases:
Controller处理存储桶请求。
- DELETE(req)¶
处理 DELETE Bucket 请求
- GET(req)¶
处理 GET Bucket (List Objects) 请求
- HEAD(req)¶
处理 HEAD Bucket (Get Metadata) 请求
- POST(req)¶
处理 POST Bucket 请求
- PUT(req)¶
处理 PUT Bucket 请求
- class swift.common.middleware.s3api.controllers.obj.ObjectController(app, conf, logger, **kwargs)¶
Bases:
Controller处理对象上的请求
- DELETE(req)¶
处理 DELETE Object 请求
- GET(req)¶
处理 GET Object 请求
- HEAD(req)¶
处理 HEAD Object 请求
- PUT(req)¶
处理 PUT Object 和 PUT Object (Copy) 请求
- class swift.common.middleware.s3api.controllers.acl.AclController(app, conf, logger, **kwargs)¶
Bases:
Controller处理以下 API
GET Bucket acl
PUT Bucket acl
GET Object acl
PUT Object acl
这些 API 在 S3 服务器日志中被记录为 ACL 操作。
- GET(req)¶
处理 GET Bucket acl 和 GET Object acl。
- PUT(req)¶
处理 PUT Bucket acl 和 PUT Object acl。
- swift.common.middleware.s3api.controllers.acl.get_acl(account_name, headers)¶
尝试根据 Swift 头部中找到的内容构建 S3 ACL。
- class swift.common.middleware.s3api.controllers.s3_acl.S3AclController(app, conf, logger, **kwargs)¶
Bases:
Controller处理以下 API
GET Bucket acl
PUT Bucket acl
GET Object acl
PUT Object acl
这些 API 在 S3 服务器日志中被记录为 ACL 操作。
- GET(req)¶
处理 GET Bucket acl 和 GET Object acl。
- PUT(req)¶
处理 PUT Bucket acl 和 PUT Object acl。
S3 分段上传的实现。
此模块使用 Swift SLO 功能实现 S3 分段上传 API。以下解释了 S3api 如何使用 Swift 容器和对象来存储 S3 上传信息。
[bucket]+segments¶
用于存储上传信息的容器。[bucket] 是发起分段上传的原始存储桶。
[bucket]+segments/[upload_id]¶
正在进行的上传 ID 的对象。该对象为空,用于检查目标上传状态。如果对象存在,则表示上传已启动,但尚未完成或已中止。
[bucket]+segments/[upload_id]/[part_number]¶
最后一个后缀是上传 ID 下的分块号。当客户端上传分块时,它们将存储在命名空间 [bucket]+segments/[upload_id]/[part_number] 中。
示例:[bucket]+segments 容器中的列表结果
[bucket]+segments/[upload_id1] # upload id object for upload_id1
[bucket]+segments/[upload_id1]/1 # part object for upload_id1
[bucket]+segments/[upload_id1]/2 # part object for upload_id1
[bucket]+segments/[upload_id1]/3 # part object for upload_id1
[bucket]+segments/[upload_id2] # upload id object for upload_id2
[bucket]+segments/[upload_id2]/1 # part object for upload_id2
[bucket]+segments/[upload_id2]/2 # part object for upload_id2
.
.
当分段上传完成时,这些分块对象将直接用作 Swift 静态大对象的段。
- class swift.common.middleware.s3api.controllers.multi_upload.PartController(app, conf, logger, **kwargs)¶
Bases:
Controller处理以下 API
上传分块
上传分块 - 复制
这些 API 在 S3 服务器日志中被记录为 PART 操作。
- PUT(req)¶
处理上传分块和上传分块复制。
- class swift.common.middleware.s3api.controllers.multi_upload.UploadController(app, conf, logger, **kwargs)¶
Bases:
Controller处理以下 API
列出分块
中止分段上传
完成分段上传
这些 API 在 S3 服务器日志中被记录为 UPLOAD 操作。
- DELETE(req)¶
处理中止分段上传。
- GET(req)¶
处理列出分块。
- POST(req)¶
处理完成分段上传。
- class swift.common.middleware.s3api.controllers.multi_upload.UploadsController(app, conf, logger, **kwargs)¶
Bases:
Controller处理以下 API
列出分段上传
初始化分段上传
这些 API 在 S3 服务器日志中被记录为 UPLOADS 操作。
- GET(req)¶
处理列出分段上传
- POST(req)¶
处理初始化分段上传。
- class swift.common.middleware.s3api.controllers.multi_delete.MultiObjectDeleteController(app, conf, logger, **kwargs)¶
Bases:
Controller处理 Delete Multiple Objects,在 S3 服务器日志中被记录为 MULTI_OBJECT_DELETE 操作。
- POST(req)¶
处理 Delete Multiple Objects。
- class swift.common.middleware.s3api.controllers.versioning.VersioningController(app, conf, logger, **kwargs)¶
Bases:
Controller处理以下 API
GET Bucket versioning
PUT Bucket versioning
这些 API 在 S3 服务器日志中被记录为 VERSIONING 操作。
- GET(req)¶
处理 GET Bucket versioning。
- PUT(req)¶
处理 PUT Bucket versioning。
- class swift.common.middleware.s3api.controllers.location.LocationController(app, conf, logger, **kwargs)¶
Bases:
Controller处理 GET Bucket location,在 S3 服务器日志中被记录为 LOCATION 操作。
- GET(req)¶
处理 GET Bucket location。
- class swift.common.middleware.s3api.controllers.logging.LoggingStatusController(app, conf, logger, **kwargs)¶
Bases:
Controller处理以下 API
GET Bucket logging
PUT Bucket logging
这些 API 在 S3 服务器日志中被记录为 LOGGING_STATUS 操作。
- GET(req)¶
处理 GET Bucket logging。
- PUT(req)¶
处理 PUT Bucket logging。
后端限速¶
- class swift.common.middleware.backend_ratelimit.BackendRateLimitMiddleware(app, filter_conf, logger=None)¶
基类:
object后端限速中间件。
对后端存储节点设备进行请求限速。每个(设备、请求方法)组合都独立限速。所有具有 'GET'、'HEAD'、'PUT'、'POST'、'DELETE'、'UPDATE' 或 'REPLICATE' 方法的请求都会按设备进行限速,同时受特定方法的速率限制和总设备速率限制。
如果请求会导致方法和/或设备的速率限制被超出,则返回状态码为 529 的响应。
批量操作(删除和归档自动提取)¶
执行许多操作的中间件,但只在单个请求中。
提取归档¶
将 tar 文件解压到 Swift 账户。请求必须是 PUT 请求,并带有查询参数 ?extract-archive=format,指定归档文件的格式。接受的格式有 tar、tar.gz 和 tar.bz2。
对于以下 URL 的 PUT 请求
/v1/AUTH_Account/$UPLOAD_PATH?extract-archive=tar.gz
UPLOAD_PATH 是文件将被展开到的位置。UPLOAD_PATH 可以是容器、容器内的伪目录或空字符串。归档中文件的目标将按如下方式构建
/v1/AUTH_Account/$UPLOAD_PATH/$FILE_PATH
其中 FILE_PATH 是 tar 文件列表中的文件名。
如果 UPLOAD_PATH 为空字符串,将自动创建容器,并且不应映射到任何容器的文件(基础目录中的文件)将被忽略。
仅上传常规文件。空目录、符号链接等将不会被上传。
内容类型¶
如果在 extract-archive 调用中设置了 content-type 头部,Swift 将为所有底层文件分配该 content-type。bulk 中间件将提取归档文件,并使用原始请求的相同头部(例如 auth-tokens、content-Type 等)通过 PUT 操作发送内部文件。请注意,任何跟在 bulk 中间件之后的中间件调用都不知道这是一个批量请求,还是用户发送的独立请求。
为了让 Swift 根据文件扩展名检测内容类型,不应设置 extract-archive 调用中的 content-type。或者,可以使用此头部显式指示 Swift 检测内容类型
X-Detect-Content-Type: true
例如
curl -X PUT http://127.0.0.1/v1/AUTH_acc/cont/$?extract-archive=tar
-T backup.tar
-H "Content-Type: application/x-tar"
-H "X-Auth-Token: xxx"
-H "X-Detect-Content-Type: true"
分配元数据¶
tar 文件格式 (1) 允许将 UTF-8 键/值对与归档中的每个文件关联。如果文件有扩展属性,则 tar 会将它们存储为键/值对。bulk 中间件可以读取这些扩展属性并将其转换为 Swift 对象元数据。以“user.meta”开头的属性会转换为对象元数据,“user.mime_type”会转换为 Content-Type。
例如
setfattr -n user.mime_type -v "application/python-setup" setup.py
setfattr -n user.meta.lunch -v "burger and fries" setup.py
setfattr -n user.meta.dinner -v "baked ziti" setup.py
setfattr -n user.stuff -v "whee" setup.py
将被转换为头部
Content-Type: application/python-setup
X-Object-Meta-Lunch: burger and fries
X-Object-Meta-Dinner: baked ziti
bulk 中间件将处理 GNU 和 BSD tar (2) 存储的 xattrs。仅处理 xattrs user.mime_type 和 user.meta.*。其他属性将被忽略。
除了扩展属性之外,对象元数据和请求中设置的 x-delete-at/x-delete-after 头部也会被分配给提取的对象。
说明
(1) POSIX 1003.1-2001 (pax) 格式。GNU tar 1.27.1 或更高版本的默认格式。
(2) 即使是 pax 格式的 tarball,不同的编码器存储 xattrs 的方式也略有不同;例如,GNU tar 将 xattr “user.userattribute”存储为 pax 头部 “SCHILY.xattr.user.userattribute”,而 BSD tar(使用 libarchive)将其存储为 “LIBARCHIVE.xattr.user.userattribute”。
响应¶
来自批量操作的功能的响应与其他 Swift 响应不同。这是因为客户端发送的简短请求体可能导致代理服务器上的许多操作,并且需要采取预防措施以防止请求因缺乏活动而超时。为此,客户端将始终收到 200 OK 响应,无论调用的实际成功与否。必须解析响应体才能确定操作的实际成功。此外,客户端可能会收到零个或多个空格字符前缀,然后才是实际响应体,而代理服务器正在完成请求。
响应体的格式默认为 text/plain,但可以根据 Accept 头部是 json 还是 xml。可接受的格式为 text/plain、application/json、application/xml 和 text/xml。示例响应如下
{"Response Status": "201 Created",
"Response Body": "",
"Errors": [],
"Number Files Created": 10}
如果所有有效文件都已成功上传,则响应状态为 201 Created。如果任何文件创建失败,响应代码将对应于子请求的错误。可能的代码是 400、401、502(服务器错误)等。在这两种情况下,响应体都将指定成功上传的文件数量以及失败的文件列表。
tar 中的每个文件(成为子请求)都会创建代理日志。子请求的代理日志将有一个 swift.source 设置为“EA”,日志的内容长度将反映解压后文件的大小。如果使用双重代理日志记录,最左侧的记录器将没有 swift.source 设置,内容长度将反映发送到代理的有效负载大小(tar.gz 的未解压大小)。
批量删除¶
将通过单个请求从其账户中删除多个对象或容器。响应 POST 请求,并带有 ?bulk-delete 查询参数。请求 URL 是您的存储 URL。Content-Type 应设置为 text/plain。POST 请求的请求体将是 url 编码的待删除对象的换行符分隔列表。您每个请求最多可以删除 10,000 个(可配置)对象。POST 请求体中指定的对象必须是 URL 编码的,并且格式为
/container_name/obj_name
或者对于一个容器(在删除时必须为空)
/container_name
响应与提取归档类似,即每个响应都是 200 OK,您必须解析响应体以获取实际结果。示例响应为
{"Number Not Found": 0,
"Response Status": "200 OK",
"Response Body": "",
"Errors": [],
"Number Deleted": 6}
如果所有项目都已成功删除(或不存在),则响应状态将为 200 OK。如果任何项目删除失败,响应代码将对应于子请求的错误。可能的代码是 400、401、502(服务器错误)等。在所有情况下,响应体都将指定成功删除的项目数量、未找到的项目数量以及失败的项目列表。返回体将按照请求的 Accept 头部指定的格式进行格式化。可接受的格式为 text/plain、application/json、application/xml 和 text/xml。
每个删除的对象或容器(成为子请求)都会创建代理日志。子请求的代理日志将有一个 swift.source 设置为“BD”,内容长度为 0。如果使用双重代理日志记录,最左侧的记录器将没有 swift.source 设置,内容长度将反映发送到代理的有效负载大小(要删除的对象/容器列表)。
- exception swift.common.middleware.bulk.CreateContainerError(msg, status_int, status)¶
基础:
Exception
捕获错误¶
- exception swift.common.middleware.catch_errors.BadResponseLength¶
基础:
Exception
- class swift.common.middleware.catch_errors.ByteEnforcer(inner_iter, nbytes)¶
基类:
object强制 inner_iter 在耗尽前恰好产生 <nbytes> 字节。
如果 inner_iter 未能做到这一点,则会引发 BadResponseLength。
- 参数:
inner_iter – bytestrings 的可迭代对象
nbytes – 预期的字节数
注意:由于我们要求 nbytes 参数并要求 inner_iter 产生恰好那么多字节,因此我们可以支持 __len__ 接口,以防有人期望非分块的 resp iterables 支持它(例如,eventlet 的 wsgi.server)。
- class swift.common.middleware.catch_errors.CatchErrorMiddleware(app, conf)¶
基类:
object提供高级错误处理并确保为每个请求设置事务 ID 的中间件。
- class swift.common.middleware.catch_errors.CatchErrorsContext(app, logger, trans_id_suffix='')¶
Bases:
WSGIContext
CNAME 查找¶
CNAME 查找中间件
通过在 DNS 中查找给定域的 CNAME 记录,将未知域转换为以配置的 storage_domain 结尾的中间件。
此中间件将继续跟踪 CNAME 链,直到找到以配置的存储域结尾的记录,或者达到配置的最大查找深度。如果找到匹配项,则会重写环境的 Host 头部,并将请求传递到 WSGI 链的其余部分。
- class swift.common.middleware.cname_lookup.CNAMELookupMiddleware(app, conf)¶
基类:
objectCNAME 查找中间件
有关完整描述,请参见上文。
- 参数:
app – paste.deploy 链中的下一个 WSGI 过滤器或应用。
conf – 中间件的配置字典。
- swift.common.middleware.cname_lookup.lookup_cname(domain, resolver)¶
给定一个域,返回其 DNS CNAME 映射和 DNS ttl。
- 参数:
domain – 要查询的域
resolver – 用于执行 DNS 查询的 dns.resolver.Resolver() 实例
- 返回值:
(ttl, result)
容器配额¶
container_quotas 中间件实现了可以由有能力设置容器元数据的用户(最可能是账户管理员)施加在 Swift 容器上的简单配额。这对于限制委派给非管理员用户、暴露给 formpost 上传的容器范围,或者仅仅作为自我施加的健全性检查非常有用。
任何超出这些配额的对象 PUT 操作都会返回一个 413 响应(请求实体过大),并带有描述性主体。
配额受几点限制:最终一致性、缓存的 container_info 的及时性(默认 60 秒 TTL),并且无法拒绝超出配额的分块传输上传(但一旦超出配额,新的分块传输将被拒绝)。
配额通过向容器添加 meta 值来设置,并在设置时进行验证
元数据 |
使用 |
|---|---|
X-Container-Meta-Quota-Bytes |
容器的最大大小,以字节为单位。 |
X-Container-Meta-Quota-Count |
容器的最大对象计数。 |
container_quotas 中间件应添加到 /etc/swift/proxy-server.conf 文件中的管道中,紧随任何认证中间件之后。例如
[pipeline:main]
pipeline = catch_errors cache tempauth container_quotas proxy-server
[filter:container_quotas]
use = egg:swift#container_quotas
容器同步中间件¶
- class swift.common.middleware.container_sync.ContainerSync(app, conf, logger=None)¶
基类:
objectWSGI 中间件,使用 container-sync-realms.conf 风格的容器同步来验证传入的容器同步请求。
跨域策略¶
- class swift.common.middleware.crossdomain.CrossDomainMiddleware(app, conf, *args, **kwargs)¶
基类:
object用于响应跨域策略信息请求的跨域中间件。
如果路径是
/crossdomain.xml,则会响应一个 xml 跨域策略文档。这允许托管在其他地方的网页使用 Flash、Java 和 Silverlight 等客户端技术与 Swift API 进行交互。要启用此中间件,请在 proxy-server.conf 文件中的管道中添加它。应在任何认证(例如 tempauth 或 keystone)中间件之前添加。在此示例中,省略号(...)表示您可能选择使用的其他中间件
[pipeline:main] pipeline = ... crossdomain ... authtoken ... proxy-server
并添加一个过滤器部分,例如
[filter:crossdomain] use = egg:swift#crossdomain cross_domain_policy = <allow-access-from domain="*.example.com" /> <allow-access-from domain="www.example.com" secure="false" />
对于续行,在续行文本前加上一些空格。请确保添加完全空白的行来终止
cross_domain_policy值。cross_domain_policy名称/值是可选的。如果省略,策略将默认为您指定了cross_domain_policy = <allow-access-from domain="*" secure="false" />
注意
默认策略非常宽松;这对于大多数公共云部署是合适的,但可能不适用于所有部署。另请参见:CWE-942
- GET(req)¶
返回带有跨域策略信息的 200 响应
可发现性¶
Swift 默认会向客户端提供有关安装的详细信息的接口。除非禁用(即在 Proxy Server Configuration 中设置为 expose_info=false),否则对 /info 的 GET 请求将以 JSON 格式返回配置数据。示例响应
{"swift": {"version": "1.11.0"}, "staticweb": {}, "tempurl": {}}
这将向客户端表明 Swift 版本 1.11.0 正在运行,并且此安装中可用 staticweb 和 tempurl。
通过 /info 可能有仅限管理员的信息可用。要检索它,必须使用 HMAC 签名请求,类似于 TempURL。签名可以如下生成
swift tempurl GET 3600 /info secret 2>/dev/null | sed s/temp_url/swiftinfo/g
域重映射¶
域重映射中间件
将域的容器和账户部分转换为代理服务器理解的路径参数的中间件。
仅当请求 URL 的主机域与配置的域列表匹配时才执行转换。此列表可以通过选项 storage_domain 进行配置,默认值为单个域 example.com。
如果尚未存在,则将可配置的 path_root(默认为 v1)添加到转换后路径的开头。
例如,使用默认配置
container.AUTH-account.example.com/object
container.AUTH-account.example.com/v1/object
都将被翻译成
container.AUTH-account.example.com/v1/AUTH_account/container/object
和
AUTH-account.example.com/container/object
AUTH-account.example.com/v1/container/object
都将被翻译成
AUTH-account.example.com/v1/AUTH_account/container/object
此外,仅当转换后路径中的账户名称以与 reseller_prefixes 选项配置的列表匹配的经销商前缀开头时,或者当未找到匹配项但已配置 default_reseller_prefix 时,才会执行转换。
reseller_prefixes 列表默认包含单个前缀 AUTH。default_reseller_prefix 默认未配置。
浏览器可以将主机头部转换为小写,因此中间件会检查账户名称上的经销商前缀是否大小写正确。这是通过将 reseller_prefixes 配置选项中的项与找到的前缀进行比较来完成的。如果它们除大小写外匹配,则使用 reseller_prefixes 中的项而不是找到的经销商前缀。中间件还会用下划线(‘_’)替换账户名称中的任何连字符(‘-’)。
例如,使用默认配置
auth-account.example.com/container/object
AUTH-account.example.com/container/object
auth_account.example.com/container/object
AUTH_account.example.com/container/object
都将被翻译成
<unchanged>.example.com/v1/AUTH_account/container/object
当在 reseller_prefixes 中找不到匹配项时,将使用 default_reseller_prefix 配置选项。当未配置 default_reseller_prefix 时,此中间件将忽略账户前缀不在 reseller_prefixes 列表中的任何请求。
例如,使用 default_reseller_prefix = AUTH
account.example.com/container/object
将被翻译成
account.example.com/v1/AUTH_account/container/object
请注意,此中间件要求容器名称和账户名称(如上所述除外)必须是 DNS 兼容的。这意味着系统中创建的账户名称和用户创建的容器名称不能超过 63 个字符,也不能包含 UTF-8 字符。这些是 Swift 所需的额外限制,并且不会被显式检查。简单来说,此中间件将尽最大努力尝试从域名元素派生账户和容器名称,并将这些派生值放入 URL 路径(保持 Host 头部不变)。
另请注意,不建议使用 Container to Container Synchronization 结合重映射的域名。使用 Container to Container Synchronization 时,应使用真实的存储端点作为同步目标。
- class swift.common.middleware.domain_remap.DomainRemapMiddleware(app, conf)¶
基类:
object域重映射中间件
有关完整描述,请参见上文。
- 参数:
app – paste.deploy 链中的下一个 WSGI 过滤器或应用。
conf – 中间件的配置字典。
动态大对象¶
DLO 支持围绕用户指定的过滤器,该过滤器匹配分块并将它们按对象列表顺序连接起来。有关更多详细信息,请参阅 DLO 文档 Dynamic Large Objects。
加密¶
加密中间件应与 Keymaster 中间件一起部署。
实现对象加密中间件,该中间件由 Decrypter 实例和 Encrypter 实例组合而成。
- swift.common.middleware.crypto.filter_factory(global_conf, **local_conf)¶
提供一个工厂函数来加载加密中间件。
- class swift.common.middleware.crypto.encrypter.EncInputWrapper(crypto, keys, req, logger)¶
Bases:
InputProxy用于替换 wsgi.input 的类文件对象。
- chunk_update(chunk, eof, *args, **kwargs)¶
每次从包装的输入读取一个字节块时调用。
- 参数:
chunk – 已读取的字节块。
eof – 如果没有更多字节可从包装的输入中读取,则为
True,否则为False。如果调用了read(),当chunk的大**小小于请求的大小或请求大小为 None 时,则此值为True。如果调用了readline,当读取了一个不完整的行(即不以b'\n'结尾)且其大**小小于请求的大小或请求大小为 None 时,则此值为True。如果使用请求的大小,该大小精确匹配包装输入中剩余的字节数来调用read()或readline(),则eof将为False。后续使用非零size调用read()或readline()将导致eof为True。或者,可以通过将bytes_received与输入的预期大**小进行比较来推断输入的结束。
- class swift.common.middleware.crypto.encrypter.Encrypter(app, conf)¶
基类:
object用于加密数据和用户元数据的中间件。
默认情况下,所有 PUT 或 POST 的对象数据和/或元数据都将被加密。可以通过将 `disable_encryption` 选项设置为 True 来禁用新数据和/或元数据的加密。但是,此中间件应保留在管道中,以便读取现有加密数据。
- class swift.common.middleware.crypto.encrypter.EncrypterObjContext(encrypter, logger)¶
Bases:
CryptoWSGIContext- encrypt_user_metadata(req, keys)¶
加密用户元数据头值。将每个 x-object-meta-\<key> 用户元数据头替换为相应的 x-object-transient-sysmeta-crypto-meta-\<key> 头,该头附加了解密所需的加密元数据到加密值。
- 参数:
req – 一个 swob 请求
keys – 一个加密密钥字典
- handle_post(req, start_response)¶
使用新的 iv 和当前加密来加密新对象的头。请注意,对象可能带有加密的头,而主体可能保持未加密。
- swift.common.middleware.crypto.encrypter.encrypt_header_val(crypto, value, key)¶
使用提供的密钥加密头值。
- 参数:
crypto – 一个 Crypto 实例
value – 要加密的值
key – 要使用的加密密钥
- 返回值:
一个元组 (加密值, crypto_meta),其中 crypto_meta 是一个字典,其形式由 `get_crypto_meta()` 返回。
- 引发:
ValueError – 如果 value 为空
- class swift.common.middleware.crypto.decrypter.BaseDecrypterContext(crypto_app, server_type, logger)¶
Bases:
CryptoWSGIContext- decrypt_value(value, key, crypto_meta, decoder)¶
使用提供的 crypto_meta 对 base64 编码的值进行解码和解密。
- 参数:
value – 要解密的 base64 编码值
key – 要使用的加密密钥
crypto_meta – 一个 crypto-meta 字典,其形式由 `get_crypto_meta()` 返回。
decoder – 将解密后的字节转换为有用数据的函数
- 返回值:
解密后的值
- decrypt_value_with_meta(value, key, required, decoder)¶
如果可以从值本身提取 crypto meta,则对值进行 base64 解码和解密,否则返回未修改的值。
值应该是不包含 ‘;’ 字符的字符串,或者应该具有以下形式:
<base64-encoded ciphertext>;swift_meta=<crypto meta>
- 参数:
value – 要解密的值
key – 要使用的加密密钥
required – 如果为 True,则必须解密该值,如果由于缺少 crypto meta 而无法解密该头,则会引发 EncryptionException。
decoder – 将解密后的字节转换为有用数据的函数
- 返回值:
如果找到 crypto meta,则返回解密后的值,否则返回未修改的值。
- 引发:
EncryptionException – 如果在解析 crypto meta 时发生错误,或者如果要求解密头值但未找到 crypto meta。
- get_crypto_meta(header_name, check=True)¶
从头中提取 crypto_meta 字典。
- 参数:
header_name – 可能包含 crypto_meta 的头名称。
check – 如果为 True,则验证 crypto meta。
- 返回值:
一个包含 crypto_meta 项的字典。
- 引发:
EncryptionException – 如果在解析 crypto meta 时发生错误。
- get_decryption_keys(req, crypto_meta=None)¶
确定响应是否应被解密,如果是,则获取密钥。
- 参数:
req – 一个请求对象。
crypto_meta – 一个 crypto 元数据字典。
- 返回值:
一个解密密钥字典。
- get_unwrapped_key(crypto_meta, wrapping_key)¶
从 crypto-meta 获取一个包装的密钥,并使用提供的包装密钥进行解包。
- 参数:
crypto_meta – 一个 crypto-meta 字典。
wrapping_key – 用于解密包装密钥的密钥。
- 返回值:
一个未包装的密钥。
- 引发:
HTTPInternalServerError – 如果 crypto-meta 没有包装的密钥或未包装的密钥无效。
- class swift.common.middleware.crypto.decrypter.Decrypter(app, conf)¶
基类:
object用于解密数据和用户元数据的中间件。
- class swift.common.middleware.crypto.decrypter.DecrypterContContext(decrypter, logger)¶
Bases:
BaseDecrypterContext- process_json_resp(req, resp_iter)¶
解析 json 主体列表并解密加密的条目。使用新的主体长度更新 Content-Length 头并返回一个主体迭代器。
- class swift.common.middleware.crypto.decrypter.DecrypterObjContext(decrypter, logger)¶
Bases:
BaseDecrypterContext- decrypt_resp_headers(put_keys, post_keys, update_cors_exposed)¶
查找加密的头并替换为解密后的版本。
- 参数:
put_keys – 用于对象 PUT 的解密密钥字典。
post_keys – 用于对象 POST 的解密密钥字典。
- 返回值:
一个包含解密后值的头的列表。
- 引发:
HTTPInternalServerError – 如果在解密头时发生任何错误。
- multipart_response_iter(resp, boundary, body_key, crypto_meta)¶
解密 multipart mime 文档响应体。
- 参数:
resp – 应用程序响应。
boundary – multipart 分隔符字符串。
body_key – 响应体的解密密钥。
crypto_meta – 响应体的 crypto_meta。
- 返回值:
解密后的响应体生成器。
- response_iter(resp, body_key, crypto_meta, offset)¶
解密响应体。
- 参数:
resp – 应用程序响应。
body_key – 响应体的解密密钥。
crypto_meta – 响应体的 crypto_meta。
offset – 响应体开始处的对象内容偏移量。
- 返回值:
解密后的响应体生成器。
Etag Quoter¶
此中间件修复响应的 Etag 头,使其符合 RFC 标准。 `RFC 7232` 指定 Etag 头的值必须是双引号括起来的。
它必须放在管道的开头,紧跟在 cache 之后。
[pipeline:main]
pipeline = ... cache etag-quoter ...
[filter:etag-quoter]
use = egg:swift#etag_quoter
在帐户级别设置 `X-Account-Rfc-Compliant-Etags: true` 以使所有对象响应中的 Etags 都被双引号括起来,例如 `"d41d8cd98f00b204e9800998ecf8427e"`。或者,您可以通过在帐户上设置 `X-Container-Rfc-Compliant-Etags: true` 来仅修复单个容器中的 Etags。这对于 Swift 与某些 CDN 正常工作可能很有用。
以上任一选项也可以明确 *禁用*,因此您可以像上面那样在整个帐户中启用带引号的 Etags,但将其关闭给单个容器,方法是设置 `X-Container-Rfc-Compliant-Etags: false`。这可能很有用,因为某些应用程序期望 Etags 是裸 MD5。
FormPost¶
FormPost 中间件
将浏览器表单 post 转换为常规的 Swift 对象 PUT。
表单的格式为:
<form action="<swift-url>" method="POST"
enctype="multipart/form-data">
<input type="hidden" name="redirect" value="<redirect-url>" />
<input type="hidden" name="max_file_size" value="<bytes>" />
<input type="hidden" name="max_file_count" value="<count>" />
<input type="hidden" name="expires" value="<unix-timestamp>" />
<input type="hidden" name="signature" value="<hmac>" />
<input type="file" name="file1" /><br />
<input type="submit" />
</form>
可选地,如果您希望上传的文件是临时的,可以通过添加 `x-delete-at` 或 `x-delete-after` 作为表单输入来设置它们。
<input type="hidden" name="x_delete_at" value="<unix-timestamp>" />
<input type="hidden" name="x_delete_after" value="<seconds>" />
如果您想指定文件的内容类型或内容编码,可以通过添加到表单输入中来设置 `content-encoding` 或 `content-type`。
<input type="hidden" name="content-type" value="text/html" />
<input type="hidden" name="content-encoding" value="gzip" />
上面的示例将这些参数应用于所有上传的文件。您还可以通过将参数添加到上传的每个部分来为每个文件设置内容类型和内容编码。
<swift-url> 是 Swift 目标的 URL,例如:
https://swift-cluster.example.com/v1/AUTH_account/container/object_prefix
上传的每个文件名都将附加到给定的 <swift-url>。因此,您可以直接上传到容器的根目录,URL 如下:
https://swift-cluster.example.com/v1/AUTH_account/container/
可选地,您可以包含一个对象前缀,以更好地分隔不同用户的上传,例如:
https://swift-cluster.example.com/v1/AUTH_account/container/object_prefix
注意,表单方法必须是 POST,enctype 必须设置为“multipart/form-data”。
redirect 属性是在上传完成后将浏览器重定向到的 URL。这是一个可选参数。如果您通过 XMLHttpRequest 上传表单,则不应包含 redirect。URL 将添加 status 和 message 查询参数,指示上传的 HTTP 状态码(2xx 表示成功)以及可能的错误消息(例如“max_file_size exceeded”)。
必须包含 max_file_size 属性,它表示单个文件上传的最大大小(以字节为单位)。
必须包含 max_file_count 属性,它表示表单可以上传的最大文件数。如果需要,请包含其他 `` 属性。
expires 属性是在此表单必须提交之前(否则将失效)的 Unix 时间戳。
signature 属性是表单的 HMAC 签名。以下是计算签名的示例代码:
import hmac
from hashlib import sha512
from time import time
path = '/v1/account/container/object_prefix'
redirect = 'https://srv.com/some-page' # set to '' if redirect not in form
max_file_size = 104857600
max_file_count = 10
expires = int(time() + 600)
key = 'mykey'
hmac_body = '%s\n%s\n%s\n%s\n%s' % (path, redirect,
max_file_size, max_file_count, expires)
signature = hmac.new(key, hmac_body, sha512).hexdigest()
密钥是帐户 (X-Account-Meta-Temp-URL-Key, X-Account-Meta-Temp-Url-Key-2) 或容器 (X-Container-Meta-Temp-URL-Key, X-Container-Meta-Temp-Url-Key-2) TempURL 密钥的值。
务必使用从 `/v1/` 开始的完整路径。请注意,`x_delete_at` 和 `x_delete_after` 不用于签名生成,因为它们都是可选属性。
命令行工具 `swift-form-signature` 可用于(主要是在测试时)计算 expires 和 signature。
另请注意,文件属性必须在其他属性之后,才能正确处理。如果属性在文件之后,则不会与子请求一起发送(服务器端无法在不将整个文件读入内存的情况下解析所有属性 - 为了服务许多请求,其中一些带有大文件,服务器上内存不足,因此将忽略文件之后的属性)。
- class swift.common.middleware.formpost.FormPost(app, conf, logger=None)¶
基类:
objectFormPost 中间件
有关完整描述,请参见上文。
为任何子请求创建的代理日志将具有 `swift.source` 设置为“FP”。
- 参数:
app – paste.deploy 链中的下一个 WSGI 过滤器或应用。
conf – 中间件的配置字典。
- app¶
paste.deploy 管道中的下一个 WSGI 应用程序/过滤器。
- conf¶
过滤器配置字典。
- swift.common.middleware.formpost.MAX_VALUE_LENGTH = 4096¶
任何属性值的最大大小。任何额外数据将被截断。
- swift.common.middleware.formpost.READ_CHUNK_SIZE = 4096¶
每次从表单读取数据的大小。
- swift.common.middleware.formpost.filter_factory(global_conf, **local_conf)¶
返回用于 paste.deploy 的 WSGI 过滤器。
GateKeeper¶
`gatekeeper` 中间件对可以包含在请求和响应中的头施加限制。请求头会被过滤以删除不应由客户端生成的头。同样,响应头会被过滤以删除不应传递给客户端的私有头。
`gatekeeper` 中间件必须始终存在于代理服务器 wsgi 管道中。它应该配置在 `/etc/swift/proxy-server.conf` 指定的管道的起始位置附近,紧跟在 `catch_errors` 之后,并在任何其他中间件之前。至关重要的是,它必须在所有使用系统元数据的中间件之前配置,以便它们能够正常工作。
如果 `gatekeeper` 中间件未在管道中配置,则代理服务器将在管道的起始位置附近自动插入它。
- swift.common.middleware.gatekeeper.outbound_exclusions = ['x-account-sysmeta-', 'x-container-sysmeta-', 'x-object-sysmeta-', 'x-object-transient-sysmeta-', 'x-backend']¶
一组 python 正则表达式,用于匹配出站响应头。匹配的头将被从响应中移除。
Healthcheck¶
- class swift.common.middleware.healthcheck.HealthCheckMiddleware(app, conf)¶
基类:
object用于监控的 Healthcheck 中间件。
如果路径是 /healthcheck,它将以“OK”作为响应体,返回 200。
如果可选配置参数 `disable_path` 被设置,并且在该路径上存在一个文件,它将以“DISABLED BY FILE”作为响应体,返回 503。
- DISABLED(req)¶
返回一个 503 响应,并在响应体中包含“DISABLED BY FILE”。
- GET(req)¶
返回一个 200 响应,并在响应体中包含“OK”。
Keymaster¶
Keymaster 中间件应与 `Encryption` 中间件结合部署。
- class swift.common.middleware.crypto.keymaster.BaseKeyMaster(app, conf)¶
基类:
object提供加密密钥的基类中间件。
这提供了一些基本的辅助功能,用于
从单独的配置路径加载,
根据路径推导密钥,以及
在请求环境中安装 `swift.callback.fetch_crypto_keys` 挂钩。
子类应定义 `log_route`、`keymaster_opts` 和 `keymaster_conf_section` 属性,并实现 `_get_root_secret` 函数。
- create_key(path, secret_id=None)¶
创建一个对于给定路径唯一的加密密钥。
- 参数:
path – 要加密的资源的 (WSGI 字符串) 路径。
secret_id – 应从中推导密钥的根密钥的 ID。
- 返回值:
一个加密密钥。
- 引发:
UnknownSecretIdError – 如果 secret_id 未被识别。
- class swift.common.middleware.crypto.keymaster.KeyMaster(app, conf)¶
Bases:
BaseKeyMaster提供加密密钥的中间件。
该中间件要求设置其加密根密钥。这是派生加密密钥的根密钥。在使用前必须将其设置为至少 256 位的值。所有加密数据的安全性都严重依赖于此密钥,因此应将其设置为高熵值。例如,可以使用密码学安全随机数生成器生成一个 32 字节(或更长)的值来获得合适的值。更改根密钥很可能会导致数据丢失。
- class swift.common.middleware.crypto.keymaster.KeyMasterContext(keymaster, account, container, obj, meta_version_to_write='2')¶
Bases:
WSGIContext简单的密钥派生方案如下:每个路径都与一个密钥关联,该密钥以确定性方式从路径本身派生,因此无需存储密钥。具体来说,任何路径的密钥都是根密钥和路径本身的 HMAC,使用 SHA256 哈希函数计算。
<path_key> = HMAC_SHA256(<root_secret>, <path>)
- fetch_crypto_keys(key_id=None, *args, **kwargs)¶
根据请求路径设置容器和对象密钥。
密钥从请求路径派生。结果字典中的 `id` 条目包括用于派生密钥的路径部分。其他 keymaster 实现可能使用不同的策略来生成密钥,并且可能包含不同类型的 `id`,因此调用者应将 `id` 视为不透明的 keymaster 特定数据。
- 参数:
key_id – 如果给定,则应包含在此方法返回的字典的 `id` 项中的项。
- 返回值:
一个包含“object”和“container”的加密密钥的字典,以及“id”和“all_ids”条目。“all_ids”条目是所有根密钥 ID 的密钥 ID 字典,包括用于生成返回密钥的那个。
KeystoneAuth¶
- class swift.common.middleware.keystoneauth.KeystoneAuth(app, conf)¶
基类:
objectSwift 中间件到 Keystone 授权系统。
在 Swift 的 `proxy-server.conf` 中,将此 keystoneauth 中间件和 authtoken 中间件添加到您的管道中。请确保 authtoken 中间件在 keystoneauth 中间件之前。
authtoken 中间件将负责验证用户,而 keystoneauth 将授权访问。
示例 proxy-server.conf 显示了一个使用 keystone 的示例管道。
authtoken 中间件随 keystonemiddleware 一起提供 - 它除了自身之外没有任何其他依赖项,因此您可以直接通过将文件复制到您的 python 路径中,或者通过安装 keystonemiddleware 来安装它。
如果需要支持未经验证的用户(例如匿名访问)或 formpost/staticweb/tempurl 中间件,则需要将 authtoken 配置为 `delay_auth_decision` 为 true。有关如何配置 authtoken 中间件的更多详细信息,请参阅 Keystone 文档。
在 proxy-server.conf 中,您需要将帐户自动创建设置为 true。
[app:proxy-server] account_autocreate = true
并添加一个 swift 授权过滤器部分,例如:
[filter:keystoneauth] use = egg:swift#keystoneauth operator_roles = admin, swiftoperator
能够授予 ACL / 创建容器权限的用户将是具有 `operator_roles` 设置中列出的角色的用户,该设置默认包括 admin 和 swiftoperator 角色。
keystoneauth 中间件通过添加前缀(默认情况下为 `AUTH_`)到租户/项目 ID 来将 Keystone 项目/租户映射到 Swift 中的帐户。例如,如果项目 ID 是 `1234`,则路径为 `/v1/AUTH_1234`。
如果您需要一个不同的 `reseller_prefix` 来混合不同的身份验证服务器,您可以在您的 keystoneauth 条目中像这样配置 `reseller_prefix` 选项:
reseller_prefix = NEWAUTH
不要忘记更新 Keystone 服务端点配置以在路径中使用 NEWAUTH。
同一个项目可以关联多个帐户。这是通过列出多个前缀来实现的,如下例所示:
reseller_prefix = AUTH, SERVICE
这意味着对于项目 ID ‘1234’,路径 ‘/v1/AUTH_1234’ 和 ‘/v1/SERVICE_1234’ 都与该项目相关联,并使用用户在该项目拥有的角色进行授权。此功能的核心用途是为每个帐户前缀提供不同的规则。以下参数可以带有相应的前缀:
operator_roles service_roles
为向后兼容起见,如果省略前缀指定了其中任何一个参数,则它适用于所有 `reseller_prefixes`。以下是一个使用两个前缀的示例:
reseller_prefix = AUTH, SERVICE # The next three lines have identical effects (since the first applies # to both prefixes). operator_roles = admin, swiftoperator AUTH_operator_roles = admin, swiftoperator SERVICE_operator_roles = admin, swiftoperator # The next line only applies to accounts with the SERVICE prefix SERVICE_operator_roles = admin, some_other_role
X-Service-Token 令牌通过包含 `service_roles` 配置选项来支持。当存在此选项时,要求 X-Service-Token 头提供来自具有 `service_roles` 中列出的角色的用户的令牌。以下是一个示例配置:
reseller_prefix = AUTH, SERVICE AUTH_operator_roles = admin, swiftoperator SERVICE_operator_roles = admin, swiftoperator SERVICE_service_roles = service
keystoneauth 中间件使用 `
: ` 的语法支持跨租户访问控制,以在容器访问控制列表 (ACL) 中指定被授权者。为了使请求被 ACL 授权,被授权者 ` ` 必须与请求 X-Auth-Token 所限定的租户的 UUID 匹配,并且被授权者 ` ` 必须与该令牌所认证的用户的 UUID 匹配。 请注意,在跨租户 ACL 中不再使用名称,因为随着 keystone 域的引入,名称不再是全局唯一的。
为向后兼容,当 keystoneauth 能够确定租户的域 ID 时,它将尝试确定租户的域 ID,并将其作为帐户元数据持久化。如果为租户创建帐户时使用了不受该租户限制的 `reselleradmin` 角色的令牌,keystoneauth 将无法确定租户的域 ID;keystoneauth 将假定该租户可能不在默认域中,因此不会匹配该帐户的 ACL 中的名称。
default_domain_id = default
此向后兼容行为可以通过将配置选项 `allow_names_in_acls` 设置为 false 来禁用。
allow_names_in_acls = false
为了启用此向后兼容性,keystoneauth 将尝试确定租户的域 ID,并在创建任何新帐户时持久化为帐户元数据。如果使用不受该租户限制的 `reselleradmin` 角色的令牌为租户创建帐户,keystoneauth 无法确定租户的域 ID;keystoneauth 将假定该租户可能不在默认域中,因此不会匹配该帐户的 ACL 中的名称。
默认情况下,WSGI 管道中较高的中间件可能会覆盖认证处理,这对于 tempurl 和 formpost 等中间件很有用。如果您知道您将不使用此类中间件,并且想要一些额外的安全性,则可以通过将 `allow_overrides` 选项设置为 `false` 来禁用此行为。
allow_overrides = false
- 参数:
app – 管道中的下一个 WSGI 应用。
conf – 配置值字典。
- authorize_anonymous(req)¶
授权匿名请求。
- 返回值:
如果授权被授予则为 None,否则为错误页面。
- denied_response(req)¶
拒绝 WSGI 响应。
返回一个标准的 WSGI 响应可调用对象,其状态码为 403 或 401,具体取决于 REMOTE_USER 是否已设置。
- swift.common.middleware.keystoneauth.filter_factory(global_conf, **local_conf)¶
返回一个 WSGI filter app,供 paste.deploy 使用。
List Endpoints¶
列出对象、帐户或容器的端点。
此中间件使得 Swift 能够与依赖于数据本地化信息以避免网络开销的软件(如 Hadoop)集成。
使用原始 API,回答以下形式的请求:
/endpoints/{account}/{container}/{object}
/endpoints/{account}/{container}
/endpoints/{account}
/endpoints/v1/{account}/{container}/{object}
/endpoints/v1/{account}/{container}
/endpoints/v1/{account}
带有一个 JSON 编码的端点列表,形式如下:
http://{server}:{port}/{dev}/{part}/{acc}/{cont}/{obj}
http://{server}:{port}/{dev}/{part}/{acc}/{cont}
http://{server}:{port}/{dev}/{part}/{acc}
相应地,例如:
http://10.1.1.1:6200/sda1/2/a/c2/o1
http://10.1.1.1:6200/sda1/2/a/c2
http://10.1.1.1:6200/sda1/2/a
使用 v2 API,回答以下形式的请求:
/endpoints/v2/{account}/{container}/{object}
/endpoints/v2/{account}/{container}
/endpoints/v2/{account}
带有一个 JSON 编码的字典,其中包含一个名为 ‘endpoints’ 的键,该键映射到具有上述形式的端点列表,以及一个名为 ‘headers’ 的键,该键映射到一个应随请求发送到端点的头字典,例如:
{ "endpoints": {"http://10.1.1.1:6210/sda1/2/a/c3/o1",
"http://10.1.1.1:6230/sda3/2/a/c3/o1",
"http://10.1.1.1:6240/sda4/2/a/c3/o1"},
"headers": {"X-Backend-Storage-Policy-Index": "1"}}
在此示例中,‘headers’ 字典表示到端点的请求应包含头 ‘X-Backend-Storage-Policy-Index: 1’,因为对象的容器正在使用存储策略索引 1。
`/endpoints/` 路径是可自定义的(`list_endpoints_path` 配置参数)。
旨在供集群内的第三方服务使用(因为端点仅在防火墙后面的集群内部有意义);可能用其他语言编写。
这就是为什么它以 REST API 的形式提供而不是仅仅作为 Python API:避免要求客户端用它们自己的语言编写 ring 解析器,以及避免将 ring 文件分发给客户端并保持其最新状态的必要性。
请注意,此调用未经验证,这意味着启用此中间件的代理不应暴露给不受信任的环境(任何人都可以使用此中间件查询本地化数据)。
- class swift.common.middleware.list_endpoints.ListEndpointsMiddleware(app, conf)¶
基类:
object列出对象、帐户或容器的端点。
有关完整描述,请参见上文。
使用配置参数 `swift_dir`(默认为 `/etc/swift`)。
- 参数:
app – paste.deploy 链中的下一个 WSGI 过滤器或应用。
conf – 中间件的配置字典。
- get_object_ring(policy_idx)¶
根据策略获取用于处理请求的环对象。
- Policy_idx:
swift.conf 中定义的策略索引。
- 返回值:
相应的环对象
Memcache¶
- class swift.common.middleware.memcache.MemcacheMiddleware(app, conf)¶
基类:
object管理 Swift 中缓存的缓存中间件。
Name Check (Forbidden Character Filter)¶
创建于 2012 年 2 月 27 日
一个过滤器,禁止包含已定义禁止字符或超出已定义长度的任何路径。
将其放在代理服务器管道的早期位置,在 `proxy-logging` 中间件(如果存在)的最左侧出现之后,以及在最终的 `proxy-logging` 中间件(如果存在)或 `proxy-serer` 应用本身之前,例如:
[pipeline:main]
pipeline = catch_errors healthcheck proxy-logging name_check cache ratelimit tempauth sos proxy-logging proxy-server
[filter:name_check]
use = egg:swift#name_check
forbidden_chars = '"`<>
maximum_length = 255
有 forbidden_chars (FORBIDDEN_CHARS) 和 maximum_length (MAX_LENGTH) 的默认设置。
如果路径无效,则过滤器返回 HTTPBadRequest。
@author: eamonn-otoole
Object Versioning¶
Swift 中的对象版本管理有 3 种不同的模式。有两种 `legacy modes` 具有相似的 API,但行为略有不同,此中间件引入了一种全新的 API 和实现的新模式。
在实现方面,此中间件严重依赖于静态链接的使用,以减少两种旧模式中涉及的后端数据移动量。它还引入了一个新的 API 来启用该功能以及与旧版本对象进行交互。
模式之间的兼容性¶
此新模式与两种旧模式不向后兼容或可互换。这意味着正在被两种旧模式版本化的现有容器无法启用新模式。新模式只能在新的容器或没有设置 `X-Versions-Location` 或 `X-History-Location` 头之一的容器上启用。尝试在新模式下启用具有任一头的容器将导致 `400 Bad Request` 响应。
在容器中启用对象版本管理¶
在此功能引入后,Swift 集群中的容器将处于以下 3 种可能状态之一:1. 对象版本管理从未启用,2. 对象版本管理已启用,或 3. 对象版本管理已禁用。一旦在容器上启用了版本管理,它将始终具有一个标志,说明它是启用还是禁用。
客户端通过执行具有 `X-Versions-Enabled: true` 头的 PUT 或 POST 请求来启用容器上的对象版本管理。首次启用版本管理时,中间件将创建一个隐藏容器来存储对象版本。此隐藏容器将继承与其父容器相同的存储策略。
要禁用,客户端发送一个带有 `X-Versions-Enabled: false` 头的 POST 请求。当版本管理被禁用时,旧版本保持不变。
要删除版本化的容器,必须先禁用版本管理并删除所有对象的*所有*版本,然后才能删除容器。届时,隐藏容器也将被删除。
对版本化容器的对象 CRUD 操作¶
当数据被 `PUT` 到版本化容器(具有版本管理标志已启用的容器)时,实际对象被写入一个隐藏容器,一个符号链接对象被写入父容器。每个对象都被分配一个版本 ID。此 ID 可以从 PUT 响应的 `X-Object-Version-Id` 头中检索。
注意
当在容器上禁用对象版本管理时,新数据将不再被版本化,但旧版本将保持不变。任何新的 `PUT` 数据都将导致一个版本 ID 为 `null` 的对象。版本管理 API 可用于在版本管理禁用时列出和操作旧版本。
如果版本管理被重新启用,并且在 `null` ID 对象上发生覆盖。该对象将被常规版本 ID 版本化。
对版本化对象的 `GET` 请求将返回对象的当前版本。`X-Object-Version-Id` 头也会在响应中返回。
对版本化对象的 `POST` 请求将正常更新当前对象元数据,但不会创建对象的新版本。换句话说,只有当对象内容发生变化时才会创建新版本。
在 `DELETE` 时,中间件将写入一个零字节的“删除标记”对象版本,该版本记录删除发生*时间*。符号链接对象也将从版本化容器中删除。该对象将不再出现在版本化容器的容器列表中,并且将来的请求将返回 `404 Not Found`。但是,以前的版本内容仍然可以恢复。
对象版本管理 API¶
客户端现在可以使用此新的版本管理 API 来操作对象的先前版本。
首先,要列出先前版本,请向版本化容器发出一个 `GET` 请求,并带上查询参数:
?versions
要列出具有大量对象版本的容器,客户端还可以使用 `version_marker` 参数与 `marker` 参数一起使用。虽然 `marker` 参数用于指定对象名称,但 `version_marker` 将用于指定版本 ID。
所有其他分页参数都可以与 `versions` 参数结合使用。
在容器列表中,删除标记可以通过内容类型 `application/x-deleted;swift_versions_deleted=1` 来识别。对象的最当前版本可以通过字段 `is_latest` 来识别。
要操作先前版本,客户端可以使用查询参数:
?version-id=<id>
其中 `
只能对先前版本执行 COPY、HEAD、GET 和 DELETE 操作。任何带有 `version-id` 参数的 PUT 或 POST 请求都将导致 `400 Bad Request` 响应。
对删除标记的 HEAD/GET 请求将导致 `404 Not Found` 响应。
在使用带有 `version-id` 参数的 DELETE 请求时,不会写入删除标记。对当前对象的带有 `version-id` 参数的 DELETE 请求将导致符号链接和后端数据都被删除。对任何其他版本的 DELETE 请求将只删除该版本,而不会更改指向当前版本的符号链接。
如何在 Swift 集群中启用对象版本管理¶
要在 Swift 集群中启用此新模式,必须将 `versioned_writes` 和 `symlink` 中间件添加到代理管道中,还必须将 `allow_object_versioning` 选项设置为 `True`。
- class swift.common.middleware.versioned_writes.object_versioning.AccountContext(wsgi_app, logger)¶
Bases:
ObjectVersioningContext
- class swift.common.middleware.versioned_writes.object_versioning.ByteCountingReader(file_like)¶
基类:
object计算从 file_like 读取的字节数,以便我们知道客户端刚刚 PUT 的对象有多大。
当客户端发送分块编码的主体时,这一点尤为重要,因为我们没有 Content-Length 头可用。
- class swift.common.middleware.versioned_writes.object_versioning.ContainerContext(wsgi_app, logger)¶
Bases:
ObjectVersioningContext- handle_delete(req, start_response)¶
处理删除用户容器的请求。
作为删除容器的一部分,此中间件还将删除保存对象版本的隐藏容器。
在删除用户容器之前,swift 必须检查该容器是否仍有旧的对象版本。只有在禁用版本管理并删除*所有*对象版本后,才能删除容器。
- handle_request(req, start_response)¶
处理容器资源的请求。
在 PUT、POST 上设置版本位置和启用的 sysmeta 标志。对于版本化容器的容器列表,更新对象的字节和 etag 以使用目标的字节和 etag,而不是使用符号链接信息。
- class swift.common.middleware.versioned_writes.object_versioning.ObjectContext(wsgi_app, logger)¶
Bases:
ObjectVersioningContext- handle_delete(req, versions_cont, api_version, account_name, container_name, object_name, is_enabled)¶
处理 DELETE 请求。
将对象当前版本复制到 versions_container,并在继续原始请求之前写入删除标记。
- 参数:
req – 原始请求。
versions_cont – 存储对象先前版本的容器。
api_version – api 版本。
account_name – 帐户名称。
object_name – 原始请求的对象名称。
- handle_post(req, versions_cont, account)¶
处理对版本化容器中对象的 POST 请求。
如果响应是 307(因为 POST 到达了符号链接),则遵循符号链接并将请求发送到版本化对象。
- 参数:
req – 原始请求。
versions_cont – 存储对象先前版本的容器。
account – 帐户名称。
- handle_put(req, versions_cont, api_version, account_name, object_name, is_enabled)¶
检查对象的当前版本是否是版本符号链接,如果不是,则是因为该对象是在版本管理未启用时添加到容器中的。现在版本管理已启用,我们需要将其复制到版本容器中。
此外,将客户端的新数据放入版本容器,并在版本化容器中添加静态符号链接。
- 参数:
req – 原始请求。
versions_cont – 存储对象先前版本的容器。
api_version – api 版本。
account_name – 帐户名称。
object_name – 原始请求的对象名称。
- handle_put_version(req, versions_cont, api_version, account_name, container, object_name, is_enabled, version)¶
处理 PUT?version-id 请求,并创建/更新 is_latest 链接以指向特定版本。期望一个有效的“version”id。
- handle_versioned_request(req, versions_cont, api_version, account, container, obj, is_enabled, version)¶
处理对象资源的“version-id”请求。当请求包含 `version-id=<id>` 参数时,请求将作用于该对象的实际版本。版本感知操作要求容器是版本化的,但不需要版本管理当前已启用。即使版本管理当前已暂停,用户也应该能够操作对象的旧版本。
不允许 PUT 和 POST 请求,因为这会覆盖版本化对象的内容。
- 参数:
req – 原始请求。
versions_cont – 包含请求对象的版本的容器。
api_version – 应为 v1,除非 swift 提升 api 版本。
account – 帐户名称字符串
container – 容器名称字符串
object – 对象名称字符串。
is_enabled – 版本管理当前是否已启用。
version – 要操作的对象版本。
- class swift.common.middleware.versioned_writes.object_versioning.ObjectVersioningContext(wsgi_app, logger)¶
Bases:
WSGIContext
Proxy Logging¶
Swift 代理的日志记录中间件。
这既是默认的日志记录实现,也是如何插入自己的日志记录格式/方法的示例。
下面实现的日志格式如下:
client_ip remote_addr end_time.datetime method path protocol
status_int referer user_agent auth_token bytes_recvd bytes_sent
client_etag transaction_id headers request_time source log_info
start_time end_time policy_index
这些值是空格分隔的,并且每个值都经过 url 编码,以便可以使用简单的 `.split()` 分隔它们。
`remote_addr` 是 REMOTE_ADDR 环境变量的内容,而 `client_ip` 是 swift 对最终用户 IP 的最佳猜测,它从 X-Forwarded-For 头、X-Cluster-Ip 头或 REMOTE_ADDR 环境变量中提取。
`status_int` 是传递给此中间件的 start_response 函数的 `status` 字符串的整数部分,除非 WSGI 环境中有一个键为 `swift.proxy_logging_status` 的项,在这种情况下,该项的值被使用。其他中间件可能会设置 `swift.proxy_logging_status` 来覆盖 `status_int` 的日志记录。在这两种情况下,如果在此中间件处理请求时检测到客户端断开连接,则记录的 `status_int` 值强制为 499;如果处理请求时捕获到异常,则强制为 500。
`source`(WSGI 环境中的 `swift.source`)指示生成请求的代码,例如大多数中间件。(有关更多详细信息,请参见下文。)
`log_info`(WSGI 环境中的 `swift.log_info`)用于提供可能有用的附加信息,例如任何 `x-delete-at` 值或其他“后台”活动,这些活动可能无法从纯日志信息中检测到。希望添加附加日志信息的代码应使用类似 `env.setdefault('swift.log_info', []).append(your_info)` 的代码,以免干扰他人的日志信息。
缺失的值(例如,由于缺少头)或零通常表示为单个连字符(‘-‘)。
注意
消息格式可以使用 `log_msg_template` 选项进行配置,允许添加、删除、重新排序甚至匿名化字段。有关更多信息,请参阅 `https://docs.openstack.org/swift/2025.2/logs.html`。
当安装了可以返回不遵循标准管道到代理服务器的自定义响应的中间件时,可以在代理服务器的管道中使用两次 proxy-logging。
例如,使用 staticweb 时,中间件可能会拦截对 `/v1/AUTH_acc/cont/` 的请求,发出一个到代理的子请求以检索 `/v1/AUTH_acc/cont/index.html`,并有效地使用第二个请求的正文响应客户端的原始请求。在这种情况下,子请求将由最右侧的中间件(设置了 `swift.source`)记录,而传出的请求(正文被覆盖)将由最左侧的中间件记录。
遵循正常管道的请求(在整个过程中使用相同的 wsgi 环境)不会被重复记录,因为在记录时会检查/设置一个环境变量(swift.proxy_access_log_made)。
所有进行子请求的中间件都应在需要时负责设置 swift.source。对于重复的代理日志,任何 swift 代理日志的消费者/处理器都应该查看 swift.source 字段,即最右边的日志值,以决定这是否是一个中间件子请求。计算带宽使用量的日志处理器将只希望汇总没有 swift.source 的日志。
- class swift.common.middleware.proxy_logging.ProxyLoggingMiddleware(app, conf, logger=None)¶
基类:
object以 Swift 代理日志格式记录 Swift 代理请求的中间件。
- get_access_user_id(req)¶
从请求环境获取访问用户 ID。
- 参数:
req – 请求的 swob.Request 对象
- 返回值:
记录用的用户 ID(如果可用),否则为 None
- log_request(req, status_int, bytes_received, bytes_sent, start_time, end_time, resp_headers=None, ttfb=0, wire_status_int=None)¶
记录一个请求。
- 参数:
req – 请求的 swob.Request 对象
status_int – 响应状态的整数代码
bytes_received – 从请求体成功读取的字节数
bytes_sent – 传输给 WSGI 服务器的字节数
start_time – 请求开始的时间戳
end_time – 请求完成的时间戳
resp_headers – 响应头字典
ttfb – 到第一个字节的时间
wire_status_int – 网络传输状态整数
Ratelimit¶
- exception swift.common.middleware.ratelimit.MaxSleepTimeHitError¶
基础:
Exception
- class swift.common.middleware.ratelimit.RateLimitMiddleware(app, conf, logger=None)¶
基类:
object速率限制中间件
对账户和容器级别的请求进行速率限制。限制是可配置的。
- get_ratelimitable_key_tuples(req, account_name, container_name=None, obj_name=None, global_ratelimit=None)¶
返回用于 memcache 的键(用于速率限制的键)和速率限制元组列表。键应按顺序检查。
- 参数:
req – swob 请求
account_name – 来自路径的账户名
container_name – 来自路径的容器名
obj_name – 来自路径的对象名
global_ratelimit – 此账户对所有写入操作都有限制
- handle_ratelimit(req, account_name, container_name, obj_name)¶
执行速率限制和账户白名单/黑名单。必要时进行休眠。如果 self.memcache_client 未设置,则立即返回 None。
- 参数:
account_name – 来自路径的账户名
container_name – 来自路径的容器名
obj_name – 来自路径的对象名
- swift.common.middleware.ratelimit.filter_factory(global_conf, **local_conf)¶
paste.deploy 应用工厂,用于创建 WSGI 代理应用。
- swift.common.middleware.ratelimit.get_maxrate(ratelimits, size)¶
返回给定大小每秒允许的请求数。
- swift.common.middleware.ratelimit.interpret_conf_limits(conf, name_prefix, info=None)¶
解析速率限制的通用参数,查找与提供的 name_prefix 匹配的配置项,并返回供内部使用和供 /info 注册的列表。
- 参数:
conf – 要解析的 conf 字典
name_prefix – 要查找的配置参数的前缀
info – 设置为返回 /info 注册的额外内容
Read Only¶
- class swift.common.middleware.read_only.ReadOnlyMiddleware(app, conf, logger=None)¶
基类:
object使整个集群或单个账户只读的中间件。
- account_read_only(req, account)¶
检查一个账户是否应被设为只读。
这同时考虑了集群范围的配置值以及 X-Account-Sysmeta-Read-Only 中的每个账户覆盖设置。
- swift.common.middleware.read_only.filter_factory(global_conf, **local_conf)¶
paste.deploy 应用工厂,用于创建 WSGI 代理应用。
Recon¶
- class swift.common.middleware.recon.ReconMiddleware(app, conf, *args, **kwargs)¶
基类:
object用于监控的 Recon 中间件。
/recon/load|mem|async… 将返回各种系统指标。
需要在管道中添加,并在 [account|container|object]-server 配置文件中声明过滤器。
[filter:recon] use = egg:swift#recon recon_cache_path = /var/cache/swift
- get_async_info()¶
获取异步待处理的数量
- get_auditor_info(recon_type)¶
获取审计员信息
- get_device_info()¶
获取设备
- get_diskusage()¶
获取磁盘利用率统计信息
- get_driveaudit_error()¶
获取驱动器审计错误的数量
- get_expirer_info(recon_type)¶
获取过期器信息
- get_load(openr=<built-in function open>)¶
从 /proc/loadavg 获取信息
- get_mem(openr=<built-in function open>)¶
从 /proc/meminfo 获取信息
- get_mounted(openr=<built-in function open>)¶
从 /proc/mounts 获取所有挂载的文件系统
- get_quarantine_count()¶
获取对象/容器/账户隔离计数
- get_reconstruction_info()¶
获取重建信息
- get_relinker_info()¶
获取重链器信息(如果存在)
- get_replication_info(recon_type)¶
获取复制信息
- get_ring_md5()¶
获取所有 ring 的 md5sum
- get_sharding_info()¶
获取分片信息
- get_socket_info(openr=<built-in function open>)¶
从 /proc/net/sockstat 和 sockstat6 获取信息
注意:mem 值实际上是内核页,但我们根据系统的页大小返回分配的字节数。
- get_swift_conf_md5()¶
获取 swift.conf 的 md5
- get_time()¶
获取当前时间
- get_unmounted()¶
列出未挂载(失败?)的设备
- get_updater_info(recon_type)¶
获取更新器信息
- get_version()¶
获取 swift 版本
Server Side Copy¶
服务器端复制功能使用户/客户端能够在 Swift 中的账户和容器之间 COPY 对象,而无需下载和重新上传对象,从而消除了额外的带宽消耗并节省了时间。这可以在重命名/移动对象时使用,在 Swift 中这是一个(COPY + DELETE)操作。
服务器端复制中间件应插入在管道中认证之后、配额和大型对象中间件之前。如果在代理服务器配置文件中未在管道中添加此中间件,则会自动插入。没有提供可配置选项来关闭服务器端复制。
元数据¶
在对象复制过程中,源对象的所有元数据都将被保留。
也可以在 PUT/COPY 请求期间提供额外的元数据。这将覆盖任何现有的冲突键。
服务器端复制也可以用于更改现有对象的 content-type。
Object Copy¶
请求复制对象之前,目标容器必须已存在。
当存在多个副本时,系统将从最新的副本复制。也就是说,复制操作的行为就像请求中包含了 X-Newest 头。
复制对象的请求不应包含主体(即请求的 content-length 必须为零)。
可以通过两种方式复制对象
向新对象(目标)发送一个 PUT 请求,并附带一个名为
X-Copy-From的附加头,指定源对象(格式为 ‘/container/object’)。例如curl -i -X PUT http://<storage_url>/container1/destination_obj -H 'X-Auth-Token: <token>' -H 'X-Copy-From: /container2/source_obj' -H 'Content-Length: 0'
使用 URL 中存在的对象发送一个 COPY 请求,并附带一个名为
Destination的附加头,指定目标对象(格式为 ‘/container/object’)。例如curl -i -X COPY http://<storage_url>/container2/source_obj -H 'X-Auth-Token: <token>' -H 'Destination: /container1/destination_obj' -H 'Content-Length: 0'
请注意,如果传入的请求包含某些条件头(例如 Range、If-Match),则会针对 *源* 对象评估这些头(例如,如果 PUT 请求同时带有 X-Copy-From 和 Range,Swift 将为目标对象执行部分复制)。
Cross Account Object Copy¶
如果用户具有必要的权限(即有权从源账户的容器读取,并有权向目标账户的容器写入),也可以将对象从一个账户复制到另一个账户。
与上述示例类似,跨账户复制对象也有两种方式
与上面的示例一样,发送 PUT 请求复制对象,但附带一个名为
X-Copy-From-Account的附加头,指定源账户。例如curl -i -X PUT http://<host>:<port>/v1/AUTH_test1/container/destination_obj -H 'X-Auth-Token: <token>' -H 'X-Copy-From: /container/source_obj' -H 'X-Copy-From-Account: AUTH_test2' -H 'Content-Length: 0'
与上一个示例一样,发送 COPY 请求,但附带一个名为
Destination-Account的附加头,指定目标账户的名称。例如curl -i -X COPY http://<host>:<port>/v1/AUTH_test2/container/source_obj -H 'X-Auth-Token: <token>' -H 'Destination: /container/destination_obj' -H 'Destination-Account: AUTH_test1' -H 'Content-Length: 0'
Large Object Copy¶
复制大型对象的最佳方法是单独复制分段。要复制大型对象的 manifest 对象,请在复制请求中添加查询参数
?multipart-manifest=get
如果请求发送时没有此查询参数,将尝试复制整个对象,但如果对象大小超过 5GB,则会失败。
- class swift.common.middleware.copy.ServerSideCopyWebContext(app, logger, yield_frequency=10)¶
Bases:
WSGIContext
Static Large Objects¶
有关更多详细信息,请参阅 Static Large Objects 的 SLO 文档。
StaticWeb¶
此 StaticWeb WSGI 中间件将容器数据作为静态网站提供服务,并具有索引文件和错误文件解析以及可选的文件列表功能。此模式通常仅对匿名请求激活。使用 keystone 进行身份验证时,请在 /etc/swift/proxy-server.conf 文件的 authtoken 中间件配置中设置 delay_auth_decision = true。如果您希望将其与已认证的请求一起使用,请在请求中设置 X-Web-Mode: true 头。
应将 staticweb 过滤器添加到 /etc/swift/proxy-server.conf 文件中的管道,紧跟在任何身份验证中间件之后。此外,还需要添加 staticweb 中间件本身的配置部分。例如
[DEFAULT]
...
[pipeline:main]
pipeline = catch_errors healthcheck proxy-logging cache ratelimit tempauth
staticweb proxy-logging proxy-server
...
[filter:staticweb]
use = egg:swift#staticweb
任何可公开读取的容器(例如,X-Container-Read: .r:*,有关更多信息,请参阅 ACLs)将检查 X-Container-Meta-Web-Index 和 X-Container-Meta-Web-Error 头值。
X-Container-Meta-Web-Index <index.name>
X-Container-Meta-Web-Error <error.name.suffix>
如果设置了 X-Container-Meta-Web-Index,任何 <index.name> 文件将在无需指定 <index.name> 部分的情况下提供服务。例如,设置 X-Container-Meta-Web-Index: index.html 将能够通过 .../pseudo/path 或 .../pseudo/path/ 提供对象 .../pseudo/path/index.html。
如果设置了 X-Container-Meta-Web-Error,任何错误(目前仅包括 401 Unauthorized 和 404 Not Found)将改为提供 .../<status.code><error.name.suffix> 对象。例如,设置 X-Container-Meta-Web-Error: error.html 将为未找到路径的请求提供 .../404error.html。
对于没有 <index.name> 的伪路径,如果将容器上的元数据项 X-Container-Meta-Web-Listings: true 设置为 true,则此中间件可以提供 HTML 文件列表。请注意,列表必须经过授权;您可能需要一个容器 ACL,如 X-Container-Read: .r:*,.rlistings。
如果启用了列表,则列表可以通过设置 X-Container-Meta-Web-Listings-CSS 头来拥有自定义样式表。例如,设置 X-Container-Meta-Web-Listings-CSS: listing.css 将使列表链接到 .../listing.css 样式表。如果您在浏览器中“查看源”,您将看到可以进行样式的定义良好的文档结构。
此外,可以使用基于前缀的 TempURL 参数来授权请求,而不是使整个容器公开可读。这使得客户端能够动态地发现该前缀内的可用对象。
注意
当与 StaticWeb 一起使用时,temp_url_prefix 值通常应以斜杠(/)结尾。StaticWeb 的重定向不会保留任何 TempURL 参数,因为它们可能表明用户创建了过于宽泛的 TempURL。
默认情况下,列表将以“Listing of /v1/account/container/path”的标签呈现。可以通过设置 X-Container-Meta-Web-Listings-Label: <label> 来更改此设置。例如,如果标签设置为“example.com”,则将使用“Listing of example.com/path”作为标签。
可以通过设置 X-Container-Meta-Web-Directory-Type 头来修改目录标记对象的 content-type。如果未设置该头,则默认使用 application/directory。目录标记对象是 0 字节对象,代表用于创建模拟分层结构的目录。
通过 swift 使用此中间件的示例
使容器公开可读
swift post -r '.r:*' container您应该能够直接获取对象,但不能进行索引文件解析或列表。
设置索引文件指令
swift post -m 'web-index:index.html' container您应该能够命中包含 index.html 的路径,而无需输入 index.html 部分。
打开列表功能
swift post -r '.r:*,.rlistings' container swift post -m 'web-listings: true' container现在您应该可以看到没有 index.html 的路径和伪路径的对象列表。
启用自定义列表样式表
swift post -m 'web-listings-css:listings.css' container设置错误文件
swift post -m 'web-error:error.html' container现在 401 应加载 401error.html,404 应加载 404error.html,依此类推。
设置目录标记对象的 Content-Type
swift post -m 'web-directory-type:text/directory' container现在 content-type 为 text/directory 的 0 字节对象将被视为目录而不是对象。
- class swift.common.middleware.staticweb.StaticWeb(app, conf)¶
基类:
objectStatic Web WSGI 中间件过滤器;将容器数据作为静态网站提供服务。请参阅 staticweb 获取概述。
为任何子请求创建的代理日志将设置 swift.source 为 “SW”。
- 参数:
app – paste.deploy 管道中的下一个 WSGI 应用程序/过滤器。
conf – 过滤器配置字典。
- app¶
paste.deploy 管道中的下一个 WSGI 应用程序/过滤器。
- conf¶
过滤器配置字典。仅在测试中使用。
- swift.common.middleware.staticweb.filter_factory(global_conf, **local_conf)¶
返回一个 Static Web WSGI 过滤器,供 paste.deploy 使用。
Symlink¶
Symlink Middleware
Symlinks 是存储在 Swift 中的对象,其中包含对另一个对象(以下称为“目标对象”)的引用。它们类似于类 Unix 操作系统的符号链接。符号链接的存在不会以任何方式影响目标对象。一个重要的用例是使用一个容器中的路径来访问另一个容器中的对象,使用不同的策略。这允许对单个对象进行策略成本/性能权衡。
客户端通过发送一个零长度的 PUT 请求并附带 X-Symlink-Target: <container>/<object> 头来创建 Swift 符号链接。对于跨账户的符号链接,必须包含 X-Symlink-Target-Account: <account> 头。如果省略,则在 PUT 请求处理过程中会自动插入符号链接对象的账户。
符号链接必须是零字节对象。尝试使用非空请求体 PUT 符号链接将导致 400 系列错误。此外,带有 X-Symlink-Target 头的 POST 请求始终会导致 400 系列错误。目标对象在创建符号链接时不必存在。
客户端可以选择在 PUT 期间包含 X-Symlink-Target-Etag: <etag> 头。如果存在,这将创建一个“静态符号链接”而不是“动态符号链接”。静态符号链接指向特定对象,而不是特定名称。它们通过在创建时设置的 X-Symlink-Target-Etag 头值来验证 GET 时它是否仍与它们指向的对象匹配。与动态符号链接相反,X-Symlink-Target 头中引用的目标对象必须存在,并且其 ETag 必须与 X-Symlink-Target-Etag 匹配,否则符号链接创建将返回客户端错误。
对符号链接的 GET/HEAD 请求将导致对符号链接的 X-Symlink-Target-Account 和 X-Symlink-Target 头引用的目标对象的请求。GET/HEAD 请求的响应将包含一个 Content-Location 头,其中包含目标对象的路径位置。对带有 ?symlink=get 查询参数的符号链接的 GET/HEAD 请求将导致请求以符号链接本身为目标。
符号链接可以指向另一个符号链接。链式符号链接将被遍历,直到目标不再是符号链接。如果链式符号链接的数量超过 symloop_max 限制,将产生错误响应。 symloop_max 的值可以在 proxy-server.conf 的 symlink 配置部分中定义。如果未指定,默认的 symloop_max 值为 2。如果指定的值小于 1,则将使用默认值。
如果静态符号链接(即使用 X-Symlink-Target-Etag 头创建的符号链接)指向另一个静态符号链接,则 GET 成功需要两个 X-Symlink-Target-Etag 头都匹配目标对象。如果静态符号链接指向动态符号链接(即未使用 X-Symlink-Target-Etag 头创建的符号链接),则静态符号链接的 X-Symlink-Target-Etag 头必须是零字节对象的 ETag。如果带有 X-Symlink-Target-Etag 的符号链接指向大型对象 manifest,它必须匹配 manifest 的 ETag(例如,multipart-manifest=get 返回的 ETag 或 X-Manifest-Etag 头中的值)。
对符号链接的 HEAD/GET 请求的行为与对目标对象的普通 HEAD/GET 请求相同。因此,对符号链接发出 HEAD 请求将返回目标元数据,对符号链接发出 GET 请求将返回目标对象的数据和元数据。要返回符号链接元数据(及其空体),必须向符号链接对象发送带有 ?symlink=get 查询参数的 GET/HEAD 请求。
对符号链接的 POST 请求将导致 307 Temporary Redirect 响应。响应将包含一个 Location 头,其值为目标对象的路径。Swift 不会将请求重定向到目标对象。然而,POST 请求中的元数据将应用于符号链接,因为对象服务器无法确定当前对象是符号链接还是普通对象(在最终一致性情况下)。
符号链接的 Content-Type 与其目标完全无关。作为一种便利,Swift 会在未明确设置的情况下自动设置符号链接 PUT 的 Content-Type。如果客户端发送了 X-Symlink-Target-Etag,Swift 将把符号链接的 Content-Type 设置为目标的 Content-Type,否则将设置为 application/symlink。您可以使用 ?symlink=get 接口查看符号链接的 Content-Type。您可以使用 POST 请求更改符号链接的 Content-Type。符号链接的 Content-Type 将出现在容器列表中。
对符号链接的 DELETE 请求将删除符号链接本身。目标对象不会被删除。
对符号链接的 COPY 请求,或带有 X-Copy-From 头的 PUT 请求将复制目标对象。对带有 ?symlink=get 查询参数的符号链接的相同请求将复制符号链接本身。
对符号链接的 OPTIONS 请求将仅响应符号链接的选项;请求不会重定向到目标对象。请注意,如果符号链接的目标对象在另一个具有 CORS 设置的容器中,响应将不反映这些设置。
Tempurls 可用于 GET/HEAD 符号链接对象,但不允许 PUT,并将导致 400 系列错误。GET/HEAD tempurls 遵守 tempurl 密钥的作用域。容器 tempurl 仅适用于目标容器与符号链接相同的符号链接。如果符号链接指向另一个容器中的对象,GET/HEAD 请求将导致 401 Unauthorized 错误。账户级别 tempurl 允许跨容器符号链接,但不允许跨账户符号链接。
如果在版本化的容器中覆盖了符号链接对象,则只有符号链接对象本身会被版本化,而引用的对象不会。
对包含符号链接的容器发出带有 ?format=json 查询参数的 GET 请求将在容器列表中为每个符号链接对象响应额外的 symlink_path 信息。symlink_path 值是符号链接的目标路径。客户端可以通过此功能区分符号链接和其他对象。请注意,其他格式的响应(例如 ?format=xml)将不包含 symlink_path 信息。如果符号链接上包含了 X-Symlink-Target-Etag 头,JSON 容器列表将在 symlink_etag 键中包含该值,目标对象的 Content-Length 将包含在 symlink_bytes 键中。
如果静态符号链接指向静态大型对象 manifest,它将在容器列表中通过 symlink_bytes 和 slo_etag 键携带 SLO 的大小和 slo_etag。然而,在 swift v2.12.0(2016 年 12 月发布)之前创建的 manifest 不包含足够元数据来将额外的 SLO 信息传播到列表中。客户端可以在创建静态符号链接之前重新创建 manifest(使用 ?multipart-manfiest=get 进行 COPY)来添加所需的元数据。
Errors
带有非零 Content-Length 的
X-Symlink-Target头的 PUT 将产生 400 BadRequest 错误。带有
X-Symlink-Target头的 POST 将产生 400 BadRequest 错误。遍历超过
symloop_max个链式符号链接的 GET/HEAD 将产生 409 Conflict 错误。包含与目标不匹配的
X-Symlink-Target-Etag头的符号链接上的 PUT/GET/HEAD 将产生 409 Conflict 错误。POST 将产生 307 Temporary Redirect 错误。
Deployment¶
通过将 symlink 中间件添加到代理服务器 WSGI 管道并包含相应的过滤器配置部分在 proxy-server.conf 文件中,可以启用符号链接。在管道中,symlink 中间件应放在 slo、dlo 和 versioned_writes 中间件之后,但在 encryption 中间件之前。有关更多详细信息,请参阅 proxy-server.conf-sample 文件。如果正在使用容器同步功能,则需要 其他步骤。
注意
在管道中部署 symlink 中间件后,您不应移除 symlink 中间件,也不应将 swift 降级到不支持符号链接的版本。这样做可能会导致意外的容器列表结果,并且符号链接对象会像普通对象一样运行。
Container sync configuration¶
如果正在使用容器同步,则必须将 symlink 中间件添加到容器同步内部客户端管道。需要执行以下配置步骤
为容器同步创建一个自定义的内部客户端配置文件(如果尚未使用),该文件基于 internal-client.conf-sample 示例文件。例如,将 internal-client.conf-sample 复制到 /etc/swift/container-sync-client.conf。
修改此文件,以与上面为代理服务器描述的方式相同,将 symlink 中间件包含在管道中。
修改所有容器服务器配置文件中的 container-sync 部分,使用
internal_client_conf_path选项指向此内部客户端配置文件。例如internal_client_conf_path = /etc/swift/container-sync-client.conf
注意
如果 symlink 中间件包含在测试集群的代理管道中,那么这些容器同步配置步骤将是容器同步探测测试通过所必需的。
- class swift.common.middleware.symlink.SymlinkContainerContext(wsgi_app, logger)¶
Bases:
WSGIContext
- class swift.common.middleware.symlink.SymlinkMiddleware(app, conf, symloop_max)¶
基类:
object实现符号链接的中间件。
Symlinks 是存储在 Swift 中的对象,其中包含对另一个对象(即目标对象)的引用。一个重要的用例是使用一个容器中的路径来访问另一个容器中的对象,使用不同的策略。这允许对单个对象进行策略成本/性能权衡。
- class swift.common.middleware.symlink.SymlinkObjectContext(wsgi_app, logger, symloop_max)¶
Bases:
WSGIContext- handle_get_head(req)¶
处理 GET/HEAD 请求,并在响应是符号链接时,将请求重定向到目标对象。
- 参数:
req – HTTP GET 或 HEAD 对象请求
- 返回值:
响应迭代器
- handle_get_head_symlink(req)¶
处理客户端发送参数 ?symlink=get 时的 GET/HEAD 请求。
- 参数:
req – 带有参数 ?symlink=get 的 HTTP GET 或 HEAD 对象请求
- 返回值:
响应迭代器
- handle_object(req, start_response)¶
处理对象请求。
- 参数:
req – 一个
Request对象start_response – start_response 函数
- 返回值:
调用 start_response 后的响应迭代器
- handle_post(req)¶
处理 POST 请求。如果 POST 到符号链接,则向客户端返回 HTTPTemporaryRedirect 错误消息。
POST 到符号链接的客户端应理解 POST 不会像 HEAD/GET 请求那样重定向到目标对象。POST 到符号链接的操作将由对象服务器像普通对象一样处理。它无法拒绝,因为它可能在 POST 落地时没有符号链接的状态。对象服务器不知道什么是符号链接对象。另一方面,在 POST 请求中,对象服务器返回对象的所有 sysmeta。此方法使用该 sysmeta 来确定存储的对象是否为符号链接。
- 参数:
req – HTTP POST 对象请求
- 引发:
如果 POST 到符号链接,则为 HTTPTemporaryRedirect。
- 返回值:
响应迭代器
- handle_put(req)¶
处理包含 X-Symlink-Target 头的 PUT 请求。
符号链接头被验证并移至 sysmeta 命名空间。:param req: HTTP PUT 对象请求 :returns: Response Iterator
- swift.common.middleware.symlink.symlink_sysmeta_to_usermeta(headers)¶
辅助函数,用于将面向集群的 X-Object-Sysmeta-Symlink-* 头转换为面向客户端的 X-Symlink-* 头。
- 参数:
headers – 请求头字典。注意,headers 字典将直接更新。
- swift.common.middleware.symlink.symlink_usermeta_to_sysmeta(headers)¶
辅助函数,用于将面向客户端的 X-Symlink-* 头转换为面向集群的 X-Object-Sysmeta-Symlink-* 头。
- 参数:
headers – 请求头字典。注意,headers 字典将直接更新。
TempAuth¶
测试认证和授权系统。
将其添加到 proxy-server.conf 的管道中,例如
[pipeline:main]
pipeline = catch_errors cache tempauth proxy-server
在 proxy-server.conf 中将账户自动创建设置为 true
[app:proxy-server]
account_autocreate = true
并添加一个 tempauth 过滤器部分,例如
[filter:tempauth]
use = egg:swift#tempauth
user_admin_admin = admin .admin .reseller_admin
user_test_tester = testing .admin
user_test2_tester2 = testing2 .admin
user_test_tester3 = testing3
# To allow accounts/users with underscores you can base64 encode them.
# Here is the account "under_score" and username "a_b" (note the lack
# of padding equal signs):
user64_dW5kZXJfc2NvcmU_YV9i = testing4
有关更多信息,请参阅 proxy-server.conf-sample。
Account/User List¶
所有账户/用户都列在过滤器部分中。格式为
user_<account>_<user> = <key> [group] [group] [...] [storage_url]
如果您想在 <account> 或 <user> 部分包含下划线,则可以使用 base64 对它们进行编码(*不*包含等号),如下一行所示:
user64_<account_b64>_<user_b64> = <key> [group] [...] [storage_url]
有三个特殊组
.reseller_admin– 对于此认证,可以对任何账户执行任何操作.reseller_reader– 对于此认证,可以 GET/HEAD 任何账户中的任何内容.admin– 可以在账户内执行任何操作
如果未指定这些组中的任何一个,则用户只能访问已被 *.admin* 或 *.reseller_admin* 显式允许其访问的容器。
后面的可选 storage_url 允许您指定一个备用 URL,在身份验证后返回给用户。如果未指定,则默认为
$HOST/v1/<reseller_prefix>_<account>
其中 $HOST 将尽力解析为请求者访问该主机所需的 URL,<reseller_prefix> 来自此部分,而 <account> 来自 user_<account>_<user> 名称。请注意,当负载均衡器在前面运行 https 而 TempAuth 本身以 http 运行时,$HOST 无法处理;在这种情况下,您必须指定 storage_url_scheme 配置值作为覆盖。
Multiple Reseller Prefix Items¶
reseller prefix 指定此中间件负责管理哪个账户命名空间中的身份验证和授权。默认情况下,前缀是 AUTH,因此账户和令牌会以 AUTH_ 为前缀。当请求的令牌和/或路径以 AUTH_ 开头时,此中间件就知道它负责。
我们允许 reseller prefix 是一个列表。在 tempauth 中,列表中的第一个项用作令牌和用户组的前缀。其他前缀提供了用户可以访问的备用账户。例如,如果 reseller prefix 列表是 AUTH, OTHER,那么对 AUTH_account 具有管理员访问权限的用户也对 OTHER_account 具有管理员访问权限。
Required Group¶
通常需要 *.admin* 组才能访问账户(ACLs 提供了另一种访问账户的方式)。您可以指定 require_group 参数。这意味着您还需要命名组才能访问账户。如果您有多个 reseller prefix 项,请用适当的前缀为 require_group 参数加上前缀。
X-Service-Token¶
如果在请求头中提供了 X-Service-Token,则从令牌派生的组将附加到从 X-Auth-Token 派生的角色。如果 X-Auth-Token 缺失或无效,则不处理 X-Service-Token。
当与多个 reseller prefix 项结合使用时,X-Service-Token 非常有用。在以下配置中,除非 X-Auth-Token 来自最终用户且 X-Service-Token 来自 glance 用户,否则无法访问以 SERVICE_ 开头的账户。
[filter:tempauth]
use = egg:swift#tempauth
reseller_prefix = AUTH, SERVICE
SERVICE_require_group = .service
user_admin_admin = admin .admin .reseller_admin
user_joeacct_joe = joepw .admin
user_maryacct_mary = marypw .admin
user_glance_glance = glancepw .service
名称 .service 是一个示例。与 .admin、.reseller_admin、.reseller_reader 不同,它不是保留名称。
请注意,ACLs 可以设置在服务账户上,并与通过 X-Auth-Token 验证的身份进行匹配。因此,ACLs 可以授予对服务账户容器的访问权限,而无需提供服务令牌,就像任何其他使用 ACLs 的跨经销商请求一样。
Account ACLs¶
如果 swift_owner 使用 X-Account-Access-Control 头在请求中发出 POST 或 PUT 到账户,那么这可能会为其他用户提供某些类型的访问权限。
只读:具有只读访问权限的用户可以列出账户中的容器,列出任何容器中的对象,检索对象,并查看非特权账户/容器/对象元数据。
读写:具有读写访问权限的用户可以(除了只读特权外)创建对象,覆盖现有对象,创建新容器,并设置非特权容器/对象元数据。
管理员:具有管理员访问权限的用户是 swift_owners,可以执行任何操作,包括查看/设置特权元数据(例如,更改账户 ACLs)。
生成用于设置账户 ACL 的头
from swift.common.middleware.acl import format_acl
acl_data = { 'admin': ['alice'], 'read-write': ['bob', 'carol'] }
header_value = format_acl(version=2, acl_dict=acl_data)
根据上述内容生成 curl 命令
token=...
storage_url=...
python -c '
from swift.common.middleware.acl import format_acl
acl_data = { 'admin': ['alice'], 'read-write': ['bob', 'carol'] }
headers = {'X-Account-Access-Control':
format_acl(version=2, acl_dict=acl_data)}
header_str = ' '.join(["-H '%s: %s'" % (k, v)
for k, v in headers.items()])
print('curl -D- -X POST -H "x-auth-token: $token" %s '
'$storage_url' % header_str)
'
- class swift.common.middleware.tempauth.TempAuth(app, conf)¶
基类:
object- 参数:
app – 管道中的下一个 WSGI 应用。
conf – Paste 配置文件中的配置值字典
- account_acls(req)¶
通过 get_account_info 从账户服务器返回 ACL 数据字典。
认证系统可以定义自己的格式、序列化、结构和 ACL 头中实现的、并持久化在 sysmeta 数据中的功能。然而,强烈鼓励认证系统与 Tempauth 互操作。
- 账户 ACLs 通过以下头设置和检索
X-Account-Access-Control
- 有关头格式和语法,请参阅
- authorize(req)¶
如果请求已授权继续,则返回 None,否则返回标准的 WSGI 响应可调用对象。
- denied_response(req)¶
返回一个标准的 WSGI 响应可调用对象,其状态码为 403 或 401,具体取决于 REMOTE_USER 是否已设置。
- extract_acl_and_report_errors(req)¶
返回一个用户可读的字符串,指示输入 ACL 中的错误,或者在没有错误时返回 None。
- get_groups(env, token)¶
获取给定令牌的组。
- 参数:
env – 当前 WSGI 环境字典。
token – 要验证并返回组字符串的令牌。
- 返回值:
如果令牌无效,则返回 None;否则返回一个包含已认证用户所属组的逗号分隔列表的字符串。列表中的第一个组也被视为该用户的唯一标识符。
- handle(env, start_response)¶
认证请求(匹配 self.auth_prefix 的请求)的 WSGI 入口点。将 env 包装在 swob.Request 对象中并向下传递。
- 参数:
env – WSGI 环境字典
start_response – WSGI 可调用对象
- handle_get_token(req)¶
处理各种 *请求令牌和服务端点* 调用。存在各种格式以支持过去的各种认证服务器。示例
GET <auth-prefix>/v1/<act>/auth X-Auth-User: <act>:<usr> or X-Storage-User: <usr> X-Auth-Key: <key> or X-Storage-Pass: <key> GET <auth-prefix>/auth X-Auth-User: <act>:<usr> or X-Storage-User: <act>:<usr> X-Auth-Key: <key> or X-Storage-Pass: <key> GET <auth-prefix>/v1.0 X-Auth-User: <act>:<usr> or X-Storage-User: <act>:<usr> X-Auth-Key: <key> or X-Storage-Pass: <key>
成功认证后,响应将设置 X-Auth-Token 和 X-Storage-Token 为与 Swift 一起使用的令牌,并设置 X-Storage-URL 为要使用的默认 Swift 集群的 URL。
- 参数:
req – 要处理的 swob.Request。
- 返回值:
swob.Response,成功时为 2xx,数据如上所述。
- handle_request(req)¶
认证请求(匹配 self.auth_prefix 的请求)的入口点。应返回一个 WSGI 风格的可调用对象(例如 swob.Response)。
- 参数:
req – swob.Request 对象
- swift.common.middleware.tempauth.filter_factory(global_conf, **local_conf)¶
返回一个 WSGI filter app,供 paste.deploy 使用。
TempURL¶
TempURL Middleware
允许创建 URL 以提供对对象的临时访问。
例如,一个网站可能希望提供一个链接来下载 Swift 中的大型对象,但 Swift 账户没有公共访问权限。网站可以生成一个 URL,该 URL 在有限的时间内提供对资源的 GET 访问。当网站用户单击链接时,浏览器将直接从 Swift 下载对象,从而无需网站充当请求的代理。
如果用户与所有朋友共享该链接,或意外地将其发布在论坛等地方,则直接访问将仅限于网站创建链接时设置的过期时间。
此外,该中间件提供了创建 URL 的能力,这些 URL 包含签名,对于共享一组对象的任何共享公共前缀的对象都有效。这些基于前缀的 URL 对于共享一组对象很有用。
还可以限制 IP 地址,以控制允许从何处访问资源。这对于锁定 URL 的使用位置很有用。
Client Usage¶
要创建临时 URL,首先需要在 Swift 账户上设置一个 X-Account-Meta-Temp-URL-Key 头部。然后,使用允许的 HTTP 方法(GET、PUT、DELETE 等)、允许访问的 Unix 时间戳、对象的完整路径以及账户上设置的密钥,生成一个 HMAC (RFC 2104) 签名。
摘要算法的使用方式可以由操作员配置。默认情况下,支持 HMAC-SHA256 和 HMAC-SHA512。请检查集群的 capabilities 响应中的 tempurl.allowed_digests 条目,以了解您的部署支持哪些算法;有关更多信息,请参阅 Discoverability。在较旧的集群中,可能会存在 tempurl 键,但不存在 allowed_digests 子键;在这种情况下,只支持 HMAC-SHA1。
例如,以下代码用于生成对 /v1/AUTH_account/container/object 在 60 秒内进行 GET 操作的签名:
import hmac
from hashlib import sha256
from time import time
method = 'GET'
expires = int(time() + 60)
path = '/v1/AUTH_account/container/object'
key = 'mykey'
hmac_body = '%s\n%s\n%s' % (method, expires, path)
sig = hmac.new(key, hmac_body, sha256).hexdigest()
请务必使用从 /v1/ 开始的完整路径。
假设 sig 的最终值为 732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b,expires 的最终值为 1512508563。那么,例如,网站可以提供一个指向的链接:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b&
temp_url_expires=1512508563
对于更长的哈希值,十六进制编码会变得笨拙。也支持 Base64 编码,通过在签名前面加上 "<摘要名称>:" 来指示。对于 HMAC-SHA512 签名,这是必需的。例如,用于生成 HMAC-SHA512 签名的类似代码将是:
import base64
import hmac
from hashlib import sha512
from time import time
method = 'GET'
expires = int(time() + 60)
path = '/v1/AUTH_account/container/object'
key = 'mykey'
hmac_body = '%s\n%s\n%s' % (method, expires, path)
sig = 'sha512:' + base64.urlsafe_b64encode(hmac.new(
key, hmac_body, sha512).digest())
假设 sig 的最终值为 sha512:ZrSijn0GyDhsv1ltIj9hWUTrbAeE45NcKXyBaz7aPbSMvROQ4jtYH4nRAmm 5ErY2X11Yc1Yhy2OMCyN3yueeXg==,expires 的最终值为 1516741234,那么网站可以提供一个指向的链接:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=sha512:ZrSijn0GyDhsv1ltIj9hWUTrbAeE45NcKXyBaz7aPbSMvRO
Q4jtYH4nRAmm5ErY2X11Yc1Yhy2OMCyN3yueeXg==&
temp_url_expires=1516741234
您也可以使用 ISO 8601 UTC 时间戳,格式为 "%Y-%m-%dT%H:%M:%SZ",而不是 URL 中的 UNIX 时间戳(但不是上面的签名生成代码!)。因此,上述 HMAC-SHA246 URL 也可以这样构建:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b&
temp_url_expires=2017-12-05T21:16:03Z
如果希望使用带有前缀 pre 的基于前缀的签名,请将路径设置为:
path = 'prefix:/v1/AUTH_account/container/pre'
生成的签名将对所有以 pre 开头的对象有效。中间件通过一个名为 temp_url_prefix 的查询参数检测基于前缀的临时 URL。因此,如果 sig 和 expires 的值如上所示,则以下 URL 将有效:
https://swift-cluster.example.com/v1/AUTH_account/container/pre/object?
temp_url_sig=732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b&
temp_url_expires=1512508563&
temp_url_prefix=pre
另一个有效的 URL
https://swift-cluster.example.com/v1/AUTH_account/container/pre/
subfolder/another_object?
temp_url_sig=732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b&
temp_url_expires=1512508563&
temp_url_prefix=pre
如果您希望将资源访问的 IP 范围限制为 IP 1.2.3.4:
import hmac
from hashlib import sha256
from time import time
method = 'GET'
expires = int(time() + 60)
path = '/v1/AUTH_account/container/object'
ip_range = '1.2.3.4'
key = b'mykey'
hmac_body = 'ip=%s\n%s\n%s\n%s' % (ip_range, method, expires, path)
sig = hmac.new(key, hmac_body.encode('ascii'), sha256).hexdigest()
生成的签名将仅从 IP 1.2.3.4 有效。中间件通过一个名为 temp_url_ip_range 的查询参数检测基于 IP 的临时 URL。因此,如果 sig 和 expires 的值如上所示,则以下 URL 将有效:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=3f48476acaf5ec272acd8e99f7b5bad96c52ddba53ed27c60613711774a06f0c&
temp_url_expires=1648082711&
temp_url_ip_range=1.2.3.4
类似地,要将 IP 限制在一个范围 1.2.3.X,即从 IP 1.2.3.0 到 1.2.3.255:
import hmac
from hashlib import sha256
from time import time
method = 'GET'
expires = int(time() + 60)
path = '/v1/AUTH_account/container/object'
ip_range = '1.2.3.0/24'
key = b'mykey'
hmac_body = 'ip=%s\n%s\n%s\n%s' % (ip_range, method, expires, path)
sig = hmac.new(key, hmac_body.encode('ascii'), sha256).hexdigest()
那么以下 URL 将有效:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=6ff81256b8a3ba11d239da51a703b9c06a56ffddeb8caab74ca83af8f73c9c83&
temp_url_expires=1648082711&
temp_url_ip_range=1.2.3.0/24
对临时 URL 的资源路径或查询参数的任何修改都将导致 401 Unauthorized。同样,如果允许的方法是 GET 而尝试使用 PUT,则会以 401 Unauthorized 拒绝。但是,如果允许 GET、PUT 或 POST,则允许 HEAD。
结合浏览器表单 POST 翻译中间件,这还可以实现从浏览器直接上传到 Swift 中的特定位置。
TempURL 同时支持账户和容器级别的密钥。每个级别最多可以设置两个密钥,从而允许密钥轮换而不使所有现有临时 URL 失效。账户密钥通过 X-Account-Meta-Temp-URL-Key 和 X-Account-Meta-Temp-URL-Key-2 指定,而容器密钥通过 X-Container-Meta-Temp-URL-Key 和 X-Container-Meta-Temp-URL-Key-2 指定。如果存在,签名将针对账户和容器密钥进行检查。
对于 GET TempURLs,响应中将设置 Content-Disposition 头部,以便浏览器将其解释为要保存的文件附件。选择的文件名基于对象名称,但您可以使用文件名查询参数覆盖它。修改上面的示例:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b&
temp_url_expires=1512508563&filename=My+Test+File.pdf
如果您不希望下载该对象,可以通过将 inline 参数添加到查询字符串中,使响应中设置 Content-Disposition: inline,如下所示:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b&
temp_url_expires=1512508563&inline
在某些情况下,客户端可能无法呈现对象的内容,但您仍希望内容能够以特定文件名保存到本地。因此,您可以通过将 inline&filename=... 参数添加到查询字符串中,使响应中设置 Content-Disposition: inline; filename=...,如下所示:
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=732fcac368abb10c78a4cbe95c3fab7f311584532bf779abd5074e13cbe8b88b&
temp_url_expires=1512508563&inline&filename=My+Test+File.pdf
集群配置¶
此中间件支持以下配置设置:
incoming_remove_headers要从传入请求中移除的头部列表,以空格分隔。名称可以可选地以
*结尾,以表示前缀匹配。incoming_allow_headers是这些移除项的异常列表。默认值:x-timestamp x-open-expiredincoming_allow_headers允许作为
incoming_remove_headers异常的头部列表,以空格分隔。名称可以可选地以*结尾,以表示前缀匹配。默认值:无
outgoing_remove_headers要从传出响应中移除的头部列表,以空格分隔。名称可以可选地以
*结尾,以表示前缀匹配。outgoing_allow_headers是这些移除项的异常列表。默认值:
x-object-meta-*outgoing_allow_headers允许作为
outgoing_remove_headers异常的头部列表,以空格分隔。名称可以可选地以*结尾,以表示前缀匹配。默认值:
x-object-meta-public-*methods允许与临时 URL 一起使用的请求方法的空格分隔列表。
默认值:
GET HEAD PUT POST DELETEallowed_digests在计算临时 URL 的签名时允许使用的摘要算法的空格分隔列表。
默认值:
sha256 sha512
- swift.common.middleware.tempurl.DEFAULT_INCOMING_ALLOW_HEADERS = ''¶
DEFAULT_INCOMING_REMOVE_HEADERS 的默认异常头部。简单来说,就是用空格分隔的头部名称列表,名称可以可选地以 '*' 结尾,表示前缀匹配。
- swift.common.middleware.tempurl.DEFAULT_INCOMING_REMOVE_HEADERS = 'x-timestamp x-open-expired'¶
从传入请求中移除的默认头部。简单来说,就是用空格分隔的头部名称列表,名称可以可选地以 '*' 结尾,表示前缀匹配。DEFAULT_INCOMING_ALLOW_HEADERS 是这些移除项的异常列表。
- swift.common.middleware.tempurl.DEFAULT_OUTGOING_ALLOW_HEADERS = 'x-object-meta-public-*'¶
DEFAULT_OUTGOING_REMOVE_HEADERS 的默认异常头部。简单来说,就是用空格分隔的头部名称列表,名称可以可选地以 '*' 结尾,表示前缀匹配。
- swift.common.middleware.tempurl.DEFAULT_OUTGOING_REMOVE_HEADERS = 'x-object-meta-*'¶
从传出响应中移除的默认头部。简单来说,就是用空格分隔的头部名称列表,名称可以可选地以 '*' 结尾,表示前缀匹配。DEFAULT_OUTGOING_ALLOW_HEADERS 是这些移除项的异常列表。
- class swift.common.middleware.tempurl.TempURL(app, conf, logger=None)¶
基类:
objectWSGI 中间件,用于为 Swift 资源授予临时 URL 的特定访问权限。有关更多信息,请参阅概述。
为任何子请求创建的代理日志将具有 swift.source 设置为“TU”。
- 参数:
app – paste.deploy 链中的下一个 WSGI 过滤器或应用。
conf – 中间件的配置字典。
- agent¶
用于子请求的 HTTP 用户代理。
- app¶
paste.deploy 管道中的下一个 WSGI 应用程序/过滤器。
- conf¶
过滤器配置字典。
- incoming_allow_headers¶
允许在传入请求中的头部。大写 WSGI env 风格,例如 HTTP_X_MATCHES_REMOVE_PREFIX_BUT_OKAY。
- incoming_allow_headers_startswith¶
带有匹配前缀的头部,允许在传入请求中。大写 WSGI env 风格,例如 HTTP_X_MATCHES_REMOVE_PREFIX_BUT_OKAY_*。
- incoming_remove_headers¶
要从传入请求中移除的头部。大写 WSGI env 风格,例如 HTTP_X_PRIVATE。
- incoming_remove_headers_startswith¶
带有匹配前缀的头部,要从传入请求中移除。大写 WSGI env 风格,例如 HTTP_X_SENSITIVE_*。
- outgoing_allow_headers¶
允许在传出响应中的头部。小写,例如 x-matches-remove-prefix-but-okay。
- outgoing_allow_headers_startswith¶
带有匹配前缀的头部,允许在传出响应中。小写,例如 x-matches-remove-prefix-but-okay-*。
- outgoing_remove_headers¶
要从传出响应中移除的头部。小写,例如 x-account-meta-temp-url-key。
- outgoing_remove_headers_startswith¶
带有匹配前缀的头部,要从传出响应中移除。小写,例如 x-account-meta-private-*。
- swift.common.middleware.tempurl.filter_factory(global_conf, **local_conf)¶
返回用于 paste.deploy 的 WSGI 过滤器。
版本化写入¶
注意
此中间件支持现在已被新模式取代的两种旧版对象版本化模式。建议为新容器使用新的 对象版本化 模式。
Swift 中的对象版本化是通过在容器上设置一个标志来实现的,该标志告诉 Swift 对容器中的所有对象进行版本化。该标志是以下两个头部之一,它决定了对象 DELETE 请求是如何处理的:
X-History-Location在
DELETE时,将对象的当前版本复制到归档容器,写入一个零字节的“删除标记”对象,该对象记录删除发生的时间,并删除版本化容器中的对象。该对象将不再出现在版本化容器的容器列表中,并且将来的请求将返回404 Not Found。但是,内容仍然可以从归档容器中恢复。X-Versions-Location在
DELETE时,只删除当前版本的对象。如果归档容器中存在任何先前版本,则最新版本将复制到当前版本之上,并且归档容器中的副本将被删除。结果是,如果您总共有 5 个对象版本,则必须删除该对象 5 次,该对象名称才会开始响应404 Not Found。
可以在帐户内的各种容器中使用任一头部,但任何给定容器只能设置一个。尝试同时设置两者将导致 400 Bad Request 响应。
注意
建议为每个正在进行版本化的容器使用不同的归档容器。
注意
不建议在归档容器上启用版本化。
当数据被 PUT 到版本化容器(启用了版本化标志的容器)时,文件中的现有数据将被重定向到归档容器中的新对象,并且 PUT 请求中的数据将作为版本化对象的数据保存。新对象名称(用于前一个版本)为 <archive_container>/<length><object_name>/<timestamp>,其中 length 是 <object_name> 的 3 位零填充十六进制长度,<timestamp> 是前一个版本创建时的时间戳。
对版本化对象的 GET 请求将返回对象的当前版本,而无需任何重定向或元数据查找。
对版本化对象的 POST 请求将像往常一样更新对象元数据,但不会创建新版本。换句话说,新版本仅在对象内容更改时创建。
对版本化对象的 DELETE 请求将按上述两种方式之一进行处理。
要恢复对象的先前版本,请在归档容器中找到所需版本,然后发出一个 COPY 请求,并在 Destination 头部中指定原始位置。这将像覆盖版本化对象的 PUT 一样,将当前版本归档。如果客户端还希望永久删除当前版本,则必须在归档容器中找到新创建的归档对象并向其发出单独的 DELETE 请求。
如何在 Swift 集群中启用对象版本化¶
此中间件是作为重构代理服务器部分组件的努力而编写的,因此此功能在之前的版本中已可用,并尽一切努力保持向后兼容性。为了允许操作员进行无缝升级,不需要将中间件添加到代理管道中,并且容器服务器配置文件中的 allow_versions 标志仍然有效,但仅在使用 X-Versions-Location 时。在将来的版本中,allow_versions 将被弃用,取而代之的是将此中间件添加到管道中以启用或禁用该功能。
如果将中间件添加到代理管道,您还必须在中间件选项中将 allow_versioned_writes 设置为 True,以便在 /info 请求中返回有关此中间件的信息。
注意
您需要将中间件添加到代理管道并将 allow_versioned_writes = True 设置为使用 X-History-Location。在容器服务器中将 allow_versions = True 设置不足以启用 X-History-Location 的使用。
升级注意事项¶
如果在过滤器配置中设置了 allow_versioned_writes,则可以保持容器服务器配置文件中的 allow_versions 标志不变。如果您决定禁用或删除 allow_versions 标志,则必须重新设置任何已配置 X-Versions-Location 标志的现有容器,以便现在可以由 versioned_writes 中间件跟踪。
在集群中的所有代理都已升级到支持 X-History-Location 标头的 Swift 版本之前,客户端不应使用 X-History-Location 头部。在滚动升级过程中尝试使用 X-History-Location 可能会导致一些请求由运行旧代码的代理提供服务,从而导致数据丢失。
使用 curl 和 X-Versions-Location 的示例¶
首先,创建一个带有 X-Versions-Location 头的容器,或者将该头添加到现有容器。另外,请确保 X-Versions-Location 引用的容器存在。在此示例中,该容器的名称为“versions”。
curl -i -XPUT -H "X-Auth-Token: <token>" -H "X-Versions-Location: versions" http://<storage_url>/container
curl -i -XPUT -H "X-Auth-Token: <token>" http://<storage_url>/versions
创建一个对象(第一个版本)
curl -i -XPUT --data-binary 1 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
现在创建一个该对象的新版本
curl -i -XPUT --data-binary 2 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
查看对象旧版本的列表
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/
现在删除当前版本的对象,并查看旧版本已从“versions”容器中消失,并回到了“container”容器中。
curl -i -XDELETE -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/
curl -i -XGET -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
使用 curl 和 X-History-Location 的示例¶
如上所述,创建一个带有 X-History-Location 头的容器,并确保 X-History-Location 引用的容器存在。在此示例中,该容器的名称为“versions”。
curl -i -XPUT -H "X-Auth-Token: <token>" -H "X-History-Location: versions" http://<storage_url>/container
curl -i -XPUT -H "X-Auth-Token: <token>" http://<storage_url>/versions
创建一个对象(第一个版本)
curl -i -XPUT --data-binary 1 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
现在创建一个该对象的新版本
curl -i -XPUT --data-binary 2 -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
现在删除当前版本的对象。后续请求将返回 404。
curl -i -XDELETE -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/container/myobject
旧对象版本的列表将包括对象的第一版和第二版,以及一个“删除标记”对象。
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/
要恢复先前版本的对象,只需将其从归档容器中 COPY 即可。
curl -i -XCOPY -H "X-Auth-Token: <token>" http://<storage_url>/versions/008myobject/<timestamp> -H "Destination: container/myobject"
请注意,归档容器仍然包含该对象的所有先前版本,包括恢复的源。
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/
要永久删除先前版本的对象,请从归档容器中 DELETE 它。
curl -i -XDELETE -H "X-Auth-Token: <token>" http://<storage_url>/versions/008myobject/<timestamp>
如何在 Swift 集群中禁用对象版本化¶
如果您想禁用所有功能,请在中间件选项中将 allow_versioned_writes 设置为 False。
从容器禁用版本化(x 是除空值以外的任何值)
curl -i -XPOST -H "X-Auth-Token: <token>" -H "X-Remove-Versions-Location: x" http://<storage_url>/container
- class swift.common.middleware.versioned_writes.legacy.VersionedWritesContext(wsgi_app, logger)¶
Bases:
WSGIContext- handle_obj_versions_delete_pop(req, versions_cont, api_version, account_name, container_name, object_name)¶
在堆栈模式下处理 DELETE 请求。
删除当前版本的对象,并用前一个版本替换它。
- 参数:
req – 原始请求。
versions_cont – 存储对象先前版本的容器。
api_version – api 版本。
account_name – 帐户名称。
container_name – 容器名称。
object_name – 对象名称。
- handle_obj_versions_delete_push(req, versions_cont, api_version, account_name, container_name, object_name)¶
在历史模式下处理 DELETE 请求。
将对象当前版本复制到 versions_container,并在继续原始请求之前写入删除标记。
- 参数:
req – 原始请求。
versions_cont – 存储对象先前版本的容器。
api_version – api 版本。
account_name – 帐户名称。
object_name – 原始请求的对象名称。
- handle_obj_versions_put(req, versions_cont, api_version, account_name, object_name)¶
在继续处理原始请求之前,将当前版本的对象复制到 versions_container。
- 参数:
req – 原始请求。
versions_cont – 存储对象先前版本的容器。
api_version – api 版本。
account_name – 帐户名称。
object_name – 原始请求的对象名称。
XProfile¶
Swift 服务器的性能分析中间件。
注意
此中间件仅用于开发和测试环境,不适用于生产环境。Web UI 不需要也不期望任何身份验证,并且性能分析可能会带来明显的性能损失。
当前实现基于 eventlet 感知的分析器(未来可能会添加更多分析器以收集更多数据进行分析)。它会对所有传入的请求进行性能分析,并累积 CPU 时间统计信息,以进行性能调优和优化。还提供了一个小型 Web UI,用于分析性能数据。可以通过以下 URL 访问:
浏览性能数据的主页
http://SERVER_IP:PORT/__profile__
列出所有性能分析,以 JSON 格式返回性能 ID
http://SERVER_IP:PORT/__profile__/
http://SERVER_IP:PORT/__profile__/all
以不同格式检索特定的性能分析数据
http://SERVER_IP:PORT/__profile__/PROFILE_ID?format=[default|json|csv|ods]
http://SERVER_IP:PORT/__profile__/current?format=[default|json|csv|ods]
http://SERVER_IP:PORT/__profile__/all?format=[default|json|csv|ods]
以 JSON 格式检索特定函数中的指标
http://SERVER_IP:PORT/__profile__/PROFILE_ID/NFL?format=json
http://SERVER_IP:PORT/__profile__/current/NFL?format=json
http://SERVER_IP:PORT/__profile__/all/NFL?format=json
NFL is defined by concatenation of file name, function name and the first
line number.
e.g.::
account.py:50(GETorHEAD)
or with full path:
opt/stack/swift/swift/proxy/controllers/account.py:50(GETorHEAD)
A list of URL examples:
https://:8080/__profile__ (proxy server)
https://:6200/__profile__/all (object server)
https://:6201/__profile__/current (container server)
https://:6202/__profile__/12345?format=json (account server)
可以在 paste 文件中为代理、账户、容器和对象服务器等 WSGI 服务器配置性能分析中间件。请参阅 etc 目录中的示例配置文件。
性能分析数据提供四种格式:二进制(默认)、JSON、CSV 和 ODF 电子表格(需要安装 odfpy 库)。
sudo pip install odfpy
还有一个简单的可视化功能,通过使用 matplotlib 工具包启用。如果您想使用它来可视化统计数据,也需要安装它。
sudo apt-get install python-matplotlib