IBM Cloud Docs
Utilisation de Python

Utilisation de Python

La prise en charge de Python est possible via une déviation de la bibliothèque boto3 avec des fonctions permettant de tirer le meilleur parti d'IBM Cloud® Object Storage.

L'installation peut s'effectuer à partir de Python Package Index via la commande pip install ibm-cos-sdk.

Le code source est disponible à l'adresse suivante GitHub.

La bibliothèque ibm_boto3 fournit un accès complet à l'API IBM Cloud® Object Storage. Des noeuds finaux, une clé d'API et l'ID instance doivent être spécifiés lors de la création d'une ressource de service ou d'un client de bas niveau, comme indiqué dans les exemples de base suivants.

L'identifiant de l'instance de service est également appelé identifiant de l'instance de ressource. Vous pouvez trouver la valeur en créant des données d'identification de service ou via l'interface CLI.

Une documentation détaillée est disponible ici.

Création d'un client et sourçage de données d'identification

Pour permettre l'établissement d'une connexion à COS, un client est créé et configuré à l'aide de données d'identification (clé d'API et ID d'instance de service). Ces valeurs peuvent aussi être automatiquement sourcées à partir d'un fichier de données d'identification ou à partir de variables d'environnement.

Après avoir généré des données d'identification de service, le document JSON résultant peut être sauvegardé dans ~/.bluemix/cos_credentials. Le SDK source automatiquement les données d'identification de ce fichier, sauf si d'autres données d'identification sont explicitement définies lors de la création du client. Si le fichier cos_credentials contient des clés HMAC, le client s'authentifie avec une signature, sinon le client utilise la clé d'API fournie pour s'authentifier à l'aide d'un jeton bearer (l'utilisation d'une clé d'API nécessite toujours que le config=Config(signature_version="oauth") soit inclus lors de la création du client).

Si vous effectuez une migration à partir de AWS S3, vous pouvez également sourcer des données d'identification à partir de ~/.aws/credentials au format suivant :

[default]
aws_access_key_id = {API_KEY}
aws_secret_access_key = {SERVICE_INSTANCE_ID}

Note: Si ~/.bluemix/cos_credentials et ~/.aws/credentials existent tous les deux, cos_credentials a la préférence.

Collecte des informations requises

Les variables suivantes apparaissent dans les exemples :

Exemples de code

Les exemples de code sont testés sur les versions d'édition prises en charge de Python.

Dans votre code, vous devez supprimer les crochets ou tout autre caractère en excès qui sont fournis ici à titre d'illustration.

Initialisation de la configuration

Cet exemple crée un objet resource. Une ressource fournit une interface orientée objet à COS. Cela permet un niveau d'abstraction plus élevé que les appels de bas niveau fournis par un objet client.

Notez que certaines opérations (telles que le transfert haut débit Aspera ) nécessitent un objet client. Aspera lui-même requiert Python version 3.6.

Avis existant: la prise en charge de Aspera est considérée comme existante. A la place, utilisez Aspera Transfer SDK.

import ibm_boto3
from ibm_botocore.client import Config, ClientError

# Constants for IBM COS values
COS_ENDPOINT = "<endpoint>" # Current list avaiable at https://control.cloud-object-storage.cloud.ibm.com/v2/endpoints
COS_API_KEY_ID = "<api-key>" # eg "W00YixxxxxxxxxxMB-odB-2ySfTrFBIQQWanc--P3byk"
COS_INSTANCE_CRN = "<service-instance-id>" # eg "crn:v1:bluemix:public:cloud-object-storage:global:a/3bf0d9003xxxxxxxxxx1c3e97696b71c:d6f04d83-6c4f-4a62-a165-696756d63903::"

# Create resource
cos_resource = ibm_boto3.resource("s3",
    ibm_api_key_id=COS_API_KEY_ID,
    ibm_service_instance_id=COS_INSTANCE_CRN,
    config=Config(signature_version="oauth"),
    endpoint_url=COS_ENDPOINT
)

Un client fournit une interface de bas niveau à l'API S3 de COS. Cela permet de traiter directement les réponses HTTP, plutôt que d'utiliser les méthodes et attributs abstraits fournis par une ressource pour accéder aux informations contenues dans les en-têtes ou les charges utiles des réponses XML.


import ibm_boto3
from ibm_botocore.client import Config, ClientError

# Constants for IBM COS values
COS_ENDPOINT = "<endpoint>" # Current list avaiable at https://control.cloud-object-storage.cloud.ibm.com/v2/endpoints
COS_API_KEY_ID = "<api-key>" # eg "W00YixxxxxxxxxxMB-odB-2ySfTrFBIQQWanc--P3byk"
COS_INSTANCE_CRN = "<service-instance-id>" # eg "crn:v1:bluemix:public:cloud-object-storage:global:a/3bf0d9003xxxxxxxxxx1c3e97696b71c:d6f04d83-6c4f-4a62-a165-696756d63903::"

# Create client
cos_client = ibm_boto3.client("s3",
    ibm_api_key_id=COS_API_KEY_ID,
    ibm_service_instance_id=COS_INSTANCE_CRN,
    config=Config(signature_version="oauth"),
    endpoint_url=COS_ENDPOINT
)

