print_chars(0, "Error creating cloudinit.d directort %s : %s" % (homedir, str(ex))) (options, args) = parser.parse_args(args=argv) _deal_with_cmd_line_globals(options) for opt in all_opts: opt.validate(options) if not options.name: options.name = str(uuid.uuid4()).split("-")[0] if options.logdir is None: options.logdir = os.path.expanduser("~/.cloudinitd/") (options.logger, logfile) = cloudinitd.make_logger(options.loglevel, options.name, logdir=options.logdir) if not options.database: dbdir = os.path.expanduser("~/.cloudinitd") options.database = dbdir if options.logstack: logger = logging.getLogger("stacktracelog") logger.propagate = False logger.setLevel(logging.DEBUG) logdir = os.path.join(options.logdir, options.name) if not os.path.exists(logdir): try: os.mkdir(logdir) except OSError: pass stacklogfile = os.path.join(logdir, "stacktrace.log")
def __init__(self, db_dir, config_file=None, db_name=None, log_level="warn", logdir=None, level_callback=None, service_callback=None, boot=True, ready=True, terminate=False, continue_on_error=False, fail_if_db_present=False): """ db_dir: a path to a directories where databases can be stored. config_file: the top_level config file describing this boot plan. if this parameter is given then it is assumed that this is a new launch plan. if it is not given the db_name parameter is required and the plan is loaded from an existing database db_name: the name of the database. this is not an actual path to a file, it is the run name given when the plan is launched. The run name can be found in self.name level_callback: a callback function that is invoked whenever a level completes or a new level is started. The signature of the callback is: def func_name(cloudinitd, action, current_level) action is a string from the set ["starting", "transition", "complete", "error"] service callback: a callbackfunciton that is invoked whenever a service is started, progresses, or finishes. The signature is: def func_name(cloudservice, action, msg) action is a string from the set: ["starting", "transition", "complete", "error"] boot=True: instructs the object to contextualized the service or now ready=True: instructs the service to run the ready program or not terminate=False: instructs the service to run the shutdown program or not fail_if_db_present=False: instructs the constructor that the caller expects DB present already When this object is configured with a config_file a new sqlite database is created under @db_dir and a new name is picked for it. the data base ends up being called <db_dir>/cloudinitd-<name>.db, but the user has no real need to know this. The contructor does not actually launch a run. It simply loads up the database with the information in the config file (in the case of a new launch) and then builds the inmemory data structures. """ if not db_name and not config_file: raise APIUsageException("Cloud boot must have a db_name or a config file to load") if not os.path.exists(db_dir): raise APIUsageException("Path to the db directory does not exist: %s" % (db_dir)) self._level_callback = level_callback self._service_callback = service_callback if not db_name: db_name = str(uuid.uuid4()).split("-")[0] db_path = "/%s/cloudinitd-%s.db" % (db_dir, db_name) self._db_path = db_path if config_file is None: if not os.path.exists(db_path): raise APIUsageException("Path to the db does not exist %s. New dbs must be given a config file" % (db_path)) if fail_if_db_present and os.path.exists(db_path): raise APIUsageException("Already exists: '%s'" % db_path) (self._log, logfile) = cloudinitd.make_logger(log_level, db_name, logdir=logdir) self._started = False self.run_name = db_name dburl = "sqlite://%s" % (db_path) self._db = CloudInitDDB(dburl) os.chmod(db_path, stat.S_IRUSR | stat.S_IWUSR) if config_file: self._bo = self._db.load_from_conf(config_file) else: self._bo = self._db.load_from_db() self._levels = [] self._boot_top = BootTopLevel(log=self._log, level_callback=self._mp_cb, service_callback=self._svc_cb, boot=boot, ready=ready, terminate=terminate, continue_on_error=continue_on_error) for level in self._bo.levels: level_list = [] for s in level.services: try: (s_log, logfile) = cloudinitd.make_logger(log_level, self.run_name, logdir=logdir, servicename=s.name) svc = self._boot_top.new_service(s, self._db, log=s_log, logfile=logfile, run_name=self.run_name) # if boot is not set we assume it was already booted and we expand if not boot: svc._do_attr_bag() level_list.append(svc) except Exception, svcex: if not continue_on_error: raise action = cloudinitd.callback_action_error msg = "ERROR creating SVC object %s, but continue on error set: %s" % (s.name, str(svcex)) if self._service_callback: cs = CloudService(self, None, name=s.name) self._service_callback(self, cs, action, msg) cloudinitd.log(self._log, logging.ERROR, msg) self._boot_top.add_level(level_list) self._levels.append(level_list)