From ad9122034ff59fb6113adfac2713c44af09bc91b Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Sat, 9 Jun 2012 12:38:19 -0700 Subject: Initial cleanups --- cloudinit/sources/__init__.py | 188 +++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 95 deletions(-) (limited to 'cloudinit/sources/__init__.py') diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py index 9a9c1316..05c8bfad 100644 --- a/cloudinit/sources/__init__.py +++ b/cloudinit/sources/__init__.py @@ -1,10 +1,12 @@ # vi: ts=4 expandtab # -# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Canonical Ltd. # Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # # Author: Scott Moser -# Author: Juerg Hafliger +# Author: Juerg Haefliger +# Author: Joshua Harlow # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as @@ -18,78 +20,78 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from cloudinit import user_data as ud +from cloudinit import importer +from cloudinit import log as logging from cloudinit import util -import socket - DEP_FILESYSTEM = "FILESYSTEM" DEP_NETWORK = "NETWORK" +DS_PREFIX = 'DataSource' +LOG = logging.getLogger(__name__) + class DataSourceNotFoundException(Exception): pass -class DataSource: - userdata = None - metadata = None - userdata_raw = None - cfgname = "" - # system config (passed in from cloudinit, - # cloud-config before input from the DataSource) - sys_cfg = {} - # datasource config, the cloud-config['datasource']['__name__'] - ds_cfg = {} # datasource config - - def __init__(self, sys_cfg=None): - if not self.cfgname: - name = str(self.__class__).split(".")[-1] - if name.startswith("DataSource"): - name = name[len("DataSource"):] - self.cfgname = name +class DataSource(object): + def __init__(self, ud_proc, cfg): + name = util.obj_name(self) + if name.startswith(DS_PREFIX): + name = name[DS_PREFIX:] + self.cfgname = name if sys_cfg: self.sys_cfg = sys_cfg - + else: + self.sys_cfg = {} + self.ud_proc = ud_proc + self.userdata = None + self.metadata = None + self.userdata_raw = None self.ds_cfg = util.get_cfg_by_path(self.sys_cfg, ("datasource", self.cfgname), self.ds_cfg) def get_userdata(self): - if self.userdata == None: - self.userdata = ud.preprocess_userdata(self.userdata_raw) + if self.userdata is None: + raw_data = self.get_userdata_raw() + self.userdata = self.ud_proc.process(raw_data) return self.userdata def get_userdata_raw(self): - return(self.userdata_raw) + return self.userdata_raw # the data sources' config_obj is a cloud-config formated # object that came to it from ways other than cloud-config # because cloud-config content would be handled elsewhere def get_config_obj(self): - return({}) + return {} def get_public_ssh_keys(self): keys = [] - if 'public-keys' not in self.metadata: - return([]) - if isinstance(self.metadata['public-keys'], str): - return(str(self.metadata['public-keys']).splitlines()) + if not self.metadata or 'public-keys' not in self.metadata: + return keys - if isinstance(self.metadata['public-keys'], list): - return(self.metadata['public-keys']) + if isinstance(self.metadata['public-keys'], (str)): + return str(self.metadata['public-keys']).splitlines() - for _keyname, klist in self.metadata['public-keys'].items(): - # lp:506332 uec metadata service responds with - # data that makes boto populate a string for 'klist' rather - # than a list. - if isinstance(klist, str): - klist = [klist] - for pkey in klist: - # there is an empty string at the end of the keylist, trim it - if pkey: - keys.append(pkey) + if isinstance(self.metadata['public-keys'], (list, set)): + return list(self.metadata['public-keys']) - return(keys) + if isinstance(self.metadata['public-keys'], (dict)): + for _keyname, klist in self.metadata['public-keys'].items(): + # lp:506332 uec metadata service responds with + # data that makes boto populate a string for 'klist' rather + # than a list. + if isinstance(klist, (str)): + klist = [klist] + if isinstance(klist, (list)): + for pkey in klist: + # there is an empty string at the end of the keylist, trim it + if pkey: + keys.append(pkey) + + return keys def device_name_to_device(self, _name): # translate a 'name' to a device @@ -97,48 +99,43 @@ class DataSource: # to consult metadata service, that has # ephemeral0: sdb # and return 'sdb' for input 'ephemeral0' - return(None) + return None def get_locale(self): - return('en_US.UTF-8') + return 'en_US.UTF-8' def get_local_mirror(self): return None def get_instance_id(self): - if 'instance-id' not in self.metadata: + if not self.metadata or 'instance-id' not in self.metadata: return "iid-datasource" - return(self.metadata['instance-id']) + return str(self.metadata['instance-id']) def get_hostname(self, fqdn=False): defdomain = "localdomain" defhost = "localhost" - domain = defdomain - if not 'local-hostname' in self.metadata: + if not self.metadata or not 'local-hostname' in self.metadata: # this is somewhat questionable really. # the cloud datasource was asked for a hostname # and didn't have one. raising error might be more appropriate # but instead, basically look up the existing hostname toks = [] - - hostname = socket.gethostname() - + hostname = util.get_hostname() fqdn = util.get_fqdn_from_hosts(hostname) - if fqdn and fqdn.find(".") > 0: toks = str(fqdn).split(".") elif hostname: toks = [hostname, defdomain] else: toks = [defhost, defdomain] - else: # if there is an ipv4 address in 'local-hostname', then # make up a hostname (LP: #475354) in format ip-xx.xx.xx.xx lhost = self.metadata['local-hostname'] - if is_ipv4(lhost): + if util.is_ipv4(lhost): toks = "ip-%s" % lhost.replace(".", "-") else: toks = lhost.split(".") @@ -155,22 +152,22 @@ class DataSource: return hostname -def find_source(cfg, ds_deps): - cfglist = cfg.get('datasource_list') or [] - dslist = list_sources(cfglist, ds_deps) - dsnames = [f.__name__ for f in dslist] - - LOG.debug("Searching for data source in %s", dsnames) - for cls in dslist: - ds = cls.__name__ +def find_source(cfg, ds_deps, cfg_list, pkg_list, **kwargs): + ds_list = list_sources(cfg_list, ds_deps, pkg_list) + ds_names = [util.obj_name(f) for f in ds_list] + ds_args = dict(kwargs) + ds_args['cfg'] = cfg + LOG.info("Searching for data source in: %s", ds_names) + for cls in ds_list: + ds = util.obj_name(cls) try: - s = cls(sys_cfg=cfg) + s = cls(**ds_args) if s.get_data(): return (s, ds) except Exception as e: - LOG.exception("Getting data from %s raised %s", ds, e) + LOG.exception("Getting data from %s failed", ds) - msg = "Did not find any data source, searched classes: %s" % dsnames + msg = "Did not find any data source, searched classes: %s" % (ds_names) raise DataSourceNotFoundException(msg) @@ -178,31 +175,33 @@ def find_source(cfg, ds_deps): # iterate through cfg_list, loading "DataSourceCollections" modules # and calling their "get_datasource_list". # return an ordered list of classes that match -# -# - modules must be named "DataSource", where 'item' is an entry -# in cfg_list -# - if pkglist is given, it will iterate try loading from that package -# ie, pkglist=[ "foo", "" ] -# will first try to load foo.DataSource -# then DataSource -def list_sources(cfg_list, depends, pkglist=None): - if pkglist is None: - pkglist = [] - retlist = [] +def list_sources(cfg_list, depends, pkg_list): + src_list = [] + LOG.info("Looking for for data source in: %s, %s that match %s", cfg_list, pkg_list, depends) for ds_coll in cfg_list: - for pkg in pkglist: + ds_name = str(ds_coll) + if not ds_name.startswith(DS_PREFIX): + ds_name = '%s%s' % (DS_PREFIX, ds_name) + for pkg in pkg_list: + pkg_name = [] + if pkg: + pkg_name.append(str(pkg)) + pkg_name.append(ds_name) + mod_name = ".".join(pkg_name) + mod = importer.import_module(mod_name) if pkg: - pkg = "%s." % pkg - try: - mod = __import__("%sDataSource%s" % (pkg, ds_coll)) - if pkg: - mod = getattr(mod, "DataSource%s" % ds_coll) - lister = getattr(mod, "get_datasource_list") - retlist.extend(lister(depends)) - break - except: - raise - return(retlist) + mod = getattr(mod, ds_name, None) + if not mod: + continue + lister = getattr(mod, "get_datasource_list", None) + if not lister: + continue + cls_matches = lister(depends) + if not cls_matches: + continue + src_list.extend(cls_matches) + break + return src_list # depends is a list of dependencies (DEP_FILESYSTEM) @@ -213,10 +212,9 @@ def list_sources(cfg_list, depends, pkglist=None): # it returns a list of 'class' that matched these deps exactly # it is a helper function for DataSourceCollections def list_from_depends(depends, dslist): - retlist = [] + ret_list = [] depset = set(depends) - for elem in dslist: - (cls, deps) = elem + for (cls, deps) in dslist: if depset == set(deps): - retlist.append(cls) - return(retlist) + ret_list.append(cls) + return ret_list -- cgit v1.2.3