ノート:

Use Oracle Cloud Infrastructure Object Storage Service with OpenStack Swift API

イントロダクション

Oracle Cloud Infrastructure (OCI) Object Storageは、デジタル情報をオブジェクトとして管理および編成するデータ・ストレージ・アーキテクチャであり、それぞれがデータ、メタデータおよび一意の識別子で構成されます。従来のファイルまたはブロック・ストレージとは異なり、OCI Object Storageは階層構造に依存せず、膨大な量の非構造化データを効率的かつスケーラブルに処理できます。オブジェクトはフラットなアドレス空間に格納されるため、データの取得が簡素化され、シームレスなスケーラビリティが可能になります。このソリューションは、マルチメディアのコンテンツやバックアップなどの多様なデータ型に最適であり、柔軟性、耐久性、アクセスのしやすさにより、クラウド環境、アーカイブ・ストレージ、分散システムに対して堅牢な選択肢となります。ユーザーは、HTTPプロトコルを介してRESTインタフェースを使用してオブジェクト・ストレージ・サービスと対話します。

OCI Object Storageサービスは、Oracleが管理の複雑さを処理し、信頼性とコスト効率の高いデータ耐久性を保証するクラウドベースのストレージ・ソリューションです。プラットフォームの弾力性により、パフォーマンスやサービスの信頼性を損なうことなく、シームレスに拡張できるため、段階的に開始できます。

OCI Object Storageは、Amazon S3 Compatibility APIを通じて、OpenStack Swift APIおよびAmazon Simple Storage Service (Amazon S3)とのAPI互換性を提供します。これにより、お客様は既存のツール(SDKクライアントなど)を引き続き使用できるため、アプリケーションに変更を加える必要が最小限に抑えられます。詳細は、Amazon S3 Compatibility APIを参照してください。このチュートリアルでは、OCI OpenStack Swift互換APIの消費に焦点を当てます。

OpenStack Swift APIについて説明する前に、OCI Object Storageで使用される構成の一部を明確にする必要があります。

OpenStack Swiftでは、アカウント、コンテナおよびオブジェクトの3つの構成を定義します。

OCI Object Storageと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 Compatibility APIまたはOCI Swift APIを使用して作成されたバケットは、Oracle Cloud Infrastructureテナンシのルート・コンパートメントに作成されます。OCI Amazon S3 Compatibility APIまたはOCI Swift APIに異なるコンパートメントを指定して、バケットを作成できます。詳細は、テナンシのAmazon S3 Compatibility APIおよびSwift APIコンパートメント指定の編集を参照してください。

OCI Swift APIは、リクエストを認証するための3つのアプローチをサポートしています。

アプローチ1: 基本認証ヘッダーの使用

ユーザー名の形式は<username>です。たとえば、john.doe@acme.comです。テナントがOracle Identity Cloud Serviceとフェデレートされている場合は、oracleidentitycloudservice/<username>の書式を使用します。

パスワードは、ユーザーに対して生成された認証トークンです。たとえば、my-auth-tokenです。詳細は、認証トークンの取得を参照してください。

OCI Swift APIへの各リクエストには、次のヘッダーを含める必要があります。

たとえば、ユーザー名がoracleidentitycloudservice/john.doe@acme.comで、パスワードが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認証を使用したトークン・ベース認証

You will have to call the OCI Swift API authorization endpoint for the region and include the X-Storage-User and X-Storage-Pass headers in the request. If the authentication request is successful, you will receive a response with X-Storage-Token header that can be used for request authorization, and X-Storage-Url header with the OCI Swift API endpoint for the account.

X-Storage-Userヘッダーの形式は<tenancy-namespace>:<username>です。

たとえば、tenancy-namespaceaxaxnpcrorw5で、ユーザー名がApproach 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. List buckets in the account, only buckets from the selected OCI Swift API compartments will be listed.

    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認証を使用したトークン・ベース認証

To illustrate the OCI Swift API v2 authorization procedure, we will use the official OpenStack Swift API Python package python-swiftclient 4.5.0, and the required dependencies for the v2 auth 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 Help Centerを参照してください。