def read(self):
        '''
        Read in the specified map and return the map structure
        '''
        map_ = None
        if self.opts.get('map', None) is None:
            if self.opts.get('map_data', None) is None:
                if self.opts.get('map_pillar', None) is None:
                    pass
                elif self.opts.get('map_pillar') not in self.opts.get('maps'):
                    log.error(
                        'The specified map not found in pillar at '
                        '\'cloud:maps:%s\'', self.opts['map_pillar']
                    )
                    raise SaltCloudNotFound()
                else:
                    # 'map_pillar' is provided, try to use it
                    map_ = self.opts['maps'][self.opts.get('map_pillar')]
            else:
                # 'map_data' is provided, try to use it
                map_ = self.opts['map_data']
        else:
            # 'map' is provided, try to use it
            local_minion_opts = copy.deepcopy(self.opts)
            local_minion_opts['file_client'] = 'local'
            self.minion = salt.minion.MasterMinion(local_minion_opts)

            if not os.path.isfile(self.opts['map']):
                if not (self.opts['map']).startswith('salt://'):
                    log.error(
                        'The specified map file does not exist: \'%s\'',
                        self.opts['map']
                    )
                    raise SaltCloudNotFound()
            if (self.opts['map']).startswith('salt://'):
                cached_map = self.minion.functions['cp.cache_file'](self.opts['map'])
            else:
                cached_map = self.opts['map']
            try:
                renderer = self.opts.get('renderer', 'jinja|yaml')
                rend = salt.loader.render(self.opts, {})
                blacklist = self.opts.get('renderer_blacklist')
                whitelist = self.opts.get('renderer_whitelist')
                map_ = compile_template(
                    cached_map, rend, renderer, blacklist, whitelist
                )
            except Exception as exc:
                log.error(
                    'Rendering map %s failed, render error:\n%s',
                    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
                )

        if not map_:
            return {}

        # Create expected data format if needed
        for profile, mapped in six.iteritems(map_.copy()):
            if isinstance(mapped, (list, tuple)):
                entries = {}
                for mapping in mapped:
                    if isinstance(mapping, six.string_types):
                        # Foo:
                        #   - bar1
                        #   - bar2
                        mapping = {mapping: None}
                    for name, overrides in six.iteritems(mapping):
                        if overrides is None or isinstance(overrides, bool):
                            # 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 six.iteritems(mapped):
                    overrides.setdefault('name', name)
                    entries[name] = overrides
                map_[profile] = entries
                continue

            if isinstance(mapped, six.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_