注意:

使用 Oracle Cloud Infrastructure Object Storage Service 和 OpenStack Swift API

简介

Oracle Cloud Infrastructure (OCI) 对象存储是一种数据存储架构,它以对象形式管理和组织数字信息,每个对象由数据、元数据和唯一标识符组成。与传统的文件或块存储不同,OCI 对象存储不依赖于分层结构,因此可以高效、可扩展地处理大量非结构化数据。对象存储在平面地址空间中,简化了数据检索并实现了无缝的可扩展性。该解决方案非常适合各种数据类型,例如多媒体内容和备份,使其成为云环境、归档存储和分布式系统的强大选择,因为它具有灵活性、耐用性和易于访问。用户通过 HTTP 协议使用 REST 接口与对象存储服务进行交互。

OCI 对象存储服务是一个基于云的存储解决方案,Oracle 可处理管理复杂性,确保可靠且经济高效的数据持久性。平台弹性允许从无缝扩展的能力逐步开始,所有这些都不会影响性能或服务可靠性。

OCI 对象存储通过 Amazon S3 兼容 API 提供了与 OpenStack Swift API 和 Amazon 简单存储服务 (Amazon S3) 的 API 兼容。这样,客户可以继续使用现有工具(例如 SDK 客户端),从而尽可能减少对应用进行更改的需求。有关详细信息,请参阅 Amazon S3 兼容 API 。本教程将重点介绍 OCI OpenStack Swift 兼容 API 使用情况。

在开始讨论 OpenStack Swift API 之前,我们需要澄清 OCI 对象存储中使用的一些构造。

OpenStack Swift 定义了三个结构:Account、Container 和 Object。

现在,我们可以确定 OCI 对象存储与 OpenStack Swift API 之间的等效资源。

目标

先决条件

使用 OCI Swift API

OCI Swift API 区域端点使用一致的 URL 格式 https://swiftobjectstorage.<region-identifier>.oraclecloud.com。例如,美国东部区域 (US-ashburn-1) 中的原生 OCI Swift API 端点为 https://swiftobjectstorage.US-ashburn-1.oraclecloud.com

考虑到区域级别的租户级别隔离,OCI Swift API 端点变为:https://swiftobjectstorage.<region-identifier>.oraclecloud.com/<tenancy-namespace>,其中 <tenancy-namespace> 是要创建资料档案库的租户的自动生成的对象存储名称空间字符串。有关详细信息,请参阅“租户信息”页

OCI Swift API 缺乏区间的概念。默认情况下,使用 OCI Amazon S3 兼容 API 或 OCI Swift API 创建的存储桶是在 Oracle Cloud Infrastructure 租户的区间中创建的。您可以为 OCI Amazon S3 兼容 API 或 OCI Swift API 指定其他区间来创建存储桶。有关详细信息,请参阅编辑租户的 Amazon S3 兼容 API 和 Swift API 区间指定

OCI Swift API 支持三种验证请求的方法。

方法 1:使用基本授权标头

用户名的格式为 <username>。例如,john.doe@acme.com。如果您的租户与 Oracle Identity Cloud Service 联合,请使用 oracleidentitycloudservice/<username> 格式。

密码是为用户生成的验证令牌。例如,my-auth-token。有关详细信息,请参阅获取验证令牌

对 OCI Swift API 的每个请求都应包含以下标头。

例如,如果 username 为 oracleidentitycloudservice/john.doe@acme.com,password 为 my-auth-token,则标头将如下所示:

我们将使用官方文档中介绍的一些 API 调用,请参阅 OpenStack Swift API

示例:

  1. 初始化以下必需的环境变量

    user='<username>'
    password='<password>'
    region='<oci-region>'
    tenancy_namespace='<tenancy-namespace>'
    bucket_name='tutorial-bucket'
    object_name='sample.txt'
    
  2. 列出账户中的存储桶,将仅列出所选 OCI Swift API 区间中的存储桶。

    curl -sS -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}" -u "${user}:${password}" | jq
    
  3. 创建存储桶。

    curl -sS -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X PUT -u "${user}:${password}"
    
  4. 将文件上载到存储桶。

    echo 'sample file' > ${object_name}
    curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X PUT --data-binary "@${object_name}" -u "${user}:${password}"
    
  5. 列出存储桶内容。

    curl -sS -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -u "${user}:${password}" | jq
    
  6. 从存储桶中提取文件。

    curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -u "${user}:${password}" -o downloaded_file.txt
    cat downloaded_file.txt
    
  7. 从存储桶中删除文件。

    curl -sS -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X DELETE -u "${user}:${password}"
    
  8. 删除存储桶。

    curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X DELETE -u "${user}:${password}"
    

