def process_request(self, req): """Process AJAX request. Args are: path - contents should be returned as JSON set_time - 0 (default) or 1 sets 'now' in contents to current epoch """ try: progress = Progress(req.args['path']) data = progress.get() if int(req.args.get('restart',0)) == 1: progress.restart() progress.error('') # clear error elif int(req.args.get('stop',0)) == 1: progress.kill() progress.error("Stopped on user request.") if int(req.args.get('set_time',0)) == 1: data['now'] = time.time() msg = json.dumps(data) req.send_response(200) req.send_header('Content-Type', 'application/json') except Exception: import traceback; msg = "Oops...\n" + traceback.format_exc()+"\n" req.send_response(500) req.send_header('Content-Type', 'text/plain') req.send_header('Content-Length', len(msg)) req.end_headers() req.write(msg);
def execute(self, req, id): """Deploy to an environment.""" launch_data, attributes, exe = self._get_data(req, id) launch_data['cmd_envs'] = [attributes['name']] launch_data['command_id'] = 'deploy' deploy = self._get_command('deploy') attributes['command'] = deploy['command'] progress_file = Progress.get_file() self._set_deploying(id, progress_file) self._spawn(req, exe, launch_data, attributes, progress_file)
def _spawn(self, req, exe, launch_data, attributes, progress_file=None): """Helper function to spawn processes with progress tracking.""" if not progress_file: progress_file = Progress.get_file() # create the command cmd = [ '/usr/bin/python', exe, '--daemonize', '--trac-base-url="%s"' % self.trac_base_url, '--progress-file="%s"' % progress_file, '--log-file="%s"' % self.log.handlers[0].stream.name, '--chef-base-path="%s"' % self.chefapi.base_path, '--aws-key="%s"' % self.cloudapi.key, '--aws-secret="%s"' % self.cloudapi.secret, '--aws-keypair="%s"' % self.cloudapi.keypair, '--aws-keypair-pem="%s"' % self.chefapi.keypair_pem, '--aws-username="******"' % self.chefapi.user, '--aws-security-groups="%s"' % self.cloudapi.security_groups, '--rds-username="******"' % self.cloudapi.username, '--rds-password="******"' % self.cloudapi.password, '--databag="%s"' % self.name, "--launch-data='%s'" % json.dumps(launch_data), "--attributes='%s'" % json.dumps(attributes), '--started-by="%s"' % req.authname, '--notify-jabber="%s"' % self.notify_jabber, '--jabber-server="%s"' % self.jabber_server, '--jabber-port="%s"' % self.jabber_port, '--jabber-server="%s"' % self.jabber_server, '--jabber-username="******"' % self.jabber_username, '--jabber-password="******"' % self.jabber_password, '--jabber-channel="%s"' % self.jabber_channel, ] cmd += ['--chef-boot-run-list="%s"' % \ r for r in self.chefapi.boot_run_list] if self.chefapi.boot_sudo: cmd += ['--chef-boot-sudo'] if self.chefapi.boot_version: cmd += ['--chef-boot-version="%s"' % self.chefapi.boot_version] cmd = ' '.join(cmd) # Spawn command as daemon to launch and bootstrap instance in background self.log.debug('Daemonizing command: %s' % cmd) if subprocess.call(cmd, shell=True): add_warning(req, _("Error daemonizing: %(cmd)s", cmd=cmd)) req.redirect(req.href.cloud(self.name)) req.redirect( req.href.cloud(self.name, action='progress', file=progress_file))
def _spawn(self, req, exe, launch_data, attributes, progress_file=None): """Helper function to spawn processes with progress tracking.""" if not progress_file: progress_file = Progress.get_file() # create the command cmd = [ '/usr/bin/python', exe, '--daemonize', '--trac-base-url="%s"' % self.trac_base_url, '--progress-file="%s"' % progress_file, '--log-file="%s"' % self.log.handlers[0].stream.name, '--chef-base-path="%s"' % self.chefapi.base_path, '--aws-key="%s"' % self.cloudapi.key, '--aws-secret="%s"' % self.cloudapi.secret, '--aws-keypair="%s"' % self.cloudapi.keypair, '--aws-keypair-pem="%s"' % self.chefapi.keypair_pem, '--aws-username="******"' % self.chefapi.user, '--aws-security-groups="%s"' % self.cloudapi.security_groups, '--rds-username="******"' % self.cloudapi.username, '--rds-password="******"' % self.cloudapi.password, '--databag="%s"' % self.name, "--launch-data='%s'" % json.dumps(launch_data), "--attributes='%s'" % json.dumps(attributes), '--started-by="%s"' % req.authname, '--notify-jabber="%s"' % self.notify_jabber, '--jabber-server="%s"' % self.jabber_server, '--jabber-port="%s"' % self.jabber_port, '--jabber-server="%s"' % self.jabber_server, '--jabber-username="******"' % self.jabber_username, '--jabber-password="******"' % self.jabber_password, '--jabber-channel="%s"' % self.jabber_channel, ] cmd += ['--chef-boot-run-list="%s"' % \ r for r in self.chefapi.boot_run_list] if self.chefapi.boot_sudo: cmd += ['--chef-boot-sudo'] if self.chefapi.boot_version: cmd += ['--chef-boot-version="%s"' % self.chefapi.boot_version] cmd = ' '.join(cmd) # Spawn command as daemon to launch and bootstrap instance in background self.log.debug('Daemonizing command: %s' % cmd) if subprocess.call(cmd, shell=True): add_warning(req, _("Error daemonizing: %(cmd)s", cmd=cmd)) req.redirect(req.href.cloud(self.name)) req.redirect(req.href.cloud(self.name, action='progress', file=progress_file))
def _is_deploying(self, env): """Determines whether there's an active deployment for the given environment and if so returns its progress file, else False.""" deploy_file = '/tmp/deploy-%s' % env if not os.path.exists(deploy_file): return False # extract progress file f = open(deploy_file, 'r') progress_file = f.read().strip() f.close() # check if progress file exists if not os.path.exists(progress_file): return False # check if done deploying if Progress(progress_file).is_done(): return False return progress_file
def process_request(self, req): """Process AJAX request. Args are: path - contents should be returned as JSON set_time - 0 (default) or 1 sets 'now' in contents to current epoch """ try: progress = Progress(req.args['path']) data = progress.get() if int(req.args.get('restart', 0)) == 1: progress.restart() progress.error('') # clear error elif int(req.args.get('stop', 0)) == 1: progress.kill() progress.error("Stopped on user request.") if int(req.args.get('set_time', 0)) == 1: data['now'] = time.time() msg = json.dumps(data) req.send_response(200) req.send_header('Content-Type', 'application/json') except Exception: import traceback msg = "Oops...\n" + traceback.format_exc() + "\n" req.send_response(500) req.send_header('Content-Type', 'text/plain') req.send_header('Content-Length', len(msg)) req.end_headers() req.write(msg)
def __init__(self, steps, title, description='', can_continue=False): # setup command line parsing parser = OptionParser() parser.add_option("-d","--daemonize",default=False,action="store_true") parser.add_option("--trac-base-url") parser.add_option("--progress-file") parser.add_option("--log-file") parser.add_option("--log-level", default=logging.DEBUG) parser.add_option("--chef-base-path") parser.add_option("--chef-boot-run-list", default=[], action='append') parser.add_option("--chef-boot-sudo",default=False, action="store_true") parser.add_option("--chef-boot-version") parser.add_option("--aws-key") parser.add_option("--aws-secret") parser.add_option("--aws-keypair") parser.add_option("--aws-keypair-pem") parser.add_option("--aws-username") parser.add_option("--aws-security-groups") parser.add_option("--rds-username") parser.add_option("--rds-password") parser.add_option("--databag") parser.add_option("--launch-data", default='{}', help="JSON dict") parser.add_option("--attributes", default='{}', help="JSON dict") parser.add_option("--started-by") parser.add_option("--notify-jabber") parser.add_option("--jabber-server") parser.add_option("--jabber-port") parser.add_option("--jabber-username") parser.add_option("--jabber-password") parser.add_option("--jabber-channel") (self.options, _args) = parser.parse_args() # setup logging (presumes something else will rotate it) self.log = logging.getLogger(self.__class__.__name__) self.log.setLevel(self.options.log_level) self.handler = logging.FileHandler(self.options.log_file) self.handler.setLevel(self.options.log_level) format = "%(asctime)s %(name)s[%(process)d] %(levelname)s: %(message)s" self.handler.setFormatter(logging.Formatter(format)) self.log.addHandler(self.handler) # setup apis self.chefapi = Chef(self.options.chef_base_path, self.options.aws_keypair_pem, self.options.aws_username, self.options.chef_boot_run_list, self.options.chef_boot_sudo, self.options.chef_boot_version, self.log) self.cloudapi = Aws(self.options.aws_key, self.options.aws_secret, self.options.aws_keypair, self.options.aws_security_groups, self.options.rds_username, self.options.rds_password, self.log) # prepare the data self.databag = self.options.databag self.launch_data = json.loads(self.options.launch_data) self.attributes = json.loads(self.options.attributes) # prepare progress command = '' if can_continue: command = ['/usr/bin/python'] + sys.argv self.pidfile = tempfile.NamedTemporaryFile(delete=False).name self.progress = Progress(self.options.progress_file, self.pidfile, steps, title, description, {'0':(time.time(),None)}, started_by=self.options.started_by, command=command) self.progress.pidfile(self.pidfile) # in case this is a restart
class Daemon(object): """ A generic daemon class with added support for chef/cloud apis and communicating with other processes via a progress file. Usage: subclass the Daemon class and override the run() method """ def __init__(self, steps, title, description='', can_continue=False): # setup command line parsing parser = OptionParser() parser.add_option("-d","--daemonize",default=False,action="store_true") parser.add_option("--trac-base-url") parser.add_option("--progress-file") parser.add_option("--log-file") parser.add_option("--log-level", default=logging.DEBUG) parser.add_option("--chef-base-path") parser.add_option("--chef-boot-run-list", default=[], action='append') parser.add_option("--chef-boot-sudo",default=False, action="store_true") parser.add_option("--chef-boot-version") parser.add_option("--aws-key") parser.add_option("--aws-secret") parser.add_option("--aws-keypair") parser.add_option("--aws-keypair-pem") parser.add_option("--aws-username") parser.add_option("--aws-security-groups") parser.add_option("--rds-username") parser.add_option("--rds-password") parser.add_option("--databag") parser.add_option("--launch-data", default='{}', help="JSON dict") parser.add_option("--attributes", default='{}', help="JSON dict") parser.add_option("--started-by") parser.add_option("--notify-jabber") parser.add_option("--jabber-server") parser.add_option("--jabber-port") parser.add_option("--jabber-username") parser.add_option("--jabber-password") parser.add_option("--jabber-channel") (self.options, _args) = parser.parse_args() # setup logging (presumes something else will rotate it) self.log = logging.getLogger(self.__class__.__name__) self.log.setLevel(self.options.log_level) self.handler = logging.FileHandler(self.options.log_file) self.handler.setLevel(self.options.log_level) format = "%(asctime)s %(name)s[%(process)d] %(levelname)s: %(message)s" self.handler.setFormatter(logging.Formatter(format)) self.log.addHandler(self.handler) # setup apis self.chefapi = Chef(self.options.chef_base_path, self.options.aws_keypair_pem, self.options.aws_username, self.options.chef_boot_run_list, self.options.chef_boot_sudo, self.options.chef_boot_version, self.log) self.cloudapi = Aws(self.options.aws_key, self.options.aws_secret, self.options.aws_keypair, self.options.aws_security_groups, self.options.rds_username, self.options.rds_password, self.log) # prepare the data self.databag = self.options.databag self.launch_data = json.loads(self.options.launch_data) self.attributes = json.loads(self.options.attributes) # prepare progress command = '' if can_continue: command = ['/usr/bin/python'] + sys.argv self.pidfile = tempfile.NamedTemporaryFile(delete=False).name self.progress = Progress(self.options.progress_file, self.pidfile, steps, title, description, {'0':(time.time(),None)}, started_by=self.options.started_by, command=command) self.progress.pidfile(self.pidfile) # in case this is a restart def daemonize(self): """ do the UNIX double-fork magic, see Stevens' "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 """ try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) except OSError, e: self.log.critical("fork 1 failed: %d (%s)\n" %(e.errno, e.strerror)) sys.exit(1) # decouple from parent environment os.chdir("/") os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent sys.exit(0) except OSError, e: self.log.critical("fork 2 failed: %d (%s)\n" %(e.errno, e.strerror)) sys.exit(1)
def __init__(self, steps, title, description='', can_continue=False): # setup command line parsing parser = OptionParser() parser.add_option("-d", "--daemonize", default=False, action="store_true") parser.add_option("--trac-base-url") parser.add_option("--progress-file") parser.add_option("--log-file") parser.add_option("--log-level", default=logging.DEBUG) parser.add_option("--chef-base-path") parser.add_option("--chef-boot-run-list", default=[], action='append') parser.add_option("--chef-boot-sudo", default=False, action="store_true") parser.add_option("--chef-boot-version") parser.add_option("--aws-key") parser.add_option("--aws-secret") parser.add_option("--aws-keypair") parser.add_option("--aws-keypair-pem") parser.add_option("--aws-username") parser.add_option("--aws-security-groups") parser.add_option("--rds-username") parser.add_option("--rds-password") parser.add_option("--databag") parser.add_option("--launch-data", default='{}', help="JSON dict") parser.add_option("--attributes", default='{}', help="JSON dict") parser.add_option("--started-by") parser.add_option("--notify-jabber") parser.add_option("--jabber-server") parser.add_option("--jabber-port") parser.add_option("--jabber-username") parser.add_option("--jabber-password") parser.add_option("--jabber-channel") (self.options, _args) = parser.parse_args() # setup logging (presumes something else will rotate it) self.log = logging.getLogger(self.__class__.__name__) self.log.setLevel(self.options.log_level) self.handler = logging.FileHandler(self.options.log_file) self.handler.setLevel(self.options.log_level) format = "%(asctime)s %(name)s[%(process)d] %(levelname)s: %(message)s" self.handler.setFormatter(logging.Formatter(format)) self.log.addHandler(self.handler) # setup apis self.chefapi = Chef(self.options.chef_base_path, self.options.aws_keypair_pem, self.options.aws_username, self.options.chef_boot_run_list, self.options.chef_boot_sudo, self.options.chef_boot_version, self.log) self.cloudapi = Aws(self.options.aws_key, self.options.aws_secret, self.options.aws_keypair, self.options.aws_security_groups, self.options.rds_username, self.options.rds_password, self.log) # prepare the data self.databag = self.options.databag self.launch_data = json.loads(self.options.launch_data) self.attributes = json.loads(self.options.attributes) # prepare progress command = '' if can_continue: command = ['/usr/bin/python'] + sys.argv self.pidfile = tempfile.NamedTemporaryFile(delete=False).name self.progress = Progress(self.options.progress_file, self.pidfile, steps, title, description, {'0': (time.time(), None)}, started_by=self.options.started_by, command=command) self.progress.pidfile(self.pidfile) # in case this is a restart
class Daemon(object): """ A generic daemon class with added support for chef/cloud apis and communicating with other processes via a progress file. Usage: subclass the Daemon class and override the run() method """ def __init__(self, steps, title, description='', can_continue=False): # setup command line parsing parser = OptionParser() parser.add_option("-d", "--daemonize", default=False, action="store_true") parser.add_option("--trac-base-url") parser.add_option("--progress-file") parser.add_option("--log-file") parser.add_option("--log-level", default=logging.DEBUG) parser.add_option("--chef-base-path") parser.add_option("--chef-boot-run-list", default=[], action='append') parser.add_option("--chef-boot-sudo", default=False, action="store_true") parser.add_option("--chef-boot-version") parser.add_option("--aws-key") parser.add_option("--aws-secret") parser.add_option("--aws-keypair") parser.add_option("--aws-keypair-pem") parser.add_option("--aws-username") parser.add_option("--aws-security-groups") parser.add_option("--rds-username") parser.add_option("--rds-password") parser.add_option("--databag") parser.add_option("--launch-data", default='{}', help="JSON dict") parser.add_option("--attributes", default='{}', help="JSON dict") parser.add_option("--started-by") parser.add_option("--notify-jabber") parser.add_option("--jabber-server") parser.add_option("--jabber-port") parser.add_option("--jabber-username") parser.add_option("--jabber-password") parser.add_option("--jabber-channel") (self.options, _args) = parser.parse_args() # setup logging (presumes something else will rotate it) self.log = logging.getLogger(self.__class__.__name__) self.log.setLevel(self.options.log_level) self.handler = logging.FileHandler(self.options.log_file) self.handler.setLevel(self.options.log_level) format = "%(asctime)s %(name)s[%(process)d] %(levelname)s: %(message)s" self.handler.setFormatter(logging.Formatter(format)) self.log.addHandler(self.handler) # setup apis self.chefapi = Chef(self.options.chef_base_path, self.options.aws_keypair_pem, self.options.aws_username, self.options.chef_boot_run_list, self.options.chef_boot_sudo, self.options.chef_boot_version, self.log) self.cloudapi = Aws(self.options.aws_key, self.options.aws_secret, self.options.aws_keypair, self.options.aws_security_groups, self.options.rds_username, self.options.rds_password, self.log) # prepare the data self.databag = self.options.databag self.launch_data = json.loads(self.options.launch_data) self.attributes = json.loads(self.options.attributes) # prepare progress command = '' if can_continue: command = ['/usr/bin/python'] + sys.argv self.pidfile = tempfile.NamedTemporaryFile(delete=False).name self.progress = Progress(self.options.progress_file, self.pidfile, steps, title, description, {'0': (time.time(), None)}, started_by=self.options.started_by, command=command) self.progress.pidfile(self.pidfile) # in case this is a restart def daemonize(self): """ do the UNIX double-fork magic, see Stevens' "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 """ try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) except OSError, e: self.log.critical("fork 1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) # decouple from parent environment os.chdir("/") os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent sys.exit(0) except OSError, e: self.log.critical("fork 2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1)