def addUser(self, user, suppress_welcome=False): if shell.is_pretend(): suppress_welcome = True logger.info("Pretending to add {0} to site {1}".format(user, self)) session = db.Session() logger.debug('Users in {0}: {1}'.format(self.shortname, self.users)) if user in self.users: raise Site.AlreadyHasUser if not shell.is_pretend(): self.users.append(user) session.commit() try: do("gpasswd -a {0} {1}".format(user.username, self.shortname)) do("ln -s {0} {1}".format(self._get_home(), shell.join(user._get_home(), self.shortname))) except shell.ShellActionFailed: if not shell.is_pretend(): self.users.remove(user) session.commit() raise else: if not suppress_welcome: email_vars = { "$FULL_NAME": user.full_name, "$SITE_SHORTNAME": self.shortname, } email_message = shell.format(open(shell.join(config.TEMPLATE_ROOT, 'site_adduser_email.txt')).read(), email_vars) email_subject = "Peninsula Account Update: {0} added to site {1}".format(user.username, self.shortname) user.send_email(email_subject, email_message) logger.info("Sent adduser email to {0}".format(user.email)) logger.info('Added {0} to {1}'.format(user.username, self.shortname))
def archive(destination=None): archive_name = '{0}.tar.gz'.format(theuser.username) if not destination: destination = shell.join(DATA_DIR, 'deleted_users', archive_name) else: destination = shell.join(destination, archive_name) try: subprocess.check_output( ["/bin/tar", "cvzf",], stderr=subprocess.STDOUT ) except subprocess.CalledProcessError, err: raise User.ShellActionFailed(err)
def _shell_create(self): do("useradd -U -b {0} -m -s /bin/bash {1}".format( config.USERS_ROOT, self.username )) self._format_append("user_bash_profile.sh", shell.join(self._get_home(), ".profile")) tmppass = shell.join(self._get_home(), '.tmppass') with open(tmppass, 'w') as t: os.chmod(tmppass, stat.S_IRWXU) t.write("{0}\n{0}\n".format(self._temp_password)) t.close() do("passwd {0} < {1}".format(self.username, tmppass), shell=True) do("passwd -e {0}".format(self.username)) do("rm {0}".format(tmppass))
def create(shortname, full_name): session = db.Session() if Site.get(shortname): raise Site.Exists elif shell.exists(shell.join(config.SITES_ROOT, shortname)): raise Site.Exists elif not config.NAME_REGEX.match(shortname) or len(shortname) > config.NAME_LIMIT: raise Site.BadName("Site names must be between 2 and {0} characters and be valid hostnames (only letters, numbers, and dashes)".format(config.NAME_LIMIT)) elif Domain.get('.'.join([shortname, config.DEFAULT_DOMAIN])): existing = Domain.get('.'.join([shortname, config.DEFAULT_DOMAIN])) raise Site.BadName("There is already a domain {0} in piccolo, so adding this site would "\ "create a name conflict. Remove {0} from {1} before "\ "adding this site.".format(existing.domain_name, existing.site.shortname)) else: logger.debug("site doesn't exist yet in db") new_site = Site(shortname, full_name) new_site.db_password = shell.generate_password(length=20) new_site.db_username = re.sub(r'[^\w\d]', '_', new_site.shortname) new_site.db_username_mysql = new_site.db_username[:16] # grrr if not shell.is_pretend(): session.add(new_site) session.commit() try: new_site._shell_create() if not shell.is_pretend(): Domain.create('.'.join([new_site.shortname, config.DEFAULT_DOMAIN]), new_site) except shell.ShellActionFailed as e: logger.exception("Shell action failed") raise else: do("service nginx reload") logger.info('Created site "{0}" [{1}]'.format(full_name, shortname))
def create(username, full_name, email, suppress_welcome=False, fake_create=False): if fake_create: suppress_welcome = True session = db.Session() if not config.NAME_REGEX.match(username) or len(username) > config.NAME_LIMIT: raise User.BadName("{0} is not a valid username (containing only letters, numbers, and dashes and being between 2 and {1} characters)".format(username, config.NAME_LIMIT)) if User.get(username): raise User.Exists("There is already a user named {0} in piccolo".format(username)) try: pwd.getpwnam(username) except KeyError: pass else: if not fake_create: raise User.Exists("There is already a user named {0} in /etc/passwd".format(username)) if shell.exists(shell.join(config.USERS_ROOT, username)) and not fake_create: raise User.BadName("Cannot create user {1} because folder {0} already exists.".format(shell.join(config.USERS_ROOT, username), username)) logger.debug("user doesn't exist yet") new_user = User(username, full_name, email) session.add(new_user) session.commit() new_user._temp_password = shell.generate_password(length=12) try: if not fake_create: new_user._shell_create() except User.ShellActionFailed: session.delete(new_user) session.commit() raise else: logger.info('Created user "{0}" [{1}] with contact email <{2}>'.format(full_name, username, email)) if not suppress_welcome: user_vars = new_user._vars() user_vars.update({"$INITIAL_PASSWORD": new_user._temp_password,}) email_message = shell.format(open(shell.join(config.TEMPLATE_ROOT, 'user_email.txt')).read(), user_vars) email_subject = "New Peninsula Account {0}".format(new_user.username) new_user.send_email(email_subject, email_message) logger.info("Sent welcome email to {0}".format(new_user.email)) elif not fake_create: logger.info("User's initial password: {0}".format(new_user._temp_password))
def delete(dbname, site): session = db.Session() the_db = Database.get(dbname) if not the_db: raise Database.DoesNotExist if the_db.site is not site: raise Database.Mismatch("Database {0} exists, but is owned by {1}, not {2}".format( dbname, the_db.site.shortname, site.shortname, )) the_db._drop() if not shell.is_pretend(): dbms_string = the_db._dbms_string() session.delete(the_db) session.commit() old_db_list = open(shell.join(site._get_home(), 'config', 'databases.txt'), 'r').read() new_db_list = old_db_list.replace("[{0}] {1}\n".format(dbms_string, dbname), '') with open(shell.join(site._get_home(), 'config', 'databases.txt'), 'w') as db_list: db_list.write(new_db_list)
def create(dbname, site, dbms, fake_create): session = db.Session() if Database.get(dbname): raise Database.Exists # do not ignore db already existing in piccolo... if len(dbname) > 63: raise Database.BadName("Database names must be < 63 characters long") new_db = Database(dbname, site, dbms) new_db._create(fake_create) if not shell.is_pretend(): session.add(new_db) session.commit() with open(shell.join(site._get_home(), 'config', 'databases.txt'), 'a') as db_list: db_list.write("[{0}] {1}\n".format(new_db._dbms_string(), new_db.dbname))
def _shell_delete(self): for service in ("httpd.sh", "php.sh"): do("sudo -u {0} {1} stop".format(self.shortname, shell.join(self._get_home(), "bin", service))) do("pkill -u {0}".format(self.shortname), ignore_errors=True) wait("Waiting for services to be removed from process list") try: self._drop_db_accounts() except: if not shell.is_forced(): raise do("rm /etc/sudoers.d/{0}".format(self.shortname)) do("rm /etc/piccolo/nginx/{0}.conf".format(self.shortname)) do("rm -rf /etc/piccolo/nginx/{0}_domains".format(self.shortname)) do("userdel -r {0}".format(self.shortname)) do("groupdel {0}".format(self.shortname), ignore_errors=True)
def removeUser(self, user): if shell.is_pretend(): logger.info("Pretending to remove {0} from site {1}".format(user, self)) session = db.Session() logger.debug('Users in {0}: {1}'.format(self.shortname, self.users)) if not user in self.users: raise Site.NoSuchUser try: do("gpasswd -d {0} {1}".format(user.username, self.shortname)) do("rm {0}".format(shell.join(user._get_home(), self.shortname))) except shell.ShellActionFailed: logger.exception("Removal failed; user is still member of site in DB.") raise else: if not shell.is_pretend(): self.users.remove(user) session.commit() logger.info('Removed {0} from {1}'.format(user.username, self.shortname))
def _get_home(self): return shell.join(config.SITES_ROOT, self.shortname)
def _format_copy(self, src, dest): src = shell.join(config.TEMPLATE_ROOT, src) shell.template_copy(src, dest, self._vars())
def _get_path(self): return shell.join(self._get_folder(), "{0}.conf".format(self.domain_name))
def _get_folder(self): return shell.join(config.NGINX_CONF_ROOT, "{0}_domains".format(self.site.shortname))
def _format_template(self, src): src = shell.join(config.TEMPLATE_ROOT, src) return shell.format(open(src, 'r').read(), self._vars())
def _shell_create(self, pretend=False): # Actual shell-level business of provisioning the site goes here # Set up siteuser and sitegroup do("useradd -U -b {0} -m -s /bin/bash {1}".format( config.SITES_ROOT, self.shortname )) # Set up template and permissions do("chmod u=rwX,g=rwXs,o=X {0}".format(self._get_home())) for path in glob.glob(shell.join(config.TEMPLATE_ROOT, 'site', '*')): do("cp -R {0} {1}".format(path, self._get_home())) for d in Site._additional_dirs: do("mkdir {0}".format(shell.join(self._get_home(), d))) do("chown -R {0}:{0} {1}".format(self.shortname, self._get_home())) for p in Site._permissions: do("chmod {0} {1}".format(p[1], shell.join(self._get_home(), p[0]))) # Do variable substitution in template files for root, dirs, files in os.walk(self._get_home()): for name in files: shell.format_file(shell.join(root, name), self._vars()) for root, dirs, files in os.walk(shell.join(self._get_home(), "bin")): for name in files: do("chmod u=rwx,g=rx,o= {0}".format(shell.join(root, name))) for root, dirs, files in os.walk(shell.join(self._get_home(), "config")): for name in files: do("chmod u=rw,g=rw,o= {0}".format(shell.join(root, name))) # Install crontab from temp file crontab_path = shell.join(self._get_home(), 'crontab') self._format_copy('site.crontab', crontab_path) do("crontab -u {0} {1}".format(self.shortname, crontab_path)) do("rm {0}".format(crontab_path)) # Install sudoers sudoers_dest = '/etc/sudoers.d/{0}'.format(self.shortname) if shell.exists(sudoers_dest): raise shell.ShellActionFailed("{0} exists. Abort!".format(sudoers_dest)) self._format_copy('site.sudoers', sudoers_dest) do("chmod u=r,g=r,o= {0}".format(sudoers_dest)) do("chown root:root {0}".format(sudoers_dest)) # Install nginx config nginx_dest = shell.join(config.NGINX_CONF_ROOT, "{0}.conf".format(self.shortname)) if shell.exists(nginx_dest): raise shell.ShellActionFailed("{0} exists. Abort!".format(nginx_dest)) self._format_copy('site.nginx.conf', nginx_dest) do("chmod u=rw,g=rw,o=r {0}".format(nginx_dest)) do("chown root:admin {0}".format(nginx_dest)) do("mkdir {0}".format(shell.join(config.NGINX_CONF_ROOT, "{0}_domains".format(self.shortname)))) # Set up db users self._create_db_accounts() # Start site for service in ("httpd.sh", "php.sh"): do("sudo -u {0} {1} start".format(self.shortname, shell.join(self._get_home(), "bin", service)))
def _get_home(self): return shell.join(config.USERS_ROOT, self.username)