方法 2:使用 v1 授权进行基于令牌的身份验证

您必须为区域调用 OCI Swift API 授权端点,并在请求中包括 X-Storage-UserX-Storage-Pass 标头。如果验证请求成功,您将收到一个响应,其中包含可用于请求授权的 X-Storage-Token 标头,以及包含账户的 OCI Swift API 端点的 X-Storage-Url 标头。

X-Storage-User 标头的格式为 <tenancy-namespace>:<username>

例如,如果 tenancy-namespaceaxaxnpcrorw5,并且用户名与方法 1 相同,则标头的值为 axaxnpcrorw5:oracleidentitycloudservice/john.doe@acme.com

X-Storage-Pass 是生成的验证令牌。

示例:

  1. 初始化以下必需的环境变量

    user='<username>'
    password='<password>'
    region='<oci-region>'
    tenancy_namespace='<tenancy-namespace>'
    bucket_name='tutorial-bucket'
    object_name='sample.txt'
    
  2. 生成令牌。

    curl -sS -D swift_headers.txt https://swiftobjectstorage.eu-frankfurt-1.oraclecloud.com/auth/v1.0 -H "X-Storage-User: ${tenancy_namespace}:${user}" -H "X-Storage-Pass: ${password}"
    X_Auth_Token=$(cat swift_headers.txt | grep X-Auth-Token | cut -d":" -f 2)
    
  3. 列出账户中的存储桶,将仅列出所选 OCI Swift API 区间中的存储桶。

    curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}" -H "X-Auth-Token: ${X_Auth_Token}" | jq
    
  4. 创建存储桶。

    curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X PUT -H "X-Auth-Token: ${X_Auth_Token}"
    
  5. 将文件上载到存储桶。

    echo 'sample file' > ${object_name}
    curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X PUT --data-binary "@${object_name}" -H "X-Auth-Token: ${X_Auth_Token}"
    
  6. 列出存储桶内容。

    curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -H "X-Auth-Token: ${X_Auth_Token}" | jq
    
  7. 从存储桶中提取文件。

    curl -s -D /dev/stderr "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -H "X-Auth-Token: ${X_Auth_Token}" -o downloaded_file.txt
    cat downloaded_file.txt
    
  8. 从存储桶中删除文件。

    curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}/${object_name}" -X DELETE -H "X-Auth-Token: ${X_Auth_Token}"
    
  9. 删除存储桶。

    curl -s -i "https://swiftobjectstorage.${region}.oraclecloud.com/v1/${tenancy_namespace}/${bucket_name}" -X DELETE -H "X-Auth-Token: ${X_Auth_Token}"
    

方法 3:使用 v2 授权进行基于令牌的身份验证

为了说明 OCI Swift API v2 授权过程,我们将使用官方的 OpenStack Swift API Python 程序包 python-swiftclient 4.5.0 ,以及 v2 验证 python-keystoneclient 5.4.0 的必需依赖项。

