Utilización de Python
El soporte de Python se proporciona a través de una bifurcación de la biblioteca boto3
con características para sacar el máximo provecho de IBM Cloud® Object Storage.
Se puede instalar desde el índice de paquetes de Python con pip install ibm-cos-sdk
.
El código fuente se encuentra en GitHub.
La biblioteca ibm_boto3
ofrece acceso completo a la API de IBM Cloud® Object Storage. Los puntos finales, una clave de API y el ID de instancia se deben especificar durante la creación de un recurso de servicio o un cliente de bajo
nivel, tal como se muestra en los siguientes ejemplos básicos.
El ID de instancia de servicio también se denomina ID de instancia de recurso. Puede encontrar el valor creando una credencial de servicio o a través de la CLI.
Encontrará documentación detallada aquí.
Creación de credenciales de cliente y de origen
Para conectar con COS, se crea y se configura un cliente utilizando la información de las credenciales (clave de API e ID de instancia de servicio). Estos valores también se pueden tomar automáticamente de un archivo de credenciales o de variables de entorno.
Después de generar una credencial de servicio, el documento JSON resultante se puede guardar en ~/.bluemix/cos_credentials
. El SDK tomará automáticamente
las credenciales de este archivo, a menos que se establezcan explícitamente otras credenciales durante la creación del cliente. Si el archivo cos_credentials
contiene claves HMAC, el cliente se autentica con una firma; de lo contrario,
el cliente utiliza la clave de API proporcionada para autenticarse utilizando una señal portadora (el uso de una clave de API todavía requiere que se incluya config=Config(signature_version="oauth")
durante la creación
del cliente).
Si se migra desde AWS S3, también puede obtener los datos de credenciales de origen de ~/.aws/credentials
en el formato:
[default]
aws_access_key_id = {API_KEY}
aws_secret_access_key = {SERVICE_INSTANCE_ID}
Nota: Si existen tanto ~/.bluemix/cos_credentials
como ~/.aws/credentials
, cos_credentials
tiene preferencia.
Obtención de la información necesaria
En los ejemplos aparecen las variables siguientes:
bucket_name
debe ser una serie exclusiva y DNS segura. Puesto que los nombres de grupo son exclusivos en todo el sistema, estos valores se tienen que modificar si este ejemplo se ejecuta varias veces. Tenga en cuenta que los nombres se reservan entre 10 y 15 minutos tras su supresión.ibm_api_key_id
es el valor que se encuentra en la credencial de servicio comoapikey
.ibm_service_instance_id
es el valor que se encuentra en la credencial de servicio comoresource_instance_id
.endpoint_url
es un URL de punto final de servicio, incluido el protocolohttps://
. No es el valor deendpoints
que se encuentra en la credencial de servicio. Para obtener más información sobre puntos finales, consulte Puntos finales y ubicaciones de almacenamiento.LocationConstraint
es un código de suministro válido que se corresponde con el valor deendpoint
.
Ejemplos de código
Los ejemplos de código se prueban en versiones de release soportadas de Python.
En el código, debe eliminar los corchetes angulados o cualquier otro exceso de caracteres que se proporcionan aquí como ilustración.
Inicialización de la configuración
Este ejemplo crea un objeto resource
. Un recurso proporciona una interfaz orientada a objetos para COS. Esto permite un nivel más alto de abstracción que las llamadas de bajo nivel proporcionadas por un objeto de cliente.
Tenga en cuenta que algunas operaciones (como la transferencia de alta velocidad de Aspera ) requieren un objeto client
. El propio Aspera requiere Python versión 3.6.
Aviso heredado: el soporte para Aspera se considera heredado. En su lugar, utilice el 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 cliente proporciona una interfaz de bajo nivel a la API de COS S3. Esto permite procesar directamente las respuestas de HTTP, en lugar de hacer uso de métodos y atributos abstractos proporcionados por un recurso para acceder a la información contenida en las cabeceras o en las cargas útiles de respuesta 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
)
Valores de clave
<endpoint>
- punto final público para su nube Object Storage con el esquema prefijado (' https:// ') (disponible en IBM Cloud Dashboard ). Para obtener más información sobre puntos finales, consulte Puntos finales y ubicaciones de almacenamiento.<api-key>
- clave api generada al crear las credenciales de servicio (se requiere acceso de escritura para los ejemplos de creación y eliminación)<service-instance-id>
- iD de recurso para su nube Object Storage (disponible a través de IBM Cloud CLI o IBM Cloud Dashboard )<location>
- ubicación por defecto para su nube Object Storage (debe coincidir con la región que se utiliza para<endpoint>
)
Referencias de SDK
Creación de un nuevo grupo
Los ejemplos siguientes utilizan un cliente que es una interfaz de bajo nivel.
Puede consultar la lista de códigos de suministro válidos para LocationConstraint
en la guía de Storage Classes.
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))
Referencias de SDK
Métodos
Creación de un nuevo archivo de texto
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))
Referencias de SDK
Métodos
Obtención de una lista de grupos 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))
Referencias de SDK
Métodos
Obtención de la lista de elementos de un grupo
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))
Referencias de SDK
Métodos
Obtención del contenido de archivo de un elemento determinado
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))
Referencias de SDK
Métodos
Supresión de un elemento de un grupo
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))
Referencias de SDK
Métodos
Supresión de varios elementos de un grupo
La solicitud de supresión puede contener un máximo de 1000 claves que desea suprimir. Aunque esto es útil para reducir el impacto en el rendimiento por petición, tenga cuidado al borrar muchas claves. Tenga también en cuenta los tamaños de los objetos para garantizar un rendimiento adecuado.
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))
Referencias de SDK
Métodos
Supresión de un grupo
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))
Referencias de SDK
Métodos
Los nombres de los cubos se reservan durante 10 - 15 minutos tras su eliminación.
Ejecución de una carga de varias partes
Carga del archivo binario (método recomendado)
El método upload_fileobj
del objeto S3 ejecuta automáticamente una carga multiparte
cuando es necesario. La clase TransferConfig sirve para determinar el umbral de utilización de la carga
multiparte.
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))
Referencias de SDK
Métodos
Ejecución manual de una carga de varias partes
Si se desea, la clase S3.Client se puede utilizar para realizar una carga multiparte. Esto puede ser útil si se necesita más control sobre el proceso de carga.
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))
Referencias de SDK continuadas
Clases
Métodos
Carga de objetos grandes mediante TransferManager
TransferManager
proporciona otra forma de ejecutar transferencias de archivos de gran tamaño incorporando automáticamente las cargas de varias partes siempre que sea necesario mediante el establecimiento de parámetros de configuración.
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()
Obtención de la lista de elementos de un grupo (v2)
S3.Client de cliente tiene un método actualizado para listar el contenido (list_objects_v2). Este método le permite limitar el número de registros que se devuelven y recuperar los registros por lotes. Esto puede resultar útil para paginar los resultados dentro de una aplicación y mejorar el rendimiento.
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))
Referencias de SDK
Métodos
Utilización de Key Protect
Key Protect se puede añadir a un grupo de almacenamiento para cifrar los datos confidenciales en reposo en la nube.
Antes de empezar
Se necesitan los elementos siguientes para crear un grupo con Key Protect habilitado:
- Un servicio de Key Protect suministrado
- Una clave raíz disponible (ya sea generada o importada)
Recuperación del CRN de la clave raíz
- Recupere el ID de instancia del servicio Key Protect
- Utilice la API de Key Protect para recuperar todas las claves disponibles
- Puede utilizar mandatos
curl
o un cliente de API REST, como Postman, para acceder a la API de Key Protect.
- Puede utilizar mandatos
- Recupere el CRN de la clave raíz que utilizará para activar Key Protect en el grupo. El CRN tiene un aspecto similar al siguiente:
crn:v1:bluemix:public:kms:us-south:a/3d624cd74a0dea86ed8efe3101341742:90b6a1db-0fe1-4fe9-b91e-962c327df531:key:0bg3e33e-a866-50f2-b715-5cba2bc93234
Creación de un grupo con Key Protect habilitado
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))
Valores de clave
<algorithm>
- El algoritmo de encriptación que se utiliza para los nuevos objetos añadidos al cubo (por defecto es AES256 ).<root-key-crn>
- CRN de la clave raíz que se obtiene del servicio Key Protect.
Referencias de SDK
Métodos
Utilización de la transferencia de alta velocidad de Aspera
Aviso heredado: el soporte para Aspera se considera heredado. Se recomienda a los usuarios que utilicen Aspera Transfer SDK[https://developer.ibm.com/apis/catalog/aspera--aspera-transfer-sdk/API Reference].
Aviso heredado: el soporte para Aspera se considera heredado. Se recomienda a los usuarios que utilicen Aspera Transfer SDK.
Si instala la biblioteca de transferencia de alta velocidad de Aspera, puede utilizar transferencias de archivos de alta velocidad dentro de la aplicación. La biblioteca de Aspera es de origen cerrado y, por lo tanto, una dependencia opcional para el SDK de COS (que utiliza una licencia de Apache).
Cada sesión de Aspera crea un proceso ascp
individual que se ejecuta en la máquina cliente para realizar la transferencia. Asegúrese de que su entorno permita ejecutar dicho proceso.
Inicialización de AsperaTransferManager
Antes de inicializar el AsperaTransferManager
, asegúrese de que tiene un objeto en funcionamiento client
(no un objeto resource
o 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)
Tiene que proporcionar una clave de API de IAM para las transferencias de alta velocidad de Aspera. Las credenciales HMAC NO están soportadas actualmente. Para obtener más información acerca de IAM, pulse aquí.
Para optimizar el rendimiento, divida la transferencia en un número especificado de sesiones paralelas que enviarán fragmentos de datos cuyo tamaño está definido por el valor threshold.
La configuración típica para utilizar la multisesión sería la siguiente:
- Tasa objetivo de 2500 MBps
- Umbral de 100 MB (este es el valor recomendado para la mayoría de aplicaciones)
ms_transfer_config = AsperaConfig(multi_session="all",
target_rate_mbps=2500,
multi_session_threshold_mb=100)
En el ejemplo anterior, el sdk abarca suficientes sesiones para intentar alcanzar la tasa objetivo de 2500 MBps.
La gestión de sesiones también se puede configurar de forma explícita en el SDK. Esto resulta útil en los casos en los que se desea un control más preciso sobre la utilización de la red.
La configuración típica para utilizar la multisesión explícita sería la siguiente:
- 2 o 10 sesiones
- Umbral de 100 MB (este es el valor recomendado para la mayoría de aplicaciones)
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)
Para obtener el mejor rendimiento en la mayoría de los escenarios, utilice siempre varias sesiones para minimizar el procesamiento asociado a la instanciación de una transferencia de alta velocidad Aspera. Si la capacidad de red es como mínimo de 1 Gbps, debe utilizar 10 sesiones. Las redes de ancho de banda inferior deben utilizar dos sesiones.
Carga de archivos
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()
Valores de clave
<bucket-name>
- nombre del cubo de destino<absolute-path-to-file>
- ruta del directorio y nombre del archivo que se va a cargar<item-name>
- nombre del nuevo archivo añadido al cubo
Descarga de archivos
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()
Valores de clave
<bucket-name>
- nombre del bucket en su instancia de servicio Object Storage que tiene Aspera habilitado.<absolute-path-to-file>
- directorio y nombre de archivo donde guardar el archivo en el sistema local.<object-to-download>
- nombre del archivo en el cubo para descargar.
Carga de directorios
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()
Valores de clave
<bucket-name>
- nombre del bucket de su instancia de servicio Object Storage que tiene habilitado Aspera<absolute-path-to-directory>
- directorio local que contiene los archivos que se van a cargar. Debe tener un signo/
inicial y final (es decir,/Users/testuser/Documents/Upload/
)<object prefix>
- nombre del directorio en el bucket para almacenar los archivos. No debe tener una barra inclinada/
inicial (es decir,newuploads/
)
Descarga de directorios
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()
Valores de clave
<bucket-name>
- nombre del bucket de su instancia de servicio Object Storage que tiene habilitado Aspera<absolute-path-to-directory>
- directorio local para guardar los archivos descargados. Debe tener barra inicial y final/
(es decir/Users/testuser/Downloads/
)<object prefix>
- nombre del directorio en el bucket para almacenar los archivos. No debe tener una barra inclinada/
inicial (es decir,todownload/
)
Utilización de suscriptores
Los suscriptores facilitan la observación de las transferencias, mediante la conexión de métodos personalizados de devolución de llamada. Todas las transferencias pasan por las fases siguientes:
Queued - In Progress - Done
Hay tres suscriptores disponibles para cada fase:
CallbackOnQueued()
: se le llama cuando se añade una nueva transferencia aAsperaTransferManager
CallbackOnProgress()
: se le llama cuando una transferencia ha transmitido datos (se activa de forma repetida mientras la transferencia está en curso).CallbackOnDone()
: se le llama cuando finaliza la transferencia
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()
Valores de clave
<bucket-name>
- nombre del bucket de su instancia de servicio Object Storage que tiene habilitado Aspera<absolute-path-to-directory>
- directorio local para guardar los archivos descargados. Debe tener una barra inclinada/
inicial y final (es decir,/Users/testuser/Downloads/
)<object prefix>
- nombre del directorio en el bucket para almacenar los archivos. No debe tener una barra inclinada/
inicial (es decir,todownload/
)
El código de ejemplo anterior genera la salida siguiente:
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!
Pausa/Reanudación/Cancelación
El SDK proporciona la capacidad de gestionar el progreso de las transferencias de archivos/directorios mediante los métodos siguientes del objeto AsperaTransferFuture
:
pause()
resume()
cancel()
No hay efectos secundarios de llamar a ninguno de los métodos mostrados anteriormente. El SDK se encarga de realizar la limpieza correspondiente.
# 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()
Resolución de problemas de Aspera
Problema: Los desarrolladores que utilizan cualquier versión de Python además de 3.6 pueden experimentar errores al instalar o utilizar Aspera SDK.
Causa: Si hay diferentes versiones de Python instaladas en su entorno, es posible que se produzcan fallos de instalación al intentar instalar Aspera SDK. Pueden deberse a que falten archivos DLL o a que haya una DLL errónea en la variable path.
Solución: el primer paso para solucionar este problema sería volver a instalar las bibliotecas de Aspera. Puede que se haya producido un error durante la instalación. Como resultado, esto podría haber afectado a los archivos DLL. Si eso no soluciona los problemas, tendrá que actualizar la versión de Python. Si no puede hacerlo, puede utilizar la instalación Intel® Distribution para Python *. Esto debería permitirle instalar el Aspera SDK en Python 3.6.x sin ningún problema.
Actualización de metadatos
Hay dos formas de actualizar los metadatos de un objeto existente:
- Una solicitud
PUT
con los nuevos metadatos y el contenido del objeto original - Ejecución de una solicitud
COPY
con los nuevos metadatos que especifican el objeto original como origen de la copia
Utilización de PUT para actualizar metadatos
Nota: La solicitud PUT
sobrescribe el contenido existente del objeto, por lo que primero debe descargarse y volver a cargarse con los nuevos metadatos.
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))
Utilización de COPY para actualizar metadatos
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))
Utilización de Immutable Object Storage
Adición de una configuración de protección a un grupo existente
Los objetos que se escriben en un grupo protegido no se pueden suprimir hasta que transcurre el periodo de protección y se eliminan todas las retenciones legales sobre el objeto. Se proporciona el valor de retención predeterminado del grupo a un objeto a menos que se proporcione un valor específico de objeto cuando se crea el objeto. Los objetos de grupos protegidos que ya no están bajo retención (el periodo de retención ha caducado y el objeto no tiene retenciones legales) vuelven a estar bajo retención cuando se sobrescriben. El nuevo periodo de retención se puede proporcionar como parte de la solicitud de sobrescritura del objeto o se asigna el tiempo de retención predeterminado del grupo al objeto.
Los valores mínimo y máximo admitidos para los ajustes del periodo de retención MinimumRetention
, DefaultRetention
, y MaximumRetention
son un mínimo de 0 días y un máximo de 365243 días (1000 años).
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))
Comprobación de la protección sobre un grupo
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))
Carga de un objeto protegido
Los objetos de grupos protegidos que ya no están bajo retención (el periodo de retención ha caducado y el objeto no tiene retenciones legales) vuelven a estar bajo retención cuando se sobrescriben. El nuevo periodo de retención se puede proporcionar como parte de la solicitud de sobrescritura del objeto o se asigna el tiempo de retención predeterminado del grupo al objeto.
Valor | Tipo | Descripción |
---|---|---|
Retention-Period |
Entero no negativo (segundos) | Periodo de retención para almacenar el objeto en segundos. El objeto no se puede sobrescribir ni suprimir hasta que transcurre el periodo de tiempo especificado en el período de retención. Si se especifica este campo y Retention-Expiration-Date ,
se devuelve el error 400 . Si no se especifica ninguno de los dos, se utiliza el periodo DefaultRetention del grupo. Cero (0 ) es un valor válido, siempre y cuando el periodo mínimo de retención
del grupo también sea 0 . |
Retention-expiration-date |
Fecha (formato ISO 8601) | Fecha en la que se podrá suprimir o modificar el objeto. Solo puede especificar esta cabecera o la cabecera Retention-Period. Si se especifican ambas, se devuelve el error 400 . Si no se especifica ninguna de los dos, se
utiliza el periodo DefaultRetention del grupo. |
Retention-legal-hold-id |
serie | Una sola retención legal que se aplicará al objeto. Una retención legal es una serie larga de caracteres Y. El objeto no se puede sobrescribir ni suprimir hasta que se eliminen todas las retenciones legales asociadas con el objeto. |
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))
Adición o eliminación de una retención legal de un objeto protegido
El objeto da soporte a 100 retenciones legales:
- Un identificador de retención legal es una serie de caracteres con una longitud máxima de 64 caracteres y una longitud mínima de 1 carácter. Los caracteres válidos son letras, números y los símbolos
!
,_
,.
,*
,(
,)
y-
. - Si la adición de la retención legal especificada supera las 100 retenciones legales en total del objeto, la nueva retención legal no se añade y se devuelve el error
400
. - Si un identificador es demasiado largo, no se añade al objeto y se devuelve el error
400
. - Si un identificador contiene caracteres no válidos, no se añade al objeto y se devuelve el error
400
. - Si un identificador ya se está utilizando sobre un objeto, la retención legal existente no se modifica y la respuesta indica que el identificador ya se está utilizando con el error
409
. - Si un objeto no tiene metadatos de periodo de retención, se devuelve el error
400
y no se permite añadir ni eliminar una retención legal.
Para añadir o eliminar una retención legal, debe tener permisos Manager
para este grupo.
def add_legal_hold_to_object(bucket_name, object_name, legal_hold_id):
print("Adding legal hold {0} to object {1} in bucket {2}\n".format(legal_hold_id, object_name, bucket_name))
cos_client.add_legal_hold(
Bucket=bucket_name,
Key=object_name,
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 delete_legal_hold_from_object(bucket_name, object_name, legal_hold_id):
print("Deleting legal hold {0} from object {1} in bucket {2}\n".format(legal_hold_id, object_name, bucket_name))
cos_client.delete_legal_hold(
Bucket=bucket_name,
Key=object_name,
RetentionLegalHoldId=legal_hold_id
)
print("Legal hold {0} deleted from object {1} in bucket {2}!\n".format(legal_hold_id, object_name, bucket_name))
Ampliación del periodo de retención de un objeto protegido
El periodo de retención de un objeto solo se puede ampliar. No se puede reducir con respecto al valor configurado actualmente.
El valor de ampliación de retención se establece de una de las tres maneras siguientes:
- tiempo adicional a partir del valor actual (
Additional-Retention-Period
o un método similar) - nuevo periodo de ampliación en segundos (
Extend-Retention-From-Current-Time
o un método similar) - nueva fecha de caducidad de retención del objeto (
New-Retention-Expiration-Date
o método similar)
El periodo de retención actual almacenado en los metadatos de objeto se incrementa en el tiempo adicional especificado o bien se sustituye por el nuevo valor, en función del parámetro establecido en la solicitud extendRetention
.
En cualquiera de los casos, el parámetro de retención de ampliación se comprueba con respecto al periodo de retención actual y el parámetro ampliado solo se acepta si el periodo de retención actualizado es mayor que el periodo de retención
actual.
Los objetos de grupos protegidos que ya no están bajo retención (el periodo de retención ha caducado y el objeto no tiene retenciones legales) vuelven a estar bajo retención cuando se sobrescriben. El nuevo periodo de retención se puede proporcionar como parte de la solicitud de sobrescritura del objeto o se asigna el tiempo de retención predeterminado del grupo al objeto.
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))
Obtención de una lista de las retenciones legales sobre un objeto protegido
Esta operación devuelve:
- Fecha de creación del objeto
- Periodo de retención del objeto en segundos
- Fecha de caducidad de retención calculada en función del periodo y de la fecha de creación
- Lista de retenciones legales
- Identificador de retención legal
- Indicación de fecha y hora en que se ha aplicado la retención legal
Si no hay ninguna retención legal sobre el objeto, se devuelve un LegalHoldSet
vacío. Si no se ha especificado ningún periodo de retención sobre el objeto, se devuelve el error 404
.
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))
Crear un sitio web estático alojado
Esta operación requiere permisos, ya que normalmente solo se permite al propietario del grupo configurar un grupo para alojar un sitio web estático. Los parámetros determinan el sufijo predeterminado para los visitantes del sitio, así como un documento de error opcional.
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))
Próximos pasos
Para obtener más información, puede encontrar el código fuente en GitHub.