<jupyter_start><jupyter_text>Python with BOTO3 and OneFS Platform API for S3 Failover **Assumptions:**1. S3 is configured and enabled on both clusters2. buckets are configured on both clusters3. users are equally created on both clusters4. S3 Users are configured with the following RBAC Permission ISI_PRIV_LOGIN_PAPI and (ptional) ISI_PRIV_NS_IFS_ACCESS5. each user has already S3 Keys generated on both clusters   If not the Function newS3Key() below can be used to generate them.6. S3 Buckets are equally set up on both clusters  Setup and Requirements<jupyter_code># Requirements
import boto3
import urllib3
from pprint import pprint

# isi_sdk 
from __future__ import print_function
import time
import isi_sdk_9_1_0
from isi_sdk_9_1_0.rest import ApiException

# Disable SSL selfsigned certificate warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Config Variables OneFS
myHost = '192.168.188.192' # source cluster
#myHost = '192.168.188.201' # target cluster
myEndpointURL = 'https://' + myHost + ':9021'
OneFSUser = 'root'
OneFSPw = 'a'<jupyter_output><empty_output><jupyter_text>Get the S3 Keys using the OneFS SDK<jupyter_code>def myS3keys(user, password, papiHost):
    # Configure HTTP
    configuration = isi_sdk_9_1_0.Configuration()
    configuration.username = user
    configuration.password = password
    configuration.verify_ssl = False
    configuration.host = "https://" + papiHost + ":8080"

    # create an instance of the API class
    api_instance = isi_sdk_9_1_0.ProtocolsApi(isi_sdk_9_1_0.ApiClient(configuration))

    try:
        api_response = api_instance.list_s3_mykeys()
    except ApiException as e:
        print("Exception when calling ProtocolsApi->list_s3_mykeys: %s\n" % e)
    else :
        return api_response
        
my = myS3keys(OneFSUser, OneFSPw, myHost)
pprint(my)
myAccessID = my.keys.access_id
mySecretKey = my.keys.secret_key<jupyter_output>{'keys': {'access_id': '1_root_accid',
          'old_key_expiry': 1636711391,
          'old_key_timestamp': 1636704440,
          'old_secret_key': '<KEY>',
          'secret_key': '<KEY>',
          'secret_key_timestamp': 1636710791}}<jupyter_text>Generate a new S3 Key using the OneFS SDK<jupyter_code>def newS3key(user, password, papiHost):
    # Configure HTTP
    configuration = isi_sdk_9_1_0.Configuration()
    configuration.username = user
    configuration.password = password
    configuration.verify_ssl = False
    configuration.host = "https://" + papiHost + ":8080"

    # create an instance of the API class
    api_instance = isi_sdk_9_1_0.ProtocolsApi(isi_sdk_9_1_0.ApiClient(configuration))
    s3_mykey = isi_sdk_9_1_0.S3Key() # S3Key | 
    force = True # bool | Forces to create new key. (optional)

    try:
        api_response = api_instance.create_s3_mykey(s3_mykey, force=force)
    except ApiException as e:
        print("Exception when calling ProtocolsApi->create_s3_mykey: %s\n" % e)
    else :
        return api_response
        
my = newS3key(OneFSUser, OneFSPw, myHost)
pprint(my)
myAccessID = my.keys.access_id
mySecretKey = my.keys.secret_key<jupyter_output>{'keys': {'access_id': '1_root_accid',
          'old_key_expiry': 1636711391,
          'old_key_timestamp': 1636704440,
          'old_secret_key': '<KEY>',
          'secret_key': '<KEY>',
          'secret_key_timestamp': 1636710791}}<jupyter_text>List objects with BOTO - lookup a new Key Pair in case of a authentication error...**Note: There are other reasons why an S3 call could return a 403 Error. => This is for demonstraion purpose only!** It can be potentially dangerous to automatially get the keys and just retry with out further sanity checks.<jupyter_code>def listObjects(myAccID, mySecret, myURL, bucket):
    global myAccessID
    global mySecretKey
    # S3 Config
    # disable unsigned SSL warning
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

    from botocore import config
    from botocore.exceptions import ClientError

    my_config = config.Config(
        region_name = "",
        signature_version = 'v4',
        retries = {
            'max_attempts' : 10,
            'mode' : 'standard'
        }
    )

    # create a S3 Session Object
    session = boto3.session.Session()

    s3_client = session.client(
        service_name='s3',
        aws_access_key_id=myAccID,
        aws_secret_access_key=mySecret,
        endpoint_url=myURL,
        use_ssl=True,
        verify=False
    )

    try:
        pprint(s3_client.list_objects(Bucket=bucket))
    except ClientError as e:
        eStatus = e.response['ResponseMetadata']['HTTPStatusCode']
        print(e.response['Error']['Message'])
        if eStatus == 403 :
            print("Time to add the call to get a new key")
            my = myS3keys(OneFSUser, OneFSPw, myHost)
            pprint(my)
            myAccessID = my.keys.access_id
            mySecretKey = my.keys.secret_key
            listObjects(myAccessID, mySecretKey, myURL, bucket)

listObjects(myAccessID, mySecretKey, myEndpointURL, 'omnibot')<jupyter_output>{'Contents': [{'ETag': '"d41d8cd98f00b204e9800998ecf8427e"',
               'Key': 'this_is_cluster_1',
               'LastModified': datetime.datetime(2021, 11, 12, 8, 52, 17, tzinfo=tzutc()),
               'Owner': {'DisplayName': 'root', 'ID': 'root'},
               'Size': 0,
               'StorageClass': 'STANDARD'}],
 'IsTruncated': False,
 'Marker': '',
 'MaxKeys': 1000,
 'Name': 'omnibot',
 'Prefix': '',
 'ResponseMetadata': {'HTTPHeaders': {'connection': 'keep-alive',
                                      'content-length': '460',
                                      'x-amz-request-id': '564950518'},
                      'HTTPStatusCode': 200,
                      'HostId': '',
                      'RequestId': '564950518',
                      'RetryAttempts': 0}}
{'fraction_non_alphanumeric': 0.10092055915444936, 'fraction_numerical': 0.040913740197749744, 'mean_word_length': 3.158043940467753, 'pattern_counts': {'":': 2, '<': 18, '<?xml version=': 0, '>': 21, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '556563', 'license': 'MIT', 'n_tokens_mistral': 2011, 'n_tokens_neox': 1880, 'n_words': 462, 'path': 'S3_Failover_w_SDK.ipynb', 'repo_name': 'mupplelabs/powerscale_papi_s3_boto', 'size': '5958'}