Exemplo n.º 1
0
def create_db(name, type_id):
    """Add a database."""
    try:
        manager = databases.get_managers("db-" + type_id)
        manager.add_db(name)
        logger.success('ctl:db:create', 'Added {0}'.format(name))
    except Exception as e:
        raise CLIException(str(e))
Exemplo n.º 2
0
def add_user(name, type_id):
    """Add a database user."""
    try:
        manager = databases.get_managers("db-" + type_id)
        manager.add_user(name)
        logger.success('ctl:dbusr:add', 'Added user {0}'.format(name))
    except Exception as e:
        raise CLIException(str(e))
Exemplo n.º 3
0
 def post(self):
     data = request.get_json()["database"]
     manager = databases.get_managers(data["database_type"])
     try:
         db = manager.add_db(data["id"])
     except errors.InvalidConfigError as e:
         logger.error("Databases", str(e))
         return jsonify(errors={"msg": str(e)}), 422
     return jsonify(database=db.serialized)
Exemplo n.º 4
0
 def post(self):
     data = json.loads(request.data)["database_user"]
     manager = databases.get_managers(data["type"])
     try:
         u = manager.add_user(data["id"], data["passwd"])
     except Exception, e:
         resp = jsonify(message="Database user couldn't be added: %s" % str(e))
         resp.status_code = 422
         return resp
Exemplo n.º 5
0
def list_types():
    """List all database types and running status."""
    try:
        dbs = databases.get_managers()
        if not dbs:
            logger.info('ctl:db:types', 'No databases found')
            return
        llen = len(sorted(dbs, key=lambda x: len(x.name))[-1].name)
        for x in sorted(dbs, key=lambda x: x.id):
            click.echo(
                click.style('{name: <{fill}}'.format(name=x.name,
                                                     fill=llen + 3),
                            fg="white",
                            bold=True) +
                click.style("Running" if x.state else "Stopped",
                            fg="green" if x.state else "red"))
    except Exception as e:
        raise CLIException(str(e))
Exemplo n.º 6
0
Arquivo: backup.py Projeto: ns408/core
    def restore(self, backup, data=True, nthread=NotificationThread()):
        """
        Restore an associated arkOS app backup.

        :param Backup backup: backup to restore
        :param bool data: Restore backed up data files too?
        :param NotificationThread nthread: notification thread to use
        :returns: ``Backup``
        :rtype: dict
        """
        nthread.title = "Restoring backup"

        # Trigger pre-restore hook for the app/site
        signals.emit("backups", "pre_restore", self)
        msg = "Running pre-restore for {0}...".format(backup["pid"])
        nthread.update(Notification("info", "Backup", msg))
        self.pre_restore()

        # Extract all files in archive
        sitename = ""
        nthread.update(Notification("info", "Backup", "Extracting files..."))
        with tarfile.open(backup["path"], "r:gz") as t:
            for x in t.getnames():
                if x.startswith("etc/nginx/sites-available"):
                    sitename = os.path.basename(x)
            t.extractall("/")

        # If it's a website that had a database, restore DB via SQL file too
        dbpasswd = ""
        if self.ctype == "site" and sitename:
            self.site = websites.get(sitename)
            if not self.site:
                websites.scan()
                self.site = websites.get(sitename)
            meta = configparser.SafeConfigParser()
            meta.read(os.path.join(self.site.path, ".arkos"))
            sql_path = "/{0}.sql".format(sitename)
            if meta.get("website", "dbengine", fallback=None) \
                    and os.path.exists(sql_path):
                nthread.update(
                    Notification("info", "Backup", "Restoring database..."))
                dbmgr = databases.get_managers(meta.get("website", "dbengine"))
                if databases.get(sitename):
                    databases.get(sitename).remove()
                db = dbmgr.add_db(sitename)
                with open(sql_path, "r") as f:
                    db.execute(f.read())
                os.unlink(sql_path)
                if dbmgr.meta.database_multiuser:
                    dbpasswd = random_string(16)
                    dbuser = databases.get_users(sitename)
                    if dbuser:
                        dbuser.remove()
                    db_user = dbmgr.add_user(sitename, dbpasswd)
                    db_user.chperm("grant", db)

        # Trigger post-restore hook for the app/site
        msg = "Running post-restore for {0}...".format(backup["pid"])
        nthread.update(Notification("info", "Backup", msg))
        if self.ctype == "site":
            self.post_restore(self.site, dbpasswd)
            self.site.nginx_enable()
        else:
            self.post_restore()
        signals.emit("backups", "post_restore", self)
        backup["is_ready"] = True
        msg = "{0} restored successfully.".format(backup["pid"])
        nthread.complete(Notification("info", "Backup", msg))
        return backup
