Module jumpscale.sals.nginx.nginx
Get nginx sal instance as an abstract parent for the websites and locations and for the nginx conf
nginx = j.sals.nginx.get("instance")
Add a webiste to the configuration
website = nginx.websites.new("website")
Configure instance
website.port = # Port to listen to will use 80 by default or 443 if ssl is true
webiste.ssl = True # If true will generate and configure the SSL certificates
website.domain = # domain of the webiste
website.letsencryptemail = # Email to receive let's encrypt notifications
Add locations to the webiste
loc = website.locations.new("location")
loc.path_url = # location path loc.is_auth = # IF True will authenticate when accessing this location loc.force_https = # If True won't allow http access loc.path_location = # alias for the location loc.index = # index of the location loc.ipaddr_dest = # Destination address for proxy pass loc.port_dest = # Destination port for proxy pass loc.path_dest = # Destination path for proxy pass loc.location_type = # static,spa,proxy type of location config loc.scheme = # https or https
Configuring the website and all its locations and generating the certificates
website.configure()
Expand source code
"""
# Get nginx sal instance as an abstract parent for the websites and locations and for the nginx conf
nginx = j.sals.nginx.get("instance")
# Add a webiste to the configuration
website = nginx.websites.new("website")
# Configure instance
website.port = # Port to listen to will use 80 by default or 443 if ssl is true
webiste.ssl = True # If true will generate and configure the SSL certificates
website.domain = # domain of the webiste
website.letsencryptemail = # Email to receive let's encrypt notifications
# Add locations to the webiste
loc = website.locations.new("location")
loc.path_url = # location path
loc.is_auth = # IF True will authenticate when accessing this location
loc.force_https = # If True won't allow http access
loc.path_location = # alias for the location
loc.index = # index of the location
loc.ipaddr_dest = # Destination address for proxy pass
loc.port_dest = # Destination port for proxy pass
loc.path_dest = # Destination path for proxy pass
loc.location_type = # static,spa,proxy type of location config
loc.scheme = # https or https
# Configuring the website and all its locations and generating the certificates
website.configure()
"""
from enum import Enum
from jumpscale.core.base import Base, fields
from jumpscale.core.exceptions import Input
from jumpscale.loader import j
from .utils import DIR_PATH, render_config_template
class PORTS:
HTTP = 80
HTTPS = 443
@classmethod
def init_default_ports(cls, local=False):
if local:
for port in range(8080, 8180):
if not j.sals.process.is_port_listening(port):
cls.HTTP = port
break
else:
j.exception.Runtime("Could not find free port to listen on")
for port in range(8443, 8500):
if not j.sals.process.is_port_listening(port):
cls.HTTPS = port
break
else:
j.exception.Runtime("Could not find free port to listen on")
class ProxyBuffering(Enum):
UNSET = ""
ON = "on"
OFF = "off"
class LocationType(Enum):
STATIC = "static"
PROXY = "proxy"
CUSTOM = "custom"
class Location(Base):
path_url = fields.String(default="/")
force_https = fields.Boolean(default=False)
path_location = fields.String(default="/")
index = fields.String(default="index.html")
scheme = fields.String(default="http")
host = fields.String(default="127.0.0.1")
port = fields.Integer()
path_dest = fields.String(default="/")
spa = fields.Boolean(default=False)
websocket = fields.Boolean(default=False)
location_type = fields.Enum(LocationType)
is_auth = fields.Boolean(default=False)
is_admin = fields.Boolean(default=False)
package_name = fields.String()
is_package_authorized = fields.Boolean(default=False)
custom_config = fields.String(default=None)
proxy_buffering = fields.Enum(ProxyBuffering)
proxy_buffers = fields.String()
proxy_buffer_size = fields.String()
@property
def cfg_dir(self):
return j.sals.fs.join_paths(self.parent.cfg_dir, "locations")
@property
def cfg_file(self):
return j.sals.fs.join_paths(self.cfg_dir, f"{self.instance_name}.conf")
def get_config(self):
return render_config_template(
"location",
base_dir=j.core.dirs.BASEDIR,
location=self,
threebot_connect=j.core.config.get_config().get("threebot_connect", True),
https_port=PORTS.HTTPS,
)
def configure(self):
j.sals.fs.mkdir(self.cfg_dir)
j.sals.fs.write_file(self.cfg_file, self.get_config())
class AcmeServer(Enum):
LETSENCRYPT = "letsencrypt"
ZEROSSL = "zerossl"
CUSTOM = "custom"
class Certbot(Base):
DEFAULT_NAME = "certbot"
DEFAULT_LOGS_DIR = j.sals.fs.join_paths(j.core.dirs.LOGDIR, DEFAULT_NAME)
DEFAULT_CONFIG_DIR = j.sals.fs.join_paths(j.core.dirs.CFGDIR, DEFAULT_NAME)
DEFAULT_WORK_DIR = j.sals.fs.join_paths(j.core.dirs.VARDIR, DEFAULT_NAME)
# the following options match the certbot command arguments
domain = fields.String(required=True)
non_interactive = fields.Boolean(default=True)
agree_tos = fields.Boolean(default=True)
logs_dir = fields.String(default=DEFAULT_LOGS_DIR)
config_dir = fields.String(default=DEFAULT_CONFIG_DIR)
work_dir = fields.String(default=DEFAULT_WORK_DIR)
email = fields.Email()
server = fields.URL()
eab_kid = fields.String()
eab_hmac_key = fields.String()
# for existing certificates
key_path = fields.String()
cert_path = fields.String()
fullchain_path = fields.String()
@property
def run_cmd(self):
args = [self.DEFAULT_NAME]
for name, value in self.to_dict().items():
if name.endswith("_"):
continue
if value:
# append only if the field has a value
name = name.replace("_", "-")
args.append(f"--{name}")
# append the value itself only if it's a boolean value
# boolean options are set by adding name only
if not isinstance(value, bool):
args.append(value)
return args
@property
def install_cmd(self):
# replace "certbot" with "certbot install"
cmd = self.run_cmd
cmd.insert(1, "install")
return cmd
@property
def renew_cmd(self):
# replace "certbot" with "certbot install"
renew_certbot = Certbot(work_dir=self.work_dir, config_dir=self.config_dir, logs_dir=self.logs_dir, domain="")
cmd = renew_certbot.run_cmd
cmd.insert(1, "renew")
return cmd
class NginxCertbot(Certbot):
nginx_server_root = fields.String(required=True)
nginx = fields.Boolean(default=True)
class LetsencryptCertbot(NginxCertbot):
"""
default installation is for let's encrypt (manual plugin), no need for other options
currently, we support only email
"""
# change required value to True here
email = fields.Email(required=True)
class ZerosslCertbot(NginxCertbot):
SERVER_URL = "https://acme.zerossl.com/v2/DV90"
KEY_CREDENTIALS_URL = "https://api.zerossl.com/acme/eab-credentials"
EMAIL_CREDENTIALS_URL = "https://api.zerossl.com/acme/eab-credentials-email"
api_key_ = fields.Secret()
server = fields.URL(default=SERVER_URL)
@property
def run_cmd(self):
# get eab_kid and eab_hmac_key based on email or api_key_
if not self.email and not self.api_key_:
raise Input("email or api_key_ must be provided")
# set them to get the full run-cmd with correct arguments
if self.api_key_:
resp = j.tools.http.post(self.KEY_CREDENTIALS_URL, params={"access_key": self.api_key_})
else:
resp = j.tools.http.post(self.EMAIL_CREDENTIALS_URL, data={"email": self.email})
resp.raise_for_status()
data = resp.json()
self.eab_kid = data["eab_kid"]
self.eab_hmac_key = data["eab_hmac_key"]
return super().run_cmd
class CustomCertbot(NginxCertbot):
# change email and server required value to True here
email = fields.Email(required=True)
server = fields.URL(required=True)
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}")
Classes
class AcmeServer (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code
class AcmeServer(Enum): LETSENCRYPT = "letsencrypt" ZEROSSL = "zerossl" CUSTOM = "custom"
Ancestors
- enum.Enum
Class variables
var CUSTOM
var LETSENCRYPT
var ZEROSSL
class Certbot (parent_=None, instance_name_=None, **values)
-
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
class Certbot(Base): DEFAULT_NAME = "certbot" DEFAULT_LOGS_DIR = j.sals.fs.join_paths(j.core.dirs.LOGDIR, DEFAULT_NAME) DEFAULT_CONFIG_DIR = j.sals.fs.join_paths(j.core.dirs.CFGDIR, DEFAULT_NAME) DEFAULT_WORK_DIR = j.sals.fs.join_paths(j.core.dirs.VARDIR, DEFAULT_NAME) # the following options match the certbot command arguments domain = fields.String(required=True) non_interactive = fields.Boolean(default=True) agree_tos = fields.Boolean(default=True) logs_dir = fields.String(default=DEFAULT_LOGS_DIR) config_dir = fields.String(default=DEFAULT_CONFIG_DIR) work_dir = fields.String(default=DEFAULT_WORK_DIR) email = fields.Email() server = fields.URL() eab_kid = fields.String() eab_hmac_key = fields.String() # for existing certificates key_path = fields.String() cert_path = fields.String() fullchain_path = fields.String() @property def run_cmd(self): args = [self.DEFAULT_NAME] for name, value in self.to_dict().items(): if name.endswith("_"): continue if value: # append only if the field has a value name = name.replace("_", "-") args.append(f"--{name}") # append the value itself only if it's a boolean value # boolean options are set by adding name only if not isinstance(value, bool): args.append(value) return args @property def install_cmd(self): # replace "certbot" with "certbot install" cmd = self.run_cmd cmd.insert(1, "install") return cmd @property def renew_cmd(self): # replace "certbot" with "certbot install" renew_certbot = Certbot(work_dir=self.work_dir, config_dir=self.config_dir, logs_dir=self.logs_dir, domain="") cmd = renew_certbot.run_cmd cmd.insert(1, "renew") return cmd
Ancestors
- Base
- types.SimpleNamespace
Subclasses
Class variables
var DEFAULT_CONFIG_DIR
var DEFAULT_LOGS_DIR
var DEFAULT_NAME
var DEFAULT_WORK_DIR
Instance variables
var agree_tos
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var cert_path
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var config_dir
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var domain
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var eab_hmac_key
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var eab_kid
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var email
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var fullchain_path
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var install_cmd
-
Expand source code
@property def install_cmd(self): # replace "certbot" with "certbot install" cmd = self.run_cmd cmd.insert(1, "install") return cmd
var key_path
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var logs_dir
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var non_interactive
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var renew_cmd
-
Expand source code
@property def renew_cmd(self): # replace "certbot" with "certbot install" renew_certbot = Certbot(work_dir=self.work_dir, config_dir=self.config_dir, logs_dir=self.logs_dir, domain="") cmd = renew_certbot.run_cmd cmd.insert(1, "renew") return cmd
var run_cmd
-
Expand source code
@property def run_cmd(self): args = [self.DEFAULT_NAME] for name, value in self.to_dict().items(): if name.endswith("_"): continue if value: # append only if the field has a value name = name.replace("_", "-") args.append(f"--{name}") # append the value itself only if it's a boolean value # boolean options are set by adding name only if not isinstance(value, bool): args.append(value) return args
var server
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var work_dir
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
Inherited members
class CustomCertbot (parent_=None, instance_name_=None, **values)
-
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
class CustomCertbot(NginxCertbot): # change email and server required value to True here email = fields.Email(required=True) server = fields.URL(required=True)
Ancestors
- NginxCertbot
- Certbot
- Base
- types.SimpleNamespace
Inherited members
class LetsencryptCertbot (parent_=None, instance_name_=None, **values)
-
default installation is for let's encrypt (manual plugin), no need for other options
currently, we support only email
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
class LetsencryptCertbot(NginxCertbot): """ default installation is for let's encrypt (manual plugin), no need for other options currently, we support only email """ # change required value to True here email = fields.Email(required=True)
Ancestors
- NginxCertbot
- Certbot
- Base
- types.SimpleNamespace
Inherited members
class Location (parent_=None, instance_name_=None, **values)
-
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
class Location(Base): path_url = fields.String(default="/") force_https = fields.Boolean(default=False) path_location = fields.String(default="/") index = fields.String(default="index.html") scheme = fields.String(default="http") host = fields.String(default="127.0.0.1") port = fields.Integer() path_dest = fields.String(default="/") spa = fields.Boolean(default=False) websocket = fields.Boolean(default=False) location_type = fields.Enum(LocationType) is_auth = fields.Boolean(default=False) is_admin = fields.Boolean(default=False) package_name = fields.String() is_package_authorized = fields.Boolean(default=False) custom_config = fields.String(default=None) proxy_buffering = fields.Enum(ProxyBuffering) proxy_buffers = fields.String() proxy_buffer_size = fields.String() @property def cfg_dir(self): return j.sals.fs.join_paths(self.parent.cfg_dir, "locations") @property def cfg_file(self): return j.sals.fs.join_paths(self.cfg_dir, f"{self.instance_name}.conf") def get_config(self): return render_config_template( "location", base_dir=j.core.dirs.BASEDIR, location=self, threebot_connect=j.core.config.get_config().get("threebot_connect", True), https_port=PORTS.HTTPS, ) def configure(self): j.sals.fs.mkdir(self.cfg_dir) j.sals.fs.write_file(self.cfg_file, self.get_config())
Ancestors
- Base
- types.SimpleNamespace
Instance variables
var cfg_dir
-
Expand source code
@property def cfg_dir(self): return j.sals.fs.join_paths(self.parent.cfg_dir, "locations")
var cfg_file
-
Expand source code
@property def cfg_file(self): return j.sals.fs.join_paths(self.cfg_dir, f"{self.instance_name}.conf")
var custom_config
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var force_https
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var host
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var index
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var is_admin
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var is_auth
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var location_type
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var package_name
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var path_dest
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var path_location
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var path_url
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var port
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var proxy_buffer_size
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var proxy_buffering
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var proxy_buffers
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var scheme
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var spa
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var websocket
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
Methods
def configure(self)
-
Expand source code
def configure(self): j.sals.fs.mkdir(self.cfg_dir) j.sals.fs.write_file(self.cfg_file, self.get_config())
def get_config(self)
-
Expand source code
def get_config(self): return render_config_template( "location", base_dir=j.core.dirs.BASEDIR, location=self, threebot_connect=j.core.config.get_config().get("threebot_connect", True), https_port=PORTS.HTTPS, )
Inherited members
class LocationType (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code
class LocationType(Enum): STATIC = "static" PROXY = "proxy" CUSTOM = "custom"
Ancestors
- enum.Enum
Class variables
var CUSTOM
var PROXY
var STATIC
class NginxCertbot (parent_=None, instance_name_=None, **values)
-
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
class NginxCertbot(Certbot): nginx_server_root = fields.String(required=True) nginx = fields.Boolean(default=True)
Ancestors
Subclasses
Instance variables
var nginx
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var nginx_server_root
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
Inherited members
class NginxConfig (*args, **kwargs)
-
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
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}")
Ancestors
- Base
- types.SimpleNamespace
Instance variables
var cert
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var cfg_dir
-
Expand source code
@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
var cfg_file
-
Expand source code
@property def cfg_file(self): return j.sals.fs.join_paths(self.cfg_dir, "nginx.conf")
var logs_dir
-
Expand source code
@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
var websites
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
Methods
def clean(self)
-
Expand source code
def clean(self): j.sals.fs.rmtree(f"{self.cfg_dir}")
def configure(self)
-
configures main nginx conf
Expand source code
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)
-
Expand source code
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
Inherited members
class PORTS
-
Expand source code
class PORTS: HTTP = 80 HTTPS = 443 @classmethod def init_default_ports(cls, local=False): if local: for port in range(8080, 8180): if not j.sals.process.is_port_listening(port): cls.HTTP = port break else: j.exception.Runtime("Could not find free port to listen on") for port in range(8443, 8500): if not j.sals.process.is_port_listening(port): cls.HTTPS = port break else: j.exception.Runtime("Could not find free port to listen on")
Class variables
var HTTP
var HTTPS
Static methods
def init_default_ports(local=False)
-
Expand source code
@classmethod def init_default_ports(cls, local=False): if local: for port in range(8080, 8180): if not j.sals.process.is_port_listening(port): cls.HTTP = port break else: j.exception.Runtime("Could not find free port to listen on") for port in range(8443, 8500): if not j.sals.process.is_port_listening(port): cls.HTTPS = port break else: j.exception.Runtime("Could not find free port to listen on")
class ProxyBuffering (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code
class ProxyBuffering(Enum): UNSET = "" ON = "on" OFF = "off"
Ancestors
- enum.Enum
Class variables
var OFF
var ON
var UNSET
class Website (parent_=None, instance_name_=None, **values)
-
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
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)
Ancestors
- Base
- types.SimpleNamespace
Instance variables
var acme_server_type
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var acme_server_url
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var cert_path
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var certbot
-
Expand source code
@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)
var cfg_dir
-
Expand source code
@property def cfg_dir(self): return j.sals.fs.join_paths(self.parent.cfg_dir, self.instance_name)
var cfg_file
-
Expand source code
@property def cfg_file(self): return j.sals.fs.join_paths(self.cfg_dir, "server.conf")
var domain
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var fullchain_path
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var include_paths
-
Expand source code
@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
var includes
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var key_path
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var letsencryptemail
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var locations
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var port
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var selfsigned
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var ssl
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
Methods
def clean(self)
-
Expand source code
def clean(self): j.sals.fs.rmtree(self.cfg_dir)
def configure(self, generate_certificates=True)
-
Expand source code
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 generate_certificates(self, retries=6)
-
Expand source code
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 generate_self_signed_certificates(self)
-
Expand source code
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 get_config(self)
-
Expand source code
def get_config(self): return render_config_template("website", base_dir=j.core.dirs.BASEDIR, website=self)
def get_custom_location(self, name)
-
Expand source code
def get_custom_location(self, name): location = self.locations.get(name) location.location_type = LocationType.CUSTOM return location
def get_locations(self)
-
Expand source code
def get_locations(self): for location in self.locations.list_all(): yield self.locations.get(location)
def get_proxy_location(self, name)
-
Expand source code
def get_proxy_location(self, name): location = self.locations.get(name) location.location_type = LocationType.PROXY return location
def get_static_location(self, name)
-
Expand source code
def get_static_location(self, name): location = self.locations.get(name) location.location_type = LocationType.STATIC return location
def install_certifcate(self)
-
Construct and Execute install certificate command Alternative to certbot install
Expand source code
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.
Expand source code
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
Inherited members
class ZerosslCertbot (parent_=None, instance_name_=None, **values)
-
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)
Args
parent_
:Base
, optional- parent instance. Defaults to None.
instance_name_
:str
, optional- instance name. Defaults to None.
**values
- any given field values to initiate the instance with
Expand source code
class ZerosslCertbot(NginxCertbot): SERVER_URL = "https://acme.zerossl.com/v2/DV90" KEY_CREDENTIALS_URL = "https://api.zerossl.com/acme/eab-credentials" EMAIL_CREDENTIALS_URL = "https://api.zerossl.com/acme/eab-credentials-email" api_key_ = fields.Secret() server = fields.URL(default=SERVER_URL) @property def run_cmd(self): # get eab_kid and eab_hmac_key based on email or api_key_ if not self.email and not self.api_key_: raise Input("email or api_key_ must be provided") # set them to get the full run-cmd with correct arguments if self.api_key_: resp = j.tools.http.post(self.KEY_CREDENTIALS_URL, params={"access_key": self.api_key_}) else: resp = j.tools.http.post(self.EMAIL_CREDENTIALS_URL, data={"email": self.email}) resp.raise_for_status() data = resp.json() self.eab_kid = data["eab_kid"] self.eab_hmac_key = data["eab_hmac_key"] return super().run_cmd
Ancestors
- NginxCertbot
- Certbot
- Base
- types.SimpleNamespace
Class variables
var EMAIL_CREDENTIALS_URL
var KEY_CREDENTIALS_URL
var SERVER_URL
Instance variables
var api_key_
-
getter method this property
will call
_get_value
, which would if the value is already defined and will get the default value if notReturns
any
- the field value
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field)
var run_cmd
-
Expand source code
@property def run_cmd(self): # get eab_kid and eab_hmac_key based on email or api_key_ if not self.email and not self.api_key_: raise Input("email or api_key_ must be provided") # set them to get the full run-cmd with correct arguments if self.api_key_: resp = j.tools.http.post(self.KEY_CREDENTIALS_URL, params={"access_key": self.api_key_}) else: resp = j.tools.http.post(self.EMAIL_CREDENTIALS_URL, data={"email": self.email}) resp.raise_for_status() data = resp.json() self.eab_kid = data["eab_kid"] self.eab_hmac_key = data["eab_hmac_key"] return super().run_cmd
Inherited members