# Buggy code
def creds(provider):
    """
    Return the credentials for AWS signing.  This could be just the id and key
    specified in the provider configuration, or if the id or key is set to the
    literal string 'use-instance-role-credentials' creds will pull the instance
    role credentials from the meta data, cache them, and provide them instead.
    """
    # Declare globals
    global __AccessKeyId__, __SecretAccessKey__, __Token__, __Expiration__

    # if id or key is 'use-instance-role-credentials', pull them from meta-data
    ## if needed
    if provider["id"] == IROLE_CODE or provider["key"] == IROLE_CODE:
        # Check to see if we have cache credentials that are still good
        if __Expiration__ != "":
            timenow = datetime.utcnow()
            timestamp = timenow.strftime("%Y-%m-%dT%H:%M:%SZ")
            if timestamp < __Expiration__:
                # Current timestamp less than expiration fo cached credentials
                return __AccessKeyId__, __SecretAccessKey__, __Token__
        # We don't have any cached credentials, or they are expired, get them

        # Connections to instance meta-data must fail fast and never be proxied
        try:
            result = requests.get(
                "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
                proxies={"http": ""},
                timeout=AWS_METADATA_TIMEOUT,
            )
            result.raise_for_status()
            role = result.text.encode(result.encoding if result.encoding else "utf-8")
        except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError):
            return provider["id"], provider["key"], ""

        try:
            result = requests.get(
                "http://169.254.169.254/latest/meta-data/iam/security-credentials/{0}".format(
                    role
                ),
                proxies={"http": ""},
                timeout=AWS_METADATA_TIMEOUT,
            )
            result.raise_for_status()
        except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError):
            return provider["id"], provider["key"], ""

        data = result.json()
        __AccessKeyId__ = data["AccessKeyId"]
        __SecretAccessKey__ = data["SecretAccessKey"]
        __Token__ = data["Token"]
        __Expiration__ = data["Expiration"]
        return __AccessKeyId__, __SecretAccessKey__, __Token__
    else:
        return provider["id"], provider["key"], ""


# Traceback (TypeError)
ubuntu@ip-XXXXX:~$ sudo python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
from salt.cloud import CloudClient
cloudcli = CloudClient(path='/etc/salt/cloud')
cloudcli.profile('ec2_test', names=['tmp0', 'tmp1'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/ubuntu/.local/lib/python3.5/site-packages/salt/cloud/__init__.py", line 348, in profile
mapper.run_profile(profile, names, vm_overrides=vm_overrides)
File "/home/ubuntu/.local/lib/python3.5/site-packages/salt/cloud/__init__.py", line 1448, in run_profile
ret[name] = self.create(vm_)
File "/home/ubuntu/.local/lib/python3.5/site-packages/salt/cloud/__init__.py", line 1278, in create
output = self.clouds[func](vm_)
File "/home/ubuntu/.local/lib/python3.5/site-packages/salt/cloud/clouds/ec2.py", line 2617, in create
data, vm_ = request_instance(vm_, location)
File "/home/ubuntu/.local/lib/python3.5/site-packages/salt/cloud/clouds/ec2.py", line 1842, in request_instance
az_ = get_availability_zone(vm_)
File "/home/ubuntu/.local/lib/python3.5/site-packages/salt/cloud/clouds/ec2.py", line 1166, in get_availability_zone
zones = _list_availability_zones(vm_)
File "/home/ubuntu/.local/lib/python3.5/site-packages/salt/cloud/clouds/ec2.py", line 1341, in _list_availability_zones
ret[zone['zoneName']] = zone['zoneState']
TypeError: string indices must be integers

# Fixed code
def creds(provider):
    """
    Return the credentials for AWS signing.  This could be just the id and key
    specified in the provider configuration, or if the id or key is set to the
    literal string 'use-instance-role-credentials' creds will pull the instance
    role credentials from the meta data, cache them, and provide them instead.
    """
    # Declare globals
    global __AccessKeyId__, __SecretAccessKey__, __Token__, __Expiration__

    # if id or key is 'use-instance-role-credentials', pull them from meta-data
    ## if needed
    if provider["id"] == IROLE_CODE or provider["key"] == IROLE_CODE:
        # Check to see if we have cache credentials that are still good
        if __Expiration__ != "":
            timenow = datetime.utcnow()
            timestamp = timenow.strftime("%Y-%m-%dT%H:%M:%SZ")
            if timestamp < __Expiration__:
                # Current timestamp less than expiration fo cached credentials
                return __AccessKeyId__, __SecretAccessKey__, __Token__
        # We don't have any cached credentials, or they are expired, get them

        # Connections to instance meta-data must fail fast and never be proxied
        try:
            result = requests.get(
                "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
                proxies={"http": ""},
                timeout=AWS_METADATA_TIMEOUT,
            )
            result.raise_for_status()
            role = result.text
        except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError):
            return provider["id"], provider["key"], ""

        try:
            result = requests.get(
                "http://169.254.169.254/latest/meta-data/iam/security-credentials/{0}".format(
                    role
                ),
                proxies={"http": ""},
                timeout=AWS_METADATA_TIMEOUT,
            )
            result.raise_for_status()
        except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError):
            return provider["id"], provider["key"], ""

        data = result.json()
        __AccessKeyId__ = data["AccessKeyId"]
        __SecretAccessKey__ = data["SecretAccessKey"]
        __Token__ = data["Token"]
        __Expiration__ = data["Expiration"]
        return __AccessKeyId__, __SecretAccessKey__, __Token__
    else:
        return provider["id"], provider["key"], ""