Exemplo n.º 7
0
def list_types():
    if request.args.get("rescan", None):
        databases.scan_managers()
    dbs = databases.get_managers()
    return jsonify(database_types=[x.serialized for x in dbs])
Exemplo n.º 8
0
    def _install(self, extra_vars, enable, nthread):
        nthread.title = "Installing website"

        msg = Notification("info", "Webs", "Preparing to install...")
        nthread.update(msg)

        # Make sure the chosen port is indeed open
        if not tracked_services.is_open_port(self.port, self.domain):
            cname = "({0})".format(self.app.id)
            raise errors.InvalidConfigError(cname, nthread)\
                from tracked_services.PortConflictError(self.port, self.domain)

        # Set some metadata values
        specialmsg, dbpasswd = "", ""
        site_dir = config.get("websites", "site_dir")
        path = (self.path or os.path.join(site_dir, self.id))
        self.path = path
        self.php = extra_vars.get("php") or self.php \
            or self.app.uses_php or False
        self.version = self.app.version.rsplit("-", 1)[0] \
            if self.app.website_updates else None

        # Classify the source package type
        if not self.app.download_url:
            ending = ""
        elif self.app.download_url.endswith(".tar.gz"):
            ending = ".tar.gz"
        elif self.app.download_url.endswith(".tgz"):
            ending = ".tgz"
        elif self.app.download_url.endswith(".tar.bz2"):
            ending = ".tar.bz2"
        elif self.app.download_url.endswith(".zip"):
            ending = ".zip"
        elif self.app.download_url.endswith(".git"):
            ending = ".git"
        else:
            raise errors.InvalidConfigError(
                "Invalid source archive format in {0}".format(self.app.id))

        msg = "Running pre-installation..."
        uid, gid = users.get_system("http").uid, groups.get_system("http").gid
        nthread.update(Notification("info", "Webs", msg))

        # Call website type's pre-install hook
        self.pre_install(extra_vars)

        # If needs DB and user didn't select an engine, choose one for them
        if len(self.app.database_engines) > 1 \
                and extra_vars.get("dbengine", None):
            self.app.selected_dbengine = extra_vars.get("dbengine")
        if not getattr(self.app, "selected_dbengine", None)\
                and self.app.database_engines:
            self.app.selected_dbengine = self.app.database_engines[0]

        # Create DB and/or DB user as necessary
        if getattr(self.app, "selected_dbengine", None):
            msg = "Creating database..."
            nthread.update(Notification("info", "Webs", msg))
            mgr = databases.get_managers(self.app.selected_dbengine)
            if not mgr:
                estr = "No manager found for {0}"
                raise errors.InvalidConfigError(
                    estr.format(self.app.selected_dbengine))
            # Make sure DB daemon is running if it has one
            if not mgr.state:
                svc = services.get(mgr.meta.database_service)
                svc.restart()
            self.db = mgr.add_db(self.id)
            if hasattr(self.db, "path"):
                os.chmod(self.db.path, 0o660)
                os.chown(self.db.path, -1, gid)
            # If multiuser DB type, create user
            if mgr.meta.database_multiuser:
                dbpasswd = random_string(16)
                db_user = mgr.add_user(self.id, dbpasswd)
                db_user.chperm("grant", self.db)

        # Make sure the target directory exists, but is empty
        pkg_path = os.path.join("/tmp", self.id + ending)
        if os.path.isdir(self.path):
            shutil.rmtree(self.path)
        os.makedirs(self.path)

        # Download and extract the source repo / package
        msg = "Downloading website source..."
        nthread.update(Notification("info", "Webs", msg))
        if self.app.download_url and ending == ".git":
            g = git.Repo.clone_from(self.app.download_url, self.path)
            if hasattr(self.app, "download_at_tag"):
                g = git.Git(self.path)
                g.checkout(self.app.download_git_tag)
        elif self.app.download_url:
            download(self.app.download_url, file=pkg_path, crit=True)

            # Format extraction command according to type
            msg = "Extracting source..."
            nthread.update(Notification("info", "Webs", msg))
            if ending in [".tar.gz", ".tgz", ".tar.bz2"]:
                arch = tarfile.open(pkg_path, "r:gz")
                r = (x for x in arch.getnames() if re.match("^[^/]*$", x))
                toplvl = next(r, None)
                if not toplvl:
                    raise errors.OperationFailedError(
                        "Malformed source archive")
                arch.extractall(site_dir)
                os.rename(os.path.join(site_dir, toplvl), self.path)
            else:
                arch = zipfile.ZipFile(pkg_path)
                r = (x for x in arch.namelist() if re.match("^[^/]*/$", x))
                toplvl = next(r, None)
                if not toplvl:
                    raise errors.OperationFailedError(
                        "Malformed source archive")
                arch.extractall(site_dir)
                os.rename(os.path.join(site_dir, toplvl.rstrip("/")),
                          self.path)
            os.remove(pkg_path)

        # Set proper starting permissions on source directory
        os.chmod(self.path, 0o755)
        os.chown(self.path, uid, gid)
        for r, d, f in os.walk(self.path):
            for x in d:
                os.chmod(os.path.join(r, x), 0o755)
                os.chown(os.path.join(r, x), uid, gid)
            for x in f:
                os.chmod(os.path.join(r, x), 0o644)
                os.chown(os.path.join(r, x), uid, gid)

        # If there is a custom path for the data directory, set it up
        if getattr(self.app, "website_datapaths", None) \
                and extra_vars.get("datadir"):
            self.data_path = extra_vars["datadir"]
            if not os.path.exists(self.data_path):
                os.makedirs(self.data_path)
            os.chmod(self.data_path, 0o755)
            os.chown(self.data_path, uid, gid)
        elif hasattr(self, "website_default_data_subdir"):
            self.data_path = os.path.join(self.path,
                                          self.website_default_data_subdir)
        else:
            self.data_path = self.path

        # Create the nginx serverblock
        addtoblock = self.addtoblock or []
        if extra_vars.get("addtoblock"):
            addtoblock += nginx.loads(extra_vars.get("addtoblock"), False)
        default_index = "index." + ("php" if self.php else "html")
        if hasattr(self.app, "website_root"):
            webroot = os.path.join(self.path, self.app.website_root)
        else:
            webroot = self.path
        block = nginx.Conf()
        server = nginx.Server(
            nginx.Key("listen", str(self.port)),
            nginx.Key("listen", "[::]:" + str(self.port)),
            nginx.Key("server_name", self.domain), nginx.Key("root", webroot),
            nginx.Key(
                "index",
                getattr(self.app, "website_index", None) or default_index),
            nginx.Location("/.well-known/acme-challenge/",
                           nginx.Key("root", self.path)))
        if addtoblock:
            server.add(*[x for x in addtoblock])
        block.add(server)
        nginx.dumpf(block, os.path.join("/etc/nginx/sites-available", self.id))
        challenge_dir = os.path.join(self.path, ".well-known/acme-challenge/")
        if not os.path.exists(challenge_dir):
            os.makedirs(challenge_dir)

        # Create arkOS metadata file
        meta = configparser.SafeConfigParser()
        meta.add_section("website")
        meta.set("website", "id", self.id)
        meta.set("website", "app", self.app.id)
        meta.set("website", "ssl",
                 self.cert.id if getattr(self, "cert", None) else "None")
        meta.set("website", "version", self.version or "None")
        if getattr(self.app, "website_datapaths", None) \
                and self.data_path:
            meta.set("website", "data_path", self.data_path)
        meta.set("website", "dbengine", "")
        meta.set("website", "dbengine",
                 getattr(self.app, "selected_dbengine", ""))
        with open(os.path.join(self.path, ".arkos"), "w") as f:
            meta.write(f)

        # Call site type's post-installation hook
        msg = "Running post-installation. This may take a few minutes..."
        nthread.update(Notification("info", "Webs", msg))
        specialmsg = self.post_install(extra_vars, dbpasswd)

        # Cleanup and reload daemons
        msg = "Finishing..."
        nthread.update(Notification("info", "Webs", msg))
        self.installed = True
        storage.websites[self.id] = self
        if self.port == 80:
            cleanup_acme_dummy(self.domain)
        signals.emit("websites", "site_installed", self)
        if enable:
            self.nginx_enable()
        if enable and self.php:
            php.open_basedir("add", "/srv/http/")
            php_reload()

        msg = "{0} site installed successfully".format(self.app.name)
        nthread.complete(Notification("success", "Webs", msg))
        if specialmsg:
            return specialmsg
Exemplo n.º 9
0
def list_types():
    dbs = databases.get_managers()
    if request.args.get("rescan", None):
        dbs = databases.scan_managers()
    return jsonify(database_types=[x.as_dict() for x in dbs])