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