Exemplo n.º 1
0
def install_updates(message=DefaultMessage()):
    updates = storage.updates.get("updates")
    if not updates:
        return
    signals.emit("updates", "pre_install")
    amount = len(updates)
    responses, ids = [], []
    for z in enumerate(updates):
        message.update("info", "%s of %s..." % (z[0]+1, amount), head="Installing updates")
        for x in sorted(z[1]["tasks"], key=lambda y: y["step"]):
            getout = False
            if x["unit"] == "shell":
                s = shell(x["order"], stdin=x.get("data", None))
                if s["code"] != 0:
                    responses.append((x["step"], s["stderr"]))
                    getout = True
                    break
            elif x["unit"] == "fetch":
                try:
                    download(x["order"], x["data"], True)
                except Exception, e:
                    code = 1
                    if hasattr(e, "code"):
                        code = e.code
                    responses.append((x["step"], str(code)))
                    getout = True
                    break
        else:
            ids.append(z[1]["id"])
            config.set("updates", "current_update", z[1]["id"])
            config.save()
            continue
        message.complete("error", "Installation of update %s failed. See logs for details." % str(z[1]["id"]))
        print responses
        break
Exemplo n.º 2
0
    def update(self, message=DefaultMessage()):
        if self.version == self.meta.version.rsplit("-", 1)[0]:
            raise Exception("Website is already at the latest version")
        elif self.version in [None, "None"]:
            raise Exception("Updates not supported for this website type")

        # Classify the source package type
        if not self.meta.download_url:
            ending = ""
        elif self.meta.download_url.endswith(".tar.gz"):
            ending = ".tar.gz"
        elif self.meta.download_url.endswith(".tgz"):
            ending = ".tgz"
        elif self.meta.download_url.endswith(".tar.bz2"):
            ending = ".tar.bz2"
        elif self.meta.download_url.endswith(".zip"):
            ending = ".zip"
        elif self.meta.download_url.endswith(".git"):
            ending = ".git"
        else:
            raise Exception("Only GIT repos, gzip, bzip, and zip packages supported for now")

        # Download and extract the source package
        message.update("info", "Downloading website source...", head="Updating website")
        if self.download_url and ending == ".git":
            pkg_path = self.download_url
        elif self.download_url:
            pkg_path = os.path.join("/tmp", self.id+ending)
            try:
                download(self.meta.download_url, file=pkg_path, crit=True)
            except Exception, e:
                raise Exception("Couldn't update - %s" % str(e))
Exemplo n.º 3
0
def install_updates(nthread=NotificationThread()):
    """
    Install all available updates from arkOS repo server.

    :param message message: Message object to update with status
    """
    nthread.title = "Installing updates"

    updates = storage.updates
    if not updates:
        return
    signals.emit("updates", "pre_install")
    amount = len(updates)
    responses, ids = [], []
    for z in enumerate(updates.values()):
        msg = "{0} of {1}...".format(z[0] + 1, amount)
        nthread.update(Notification("info", "Updates", msg))
        for x in sorted(z[1]["tasks"], key=lambda y: y["step"]):
            if x["unit"] == "shell":
                s = shell(x["order"], stdin=x.get("data", None))
                if s["code"] != 0:
                    responses.append((x["step"], s["stderr"]))
                    break
            elif x["unit"] == "fetch":
                try:
                    download(x["order"], x["data"], True)
                except Exception as e:
                    code = getattr(e, "code", 1)
                    responses.append((x["step"], str(code)))
                    break
        else:
            ids.append(z[1]["id"])
            config.set("updates", "current_update", z[1]["id"])
            config.save()
            continue
        for x in responses:
            nthread.update(Notification("debug", "Updates", x))
        msg = "Installation of update {0} failed. See logs for details."
        msg = msg.format(z[1]["id"])
        nthread.complete(Notification("error", "Updates", msg))
        break
    else:
        signals.emit("updates", "post_install")
        for x in responses:
            nthread.update(Notification("debug", "Updates", x))
        msg = "Please restart your system for the updates to take effect."
        nthread.complete(Notification("success", "Updates", msg))
        return ids
Exemplo n.º 4
0
    def _update(self, nthread):
        nthread.title = "Updating website"
        if self.version == self.app.version.rsplit("-", 1)[0]:
            raise errors.InvalidConfigError(
                "Website is already at the latest version")
        elif self.version in [None, "None"]:
            raise errors.InvalidConfigError(
                "Updates not supported for this website type")

        # 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))

        # Download and extract the source package
        msg = "Downloading website source..."
        nthread.update(Notification("info", "Webs", msg))
        if self.app.download_url and ending == ".git":
            pkg_path = self.download_url
        elif self.app.download_url:
            pkg_path = os.path.join("/tmp", self.id + ending)
            download(self.app.download_url, file=pkg_path, crit=True)

        # Call the site type's update hook
        msg = "Updating website..."
        nthread.update(Notification("info", "Webs", msg))
        self.update_site(pkg_path, self.app.version)

        # Update stored version and remove temp source archive
        msg = "{0} updated successfully".format(self.id)
        nthread.complete(Notification("success", "Webs", msg))
        self.version = self.app.version.rsplit("-", 1)[0]
        if pkg_path:
            os.unlink(pkg_path)
Exemplo n.º 5
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.º 6
0
            except Exception, e:
                raise Exception("Database could not be created - %s" % str(e))

        # Make sure the target directory exists, but is empty
        pkg_path = "/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
        message.update("info", "Downloading website source...", head="Installing website")
        if self.meta.download_url and ending == ".git":
            git.Repo.clone_from(self.meta.download_url, self.path)
        elif self.meta.download_url:
            try:
                download(self.meta.download_url, file=pkg_path, crit=True)
            except Exception, e:
                raise Exception("Couldn't download - %s" % str(e))

            # Format extraction command according to type
            message.update("info", "Extracting source...", head="Installing website")
            if ending in [".tar.gz", ".tgz", ".tar.bz2"]:
                extract_cmd = "tar "
                extract_cmd += "xzf" if ending in [".tar.gz", ".tgz"] else "xjf"
                extract_cmd += " /tmp/%s -C %s --strip 1" % (self.id+ending, self.path)
            else:
                extract_cmd = "unzip -d %s /tmp/%s" % (self.path, self.id+ending)
            status = shell(extract_cmd)
            if status["code"] >= 1:
                raise Exception(status["stderr"])
            os.remove(pkg_path)