diff options
Diffstat (limited to 'cloudinit/sources/helpers')
| -rw-r--r-- | cloudinit/sources/helpers/openstack.py | 68 | 
1 files changed, 50 insertions, 18 deletions
| diff --git a/cloudinit/sources/helpers/openstack.py b/cloudinit/sources/helpers/openstack.py index 3c6bb6aa..b7e19314 100644 --- a/cloudinit/sources/helpers/openstack.py +++ b/cloudinit/sources/helpers/openstack.py @@ -21,6 +21,7 @@  import abc  import base64  import copy +import functools  import os  from cloudinit import ec2_utils @@ -48,6 +49,7 @@ OS_LATEST = 'latest'  OS_FOLSOM = '2012-08-10'  OS_GRIZZLY = '2013-04-04'  OS_HAVANA = '2013-10-17' +# keep this in chronological order. new supported versions go at the end.  OS_VERSIONS = (      OS_FOLSOM,      OS_GRIZZLY, @@ -161,25 +163,27 @@ class BaseReader(object):      def _read_ec2_metadata(self):          pass -    def _find_working_version(self, version): +    def _find_working_version(self):          try: -            versions_available = self._fetch_available_versions(self) +            versions_available = self._fetch_available_versions()          except Exception as e: -            LOG.warn("Unable to read openstack versions from %s due to: %s", -                     self.base_path, e) +            LOG.debug("Unable to read openstack versions from %s due to: %s", +                      self.base_path, e)              versions_available = [] -        search_versions = [version] + list(OS_VERSIONS) +        # openstack.OS_VERSIONS is stored in chronological order, so +        # reverse it to check newest first. +        supported = [v for v in reversed(list(OS_VERSIONS))]          selected_version = OS_LATEST -        for potential_version in search_versions: + +        for potential_version in supported:              if potential_version not in versions_available:                  continue              selected_version = potential_version              break -        if selected_version != version: -            LOG.warn("Version '%s' not available, attempting to use" -                     " version '%s' instead", version, selected_version) +        LOG.debug("Selected version '%s' from %s", selected_version, +                  versions_available)          return selected_version      def _read_content_path(self, item): @@ -191,7 +195,7 @@ class BaseReader(object):          path = self._path_join(self.base_path, "openstack", *path_pieces)          return self._path_read(path) -    def read_v2(self, version=None): +    def read_v2(self):          """Reads a version 2 formatted location.          Return a dict with metadata, userdata, ec2-metadata, dsmode, @@ -200,6 +204,9 @@ class BaseReader(object):          If not a valid location, raise a NonReadable exception.          """ +        load_json_anytype = functools.partial( +            util.load_json, root_types=(dict, basestring, list)) +          def datafiles(version):              files = {}              files['metadata'] = ( @@ -218,16 +225,15 @@ class BaseReader(object):              files['vendordata'] = (                  self._path_join("openstack", version, 'vendor_data.json'),                  False, -                util.load_json, +                load_json_anytype,              )              return files -        version = self._find_working_version(version)          results = {              'userdata': '',              'version': 2,          } -        data = datafiles(version) +        data = datafiles(self._find_working_version())          for (name, (path, required, translator)) in data.iteritems():              path = self._path_join(self.base_path, path)              data = None @@ -239,7 +245,8 @@ class BaseReader(object):                      LOG.debug("Failed reading optional path %s due"                                " to: %s", path, e)                  else: -                    LOG.exception("Failed reading mandatory path %s", path) +                    LOG.debug("Failed reading mandatory path %s due" +                              " to: %s", path, e)              else:                  found = True              if required and not found: @@ -325,7 +332,7 @@ class ConfigDriveReader(BaseReader):              path = self._path_join(self.base_path, 'openstack')              found = [d for d in os.listdir(path)                       if os.path.isdir(os.path.join(path))] -            self._versions = tuple(found) +            self._versions = found          return self._versions      def _read_ec2_metadata(self): @@ -418,18 +425,18 @@ class MetadataReader(BaseReader):      def _fetch_available_versions(self):          # <baseurl>/openstack/ returns a newline separated list of versions          if self._versions is not None: -            return self.os_versions +            return self._versions          found = [] +        version_path = self._path_join(self.base_path, "openstack")          content = self._path_read(version_path)          for line in content.splitlines():              line = line.strip()              if not line:                  continue              found.append(line) -        self._versions = tuple(found) +        self._versions = found          return self._versions -      def _path_read(self, path):          def should_retry_cb(_request_args, cause): @@ -456,3 +463,28 @@ class MetadataReader(BaseReader):          return ec2_utils.get_instance_metadata(ssl_details=self.ssl_details,                                                 timeout=self.timeout,                                                 retries=self.retries) + + +def convert_vendordata_json(data, recurse=True): +    """ data: a loaded json *object* (strings, arrays, dicts). +    return something suitable for cloudinit vendordata_raw. + +    if data is: +       None: return None +       string: return string +       list: return data +             the list is then processed in UserDataProcessor +       dict: return convert_vendordata_json(data.get('cloud-init')) +    """ +    if not data: +        return None +    if isinstance(data, (str, unicode, basestring)): +        return data +    if isinstance(data, list): +        return copy.deepcopy(data) +    if isinstance(data, dict): +        if recurse is True: +            return convert_vendordata_json(data.get('cloud-init'), +                                           recurse=False) +        raise ValueError("vendordata['cloud-init'] cannot be dict") +    raise ValueError("Unknown data type for vendordata: %s" % type(data)) | 