示例:

  1. 运行以下命令以确保您可以访问 3.6 以上的 Python 版本。有关详细信息,请参见下载 Python

    python3 --version
    
  2. 安装所需的 Python 模块。

    python3 -m pip install python-swiftclient python-keystoneclient click
    
  3. 您可以使用以下代码与 OCI Swift API v2 进行交互。在运行之前,请确保在以下代码中替换 <user><password><region><tenancy-namespace> 的占位符。

    import click
    import os
    
    from swiftclient.client import Connection
    from swiftclient.exceptions import ClientException
    
    user='<username>'
    password='<password>'
    region='<oci-region>'
    tenancy_namespace='<tenancy-namespace>'
    bucket_name='tutorial-bucket'
    object_name='sample.txt'
    
    _authurl = f'https://swiftobjectstorage.{region}.oraclecloud.com/auth/v2.0/'
    _auth_version = '2'
    _user = f'{user}'
    _key = f'{password}'
    _tenant_name = f'{tenancy_namespace}'
    
    conn = Connection(
        authurl=_authurl,
        user=_user,
        key=_key,
        tenant_name=_tenant_name,
        auth_version=_auth_version
    )
    
    @click.group(invoke_without_command=True)
    @click.pass_context
    def main(ctx):
        available_commands = {
            "a": ("List buckets in the account", get_account),
            "b": ("Create a new bucket", put_container),
            "c": ("Upload an object to the bucket", put_object),
            "d": ("List objects in the bucket", get_container),
            "e": ("Download object from the bucket", get_object),
            "f": ("Delete object from the bucket", delete_object),
            "g": ("Delete bucket from the account", delete_container)
        }
        while True:
            click.echo("Available actions")
            for index, command in available_commands.items():
                click.echo(f"{index} - {command[0]}")
            action = click.prompt("Please select an option from the list")
            if action in available_commands.keys():
                ctx.invoke(available_commands[action][1])
            print("###"*10)
    
    @main.command()
    def get_account(conn=conn):
        print("Listing buckets in the account.")
        try:
            resp_headers = conn.get_account()
            for entry in resp_headers[1]:
                print(entry["name"])
        except ClientException as e:
            print(f"Failed to get the buckets in the tenancy. Error: {e}")
            raise
        else:
            print(f"Successfuly listed bucket in the '{_tenant_name}' account.")
    
    @main.command()
    def put_container(conn=conn, bucket_name=bucket_name):
        print(f"Creating a new bucket named {bucket_name}.")
        try:
            resp_headers = conn.put_container(container=bucket_name)
        except ClientException as e:
            print(f"Failed to create the new bucket named {bucket_name} in the tenancy. Error: {e}")
            raise
        else:
            print(f"The '{bucket_name}' was successfuly created.")
    
    @main.command()
    def put_object(conn=conn, bucket_name=bucket_name, object_name=object_name):
        print(f"Uploading a new file, '{object_name}' to the new bucket '{bucket_name}'.")
        try:
            if not os.path.isfile(object_name):
                with open(object_name, "w") as f:
                    f.write("sample file")
            with open(object_name) as f:
                resp_headers = conn.put_object(container=bucket_name, obj=object_name, contents=object_name)
        except ClientException as e:
            print(f"Failed to create a new object named '{object_name}' in the bucket '{bucket_name}'. Error: {e}")
            raise
        else:
            print(f"The '{object_name}' file was successfuly uploaded to '{bucket_name}' bucket.")
    
    @main.command()
    def get_container(conn=conn, bucket_name=bucket_name):
        print(f"List {bucket_name} bucket contents.")
        try:
            resp_headers = conn.get_container(container=bucket_name)
            for entry in resp_headers[1]:
                print(entry["name"])
        except ClientException as e:
            print(f"Failed to list objects in the bucket {bucket_name}. Error: {e}")
            raise
        else:
            print(f"The '{bucket_name}' content was successfuly listed.")
    
    @main.command()
    def get_object(conn=conn, bucket_name=bucket_name, object_name=object_name, dest_file="downloaded_file.txt"):
        print(f"Fetch {object_name} object from the bucket {bucket_name}.")
        try:
            resp_headers = conn.get_object(container=bucket_name, obj=object_name)
            with open(dest_file, "wb") as f:
                f.write(resp_headers[1])
        except ClientException as e:
            print(f"Failed to download {object_name} from {bucket_name} to local file named '{dest_file}'. Error: {e}")
            raise
        else:
            print(f"The '{object_name}' object was saved locally to '{dest_file}'.")
    
    @main.command()
    def delete_object(conn=conn, bucket_name=bucket_name, object_name=object_name):
        print(f"Deleting {object_name} object from the bucket {bucket_name}.")
        try:
            resp_headers = conn.delete_object(container=bucket_name, obj=object_name)
        except ClientException as e:
            print(f"Failed to delete {object_name} from {bucket_name}. Error: {e}")
            raise
        else:
            print(f"The '{object_name}' object was deleted.")
    
    @main.command()
    def delete_container(conn=conn, bucket_name=bucket_name):
        print(f"Deleting the bucket {bucket_name}.")
        try:
            resp_headers = conn.delete_container(container=bucket_name)
        except ClientException as e:
            print(f"Failed to delete {object_name} from {bucket_name}. Error: {e}")
            raise
        else:
            print(f"The '{bucket_name}' bucket was deleted.")
    
    
    if __name__ == "__main__":
        main()
    

确认

更多学习资源

浏览 docs.oracle.com/learn 上的其他实验室,或者通过 Oracle Learning YouTube 频道访问更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 以成为 Oracle Learning Explorer。

有关产品文档,请访问 Oracle 帮助中心