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 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 delete(shortname): session = db.Session() the_site = Site.get(shortname) if not the_site: raise Site.DoesNotExist("Cannot delete {0} because it does not exist in the DB".format(shortname)) try: the_site._shell_delete() except shell.ShellActionFailed as e: logger.exception("Shell action failed") raise else: if not shell.is_pretend(): session.delete(the_site) session.commit() do("service nginx reload") logger.info("Deleted {0} from the DB".format(shortname))
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 _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 _shell_delete(self): do("rm {0}".format(self._get_path())) do("service nginx reload")
def _shell_create(self): self._format_copy("site.nginx.domain.conf", self._get_path()) do("service nginx reload")
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 _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 _shell_delete(self): do("pkill -u {0}".format(self.username), ignore_errors=True) wait("Waiting for user's processes to exit") do("userdel -r {0}".format(self.username))