class Website(Base): port = fields.Integer(default=80) ssl = fields.Boolean() domain = fields.String() path = fields.String() locations = fields.Factory(Location) @property def path_cfg_dir(self): return f"{self.parent.path_cfg_dir}/servers" @property def path_cfg(self): return f"{self.path_cfg_dir}/{self.instance_name}.http.conf" @property def path_web(self): return self.parent.path_web def configure(self): """Writes configuration of the website and its locations """ j.sals.fs.mkdir(self.path_cfg_dir) config = render_config_template("website", base_dir=j.core.dirs.BASEDIR, website=self) j.sals.fs.write_file(self.path_cfg, config) for location_name in self.locations.list_all(): location = self.locations.get(location_name) location.configure()
class Wallet(Base): ID = fields.Integer(required=True) origin = fields.Typed(dict, default=dict) addresses = fields.Factory(Address) key = fields.Bytes() email = fields.Email() url = fields.URL(required=False, allow_empty=True) data = fields.Json(allow_empty=False)
class Website(Base): port = fields.Integer(default=80) ssl = fields.Boolean() domain = fields.String() path = fields.String() locations = fields.Factory(Location) letsencryptemail = fields.String() @property def path_cfg_dir(self): return f"{self.parent.path_cfg_dir}/servers" @property def path_cfg(self): return f"{self.path_cfg_dir}/{self.instance_name}.http.conf" @property def path_web(self): return self.parent.path_web def generate_certificates(self): """Generate ssl certificate if ssl is enabled """ if self.ssl: j.sals.process.execute( f"certbot --nginx -d {self.domain} --non-interactive --agree-tos -m {self.letsencryptemail} --nginx-server-root {self.parent.path_cfg_dir}" ) def configure(self, generate_certificates=True): """Writes configuration of the website and its locations Args: generate_certificates (bool, optional): Will generate certificates if true. Defaults to True. """ j.sals.fs.mkdir(self.path_cfg_dir) config = render_config_template("website", base_dir=j.core.dirs.BASEDIR, website=self) j.sals.fs.write_file(self.path_cfg, config) for location_name in self.locations.list_all(): location = self.locations.get(location_name) location.configure() if generate_certificates: self.generate_certificates()
class User(Base): id = fields.Integer() first_name = fields.String(default="") last_name = fields.String(default="") emails = fields.List(fields.String()) permissions = fields.List(fields.Object(Permission)) custom_config = fields.Typed(dict) rating = fields.Integer() created_time = fields.DateTime(default=datetime.datetime.now) password = fields.Secret() machines = fields.Factory(Machine) def get_full_name(self): name = self.first_name if self.last_name: name += " " + self.last_name return name def get_unique_name(self): return self.full_name.replace(" ", "") + ".user" full_name = fields.String(compute=get_full_name) unique_name = fields.String(compute=get_unique_name)
class ThreebotServer(Base): _package_manager = fields.Factory(PackageManager) domain = fields.String() email = fields.String() acme_server_type = fields.Enum(AcmeServer) acme_server_url = fields.URL() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._rack = None self._gedis = None self._db = None self._gedis_http = None self._services = None self._packages = None self._started = False self._nginx = None self._redis = None self.rack.add(GEDIS, self.gedis) self.rack.add(GEDIS_HTTP, self.gedis_http.gevent_server) self.rack.add(SERVICE_MANAGER, self.services) def is_running(self): nginx_running = self.nginx.is_running() redis_running = self.redis.cmd.is_running( ) or j.sals.nettools.wait_connection_test("127.0.0.1", 6379, timeout=1) gedis_running = j.sals.nettools.wait_connection_test("127.0.0.1", 16000, timeout=1) return nginx_running and redis_running and gedis_running @property def started(self): return self._started @property def nginx(self): if self._nginx is None: self._nginx = j.tools.nginx.get("default") return self._nginx @property def redis(self): if self._redis is None: self._redis = j.tools.redis.get("default") return self._redis @property def db(self): if self._db is None: self._db = j.core.db return self._db @property def rack(self): if self._rack is None: self._rack = j.servers.rack return self._rack @property def gedis(self): if self._gedis is None: self._gedis = j.servers.gedis.get("threebot") return self._gedis @property def gedis_http(self): if self._gedis_http is None: self._gedis_http = j.servers.gedis_http.get("threebot") return self._gedis_http @property def services(self): if self._services is None: self._services = j.tools.servicemanager.get("threebot") return self._services @property def chatbot(self): return self.gedis._loaded_actors.get("chatflows_chatbot") @property def packages(self): if self._packages is None: self._packages = self._package_manager.get(self.instance_name) return self._packages def check_dependencies(self): install_msg = "Visit https://github.com/threefoldtech/js-sdk/blob/development/docs/wiki/quick_start.md for installation guide" if not self.nginx.installed: raise j.exceptions.NotFound( f"nginx is not installed.\n{install_msg}") ret = shutil.which("certbot") if not ret: raise j.exceptions.NotFound( f"certbot is not installed.\n{install_msg}") rc, out, err = j.sals.process.execute("certbot plugins") if "* nginx" not in out: raise j.exceptions.NotFound( f"python-certbot-nginx is not installed.\n{install_msg}") if not self.redis.installed: raise j.exceptions.NotFound( f"redis is not installed.\n{install_msg}") ret = shutil.which("tmux") if not ret: raise j.exceptions.NotFound( f"tmux is not installed.\n{install_msg}") ret = shutil.which("git") if not ret: raise j.exceptions.NotFound( f"git is not installed.\n{install_msg}") def start(self, wait: bool = False): # start default servers in the rack # handle signals for signal_type in (signal.SIGTERM, signal.SIGINT, signal.SIGKILL): gevent.signal(signal_type, self.stop) # mark app as started if self.is_running(): return self.check_dependencies() self.redis.start() self.nginx.start() self.rack.start() j.logger.register(f"threebot_{self.instance_name}") # add default packages for package_name in DEFAULT_PACKAGES: j.logger.info(f"Configuring package {package_name}") try: package = self.packages.get(package_name) self.packages.install(package) except Exception as e: self.stop() raise j.core.exceptions.Runtime( f"Error happened during getting or installing {package_name} package, the detailed error is {str(e)}" ) from e # install all package self.packages._install_all() j.logger.info("Reloading nginx") self.nginx.reload() # mark server as started self._started = True j.logger.info( f"Threebot is running at http://localhost:{PORTS.HTTP} and https://localhost:{PORTS.HTTPS}" ) self.rack.start(wait=wait) # to keep the server running def stop(self): server_packages = self.packages.list_all() for package_name in server_packages: package = self.packages.get(package_name) package.stop() self.nginx.stop() # mark app as stopped, do this before stopping redis j.logger.unregister() self.redis.stop() self.rack.stop() self._started = False
class Website(Base): domain = fields.String() ssl = fields.Boolean() port = fields.Integer(default=PORTS.HTTP) locations = fields.Factory(Location) includes = fields.List(fields.String()) letsencryptemail = fields.String() selfsigned = fields.Boolean(default=True) @property def cfg_dir(self): return j.sals.fs.join_paths(self.parent.cfg_dir, self.instance_name) @property def cfg_file(self): return j.sals.fs.join_paths(self.cfg_dir, "server.conf") @property def include_paths(self): paths = [] for include in self.includes: ## TODO validate location name and include website_name, location_name = include.split(".", 1) website = self.parent.websites.find(website_name) if not website: continue paths.append( j.sals.fs.join_paths(website.cfg_dir, "locations", location_name)) return paths def get_locations(self): for location in self.locations.list_all(): yield self.locations.get(location) def get_proxy_location(self, name): location = self.locations.get(name) location.location_type = LocationType.PROXY return location def get_custom_location(self, name): location = self.locations.get(name) location.location_type = LocationType.CUSTOM return location def get_static_location(self, name): location = self.locations.get(name) location.location_type = LocationType.STATIC return location def get_config(self): return render_config_template("website", base_dir=j.core.dirs.BASEDIR, website=self) def generate_certificates(self): if self.domain: rc, out, err = j.sals.process.execute( f"certbot --nginx -d {self.domain} " f"--non-interactive --agree-tos -m {self.letsencryptemail} " f"--nginx-server-root {self.parent.cfg_dir} " f"--logs-dir {j.core.dirs.LOGDIR}/certbot " f"--config-dir {j.core.dirs.CFGDIR}/certbot " f"--work-dir {j.core.dirs.VARDIR}/certbot ") if rc > 0: j.logger.error(f"Generating certificate failed {out}\n{err}") def generate_self_signed_certificates(self): keypempath = f"{self.parent.cfg_dir}/key.pem" certpempath = f"{self.parent.cfg_dir}/cert.pem" if j.sals.process.is_installed("mkcert"): res = j.sals.process.execute( f"mkcert -key-file {keypempath} -cert-file {certpempath} localhost *.localhost 127.0.0.1 ::1" ) if res[0] != 0: raise j.exceptions.JSException( f"Failed to generate self-signed certificate (using mkcert).{res}" ) else: if j.sals.fs.exists(f"{keypempath}") and j.sals.fs.exists( f"{certpempath}"): return res = j.sals.process.execute( f"openssl req -nodes -x509 -newkey rsa:4096 -keyout {keypempath} -out {certpempath} -days 365 -subj '/CN=localhost'" ) if res[0] != 0: raise j.exceptions.JSException( f"Failed to generate self-signed certificate (using openssl).{res}" ) def configure(self, generate_certificates=True): j.sals.fs.mkdir(self.cfg_dir) needed_dirs = ("body", "client-body", "fastcgi", "proxy", "scgi", "uwsgi") for d in needed_dirs: j.sals.fs.mkdir(j.sals.fs.join_paths(self.cfg_dir, d)) for location in self.get_locations(): location.configure() j.sals.fs.write_file(self.cfg_file, self.get_config()) if generate_certificates and self.ssl: self.generate_self_signed_certificates() self.generate_certificates() def clean(self): j.sals.fs.rmtree(self.cfg_dir)
class Website(Base): domain = fields.String() ssl = fields.Boolean() port = fields.Integer(default=PORTS.HTTP) locations = fields.Factory(Location, stored=False) includes = fields.List(fields.String()) selfsigned = fields.Boolean(default=True) # keep it as letsencryptemail for compatibility letsencryptemail = fields.String() acme_server_type = fields.Enum(AcmeServer) acme_server_url = fields.URL() # in case of using existing key/certificate key_path = fields.String() cert_path = fields.String() fullchain_path = fields.String() @property def certbot(self): kwargs = dict( domain=self.domain, email=self.letsencryptemail, server=self.acme_server_url, nginx_server_root=self.parent.cfg_dir, key_path=self.key_path, cert_path=self.cert_path, fullchain_path=self.fullchain_path, ) if self.acme_server_type == AcmeServer.LETSENCRYPT: certbot_type = LetsencryptCertbot elif self.acme_server_type == AcmeServer.ZEROSSL: certbot_type = ZerosslCertbot else: certbot_type = CustomCertbot return certbot_type(**kwargs) @property def cfg_dir(self): return j.sals.fs.join_paths(self.parent.cfg_dir, self.instance_name) @property def cfg_file(self): return j.sals.fs.join_paths(self.cfg_dir, "server.conf") @property def include_paths(self): paths = [] for include in self.includes: ## TODO validate location name and include website_name, location_name = include.split(".", 1) website = self.parent.websites.find(website_name) if not website: continue paths.append(j.sals.fs.join_paths(website.cfg_dir, "locations", location_name)) return paths def get_locations(self): for location in self.locations.list_all(): yield self.locations.get(location) def get_proxy_location(self, name): location = self.locations.get(name) location.location_type = LocationType.PROXY return location def get_custom_location(self, name): location = self.locations.get(name) location.location_type = LocationType.CUSTOM return location def get_static_location(self, name): location = self.locations.get(name) location.location_type = LocationType.STATIC return location def get_config(self): return render_config_template("website", base_dir=j.core.dirs.BASEDIR, website=self) def generate_certificates(self, retries=6): if self.domain: if self.key_path and self.cert_path and self.fullchain_path: # only use install command if an existing key and certificate were set self.install_certifcate() else: self.obtain_and_install_certifcate(retries=retries) def install_certifcate(self): """Construct and Execute install certificate command Alternative to certbot install """ cmd = self.certbot.install_cmd j.logger.debug(f"Execute: {' '.join(cmd)}") rc, out, err = j.sals.process.execute(cmd) if rc > 0: j.logger.error(f"Installing certificate failed {out}\n{err}") else: j.logger.info(f"Certificate installed successfully {out}") def obtain_and_install_certifcate(self, retries=6): """Construct and Execute run certificate command,This will issue a new certificate managed by Certbot Alternative to certbot run Args: retries (int, optional): Number of retries Certbot will try to install the certificate if failed. Defaults to 6. """ cmd = self.certbot.run_cmd j.logger.debug(f"Execute: {' '.join(cmd)}") for _ in range(retries): rc, out, err = j.sals.process.execute(cmd) if rc > 0: j.logger.error(f"Generating certificate failed {out}\n{err}") else: j.logger.error(f"Certificate Generated successfully {out}") break def generate_self_signed_certificates(self): keypempath = f"{self.parent.cfg_dir}/key.pem" certpempath = f"{self.parent.cfg_dir}/cert.pem" if j.sals.process.is_installed("mkcert"): res = j.sals.process.execute( f"mkcert -key-file {keypempath} -cert-file {certpempath} localhost *.localhost 127.0.0.1 ::1" ) if res[0] != 0: raise j.exceptions.JSException(f"Failed to generate self-signed certificate (using mkcert).{res}") else: if j.sals.fs.exists(f"{keypempath}") and j.sals.fs.exists(f"{certpempath}"): return res = j.sals.process.execute( f"openssl req -nodes -x509 -newkey rsa:4096 -keyout {keypempath} -out {certpempath} -days 365 -subj '/CN=localhost'" ) if res[0] != 0: raise j.exceptions.JSException(f"Failed to generate self-signed certificate (using openssl).{res}") def configure(self, generate_certificates=True): j.sals.fs.mkdir(self.cfg_dir) needed_dirs = ("body", "client-body", "fastcgi", "proxy", "scgi", "uwsgi") for d in needed_dirs: j.sals.fs.mkdir(j.sals.fs.join_paths(self.cfg_dir, d)) for location in self.get_locations(): location.configure() j.sals.fs.write_file(self.cfg_file, self.get_config()) if self.ssl: self.generate_self_signed_certificates() if generate_certificates and self.ssl: self.generate_certificates() def clean(self): j.sals.fs.rmtree(self.cfg_dir)
class NginxConfig(Base): websites = fields.Factory(Website, stored=False) cert = fields.Boolean(default=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._cmd = None self._path_web = None self._cfg_dir = None self._logs_dir = None @property def cfg_dir(self): if not self._cfg_dir: self._cfg_dir = j.sals.fs.join_paths(j.core.dirs.CFGDIR, "nginx", self.instance_name) j.sals.fs.mkdirs(self._cfg_dir) return self._cfg_dir @property def cfg_file(self): return j.sals.fs.join_paths(self.cfg_dir, "nginx.conf") @property def logs_dir(self): if not self._logs_dir: self._logs_dir = j.sals.fs.join_paths(j.core.dirs.LOGDIR, "nginx", self.instance_name) j.sals.fs.mkdirs(self._logs_dir) return self._logs_dir def configure(self): """configures main nginx conf""" self.clean() j.sals.fs.mkdir(self.cfg_dir) user = j.sals.unix.get_current_pwd() group = j.sals.unix.get_current_grp() def_index_dir = j.sals.fs.join_paths(DIR_PATH, "static") configtext = j.tools.jinja2.render_template( template_path=j.sals.fs.join_paths(DIR_PATH, "templates", "nginx.conf"), logs_dir=self.logs_dir, cfg_dir=self.cfg_dir, user=user, group=group, def_index_dir=def_index_dir, ) j.sals.fs.write_file(self.cfg_file, configtext) j.sals.fs.copy_tree(f"{DIR_PATH}/resources/", self.cfg_dir) def get_website(self, name: str, port: int = 0): port = port or PORTS.HTTP website_name = f"{name}_{port}" website = self.websites.find(website_name) if website: return website website = self.websites.get(website_name) website.port = port website.ssl = port in [443, 8443] return website def clean(self): j.sals.fs.rmtree(f"{self.cfg_dir}")
class Client(Base): wallets = fields.Factory(Wallet) users = fields.Factory(User)
class DigitalOcean(Client): name = fields.String() token = fields.Secret() projects = fields.Factory(Project, factory_type=ProjectFactory) droplets = fields.Factory(Droplet, factory_type=DropletFactory) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._client = None @property def client(self): """Return a new client if it is not set or it will return the already existed one e.g dg.client -> <Manager> Returns Manager: client form digital ocean manager """ if not self._client: self._client = digitalocean.Manager(token=self.token) return self._client # Images @property def images(self): """Return a list of digital ocean availabe images e.g dg.images -> [<Image: 31354013 CentOS 6.9 x32>, <Image: 34902021 CentOS 6.9 x64>,...] Returns List : list of images on digital ocean available """ return self.client.get_distro_images() @property def myimages(self): """Return a list of digital ocean images, you have created e.g dg.myimages -> [<Image: 48614453 Unknown Zero_OS>, <Image: 50898718 Ubuntu JumpScale>,...] Returns List : list of images on digital ocean, you have created """ return self.client.get_images(private=True) @property def account_images(self): """Return a list of digital ocean images and the images you have created e.g dg.account_images -> [<Image: 31354013 CentOS 6.9 x32>, <Image: 34902021 CentOS 6.9 x64>,...] Returns List : list of images on digital ocean images and the images you have created """ return self.images + self.myimages def get_image(self, name): """Return an image e.g dg.get_image(name="CentOS") -> <Image: 31354013 CentOS 6.9 x32> Args name (str): name of the required image Returns Image : list of images on digital ocean images and the images you have created """ for item in self.account_images: if item.description: name_do1 = item.description.lower() else: name_do1 = "" name_do2 = item.distribution + " " + item.name print(f" - {name_do1}--{name_do2}") if name_do1.lower().find(name.lower()) != -1 or name_do2.lower().find(name.lower()) != -1: return item raise j.exceptions.Base("did not find image:%s" % name) def get_image_names(self, name=""): """ Return all the image or images with a specified name e.g dg.get_image_names() -> ['centos 6.9 x32 20180130', 'centos 6.9 x64 20180602',...] dg.get_image_names("centos") -> ['centos 6.9 x32 20180130', 'centos 6.9 x64 20180602'] Args name (str): name of the required image Returns Image : list of images """ res = [] name = name.lower() for item in self.images: if item.description: name_do = item.description.lower() else: name_do = item.distribution + " " + item.name if name_do.find(name) != -1: res.append(name_do) return res # Size @property def sizes(self): """Return a list sizes available on digital ocean e.g dg.sizes -> [s-1vcpu-1gb, 512mb, s-1vcpu-2gb, 1gb, s-3vcpu-1gb,.....] Returns List : list of sizes """ return self.client.get_all_sizes() # Regions @property def regions(self): """Return a list regions available on digital ocean e.g dg.regions -> [<Region: nyc1 New York 1>, <Region: sgp1 Singapore 1>,...] Returns List : list of regions """ return self.client.get_all_regions() @property def region_names(self): """Returns Digital Ocean regions e.g dg.region_names -> ['nyc1', 'sgp1', 'lon1', 'nyc3', 'ams3', 'fra1', 'tor1', 'sfo2', 'blr1'] Returns list : list of digital ocean regions """ return [i.slug for i in self.regions] def get_region(self, name): """ Returns specific region e.g dg.get_region(name = 'nyc1') -> <Region: nyc1 New York 1> Args name (str) : name of the required region Returns Region : the region with the name specified """ for item in self.regions: if name == item.slug: return item if name == item.name: return item raise j.exceptions.Base("did not find region:%s" % name) # SSHkeys @property def sshkeys(self): """ Return list of sshkeys on digital ocean e.g dg.sshkeys -> [<SSHKey: 25882170 3bot_container_sandbox>, <SSHKey: 27130645 Geert-root>,...] Returns list : list of sshkeys """ return self.client.get_all_sshkeys() def get_default_sshkey(self): """ Return sshkey you have added to your Digital Ocean client e.g dg.get_default_sshkey() -> <SSHKey: 25589987 rafy@rafy-Inspiron-3576> Returns list : list of sshkeys """ pubkeyonly = self.sshkey.public_key for item in self.sshkeys: if item.public_key.find(pubkeyonly) != -1: return item return None def set_default_sshkey(self, default_sshkey): """ Set sshkey you Digital Ocean client e.g dg.set_default_sshkey(ssh) -> <SSHKey: 25589987 rafy@rafy-Inspiron-3576> Args default_sshkey (SSHKeyClient) : sshkey client you have created """ self.sshkey = default_sshkey def get_sshkey(self, name): """ get sshkey from Digital Ocean e.g dg.get_sshkey("rafy@rafy-Inspiron-3576") -> <SSHKey: 25589987 rafy@rafy-Inspiron-3576> Args name (string) : sshkey name Returns SSHKey : return the specified sshkey """ for item in self.sshkeys: if name == item.name: return item raise j.exceptions.Base("did not find key:%s" % name) def __str__(self): return "digital ocean client:%s" % self.name __repr__ = __str__
class NginxConfig(Base): websites = fields.Factory(Website) def __init__(self): super().__init__() self._cmd = None self._path_web = None self._path_cfg_dir = None self._logs_dir = None @property def path_web(self): if not self._path_web: self._path_web = j.sals.fs.join_paths(j.core.dirs.VARDIR, "web", self.instance_name) j.sals.fs.mkdirs(j.sals.fs.join_paths(self._path_web, "static")) return self._path_web @property def path_cfg_dir(self): if not self._path_cfg_dir: self._path_cfg_dir = j.sals.fs.join_paths(j.core.dirs.CFGDIR, "nginx", self.instance_name) j.sals.fs.mkdirs(self._path_cfg_dir) return self._path_cfg_dir @property def path_cfg(self): return j.sals.fs.join_paths(self.path_cfg_dir, "nginx.conf") @property def logs_dir(self): if not self._logs_dir: self._logs_dir = j.sals.fs.join_paths(j.core.dirs.LOGDIR, "nginx", self.instance_name) j.sals.fs.mkdirs(self._logs_dir) return self._logs_dir def configure(self): """configures main nginx conf """ # clean old websites config self.cleanup() configtext = j.tools.jinja2.render_template( template_path=j.sals.fs.join_paths(DIR_PATH, "templates", "nginx.conf"), logs_dir=self.logs_dir, ) j.sals.fs.write_file(self.path_cfg, configtext) j.sals.fs.copy_tree(f"{DIR_PATH}/resources/", self.path_cfg_dir) def get_from_port(self, port, domain=None, ssl=None): """will try to get a website listening on port, if it doesn't exist it will create one Args: port (int): port to search for domain (str, optional): domain. Defaults to None. ssl (bool, optional): Will set ssl if True. Defaults to None. Returns: Website: A new or an old website instance with the needed port """ website_name = f"{self.instance_name}_website_{port}" website = self.websites.find(website_name) if website: return website website = self.websites.get(website_name) ssl = ssl or port == 443 # Use ssl if port is 443 if ssl in not specified website.domain = domain website.port = port website.ssl = ssl return website def cleanup(self): j.sals.fs.rmtree(f"{self.path_cfg_dir}/servers")
class OpenRestyServer(Base): status = fields.Enum(Status) websites = fields.Factory(Website) def __init__(self, **kwargs): super().__init__(**kwargs) self._cmd = None self._path_web = None self._path_cfg_dir = None self._logs_dir = None self.executor = "tmux" # only tmux for now @property def path_web(self): if not self._path_web: self._path_web = j.sals.fs.join_paths(j.core.dirs.VARDIR, "web", self.instance_name) j.sals.fs.mkdirs(j.sals.fs.join_paths(self._path_web, "static")) return self._path_web @property def path_cfg_dir(self): if not self._path_cfg_dir: self._path_cfg_dir = j.sals.fs.join_paths(j.core.dirs.CFGDIR, "nginx", self.instance_name) j.sals.fs.mkdirs(self._path_cfg_dir) return self._path_cfg_dir @property def path_cfg(self): return j.sals.fs.join_paths(self.path_cfg_dir, "nginx.conf") @property def logs_dir(self): if not self._logs_dir: self._logs_dir = j.sals.fs.join_paths(j.core.dirs.LOGDIR, "openresty", self.instance_name) j.sals.fs.mkdirs(self._logs_dir) return self._logs_dir def configure(self): # clean old websites config self.cleanup() """configures main nginx conf """ # self.install() This is commented for now until the repo and necessary deps are handled configtext = j.tools.jinja2.render_template( template_path=j.sals.fs.join_paths(DIR_PATH, "templates", "nginx.conf"), logs_dir=self.logs_dir, ) j.sals.fs.write_file(self.path_cfg, configtext) def get_from_port(self, port, domain=None, ssl=None): """will try to get a website listening on port, if it doesn't exist it will create one Args: port (int): port to search for domain (str, optional): domain. Defaults to None. ssl (bool, optional): Will set ssl if True. Defaults to None. Returns: Website: A new or an old website instance with the needed port """ website_name = f"{self.instance_name}_website_{port}" website = self.websites.find(website_name) if website: return website website = self.websites.get(website_name) ssl = ssl or port == 443 # Use ssl if port is 443 if ssl in not specified website.domain = domain website.port = port website.ssl = ssl return website def install(self, reset=False): """Install required deps for openresty Args: reset (bool, optional): If true will redo the installation. Defaults to False. """ if reset or self.status == "init": # get weblib weblibs_path = j.tools.git.ensure_repo( "https://github.com/threefoldtech/js-weblibs" # Place holder repo might be changed ) # copy the templates to the right location j.sals.fs.copy_tree(f"{DIR_PATH}/web_resources/", self.path_cfg_dir) j.sals.fs.symlink( f"{weblibs_path}/static", f"{self.path_web}/static/weblibs", overwrite=True, ) self.status = Status.INSTALLED self.save() @property def startup_cmd(self): pass def start(self, reset=False): pass def stop(self): pass def is_running(self): pass def reload(self): self.configure() j.sals.process.execute("lapis build", cwd=self.path_cfg_dir) def cleanup(self): j.sals.fs.rmtree(f"{self.path_cfg_dir}/servers")
class Wallet(Base): ID = fields.Integer() addresses = fields.Factory(Address, stored=False)
class Github(Client): users = fields.Factory(User) def hi(self): print("hii") j.sals.fs.basename("aa")
class User(Base): username = fields.String() password = fields.String() emails = fields.Factory(Email)
class StudentClient(Base): students = fields.Factory(Student, stored=False)
class Client(Base): wallets = fields.Factory(RichWallet, stored=False)