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 _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)))
import piccolo.log import piccolo.config from piccolo.shell import flags_to_mode, ugo_mode, exists from piccolo import db import os, stat, logging, sys from piccolo import sites, users, databases """ Really just serves to set things up (initialize database, etc.) """ VERSION = (0, 1) logger = logging.getLogger(__name__) if not exists(piccolo.config.DATABASE): db.Base.metadata.create_all(db.sqlite_db) os.chmod(piccolo.config.DATABASE, flags_to_mode("u=rw")) # Test security settings mode_checks = [ (piccolo.config.DATA_DIR, "u=rwx,g=rx"), (piccolo.config.LOGGING['directory'], "u=rwx,g=rx"), (piccolo.config.CONFIG_PATH, "u=rw"), (piccolo.config.PICCOLO_SRC_DIR, "u=rwx"), (piccolo.config.NGINX_CONF_ROOT, "u=rwx,g=rx,o=rx"), (piccolo.config.DATABASE, "u=rw") ] for path, required_flags in mode_checks: if not exists(path): logger.error("{0} is missing. Cannot start.".format(path))