Valeurs de clé

  • <endpoint>- point de terminaison public pour votre nuage Object Storage avec le schéma préfixé (' https:// ') (disponible sur le tableau de bord IBM Cloud ). Pour plus d'informations sur les noeuds finaux, voir Noeuds finaux et emplacements de stockage.
  • <api-key>- clé api générée lors de la création des identifiants du service (l'accès en écriture est requis pour les exemples de création et de suppression)
  • <service-instance-id>- iD de la ressource pour votre nuage Object Storage (disponible via IBM Cloud CLI ou IBM Cloud Dashboard )
  • <location>- emplacement par défaut de votre nuage Object Storage (doit correspondre à la région utilisée pour <endpoint>)

Références SDK

Création d'un nouveau compartiment

Les exemples ci-dessous utilisent un client qui est une interface de bas niveau.

Une liste de codes de mise à disposition valides pour LocationConstraint peut être référencée dans le guide sur les classes de stockage.

def create_bucket(bucket_name):
    print("Creating new bucket: {0}".format(bucket_name))
    try:
        cos_client.create_bucket(
            Bucket=bucket_name,
            CreateBucketConfiguration={
                "LocationConstraint":COS_BUCKET_LOCATION
            }
        )
        print("Bucket: {0} created!".format(bucket_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to create bucket: {0}".format(e))

Références SDK

Méthodes

Création d'un nouveau fichier texte

def create_text_file(bucket_name, item_name, file_text):
    print("Creating new item: {0}".format(item_name))
    try:
        cos_client.put_object(
            Bucket=bucket_name,
            Key=item_name,
            Body=file_text
        )
        print("Item: {0} created!".format(item_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to create text file: {0}".format(e))

Références SDK

Méthodes

Création de la liste des compartiments disponibles

def get_buckets():
    print("Retrieving list of buckets")
    try:
        buckets = cos_client.list_buckets()
        for bucket in buckets["Buckets"]:
            print("Bucket Name: {0}".format(bucket["Name"]))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to retrieve list buckets: {0}".format(e))

Références SDK

Méthodes

Création de la liste des éléments contenus dans un compartiment

def get_bucket_contents(bucket_name):
    print("Retrieving bucket contents from: {0}".format(bucket_name))
    try:
        files = cos_client.list_objects(Bucket=bucket_name)
        for file in files.get("Contents", []):
            print("Item: {0} ({1} bytes).".format(file["Key"], file["Size"]))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to retrieve bucket contents: {0}".format(e))

Références SDK

Méthodes

Obtention du contenu de fichier d'un élément particulier

def get_item(bucket_name, item_name):
    print("Retrieving item from bucket: {0}, key: {1}".format(bucket_name, item_name))
    try:
        file = cos_client.get_object(Bucket=bucket_name, Key=item_name)
        print("File Contents: {0}".format(file["Body"].read()))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to retrieve file contents: {0}".format(e))

Références SDK

Méthodes

Suppression d'un élément d'un compartiment

def delete_item(bucket_name, object_name):
    try:
        cos_client.delete_object(Bucket=bucket_name, Key=object_name)
        print("Item: {0} deleted!\n".format(object_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to delete object: {0}".format(e))

Références SDK

Méthodes

Suppression de plusieurs éléments d'un compartiment

La demande de suppression peut contenir un maximum de 1000 clés. Bien que cela soit utile pour réduire les performances par requête, il faut faire attention lorsque l'on supprime de nombreuses clés. Tenez compte également de la taille des objets de manière à obtenir de bonnes performances.

def delete_items(bucket_name):
    try:
        delete_request = {
            "Objects": [
                { "Key": "deletetest/testfile1.txt" },
                { "Key": "deletetest/testfile2.txt" },
                { "Key": "deletetest/testfile3.txt" },
                { "Key": "deletetest/testfile4.txt" },
                { "Key": "deletetest/testfile5.txt" }
            ]
        }

        response = cos_client.delete_objects(
            Bucket=bucket_name,
            Delete=delete_request
        )

        print("Deleted items for {0}\n".format(bucket_name))
        print(json.dumps(response.get("Deleted"), indent=4))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to copy item: {0}".format(e))

Références SDK

Méthodes

Suppression d'un compartiment

def delete_bucket(bucket_name):
    print("Deleting bucket: {0}".format(bucket_name))
    try:
        cos_client.delete_bucket(Bucket=bucket_name)
        print("Bucket: {0} deleted!".format(bucket_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to delete bucket: {0}".format(e))

Références SDK

Méthodes

Les noms des seaux sont réservés pendant 10 à 15 minutes après leur suppression.

Exécution d'un envoi par téléchargement en plusieurs parties

Envoi par téléchargement de fichier binaire (méthode préférée)

La méthode upload_fileobj de l'objet S3 exécute automatiquement un téléchargement en plusieurs parties si nécessaire. La classe TransferConfig est utilisée pour déterminer le seuil d'utilisation du téléchargement en plusieurs parties.

def multi_part_upload(bucket_name, item_name, file_path):
    try:
        print("Starting file transfer for {0} to bucket: {1}\n".format(item_name, bucket_name))
        # set 5 MB chunks
        part_size = 1024 * 1024 * 5

        # set threadhold to 15 MB
        file_threshold = 1024 * 1024 * 15

        # set the transfer threshold and chunk size
        transfer_config = ibm_boto3.s3.transfer.TransferConfig(
            multipart_threshold=file_threshold,
            multipart_chunksize=part_size
        )

        # the upload_fileobj method will automatically execute a multi-part upload
        # in 5 MB chunks for all files over 15 MB
        with open(file_path, "rb") as file_data:
            cos_client.upload_fileobj(
                Bucket=bucket_name,
                Key=item_name,
                Fileobj=file_data,
                Config=transfer_config
            )

        print("Transfer for {0} Complete!\n".format(item_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to complete multi-part upload: {0}".format(e))

Références SDK

Méthodes

Exécution manuelle d'un envoi par téléchargement en plusieurs parties

Si vous le souhaitez, la classe S3.Client peut être utilisée pour effectuer un téléchargement en plusieurs parties. Cela peut être utile si un contrôle plus important sur le processus d'envoi par téléchargement est nécessaire.

def multi_part_upload_manual(bucket_name, item_name, file_path):
    try:
        # create client object
        cos_client = ibm_boto3.client("s3",
            ibm_api_key_id=COS_API_KEY_ID,
            ibm_service_instance_id=COS_SERVICE_CRN,
            config=Config(signature_version="oauth"),
            endpoint_url=COS_ENDPOINT
        )

        print("Starting multi-part upload for {0} to bucket: {1}\n".format(item_name, bucket_name))

        # initiate the multi-part upload
        mp = cos_client.create_multipart_upload(
            Bucket=bucket_name,
            Key=item_name
        )

        upload_id = mp["UploadId"]

        # min 20MB part size
        part_size = 1024 * 1024 * 20
        file_size = os.stat(file_path).st_size
        part_count = int(math.ceil(file_size / float(part_size)))
        data_packs = []
        position = 0
        part_num = 0

        # begin uploading the parts
        with open(file_path, "rb") as file:
            for i in range(part_count):
                part_num = i + 1
                part_size = min(part_size, (file_size - position))

                print("Uploading to {0} (part {1} of {2})".format(item_name, part_num, part_count))

                file_data = file.read(part_size)

                mp_part = cos_client.upload_part(
                    Bucket=bucket_name,
                    Key=item_name,
                    PartNumber=part_num,
                    Body=file_data,
                    ContentLength=part_size,
                    UploadId=upload_id
                )

                data_packs.append({
                    "ETag":mp_part["ETag"],
                    "PartNumber":part_num
                })

                position += part_size

        # complete upload
        cos_client.complete_multipart_upload(
            Bucket=bucket_name,
            Key=item_name,
            UploadId=upload_id,
            MultipartUpload={
                "Parts": data_packs
            }
        )
        print("Upload for {0} Complete!\n".format(item_name))
    except ClientError as be:
        # abort the upload
        cos_client.abort_multipart_upload(
            Bucket=bucket_name,
            Key=item_name,
            UploadId=upload_id
        )
        print("Multi-part upload aborted for {0}\n".format(item_name))
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to complete multi-part upload: {0}".format(e))

Références SDK (suite)

Classes

Méthodes

Envoi par téléchargement d'objet volumineux à l'aide de TransferManager

TransferManager représente un autre moyen d'exécuter des transferts de fichiers volumineux en incorporant automatiquement des envois par téléchargement en plusieurs parties chaque fois que cela est nécessaire lors de la définition des paramètres de configuration.

def upload_large_file(bucket_name, item_name, file_path):
    print("Starting large file upload for {0} to bucket: {1}".format(item_name, bucket_name))

    # set the chunk size to 5 MB
    part_size = 1024 * 1024 * 5

    # set threadhold to 5 MB
    file_threshold = 1024 * 1024 * 5

    # Create client connection
    cos_client = ibm_boto3.client("s3",
        ibm_api_key_id=COS_API_KEY_ID,
        ibm_service_instance_id=COS_SERVICE_CRN,
        config=Config(signature_version="oauth"),
        endpoint_url=COS_ENDPOINT
    )

    # set the transfer threshold and chunk size in config settings
    transfer_config = ibm_boto3.s3.transfer.TransferConfig(
        multipart_threshold=file_threshold,
        multipart_chunksize=part_size
    )

    # create transfer manager
    transfer_mgr = ibm_boto3.s3.transfer.TransferManager(cos_client, config=transfer_config)

    try:
        # initiate file upload
        future = transfer_mgr.upload(file_path, bucket_name, item_name)

        # wait for upload to complete
        future.result()

        print ("Large file upload complete!")
    except Exception as e:
        print("Unable to complete large file upload: {0}".format(e))
    finally:
        transfer_mgr.shutdown()

Création de la liste des éléments contenus dans un compartiment (v2)

S3.Client du client comporte une méthode mise à jour pour répertorier le contenu (list_objects_v2). Cette méthode vous permet de limiter le nombre d'enregistrements renvoyés et d'extraire les enregistrements par lots. Cela peut s'avérer utile pour paginer vos résultats dans une application et améliorer les performances.

def get_bucket_contents_v2(bucket_name, max_keys):
    print("Retrieving bucket contents from: {0}".format(bucket_name))
    try:
        # create client object
        cos_client = ibm_boto3.client("s3",
            ibm_api_key_id=COS_API_KEY_ID,
            ibm_service_instance_id=COS_SERVICE_CRN,
            config=Config(signature_version="oauth"),
            endpoint_url=COS_ENDPOINT)

        more_results = True
        next_token = ""

        while (more_results):
            response = cos_client.list_objects_v2(Bucket=bucket_name, MaxKeys=max_keys, ContinuationToken=next_token)
            files = response["Contents"]
            for file in files:
                print("Item: {0} ({1} bytes).".format(file["Key"], file["Size"]))

            if (response["IsTruncated"]):
                next_token = response["NextContinuationToken"]
                print("...More results in next batch!\n")
            else:
                more_results = False
                next_token = ""

    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to retrieve bucket contents: {0}".format(e))

Références SDK

Méthodes

Utilisation de Key Protect

Key Protect peut être ajouté à un compartiment de stockage pour chiffrer les données sensibles qui sont au repos dans le cloud.

Avant de commencer

Les éléments suivants sont nécessaires pour créer un compartiment avec Key Protect activé :

Extraction du CRN de clé racine

  1. Extrayez l'ID d'instance pour votre service Key Protect.
  2. Utilisez l'API Key Protect pour extraire toutes vos clés disponibles.
    • Vous pouvez utiliser des commandes curl ou un client REST API, tel que Postman, pour accéder à l'API Key Protect.
  3. Extrayez le CRN de la clé racine que vous utiliserez pour activer Key Protect sur votre compartiment. Le CRN se présente comme suit :

crn:v1:bluemix:public:kms:us-south:a/3d624cd74a0dea86ed8efe3101341742:90b6a1db-0fe1-4fe9-b91e-962c327df531:key:0bg3e33e-a866-50f2-b715-5cba2bc93234

Création d'un compartiment avec Key Protect activé

COS_KP_ALGORITHM = "<algorithm>"
COS_KP_ROOTKEY_CRN = "<root-key-crn>"

# Create a new bucket with key protect (encryption)
def create_bucket_kp(bucket_name):
    print("Creating new encrypted bucket: {0}".format(bucket_name))
    try:
        cos_client.create_bucket(
            Bucket=bucket_name,
            CreateBucketConfiguration={
                "LocationConstraint":COS_BUCKET_LOCATION
            },
            IBMSSEKPEncryptionAlgorithm=COS_KP_ALGORITHM,
            IBMSSEKPCustomerRootKeyCrn=COS_KP_ROOTKEY_CRN
        )
        print("Encrypted Bucket: {0} created!".format(bucket_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to create encrypted bucket: {0}".format(e))

Valeurs de clé

  • <algorithm>- Algorithme de chiffrement utilisé pour les nouveaux objets ajoutés au seau ( AES256 par défaut).
  • <root-key-crn>- CRN de la clé racine obtenue auprès du service Key Protect.

Références SDK

Méthodes

Utilisation du Transfert haut débit Aspera

Avis existant: la prise en charge de Aspera est considérée comme existante. Il est recommandé aux utilisateurs d'utiliser Aspera Transfer SDK[https://developer.ibm.com/apis/catalog/aspera--aspera-transfer-sdk/API Reference].

Avis existant: la prise en charge de Aspera est considérée comme existante. Il est recommandé aux utilisateurs d'utiliser Aspera Transfer SDK.

En installant la bibliothèque de transfert haut débit Aspera, vous pouvez utiliser des transferts de fichiers à haut débit dans votre application. La bibliothèque Aspera est un logiciel propriétaire (closed source), il s'agit donc d'une dépendance facultative pour le SDK COS (qui utilise une licence Apache).

Chaque session Aspera génère un processus ascp individuel qui s'exécute sur la machine client pour effectuer le transfert. Assurez-vous que votre environnement de calcul puisse permettre l'exécution de ce processus.

Initialisation de AsperaTransferManager

Avant d'initialiser le site AsperaTransferManager, assurez-vous que vous disposez d'un objet fonctionnel (pas un objet ou ) client (et non un objet resource ou session).

import ibm_boto3
from ibm_botocore.client import Config
from ibm_s3transfer.aspera.manager import AsperaTransferManager

COS_ENDPOINT = "<endpoint>" # Current list avaiable at https://control.cloud-object-storage.cloud.ibm.com/v2/endpoints
COS_API_KEY_ID = "<api-key>"
COS_RESOURCE_CRN = "<resource-instance-id>"
COS_BUCKET_LOCATION = "<location>"

# Create resource
cos_client = ibm_boto3.client("s3",
    ibm_api_key_id=COS_API_KEY_ID,
    ibm_service_instance_id=COS_RESOURCE_CRN,
    config=Config(signature_version="oauth"),
    endpoint_url=COS_ENDPOINT
)

transfer_manager = AsperaTransferManager(cos)

Vous devez fournir une clé d'API IAM pour Aspera High-Speed Transfer. Les données d'identification HMAC ne sont PAS actuellement prises en charge. Pour plus d'informations sur IAM, cliquez ici.

Pour obtenir une capacité de traitement la plus élevée possible, fractionnez le transfert en un certain nombre de sessions parallèles qui envoient des blocs de données dont la taille est définie par la valeur threshold.

La configuration standard pour l'utilisation de plusieurs sessions doit être la suivante :

  • Débit cible de 2500 Mbit/s
  • Seuil de 100 Mo (il s'agit de la valeur recommandée pour la plupart des applications)
ms_transfer_config = AsperaConfig(multi_session="all",
                                  target_rate_mbps=2500,
                                  multi_session_threshold_mb=100)

Dans l'exemple ci-dessus, le SDK génère suffisamment de sessions pour tenter d'atteindre le débit cible correspondant à 2500 Mbit/s.

La gestion de session peut également être configurée explicitement dans le SDK. Cela s'avère utile si vous souhaitez obtenir un contrôle plus précis de l'utilisation du réseau.

La configuration standard pour l'utilisation de plusieurs sessions explicites doit être la suivante :

  • 2 ou 10 sessions
  • Seuil de 100 Mo (il s'agit de la valeur recommandée pour la plupart des applications)
from ibm_s3transfer.aspera.manager import AsperaConfig
# Configure 2 sessions for transfer
ms_transfer_config = AsperaConfig(multi_session=2,
                                  multi_session_threshold_mb=100)

# Create the Aspera Transfer Manager
transfer_manager = AsperaTransferManager(client=client,
                                         transfer_config=ms_transfer_config)

Pour obtenir les meilleures performances dans la plupart des scénarios, utilisez toujours plusieurs sessions afin de minimiser le traitement associé à l'instanciation d'un transfert à grande vitesse à l'adresse Aspera. **Si votre capacité réseau est d'au moins 1 Gbit/s, vous devez utiliser 10 sessions. ** Des réseaux avec une bande passante inférieure doivent utiliser 2 sessions.

Envoi par téléchargement d'un fichier

bucket_name = "<bucket-name>"
upload_filename = "<absolute-path-to-file>"
object_name = "<item-name>"

# Create Transfer manager
with AsperaTransferManager(client) as transfer_manager:

    # Perform upload
    future = transfer_manager.upload(upload_filename, bucket_name, object_name)

    # Wait for upload to complete
    future.result()

Valeurs de clé

  • <bucket-name>- nom du seau cible
  • <absolute-path-to-file>- chemin d'accès au répertoire et nom du fichier à télécharger
  • <item-name>- nom du nouveau fichier ajouté au seau

Réception par téléchargement d'un fichier

bucket_name = "<bucket-name>"
download_filename = "<absolute-path-to-file>"
object_name = "<object-to-download>"

# Create Transfer manager
with AsperaTransferManager(client) as transfer_manager:

    # Get object with Aspera
    future = transfer_manager.download(bucket_name, object_name, download_filename)

    # Wait for download to complete
    future.result()

Valeurs de clé

  • <bucket-name>- nom du godet de votre instance de service Object Storage pour lequel l'option Aspera a été activée.
  • <absolute-path-to-file>- le répertoire et le nom du fichier où enregistrer le fichier sur le système local.
  • <object-to-download>- nom du fichier à télécharger dans le panier.

Envoi par téléchargement d'un répertoire

bucket_name = "<bucket-name>"
# THIS DIRECTORY MUST EXIST LOCALLY, and have objects in it.
local_upload_directory = "<absolute-path-to-directory>"
# THIS SHOULD NOT HAVE A LEADING "/"
remote_directory = "<object prefix>"

# Create Transfer manager
with AsperaTransferManager(client) as transfer_manager:

    # Perform upload
    future = transfer_manager.upload_directory(local_upload_directory, bucket_name, remote_directory)

    # Wait for upload to complete
    future.result()

Valeurs de clé

  • <bucket-name>- nom du seau de votre instance de service Object Storage pour lequel l'option Aspera a été activée
  • <absolute-path-to-directory>- répertoire local contenant les fichiers à télécharger. Doit comporter une barre oblique (/) de début et de fin (par exemple, /Users/testuser/Documents/Upload/).
  • <object prefix>- nom du répertoire dans le seau où sont stockés les fichiers. Ne doit pas comporter de barre oblique (/) de début (par exemple, newuploads/).

Réception par téléchargement d'un répertoire

bucket_name = "<bucket-name>"
# THIS DIRECTORY MUST EXIST LOCALLY
local_download_directory = "<absolute-path-to-directory>"
remote_directory = "<object prefix>"

# Create Transfer manager
with AsperaTransferManager(client) as transfer_manager:

    # Get object with Aspera
    future = transfer_manager.download_directory(bucket_name, remote_directory, local_download_directory)

    # Wait for download to complete
    future.result()

Valeurs de clé

  • <bucket-name>- nom du seau de votre instance de service Object Storage pour lequel l'option Aspera a été activée
  • <absolute-path-to-directory>- répertoire local pour enregistrer les fichiers téléchargés. Doit avoir une barre oblique en tête et en queue / (c'est-à-dire /Users/testuser/Downloads/)
  • <object prefix>- nom du répertoire dans le seau où sont stockés les fichiers. Ne doit pas comporter de barre oblique (/) de début (par exemple, todownload/).

Utilisation des abonnés

Les abonnés offrent une certaine observabilité des transferts en associant des méthodes de rappel personnalisées. Tous les transferts passent par les phases suivantes :

Queued - In Progress - Done

Trois abonnés sont disponibles pour chaque phase :

  • CallbackOnQueued() - Appelé lorsqu'un nouveau transfert est ajouté à AsperaTransferManager.
  • CallbackOnProgress() - Appelé lorsqu'un transfert a transmis des données (déclenché de manière répétée pendant que le transfert est en cours).
  • CallbackOnDone() - Appelé lorsque le transfert est terminé.
bucket_name = "<bucket-name>"
local_download_directory = "<absolute-path-to-directory>"
remote_directory = "<object prefix>"

# Subscriber callbacks
class CallbackOnQueued(AsperaBaseSubscriber):
    def __init__(self):
        pass

    def on_queued(self, future, **kwargs):
        print("Directory download queued.")

class CallbackOnProgress(AsperaBaseSubscriber):
    def __init__(self):
        pass

    def on_progress(self, future, bytes_transferred, **kwargs):
        print("Directory download in progress: %s bytes transferred" % bytes_transferred)

class CallbackOnDone(AsperaBaseSubscriber):
    def __init__(self):
        pass

    def on_done(self, future, **kwargs):
        print("Downloads complete!")

# Create Transfer manager
transfer_manager = AsperaTransferManager(client)

# Attach subscribers
subscribers = [CallbackOnQueued(), CallbackOnProgress(), CallbackOnDone()]

# Get object with Aspera
future = transfer_manager.download_directory(bucket_name, remote_directory, local_download_directory, None, subscribers)

# Wait for download to complete
future.result()

Valeurs de clé

  • <bucket-name>- nom du seau de votre instance de service Object Storage pour lequel l'option Aspera a été activée
  • <absolute-path-to-directory>- répertoire local pour enregistrer les fichiers téléchargés. Doit comporter une barre oblique (/) de début et de fin (par exemple, /Users/testuser/Downloads/).
  • <object prefix>- nom du répertoire dans le seau où sont stockés les fichiers. Ne doit pas comporter de barre oblique (/) de début (par exemple, todownload/).

L'exemple de code ci-dessus produit le résultat suivant :

Directory download queued.
Directory download in progress: 5632 bytes transferred
Directory download in progress: 1047552 bytes transferred
...
Directory download in progress: 53295130 bytes transferred
Directory download in progress: 62106855 bytes transferred
Download complete!

Pause/Reprise/Annulation

Le SDK permet de gérer la progression des transferts de fichiers/répertoires via les méthodes suivantes de l'objet AsperaTransferFuture :

  • pause()
  • resume()
  • cancel()

Il n'y a pas d'effets secondaires liés à l'appel de l'une ou l'autre des méthodes ci-dessus. Le nettoyage adéquat est géré par le SDK.

# Create Transfer manager
bucket_name = "<bucket-name>"
local_download_directory = "<absolute-path-to-directory>"
remote_directory = "<object prefix>"

with AsperaTransferManager(client) as transfer_manager:

    # download a directory with Aspera
    future = transfer_manager.download_directory(bucket_name, remote_directory, local_download_directory, None, None)

    # pause the transfer
    future.pause()

    # resume the transfer
    future.resume()

    # cancel the transfer
    future.cancel()

Traitement des incidents liés à Aspera

Problème: Les développeurs qui utilisent n'importe quelle version de Python en plus de 3.6 peuvent rencontrer des échecs lors de l'installation ou de l'utilisation de Aspera SDK.

Cause : Si différentes versions de Python sont installées dans votre environnement, il se peut que vous rencontriez des problèmes d'installation lorsque vous essayez d'installer Aspera SDK. Cela peut être dû à un fichier DLL manquant ou à une DLL incorrecte dans le chemin.

Solution : en premier lieu, réinstallez les bibliothèques Aspera. Il se peut que leur installation ait échoué. Cela peut avoir affecté les fichiers DLL. Si cela ne permet pas de résoudre les problèmes, vous serez obligé de mettre à jour votre version de Python. Si vous ne pouvez pas le faire, vous pouvez utiliser l'installation Intel® Distribution for Python *. Cela doit vous permettre d'installer le Aspera SDK sur Python 3.6.x sans aucun problème.

Mise à jour des métadonnées

Il existe deux manières de mettre à jour les métadonnées sur un objet existant :

  • Exécuter une demande PUT avec les nouvelles métadonnées et le contenu de l'objet d'origine
  • Exécuter une demande COPY avec les nouvelles métadonnées en spécifiant l'objet d'origine comme source de la copie

Utilisation de PUT pour mettre à jour les métadonnées

Remarque : la demande PUT écrase le contenu existant de l'objet, qui doit donc d'abord être téléchargé et rechargé avec les nouvelles métadonnées.

def update_metadata_put(bucket_name, item_name, key, value):
    try:
        # retrieve the existing item to reload the contents
        response = cos_client.get_object(Bucket=bucket_name, Key=item_name)
        existing_body = response.get("Body").read()

        # set the new metadata
        new_metadata = {
            key: value
        }

        cos_client.put_object(Bucket=bucket_name, Key=item_name, Body=existing_body, Metadata=new_metadata)

        print("Metadata update (PUT) for {0} Complete!\n".format(item_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        log_error("Unable to update metadata: {0}".format(e))

Utilisation de COPY pour mettre à jour les métadonnées

def update_metadata_copy(bucket_name, item_name, key, value):
    try:
        # set the new metadata
        new_metadata = {
            key: value
        }

        # set the copy source to itself
        copy_source = {
            "Bucket": bucket_name,
            "Key": item_name
        }

        cos_client.copy_object(Bucket=bucket_name, Key=item_name, CopySource=copy_source, Metadata=new_metadata, MetadataDirective="REPLACE")

        print("Metadata update (COPY) for {0} Complete!\n".format(item_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        log_error("Unable to update metadata: {0}".format(e))

Utilisation d'Immutable Object Storage

Ajout d'une configuration de protection à un compartiment existant

Les objets écrits dans un compartiment protégé ne peuvent pas être supprimés tant que la période de protection n'est pas arrivée à expiration et que les conservations légales associées à l'objet n'ont pas toutes été retirées. La valeur de conservation par défaut du compartiment est attribuée à un objet, sauf si une valeur spécifique à l'objet est fournie lors de la création de l'objet. Lorsqu'ils sont écrasés, les objets des compartiments protégés auxquels plus aucune règle de conservation ne s'applique (la durée de conservation est arrivée à expiration et aucune conservation légale n'est associée à l'objet) sont de nouveau soumis à une durée de conservation. La nouvelle durée de conservation peut être fournie dans la demande d'écrasement de l'objet ou bien la durée de conservation par défaut du compartiment est attribuée à l'objet.

Les valeurs minimales et maximales prises en charge pour les paramètres de la période de conservation MinimumRetention, DefaultRetention et MaximumRetention sont un minimum de 0 jour et un maximum de 365243 jours (1000 ans).

def add_protection_configuration_to_bucket(bucket_name):
    try:
        new_protection_config = {
            "Status": "Retention",
            "MinimumRetention": {"Days": 10},
            "DefaultRetention": {"Days": 100},
            "MaximumRetention": {"Days": 1000}
        }

        cos_client.put_bucket_protection_configuration(Bucket=bucket_name, ProtectionConfiguration=new_protection_config)

        print("Protection added to bucket {0}\n".format(bucket_name))
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to set bucket protection config: {0}".format(e))

Vérification de la protection d'un compartiment

def get_protection_configuration_on_bucket(bucket_name):
    try:
        response = cos_client.get_bucket_protection_configuration(Bucket=bucket_name)
        protection_config = response.get("ProtectionConfiguration")

        print("Bucket protection config for {0}\n".format(bucket_name))
        print(protection_config)
        print("\n")
    except ClientError as be:
        print("CLIENT ERROR: {0}\n".format(be))
    except Exception as e:
        print("Unable to get bucket protection config: {0}".format(e))

Envoi par téléchargement d'un objet protégé

Lorsqu'ils sont écrasés, les objets des compartiments protégés auxquels plus aucune règle de conservation ne s'applique (la durée de conservation est arrivée à expiration et aucune conservation légale n'est associée à l'objet) sont de nouveau soumis à une durée de conservation. La nouvelle durée de conservation peut être fournie dans la demande d'écrasement de l'objet ou bien la durée de conservation par défaut du compartiment est attribuée à l'objet.

Valeur Type Description
Retention-Period Entier non négatif (secondes) Durée de conservation, exprimée en secondes, pendant laquelle stocker l'objet. L'objet ne peut être ni écrasé, ni supprimé tant que la durée de conservation n'est pas écoulée. Si cette zone et la zone Retention-Expiration-Date sont spécifiées, un code d'erreur 400 est renvoyé. Si aucune de ces deux zones n'est spécifiée, la période DefaultRetention du compartiment est utilisée. Zéro (0) est une valeur légale qui part du principe que la durée de conservation minimale du compartiment est également fixée à 0.
Retention-expiration-date Date (format ISO 8601) Date à laquelle la suppression ou la modification de l'objet devient légale. Vous pouvez uniquement spécifier cette zone ou bien la zone d'en-tête Retention-Period. Si ces deux zones sont spécifiées, un code d'erreur 400 est renvoyé. Si aucune de ces deux zones n'est spécifiée, la durée de conservation par défaut du compartiment est utilisée.
Retention-legal-hold-id chaîne Conservation légale unique à appliquer à l'objet. Une conservation légale est une chaîne comportant Y caractères. L'objet ne peut être ni écrasé ni supprimé tant que les conservations légales associées à l'objet n'ont pas toutes été retirées.
def put_object_add_legal_hold(bucket_name, object_name, file_text, legal_hold_id):
    print("Add legal hold {0} to {1} in bucket {2} with a putObject operation.\n".format(legal_hold_id, object_name, bucket_name))
    cos_client.put_object(
        Bucket=bucket_name,
        Key=object_name,
        Body=file_text,
        RetentionLegalHoldId=legal_hold_id)
    print("Legal hold {0} added to object {1} in bucket {2}\n".format(legal_hold_id, object_name, bucket_name))

def copy_protected_object(source_bucket_name, source_object_name, destination_bucket_name, new_object_name):
    print("Copy protected object {0} from bucket {1} to {2}/{3}.\n".format(source_object_name, source_bucket_name, destination_bucket_name, new_object_name))

    copy_source = {
        "Bucket": source_bucket_name,
        "Key": source_object_name
    }

    cos_client.copy_object(
        Bucket=destination_bucket_name,
        Key=new_object_name,
        CopySource=copy_source,
        RetentionDirective="Copy"
    )

    print("Protected object copied from {0}/{1} to {2}/{3}\n".format(source_bucket_name, source_object_name, destination_bucket_name, new_object_name));

def complete_multipart_upload_with_retention(bucket_name, object_name, upload_id, retention_period):
    print("Completing multi-part upload for object {0} in bucket {1}\n".format(object_name, bucket_name))
    cos_client.complete_multipart_upload(
        Bucket=bucket_name,
        Key=object_name,
        MultipartUpload={
            "Parts":[{
                "ETag": part["ETag"],
                "PartNumber": 1
            }]
        },
        UploadId=upload_id,
        RetentionPeriod=retention_period
    )

    print("Multi-part upload completed for object {0} in bucket {1}\n".format(object_name, bucket_name))

def upload_file_with_retention(bucket_name, object_name, path_to_file, retention_period):
    print("Uploading file {0} to object {1} in bucket {2}\n".format(path_to_file, object_name, bucket_name))

    args = {
        "RetentionPeriod": retention_period
    }

    cos_client.upload_file(
        Filename=path_to_file,
        Bucket=bucket_name,
        Key=object_name,
        ExtraArgs=args
    )

    print("File upload complete to object {0} in bucket {1}\n".format(object_name, bucket_name))

Prolongement de la durée de conservation d'un objet protégé

La durée de conservation d'un objet ne peut être que prolongée. La valeur actuellement configurée ne peut pas être diminuée.

La valeur de prolongement de la conservation est définie de l'une des trois façons suivantes :

  • En ajoutant une durée supplémentaire par rapport à la valeur en cours (Additional-Retention-Period ou méthode similaire)
  • En définissant une nouvelle période de prolongement, exprimée en secondes (Extend-Retention-From-Current-Time ou méthode similaire)
  • En définissant une nouvelle date d'expiration de la conservation de l'objet (New-Retention-Expiration-Date ou méthode similaire)

La durée de conservation en cours qui est stockée dans les métadonnées de l'objet est soit augmentée de la durée prolongée indiquée, soit remplacée par la nouvelle valeur, en fonction du paramètre défini dans la demande extendRetention. Dans tous les cas, le paramètre de prolongement de la conservation est vérifié par rapport à la durée de conservation en cours et le paramètre de prolongement n'est accepté que si la durée de conservation mise à jour est supérieure à la durée de conservation en cours.

Lorsqu'ils sont écrasés, les objets des compartiments protégés auxquels plus aucune règle de conservation ne s'applique (la durée de conservation est arrivée à expiration et aucune conservation légale n'est associée à l'objet) sont de nouveau soumis à une durée de conservation. La nouvelle durée de conservation peut être fournie dans la demande d'écrasement de l'objet ou bien la durée de conservation par défaut du compartiment est attribuée à l'objet.

def extend_retention_period_on_object(bucket_name, object_name, additional_seconds):
    print("Extend the retention period on {0} in bucket {1} by {2} seconds.\n".format(object_name, bucket_name, additional_seconds))

    cos_client.extend_object_retention(
        Bucket=bucket_ame,
        Key=object_name,
        AdditionalRetentionPeriod=additional_seconds
    )

    print("New retention period on {0} is {1}\n".format(object_name, additional_seconds))

Création de la liste des conservations légales associées à un objet protégé

Cette opération renvoie les éléments suivants :

  • La date de création de l'objet
  • La durée de conservation, exprimée en secondes
  • La date d'expiration de la conservation, calculée sur la base de la durée de conservation et de la date de création
  • La liste des conservations légales
  • L'identificateur de conservation légale
  • L'horodatage correspondant à l'application de la conservation légale

Si aucune conservation légale n'est associée à l'objet, un élément LegalHoldSet vide est renvoyé. Si aucune durée de conservation n'est spécifiée pour l'objet, un code d'erreur 404 est renvoyé.

def list_legal_holds_on_object(bucket_name, object_name):
    print("List all legal holds on object {0} in bucket {1}\n".format(object_name, bucket_name));

    response = cos_client.list_legal_holds(
        Bucket=bucket_name,
        Key=object_name
    )

    print("Legal holds on bucket {0}: {1}\n".format(bucket_name, response))

Créer un site Web statique hébergé

Cette opération requiert des droits d'accès, car seul le propriétaire du compartiment est généralement autorisé à configurer un compartiment pour héberger un site Web statique. Les paramètres déterminent le suffixe par défaut pour les visiteurs du site ainsi qu'un document d'erreur facultatif.

def putBucketWebsiteConfiguration(bucket_name):
    website_defaults = {
        'ErrorDocument': {'Key': 'error.html'},
        'IndexDocument': {'Suffix': 'index.html'},
    }
    cos_client.put_bucket_website(Bucket=bucket_name, WebsiteConfiguration=website_defaults)
    print("Website configuration set on bucket {0}\n".format(bucket_name))

Etapes suivantes

Pour plus d'informations, le code source est disponible à l'adresse GitHub.