OpenStack Object Storage API Client Library
High-level service for bulk operations with multi-threading, progress reporting, automatic retries, and comprehensive error handling for upload, download, delete, and copy operations.
Main service class providing high-level bulk operations with automatic threading, retries, and progress tracking.
class SwiftService:
def __init__(self, options=None):
"""
Initialize Swift service with configuration options.
Parameters:
- options: dict, service configuration options
Service options include:
- auth_url: str, authentication URL
- username: str, username for authentication
- password: str, password for authentication
- auth_version: str, authentication version
- os_*: OpenStack identity options
- retries: int, number of operation retries
- object_dd_threads: int, object download/delete thread count
- object_uu_threads: int, object upload/update thread count
- container_threads: int, container operation thread count
- segment_threads: int, segment operation thread count
"""
def upload(self, container, objects, options=None):
"""
Upload objects to Swift.
Parameters:
- container: str, container name to upload to
- objects: iterable, SwiftUploadObject instances or file paths
- options: dict, upload-specific options
Yields:
dict: upload result for each object
Upload options include:
- leave_segments: bool, don't delete old segments on update
- changed: bool, only upload changed files
- skip_identical: bool, skip files with matching ETags
- fail_fast: bool, stop on first error
- dir_marker: bool, create directory marker objects
"""
def download(self, container=None, objects=None, options=None):
"""
Download objects from Swift.
Parameters:
- container: str, container name to download from (None for all containers)
- objects: iterable, object names to download (None for all objects)
- options: dict, download-specific options
Yields:
dict: download result for each object
Download options include:
- out_directory: str, local directory to download to
- prefix: str, only download objects with this prefix
- remove_prefix: bool, remove prefix from local file names
- no_download: bool, print download URLs without downloading
- skip_identical: bool, skip files with matching local copies
"""
def delete(self, container=None, objects=None, options=None):
"""
Delete objects and containers from Swift.
Parameters:
- container: str, container name to delete from (None for account)
- objects: iterable, object names to delete (None for all objects)
- options: dict, delete-specific options
Yields:
dict: delete result for each object/container
Delete options include:
- prefix: str, only delete objects with this prefix
- yes_all: bool, delete all containers and objects
- leave_segments: bool, don't delete segments of manifest objects
"""
def copy(self, container=None, objects=None, options=None):
"""
Copy objects in Swift.
Parameters:
- container: str, source container name
- objects: iterable, SwiftCopyObject instances
- options: dict, copy-specific options
Yields:
dict: copy result for each object
Copy options include:
- destination: str, destination container
- fresh_metadata: bool, don't copy existing metadata
"""
def post(self, container=None, objects=None, options=None):
"""
Update metadata for containers and objects.
Parameters:
- container: str, container name to update (None for account)
- objects: iterable, SwiftPostObject instances
- options: dict, post-specific options
Yields:
dict: post result for each container/object
"""
def list(self, container=None, options=None):
"""
List containers and objects.
Parameters:
- container: str, container name to list (None for containers)
- options: dict, list-specific options
Yields:
dict: listing result for each container/object
List options include:
- long: bool, include detailed information
- prefix: str, only list items with this prefix
- delimiter: str, delimiter for hierarchical listings
"""
def stat(self, container=None, objects=None, options=None):
"""
Display account, container, and object statistics.
Parameters:
- container: str, container name to stat (None for account)
- objects: iterable, object names to stat (None for container)
- options: dict, stat-specific options
Yields:
dict: stat result for each item
"""
def get_capabilities(self, url=None):
"""
Retrieve Swift cluster capabilities.
Parameters:
- url: str, Swift cluster URL (uses auth URL if None)
Returns:
dict: cluster capabilities
"""Configuration objects for specifying bulk operation parameters.
class SwiftUploadObject:
def __init__(
self,
source,
object_name=None,
options=None
):
"""
Specify object for upload operation.
Parameters:
- source: str, local file path or file-like object
- object_name: str, object name in Swift (derived from source if None)
- options: dict, per-object upload options
"""
class SwiftPostObject:
def __init__(
self,
object_name,
options=None
):
"""
Specify object for metadata update operation.
Parameters:
- object_name: str, object name to update
- options: dict, per-object options including headers
"""
class SwiftDeleteObject:
def __init__(
self,
object_name,
options=None
):
"""
Specify object for delete operation.
Parameters:
- object_name: str, object name to delete
- options: dict, per-object delete options
"""
class SwiftCopyObject:
def __init__(
self,
object_name,
source_container,
destination_container,
destination_object=None,
options=None
):
"""
Specify object for copy operation.
Parameters:
- object_name: str, source object name
- source_container: str, source container name
- destination_container: str, destination container name
- destination_object: str, destination object name (same as source if None)
- options: dict, per-object copy options
"""class SwiftError(Exception):
def __init__(
self,
value,
container=None,
obj=None,
segment=None,
exc=None,
transaction_id=None
):
"""
Service-level error with operation context.
Parameters:
- value: str, error description
- container: str, container name involved in error
- obj: str, object name involved in error
- segment: str, segment name for large object operations
- exc: Exception, underlying exception
- transaction_id: str, Swift transaction ID
"""def get_conn(options):
"""
Create Connection object from service options.
Parameters:
- options: dict, connection options
Returns:
Connection: configured connection object
"""
def process_options(options):
"""
Process and normalize authentication and service options.
Parameters:
- options: dict, raw options dictionary
Returns:
dict: processed options with normalized authentication settings
"""from swiftclient.service import SwiftService, SwiftUploadObject
# Configure service
options = {
'auth_url': 'https://identity.example.com:5000/v3',
'username': 'myuser',
'password': 'mypassword',
'auth_version': '3',
'os_project_name': 'myproject',
'os_user_domain_name': 'mydomain',
'os_project_domain_name': 'mydomain',
}
with SwiftService(options=options) as swift:
# Upload individual files
upload_objects = [
SwiftUploadObject('local/file1.txt'),
SwiftUploadObject('local/file2.txt', object_name='remote/file2.txt'),
SwiftUploadObject('local/image.jpg', options={'content-type': 'image/jpeg'}),
]
for result in swift.upload('documents', upload_objects):
if result['success']:
print(f"Uploaded: {result['object']}")
else:
print(f"Failed to upload {result['object']}: {result['error']}")
# Upload directory recursively
for result in swift.upload('backup', ['./my_directory']):
if result['success']:
print(f"Uploaded: {result['object']}")# Download entire container
download_options = {
'out_directory': './downloads',
'skip_identical': True,
}
with SwiftService(options=options) as swift:
for result in swift.download('documents', options=download_options):
if result['success']:
print(f"Downloaded: {result['object']} -> {result['path']}")
else:
print(f"Failed to download {result['object']}: {result['error']}")
# Download specific objects
object_names = ['file1.txt', 'images/photo1.jpg', 'data/dataset.csv']
for result in swift.download('documents', object_names, options=download_options):
if result['success']:
print(f"Downloaded: {result['object']}")# Delete specific objects
delete_objects = ['old_file1.txt', 'temp/old_file2.txt', 'cache/temp.dat']
with SwiftService(options=options) as swift:
for result in swift.delete('documents', delete_objects):
if result['success']:
print(f"Deleted: {result['object']}")
else:
print(f"Failed to delete {result['object']}: {result['error']}")
# Delete all objects with prefix
delete_options = {'prefix': 'temp/'}
for result in swift.delete('documents', options=delete_options):
if result['success']:
print(f"Deleted: {result['object']}")from swiftclient.service import SwiftCopyObject
copy_objects = [
SwiftCopyObject('file1.txt', 'documents', 'backup'),
SwiftCopyObject('data.csv', 'documents', 'archive', 'data-2024.csv'),
]
with SwiftService(options=options) as swift:
for result in swift.copy('documents', copy_objects):
if result['success']:
print(f"Copied: {result['object']} -> {result['destination']}")
else:
print(f"Failed to copy {result['object']}: {result['error']}")from swiftclient.service import SwiftPostObject
# Update object metadata
post_objects = [
SwiftPostObject('file1.txt', options={
'header': ['X-Object-Meta-Author:John Doe', 'X-Object-Meta-Version:2.0']
}),
SwiftPostObject('file2.txt', options={
'header': ['X-Object-Meta-Department:Engineering']
}),
]
with SwiftService(options=options) as swift:
for result in swift.post('documents', post_objects):
if result['success']:
print(f"Updated metadata: {result['object']}")
else:
print(f"Failed to update {result['object']}: {result['error']}")
# Update container metadata
container_options = {
'header': ['X-Container-Meta-Owner:TeamA', 'X-Container-Read:.r:*']
}
for result in swift.post('documents', options=container_options):
if result['success']:
print(f"Updated container: {result['container']}")# List containers with details
with SwiftService(options=options) as swift:
for result in swift.list(options={'long': True}):
if result['success']:
if 'container' in result:
container = result['container']
print(f"Container: {container['name']}")
print(f" Count: {container['count']}, Bytes: {container['bytes']}")
# List objects in container
for result in swift.list('documents', options={'long': True, 'prefix': 'images/'}):
if result['success'] and 'object' in result:
obj = result['object']
print(f"Object: {obj['name']}, Size: {obj['bytes']}, ETag: {obj['hash']}")
# Get statistics
for result in swift.stat('documents'):
if result['success']:
stats = result['items']
for key, value in stats:
print(f"{key}: {value}")# Upload with advanced options
upload_options = {
'segment_size': 1048576 * 100, # 100MB segments for large files
'use_slo': True, # Use Static Large Objects
'segment_container': 'documents_segments',
'leave_segments': False, # Clean up old segments
'changed': True, # Only upload changed files
'skip_identical': True, # Skip identical files
'fail_fast': False, # Continue on errors
'object_uu_threads': 10, # Upload thread count
}
large_files = [
SwiftUploadObject('large_dataset.csv', options={'content-type': 'text/csv'}),
SwiftUploadObject('video.mp4', options={'content-type': 'video/mp4'}),
]
with SwiftService(options={**options, **upload_options}) as swift:
for result in swift.upload('documents', large_files):
if result['success']:
print(f"Uploaded: {result['object']} ({result['bytes_uploaded']} bytes)")
if 'manifest' in result:
print(f" Created manifest with {len(result['manifest'])} segments")
else:
print(f"Failed: {result['object']} - {result['error']}")import time
def monitor_operations(swift_generator, operation_name):
"""Monitor and report progress of bulk operations."""
start_time = time.time()
success_count = 0
error_count = 0
total_bytes = 0
for result in swift_generator:
if result['success']:
success_count += 1
total_bytes += result.get('bytes_uploaded', result.get('bytes_downloaded', 0))
else:
error_count += 1
print(f"ERROR: {result.get('object', result.get('container', 'unknown'))}: {result['error']}")
if (success_count + error_count) % 10 == 0:
elapsed = time.time() - start_time
print(f"{operation_name}: {success_count} success, {error_count} errors, "
f"{total_bytes} bytes in {elapsed:.1f}s")
total_time = time.time() - start_time
print(f"\n{operation_name} Complete:")
print(f" Successful: {success_count}")
print(f" Failed: {error_count}")
print(f" Total bytes: {total_bytes}")
print(f" Total time: {total_time:.1f}s")
# Usage
with SwiftService(options=options) as swift:
upload_generator = swift.upload('documents', ['./large_directory'])
monitor_operations(upload_generator, "Upload")Install with Tessl CLI
npx tessl i tessl/pypi-python-swiftclient