# Buggy code
def read(self):
    """
    Read in the specified map file and return the map structure
    """
    if self.opts.get("map", None) is None:
        return {}

    if not os.path.isfile(self.opts["map"]):
        log.error(
            "The specified map file does not exist: '{0}'".format(self.opts["map"])
        )
        raise SaltCloudNotFound()
    try:
        renderer = self.opts.get("renderer", "yaml_jinja")
        rend = salt.loader.render(self.opts, {})
        map_ = compile_template(self.opts["map"], rend, renderer)
    except Exception as exc:
        log.error(
            "Rendering map {0} failed, render error:\n{1}".format(
                self.opts["map"], exc
            ),
            exc_info_on_loglevel=logging.DEBUG,
        )
        return {}

    if "include" in map_:
        map_ = salt.config.include_config(map_, self.opts["map"], verbose=False)

    # Create expected data format if needed
    for profile, mapped in map_.copy().items():
        if isinstance(mapped, (list, tuple)):
            entries = {}
            for mapping in mapped:
                if isinstance(mapping, string_types):
                    # Foo:
                    #   - bar1
                    #   - bar2
                    mapping = {mapping: None}
                for name, overrides in mapping.items():
                    if overrides is None:
                        # Foo:
                        #   - bar1:
                        #   - bar2:
                        overrides = {}
                    overrides.setdefault("name", name)
                    entries[name] = overrides
            map_[profile] = entries
            continue

        if isinstance(mapped, dict):
            # Convert the dictionary mapping to a list of dictionaries
            # Foo:
            #  bar1:
            #    grains:
            #      foo: bar
            #  bar2:
            #    grains:
            #      foo: bar
            entries = {}
            for name, overrides in mapped.items():
                overrides.setdefault("name", name)
                entries[name] = overrides
            map_[profile] = entries
            continue

        if isinstance(mapped, string_types):
            # If it's a single string entry, let's make iterable because of
            # the next step
            mapped = [mapped]

        map_[profile] = {}
        for name in mapped:
            map_[profile][name] = {"name": name}
    return map_


# Traceback (AttributeError)
# salt-cloud -P -m map_saltify
[INFO    ] salt-cloud starting
ursa:
True
[INFO    ] Runner completed: 20150521122436271395
[ERROR   ] An un-handled exception was caught by salt's global exception handler:
AttributeError: 'str' object has no attribute 'setdefault'
Traceback (most recent call last):
File "/usr/bin/salt-cloud", line 10, in <module>
salt_cloud()
File "/usr/lib/python2.7/dist-packages/salt/scripts.py", line 316, in salt_cloud
client.run()
File "/usr/lib/python2.7/dist-packages/salt/cloud/cli.py", line 86, in run
mapper = salt.cloud.Map(self.config)
File "/usr/lib/python2.7/dist-packages/salt/cloud/__init__.py", line 1558, in __init__
self.rendered_map = self.read()
File "/usr/lib/python2.7/dist-packages/salt/cloud/__init__.py", line 1685, in read
overrides.setdefault('name', name)
AttributeError: 'str' object has no attribute 'setdefault'
Traceback (most recent call last):
File "/usr/bin/salt-cloud", line 10, in <module>
salt_cloud()
File "/usr/lib/python2.7/dist-packages/salt/scripts.py", line 316, in salt_cloud
client.run()
File "/usr/lib/python2.7/dist-packages/salt/cloud/cli.py", line 86, in run
mapper = salt.cloud.Map(self.config)
File "/usr/lib/python2.7/dist-packages/salt/cloud/__init__.py", line 1558, in __init__
self.rendered_map = self.read()
File "/usr/lib/python2.7/dist-packages/salt/cloud/__init__.py", line 1685, in read
overrides.setdefault('name', name)
AttributeError: 'str' object has no attribute 'setdefault'
# salt-cloud --versions-report
Salt: 2015.5.0
Python: 2.7.6 (default, Mar 22 2014, 22:59:56)
Jinja2: 2.7.2
M2Crypto: 0.21.1
msgpack-python: 0.3.0
msgpack-pure: Not Installed
pycrypto: 2.6.1
libnacl: Not Installed
PyYAML: 3.10
ioflo: Not Installed
PyZMQ: 14.0.1
RAET: Not Installed
ZMQ: 4.0.4
Mako: 0.9.1
Apache Libcloud: 0.15.1
Debian source package: 2015.5.0+ds-1trusty1
# more map_saltify
make_salty:
- name:
ssh_host: 172.17.17.28
ssh_username: debian
ssh_keyfile: '/etc/salt/ursa-salt-key.pem'
sudo: True

# Fixed code
def read(self):
    """
    Read in the specified map file and return the map structure
    """
    if self.opts.get("map", None) is None:
        return {}

    if not os.path.isfile(self.opts["map"]):
        log.error(
            "The specified map file does not exist: '{0}'".format(self.opts["map"])
        )
        raise SaltCloudNotFound()
    try:
        renderer = self.opts.get("renderer", "yaml_jinja")
        rend = salt.loader.render(self.opts, {})
        map_ = compile_template(self.opts["map"], rend, renderer)
    except Exception as exc:
        log.error(
            "Rendering map {0} failed, render error:\n{1}".format(
                self.opts["map"], exc
            ),
            exc_info_on_loglevel=logging.DEBUG,
        )
        return {}

    if "include" in map_:
        map_ = salt.config.include_config(map_, self.opts["map"], verbose=False)

    # Create expected data format if needed
    for profile, mapped in map_.copy().items():
        if isinstance(mapped, (list, tuple)):
            entries = {}
            for mapping in mapped:
                if isinstance(mapping, string_types):
                    # Foo:
                    #   - bar1
                    #   - bar2
                    mapping = {mapping: None}
                for name, overrides in mapping.items():
                    if overrides is None:
                        # Foo:
                        #   - bar1:
                        #   - bar2:
                        overrides = {}
                    try:
                        overrides.setdefault("name", name)
                    except AttributeError:
                        log.error(
                            "Cannot use 'name' as a minion id in a cloud map as it "
                            "is a reserved word. Please change 'name' to a different "
                            "minion id reference."
                        )
                        return ""
                    entries[name] = overrides
            map_[profile] = entries
            continue

        if isinstance(mapped, dict):
            # Convert the dictionary mapping to a list of dictionaries
            # Foo:
            #  bar1:
            #    grains:
            #      foo: bar
            #  bar2:
            #    grains:
            #      foo: bar
            entries = {}
            for name, overrides in mapped.items():
                overrides.setdefault("name", name)
                entries[name] = overrides
            map_[profile] = entries
            continue

        if isinstance(mapped, string_types):
            # If it's a single string entry, let's make iterable because of
            # the next step
            mapped = [mapped]

        map_[profile] = {}
        for name in mapped:
            map_[profile][name] = {"name": name}
    return map_