7 |11 | 12 | 13 | -------------------------------------------------------------------------------- /salt/hg/files/hg/web/robots.txt: -------------------------------------------------------------------------------- 1 | # File referred to in the Apache conf, don't remove 2 | User-agent: * 3 | Disallow: / 4 | -------------------------------------------------------------------------------- /salt/moin/configs/logrotate.conf: -------------------------------------------------------------------------------- 1 | /data/moin/instances/jython/data/event-log 2 | /data/moin/instances/psf/data/event-log 3 | /data/moin/instances/python/data/event-log 4 | { 5 | rotate 4 6 | weekly 7 | missingok 8 | notifempty 9 | compress 10 | sharedscripts 11 | postrotate 12 | /etc/init.d/apache2 reload > /dev/null 13 | endscript 14 | } 15 | -------------------------------------------------------------------------------- /salt/moin/configs/moin.wsgi: -------------------------------------------------------------------------------- 1 | # -*- coding: iso-8859-1 -*- 2 | """ 3 | MoinMoin - mod_wsgi driver script 4 | 5 | To use this, add those statements to your Apache's VirtualHost definition: 6 | 7 | # you will invoke your moin wiki at the root url, like http://servername/FrontPage: 8 | WSGIScriptAlias / /some/path/moin.wsgi 9 | 10 | # create some wsgi daemons - use someuser.somegroup same as your data_dir: 11 | WSGIDaemonProcess daemonname user=someuser group=somegroup processes=5 threads=10 maximum-requests=1000 umask=0007 12 | 13 | # use the daemons we defined above to process requests! 14 | WSGIProcessGroup daemonname 15 | 16 | @copyright: 2008 by MoinMoin:ThomasWaldmann 17 | @license: GNU GPL, see COPYING for details. 18 | """ 19 | 20 | import sys, os 21 | 22 | # a) Configuration of Python's code search path 23 | # If you already have set up the PYTHONPATH environment variable for the 24 | # stuff you see below, you don't need to do a1) and a2). 25 | 26 | # a1) Path of the directory where the MoinMoin code package is located. 27 | # Needed if you installed with --prefix=PREFIX or you didn't use setup.py. 28 | #sys.path.insert(0, 'PREFIX/lib/python2.3/site-packages') 29 | 30 | # a2) Path of the directory where wikiconfig.py / farmconfig.py is located. 31 | # See wiki/config/... for some sample config files. 32 | sys.path.insert(0, '/etc/moin') 33 | 34 | # b) Configuration of moin's logging 35 | # If you have set up MOINLOGGINGCONF environment variable, you don't need this! 36 | # You also don't need this if you are happy with the builtin defaults. 37 | # See wiki/config/logging/... for some sample config files. 38 | #from MoinMoin import log 39 | #log.load_config('/path/to/logging_configuration_file') 40 | 41 | from MoinMoin.web.serving import make_application 42 | 43 | # Creating the WSGI application 44 | # use shared=True to have moin serve the builtin static docs 45 | # use shared=False to not have moin serve static docs 46 | # use shared='/my/path/to/htdocs' to serve static docs from that path 47 | application = make_application(shared=True) 48 | #application = make_application(shared=True, trusted_proxies=['140.211.10.66', '127.0.0.1']) 49 | 50 | # Apply proxy fixes to get moin to use HTTPS links 51 | from werkzeug.middleware.proxy_fix import ProxyFix 52 | application = ProxyFix(application) 53 | -------------------------------------------------------------------------------- /salt/moin/configs/moin_wsgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import urlparse 4 | 5 | from MoinMoin.web.serving import make_application 6 | 7 | sys.path.insert(0, "/etc/moin") 8 | os.environ['PYTHONIOENCODING'] = 'utf-8' 9 | 10 | 11 | class ScriptFixerMiddleware(object): 12 | 13 | def __init__(self, application): 14 | self.application = application 15 | 16 | def __call__(self, environ, start_response): 17 | if not environ.get("SCRIPT_NAME"): 18 | path = environ.get("PATH_INFO", "") 19 | if path.startswith("/"): 20 | path = path[1:] 21 | 22 | parsed = urlparse.urlparse(path) 23 | 24 | script_name = "/".join(parsed.path.split("/")[:1]) 25 | if not script_name.startswith("/"): 26 | script_name = "/" + script_name 27 | 28 | environ["SCRIPT_NAME"] = script_name 29 | environ["PATH_INFO"] = "/".join(parsed.path.split("/")[1:]) 30 | 31 | return self.application(environ, start_response) 32 | 33 | 34 | application = ScriptFixerMiddleware(make_application(shared=False)) 35 | -------------------------------------------------------------------------------- /salt/moin/configs/ports.apache.conf.jinja: -------------------------------------------------------------------------------- 1 | {% set internal = salt["pillar.get"]("psf_internal_network") %} 2 | Listen {{ salt["network.ip_addrs"](cidr=internal)[0] }}:9000 3 | Listen 127.0.0.1:9000 4 | -------------------------------------------------------------------------------- /salt/moin/configs/shared_intermap.txt: -------------------------------------------------------------------------------- 1 | PEP http://www.python.org/dev/peps/pep-$PAGE/ 2 | SF http://bugs.python.org/issue$PAGE 3 | PythonMac http://pythonmac.org/wiki/ 4 | WxPython http://wiki.wxpython.org/index.cgi/ 5 | ISBN http://www.amazon.com/exec/obidos/ASIN/$PAGE/pythonsoftwar-20 6 | -------------------------------------------------------------------------------- /salt/moin/scripts/moin_maint_cleanpage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to clean up unused and deleted wiki pages. 4 | # 5 | # This script has to be run using a cronjob once a day to 6 | # prevent the number of unused pages from blowing up. 7 | # 8 | # WARNING: This script may only be run as moin user. 9 | # 10 | 11 | # Make sure only moin can run our script 12 | if [ "$(id -nu)" != "moin" ]; then 13 | echo "This script must be run as moin user" 1>&2 14 | exit 1 15 | fi 16 | 17 | # Globals 18 | DATE=`date +'%Y-%m-%d-%H%M%S'` 19 | 20 | # Clean sessions 21 | cd /srv/moin/ 22 | . venv/bin/activate 23 | 24 | # Clean up Python wiki 25 | cd /data/moin/instances/python/data 26 | echo "Clean up Python wiki..." 27 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/moin maint cleanpage > cleanpage.sh 28 | # create maintenance dirs 29 | mkdir trash deleted 30 | # move the pages to trash/ and deleted/ 31 | bash ./cleanpage.sh 32 | # archive cleanup 33 | tar cfz ../maintenance/$DATE.tgz cleanpage.sh deleted/ trash/ 34 | rm -rf cleanpage.sh deleted trash 35 | 36 | # Clean up PSF wiki 37 | cd /data/moin/instances/psf/data 38 | echo "Clean up PSF wiki..." 39 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/psf maint cleanpage > cleanpage.sh 40 | # create maintenance dirs 41 | mkdir trash deleted 42 | # move the pages to trash/ and deleted/ 43 | bash ./cleanpage.sh 44 | # archive cleanup 45 | tar cfz ../maintenance/$DATE.tgz cleanpage.sh deleted/ trash/ 46 | rm -rf cleanpage.sh deleted trash 47 | 48 | # Clean up Jython wiki 49 | cd /data/moin/instances/jython/data 50 | echo "Clean up Jython wiki..." 51 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/jython maint cleanpage > cleanpage.sh 52 | # create maintenance dirs 53 | mkdir trash deleted 54 | # move the pages to trash/ and deleted/ 55 | bash ./cleanpage.sh 56 | # archive cleanup 57 | tar cfz ../maintenance/$DATE.tgz cleanpage.sh deleted/ trash/ 58 | rm -rf cleanpage.sh deleted trash 59 | -------------------------------------------------------------------------------- /salt/moin/scripts/moin_maint_cleansessions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to clean up the outdated MoinMoin sessions. 4 | # 5 | # This script has to be run using a cronjob at least once a day 6 | # to prevent the number of used inodes from blowing up. 7 | # 8 | # WARNING: This script may only be run as moin user. 9 | # 10 | 11 | # Make sure only moin can run our script 12 | if [ "$(id -nu)" != "moin" ]; then 13 | echo "This script must be run as moin user" 1>&2 14 | exit 1 15 | fi 16 | 17 | # Clean sessions 18 | cd /srv/moin/ 19 | . venv/bin/activate 20 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/moin maint cleansessions 21 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/jython maint cleansessions 22 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/psf maint cleansessions 23 | -------------------------------------------------------------------------------- /salt/moin/scripts/moin_maint_cleansessions_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to clean out all MoinMoin sessions (including ones which 4 | # are marked to not expire). 5 | # 6 | # This script should be run every week or month to prevent the 7 | # number of used inodes from blowing up. 8 | # 9 | # WARNING: This script may only be run as moin user. 10 | # 11 | 12 | # Make sure only moin can run our script 13 | if [ "$(id -nu)" != "moin" ]; then 14 | echo "This script must be run as moin user" 1>&2 15 | exit 1 16 | fi 17 | 18 | # Clean sessions 19 | cd /srv/moin/ 20 | . venv/bin/activate 21 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/moin maint cleansessions --all 22 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/jython maint cleansessions --all 23 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/psf maint cleansessions --all 24 | -------------------------------------------------------------------------------- /salt/moin/scripts/moin_maint_index_rebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Script to rebuild the MoinMoin Xapian indexes. 4 | # 5 | # WARNING: This script may only be run as moin user. 6 | # 7 | 8 | # Make sure only moin can run our script 9 | if [ "$(id -nu)" != "moin" ]; then 10 | echo "This script must be run as moin user" 1>&2 11 | exit 1 12 | fi 13 | 14 | # Rebuild indexes 15 | cd /srv/moin/ 16 | . venv/bin/activate 17 | 18 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/moin index build --mode=rebuild 19 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/jython index build --mode=rebuild 20 | moin --config-dir=/etc/moin --wiki-url=http://wiki.python.org/psf index build --mode=rebuild 21 | -------------------------------------------------------------------------------- /salt/nginx/config/fastly_params.jinja: -------------------------------------------------------------------------------- 1 | port_in_redirect off; 2 | 3 | ssl_ciphers {{ pillar["tls"]["ciphers"].get("backend", pillar["tls"]["ciphers"]["default"]) }}; 4 | ssl_protocols TLSv1.2; 5 | 6 | set_real_ip_from {{ pillar["psf_internal_network"] }}; 7 | real_ip_header X-Forwarded-For; 8 | -------------------------------------------------------------------------------- /salt/nginx/config/nginx.conf.jinja: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes auto; 3 | worker_rlimit_nofile 10000; 4 | 5 | error_log /var/log/nginx/global-error.log; 6 | pid /var/run/nginx.pid; 7 | 8 | events { 9 | worker_connections 1024; 10 | } 11 | 12 | http { 13 | include /etc/nginx/mime.types; 14 | default_type application/octet-stream; 15 | 16 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 17 | '$status $body_bytes_sent "$http_referer" ' 18 | '"$http_user_agent" "$http_x_forwarded_for"'; 19 | 20 | access_log /var/log/nginx/global-access.log main; 21 | sendfile on; 22 | tcp_nopush on; 23 | tcp_nodelay on; 24 | server_tokens off; 25 | 26 | include /etc/nginx/conf.d/*.conf; 27 | include /etc/nginx/sites.d/*.conf; 28 | } 29 | -------------------------------------------------------------------------------- /salt/nginx/config/nginx.logrotate: -------------------------------------------------------------------------------- 1 | /var/log/nginx/*.log { 2 | daily 3 | rotate 30 4 | missingok 5 | notifempty 6 | compress 7 | sharedscripts 8 | postrotate 9 | /bin/kill -USR1 $(cat /var/run/nginx.pid 2>/dev/null) 2>/dev/null || : 10 | endscript 11 | } 12 | -------------------------------------------------------------------------------- /salt/nodejs/init.sls: -------------------------------------------------------------------------------- 1 | nodejs: 2 | pkgrepo.managed: 3 | - name: deb https://deb.nodesource.com/node_6.x {{ grains["oscodename"] }} main 4 | - file: /etc/apt/sources.list.d/nodesource.list 5 | - key_url: salt://nodejs/APT-GPG-KEY 6 | - require_in: 7 | - pkg: nodejs 8 | 9 | pkg.latest: 10 | - pkgs: 11 | - nodejs 12 | - refresh: True 13 | -------------------------------------------------------------------------------- /salt/pgbouncer/init.sls: -------------------------------------------------------------------------------- 1 | 2 | pgbouncer-pkg: 3 | pkg.installed: 4 | - pkgs: 5 | - pgbouncer 6 | 7 | /etc/pgbouncer/pgbouncer.ini: 8 | file.managed: 9 | - source: salt://pgbouncer/templates/pgbouncer.ini 10 | - template: jinja 11 | - user: postgres 12 | - group: postgres 13 | - mode: "0600" 14 | - show_changes: False 15 | - require: 16 | - pkg: pgbouncer-pkg 17 | 18 | /etc/pgbouncer/userlist.txt: 19 | file.managed: 20 | - source: salt://pgbouncer/templates/userlist.txt 21 | - template: jinja 22 | - user: postgres 23 | - group: postgres 24 | - mode: "0600" 25 | - show_changes: False 26 | - require: 27 | - pkg: pgbouncer-pkg 28 | 29 | pgbouncer-service: 30 | service.running: 31 | - name: pgbouncer 32 | - enable: True 33 | - reload: True 34 | - require: 35 | - pkg: pgbouncer-pkg 36 | - file: /etc/pgbouncer/pgbouncer.ini 37 | - file: /etc/pgbouncer/userlist.txt 38 | - watch: 39 | - file: /etc/pgbouncer/pgbouncer.ini 40 | - file: /etc/pgbouncer/userlist.txt 41 | -------------------------------------------------------------------------------- /salt/pgbouncer/templates/pgbouncer.ini: -------------------------------------------------------------------------------- 1 | [databases] 2 | {% for user, config in pillar.get('postgresql-users', {}).items() %} 3 | {{ user }} = host={{ pillar.get('postgresql-clusters', {}).get(config['cluster']).get('host') }} port={{ pillar.get('postgresql-clusters', {}).get(config['cluster']).get('port') }} dbname={{ config.get('dbname') }} user={{ user }} password={{ config.get('password', '') }} 4 | {% endfor %} 5 | 6 | [users] 7 | 8 | [pgbouncer] 9 | logfile = /var/log/postgresql/pgbouncer.log 10 | pidfile = /var/run/postgresql/pgbouncer.pid 11 | 12 | listen_addr = 127.0.0.1 13 | listen_port = 6432 14 | 15 | unix_socket_dir = /var/run/postgresql 16 | 17 | server_tls_sslmode = require 18 | server_tls_ca_file = /etc/ssl/postgres/root-certs.crt 19 | 20 | auth_type = trust 21 | auth_file = /etc/pgbouncer/userlist.txt 22 | -------------------------------------------------------------------------------- /salt/pgbouncer/templates/userlist.txt: -------------------------------------------------------------------------------- 1 | {%- for user, config in pillar.get('postgresql-users', {}).items() -%} 2 | "{{ user }}" "" 3 | {% endfor -%} 4 | -------------------------------------------------------------------------------- /salt/planet/config/nginx.planet.conf.jinja: -------------------------------------------------------------------------------- 1 | {% for site, info in salt["pillar.get"]("planet", {}).get("sites").items() %} 2 | 3 | server { 4 | listen 9000 ssl; 5 | server_name {{ info["domain"] }}; 6 | error_log /var/log/nginx/{{ site }}.error.log; 7 | access_log /var/log/nginx/{{ site }}.access.log; 8 | ssl_certificate /etc/ssl/private/planet.psf.io.pem; 9 | ssl_certificate_key /etc/ssl/private/planet.psf.io.pem; 10 | 11 | root {{ info["output"] }}; 12 | } 13 | 14 | {% for domain in info.get("subject_alternative_names", []) %} 15 | server { 16 | server_name {{ domain }}; 17 | error_log /var/log/nginx/redir-{{ domain }}.error.log; 18 | access_log /var/log/nginx/redir-{{ domain }}.error.log; 19 | 20 | return 302 $scheme://{{ site }}$request_uri; 21 | } 22 | {% endfor %} 23 | 24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /salt/planet/config/run-planet.sh.jinja: -------------------------------------------------------------------------------- 1 | cd /srv/planet/ 2 | git pull 3 | {% for site, site_config in salt["pillar.get"]("planet", {}).get("sites").items() %} 4 | docker run --pull=always --rm \ 5 | -v {{ site_config["cache"] }}:/srv/cache/ \ 6 | -v {{ site_config["output"] }}:/srv/planetpython.org/ \ 7 | -v /srv/planet/config/{{ site_config["config"] }}:/planet/config/config.ini \ 8 | {{ site_config["image"] }} \ 9 | python /planet/code/planet.py /planet/config/config.ini 10 | {% endfor %} 11 | -------------------------------------------------------------------------------- /salt/planet/init.sls: -------------------------------------------------------------------------------- 1 | include: 2 | - nginx 3 | 4 | git: 5 | pkg.installed 6 | 7 | docker.io: 8 | pkg.installed 9 | docker: 10 | service.running: 11 | - enable: True 12 | 13 | planet-user: 14 | user.present: 15 | - name: planet 16 | - createhome: False 17 | - groups: 18 | - docker 19 | - require: 20 | - pkg: docker.io 21 | 22 | /etc/nginx/sites.d/planet.conf: 23 | file.managed: 24 | - source: salt://planet/config/nginx.planet.conf.jinja 25 | - template: jinja 26 | - user: root 27 | - group: root 28 | - mode: "0644" 29 | - require: 30 | - file: /etc/nginx/sites.d/ 31 | 32 | /etc/consul.d/service-planet.json: 33 | file.managed: 34 | - source: salt://consul/etc/service.jinja 35 | - template: jinja 36 | - context: 37 | name: planet 38 | port: 9000 39 | - user: root 40 | - group: root 41 | - mode: "0644" 42 | - require: 43 | - pkg: consul-pkgs 44 | 45 | /srv/planet/: 46 | file.directory: 47 | - user: planet 48 | - group: planet 49 | - mode: "0755" 50 | 51 | https://github.com/python/planet: 52 | git.latest: 53 | - branch: main 54 | - target: /srv/planet/ 55 | - user: planet 56 | - require: 57 | - user: planet-user 58 | - pkg: git 59 | - file: /srv/planet/ 60 | 61 | /srv/run-planet.sh: 62 | file.managed: 63 | - source: salt://planet/config/run-planet.sh.jinja 64 | - template: jinja 65 | - user: planet 66 | - group: planet 67 | - mode: "0544" 68 | cron.present: 69 | - identifier: run-planet 70 | - user: planet 71 | - minute: 37 72 | - hour: 1,4,7,10,13,16,19,21 73 | 74 | {% for site, site_config in salt["pillar.get"]("planet", {}).get("sites", {}).items() %} 75 | {{ site_config["cache"] }}: 76 | file.directory: 77 | - user: planet 78 | - group: planet 79 | - mode: "0755" 80 | {{ site_config["output"] }}: 81 | file.directory: 82 | - user: planet 83 | - group: planet 84 | - mode: "0755" 85 | {{ site_config["output"] }}/static: 86 | file.symlink: 87 | - target: /srv/planet/static 88 | - user: planet 89 | - group: planet 90 | - mode: "0644" 91 | - require: 92 | - file: {{ site_config["output"] }} 93 | {% endfor %} 94 | -------------------------------------------------------------------------------- /salt/postgresql/admin.sls: -------------------------------------------------------------------------------- 1 | include: 2 | - postgresql.client 3 | 4 | {% if 'postgres-admin' in pillar %} 5 | {% for user, settings in salt["pillar.get"]("postgresql-users", {}).items() %} 6 | {{ user }}-user: 7 | postgres_user.present: 8 | - name: {{ user }} 9 | - password: {{ settings['password'] }} 10 | - refresh_password: True 11 | - db_host: {{ pillar['postgresql-clusters'][settings['cluster']]['host'] }} 12 | - db_port: {{ pillar['postgresql-clusters'][settings['cluster']]['port'] }} 13 | - db_user: {{ pillar['postgres-admin'][settings['cluster']]['user'] }} 14 | - db_password: {{ pillar['postgres-admin'][settings['cluster']]['password'] }} 15 | - require: 16 | - pkg: postgresql-client 17 | {% endfor %} 18 | 19 | {% for database, settings in pillar.get("postgresql-databases", {}).items() %} 20 | {{ database }}-database: 21 | postgres_database.present: 22 | - name: {{ database }} 23 | - owner: {{ settings['owner'] }} 24 | - db_host: {{ pillar['postgresql-clusters'][settings['cluster']]['host'] }} 25 | - db_port: {{ pillar['postgresql-clusters'][settings['cluster']]['port'] }} 26 | - db_user: {{ pillar['postgres-admin'][settings['cluster']]['user'] }} 27 | - db_password: {{ pillar['postgres-admin'][settings['cluster']]['password'] }} 28 | - require: 29 | - pkg: postgresql-client 30 | - postgres_user: {{ settings['owner'] }}-user 31 | {% endfor %} 32 | {% endif %} 33 | -------------------------------------------------------------------------------- /salt/postgresql/base/init.sls: -------------------------------------------------------------------------------- 1 | {% if grains["oscodename"] in ["jammy", "noble"] %} 2 | postgresql-key: 3 | file.managed: 4 | - name: /etc/apt/keyrings/postgresql.asc 5 | - mode: "0644" 6 | - source: salt://postgresql/base/APT-GPG-KEY-POSTGRESQL 7 | 8 | postgresql-repo: 9 | pkgrepo.managed: 10 | - name: "deb [signed-by=/etc/apt/keyrings/postgresql.asc arch={{ grains["osarch"] }}] https://apt.postgresql.org/pub/repos/apt {{ grains['oscodename'] }}-pgdg main" 11 | - aptkey: False 12 | - require: 13 | - file: postgresql-key 14 | - file: /etc/apt/sources.list.d/postgresql.list 15 | {% else %} 16 | postgresql-repo: 17 | pkgrepo.managed: 18 | - name: "deb http://apt.postgresql.org/pub/repos/apt {{ grains['oscodename'] }}-pgdg main" 19 | - key_url: salt://postgresql/base/APT-GPG-KEY-POSTGRESQL 20 | - file: /etc/apt/sources.list.d/postgresql.list 21 | {% endif %} 22 | -------------------------------------------------------------------------------- /salt/postgresql/client/init.sls: -------------------------------------------------------------------------------- 1 | include: 2 | - postgresql.base 3 | 4 | postgresql-client: 5 | pkg.installed: 6 | - pkgs: 7 | - postgresql-client-11 8 | - python3-psycopg2 9 | 10 | /etc/ssl/postgres: 11 | file.directory: 12 | - user: root 13 | - group: root 14 | - mode: "0755" 15 | 16 | {% for postgres_cluster, config in pillar.get('postgresql-clusters', {}).items() %} 17 | {% if 'ca_cert' in config %} 18 | /etc/ssl/postgres/{{ postgres_cluster }}.crt: 19 | file.managed: 20 | - contents_pillar: postgresql-clusters:{{ postgres_cluster }}:ca_cert 21 | - user: root 22 | - group: root 23 | - mode: "0644" 24 | {% endif %} 25 | {% if 'ca_cert_pillar' in config %} 26 | /etc/ssl/postgres/{{ postgres_cluster }}.crt: 27 | file.managed: 28 | - contents_pillar: {{ config['ca_cert_pillar'] }} 29 | - user: root 30 | - group: root 31 | - mode: "0644" 32 | {% endif %} 33 | {% endfor %} 34 | 35 | /etc/ssl/postgres/root-certs.crt: 36 | file.managed: 37 | - source: salt://postgresql/client/root-certs.crt.jinja 38 | - template: jinja 39 | - user: root 40 | - group: root 41 | - mode: "0644" 42 | -------------------------------------------------------------------------------- /salt/postgresql/client/root-certs.crt.jinja: -------------------------------------------------------------------------------- 1 | {%- for postgresql_cluster, config in pillar.get('postgresql-clusters', {}).items() %}{% if 'ca_cert' in config -%} 2 | {{ config['ca_cert'] }} 3 | {%- endif %}{% endfor -%} 4 | -------------------------------------------------------------------------------- /salt/postgresql/server/configs/gpg.conf.jinja: -------------------------------------------------------------------------------- 1 | trusted-key {{ pillar["wal-e"]["gpg-key-id"] }} 2 | -------------------------------------------------------------------------------- /salt/postgresql/server/configs/pg_hba.conf.jinja: -------------------------------------------------------------------------------- 1 | {% set psf_internal = salt["pillar.get"]("psf_internal_network") %} 2 | # PostgreSQL Client Authentication Configuration File 3 | # =================================================== 4 | # 5 | 6 | # TYPE DATABASE USER ADDRESS METHOD 7 | 8 | # Database administrative login by Unix domain socket 9 | local all postgres peer 10 | 11 | # Administration 12 | hostssl all salt-master {{ psf_internal }} md5 13 | 14 | # Replication 15 | hostssl replication replicator {{ psf_internal }} md5 16 | 17 | # Application Databases 18 | {% for database, settings in pillar.get("postgresql-databases", {}).items() %} 19 | hostssl {{ database }} {{ settings.owner }} 0.0.0.0/0 md5 20 | {% endfor %} 21 | -------------------------------------------------------------------------------- /salt/postgresql/server/configs/pg_ident.conf.jinja: -------------------------------------------------------------------------------- 1 | # PostgreSQL User Name Maps 2 | # ========================= 3 | # 4 | # Refer to the PostgreSQL documentation, chapter "Client 5 | # Authentication" for a complete description. A short synopsis 6 | # follows. 7 | # 8 | # This file controls PostgreSQL user name mapping. It maps external 9 | # user names to their corresponding PostgreSQL user names. Records 10 | # are of the form: 11 | # 12 | # MAPNAME SYSTEM-USERNAME PG-USERNAME 13 | # 14 | # (The uppercase quantities must be replaced by actual values.) 15 | # 16 | # MAPNAME is the (otherwise freely chosen) map name that was used in 17 | # pg_hba.conf. SYSTEM-USERNAME is the detected user name of the 18 | # client. PG-USERNAME is the requested PostgreSQL user name. The 19 | # existence of a record specifies that SYSTEM-USERNAME may connect as 20 | # PG-USERNAME. 21 | # 22 | # If SYSTEM-USERNAME starts with a slash (/), it will be treated as a 23 | # regular expression. Optionally this can contain a capture (a 24 | # parenthesized subexpression). The substring matching the capture 25 | # will be substituted for \1 (backslash-one) if present in 26 | # PG-USERNAME. 27 | # 28 | # Multiple maps may be specified in this file and used by pg_hba.conf. 29 | # 30 | # No map names are defined in the default configuration. If all 31 | # system user names and PostgreSQL user names are the same, you don't 32 | # need anything in this file. 33 | # 34 | # This file is read on server startup and when the postmaster receives 35 | # a SIGHUP signal. If you edit the file on a running system, you have 36 | # to SIGHUP the postmaster for the changes to take effect. You can 37 | # use "pg_ctl reload" to do that. 38 | 39 | # Put your actual configuration here 40 | # ---------------------------------- 41 | 42 | # MAPNAME SYSTEM-USERNAME PG-USERNAME 43 | -------------------------------------------------------------------------------- /salt/postgresql/server/configs/recovery.conf.jinja: -------------------------------------------------------------------------------- 1 | {% set postgresql = salt["pillar.get"]("postgresql") %} 2 | {% set postgresql_password = salt["pillar.get"]("postgresql-users:replicator") %} 3 | 4 | standby_mode = on 5 | 6 | primary_slot_name = '{{ grains["host"] }}' 7 | 8 | {{ "{{" }} with service "primary.postgresql@{{ pillar.dc }}" }} 9 | primary_conninfo = 'application_name={{ grains["fqdn"] }} host=postgresql.psf.io hostaddr={{ "{{(index . 0).Address}}" }} port={{ "{{(index . 0).Port}}" }} sslmode=verify-full sslrootcert=/etc/ssl/certs/PSF_CA.pem user=replicator password={{ postgresql_password }}' 10 | {{ "{{ end }}" }} 11 | -------------------------------------------------------------------------------- /salt/postgresql/server/configs/wal-e.conf.jinja: -------------------------------------------------------------------------------- 1 | {% set swift_tenant = salt["pillar.get"]("wal-e:swift-tenant") %} 2 | 3 | #------------------------------------------------------------------------------ 4 | # WRITE AHEAD LOG 5 | #------------------------------------------------------------------------------ 6 | 7 | # - Archiving - 8 | 9 | archive_mode = on 10 | archive_command = 'SWIFT_TENANT="{{ swift_tenant }}" envdir /etc/wal-e.d /var/lib/postgresql/wal-e/bin/wal-e wal-push %p' 11 | archive_timeout = 60 12 | -------------------------------------------------------------------------------- /salt/pythontest/config/nginx.pythontest.conf.jinja: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name www.pythontest.net pythontest.net; 4 | root /srv/python-testdata/www/; 5 | 6 | location = /redir/ { 7 | return 302 $scheme://$host/elsewhere/; 8 | } 9 | 10 | location = /redir/with_frag/ { 11 | return 302 $scheme://$host/elsewhere/#frag; 12 | } 13 | 14 | location /unicode/ { 15 | gzip on; 16 | gzip_min_length 1000; 17 | gzip_types text/plain application/xml; 18 | } 19 | } 20 | 21 | server { 22 | listen 443 ssl; 23 | server_name self-signed.pythontest.net; 24 | root /srv/python-testdata/www/; 25 | 26 | ssl_certificate /srv/python-testdata/tls/self-signed-cert.pem; 27 | ssl_certificate_key /srv/python-testdata/tls/self-signed-key.pem; 28 | } 29 | -------------------------------------------------------------------------------- /salt/pythontest/config/vsftpd.conf: -------------------------------------------------------------------------------- 1 | ftpd_banner=Welcome to the pythontest FTP server 2 | 3 | # Run vsftp as a standalone server 4 | listen=YES 5 | 6 | # Allow anonymous FTP. (This is what the test suite uses) 7 | anonymous_enable=YES 8 | 9 | # Use nobody as the FTP user for least privelege 10 | ftp_username=nobody 11 | 12 | # Use the ftp folder from the git repo as the root 13 | anon_root=/srv/python-testdata/ftp 14 | 15 | # The only local users are the python infra team and they 16 | # do not use ftp for administration 17 | local_enable=NO 18 | 19 | # This option prevents any writing ftp commands from being issued 20 | write_enable=NO 21 | 22 | # Activate directory messages - messages given to remote users when they 23 | # go into a certain directory. 24 | dirmessage_enable=YES 25 | 26 | # If enabled, vsftpd will display directory listings with the time 27 | # in your local time zone. The default is to display GMT. The 28 | # times returned by the MDTM FTP command are also affected by this 29 | # option. 30 | use_localtime=YES 31 | 32 | # Activate logging of uploads/downloads. 33 | xferlog_enable=YES 34 | 35 | # Make sure PORT transfer connections originate from port 20 (ftp-data). 36 | connect_from_port_20=YES 37 | # These ports must be opened in the firewall to enable data transfer 38 | pasv_enable=YES 39 | pasv_addr_resolve=YES 40 | pasv_address=www.pythontest.net 41 | pasv_max_port=10190 42 | pasv_min_port=10090 43 | 44 | # This option should be the name of a directory which is empty. Also, the 45 | # directory should not be writable by the ftp user. This directory is used 46 | # as a secure chroot() jail at times vsftpd does not require filesystem 47 | # access. 48 | secure_chroot_dir=/var/run/vsftpd/empty 49 | 50 | # Disable PAM support 51 | session_support=NO 52 | -------------------------------------------------------------------------------- /salt/redis/init.sls: -------------------------------------------------------------------------------- 1 | redis: 2 | pkg.installed: 3 | - name: redis-server 4 | -------------------------------------------------------------------------------- /salt/rsyslog/init.sls: -------------------------------------------------------------------------------- 1 | rsyslog: 2 | 3 | pkg: 4 | - installed 5 | 6 | service.running: 7 | - enable: True 8 | - restart: True 9 | - watch: 10 | - file: /etc/rsyslog.d/*.conf 11 | 12 | 13 | /etc/rsyslog.d/PLACEHOLDER.conf: 14 | file.managed: 15 | - replace: False 16 | -------------------------------------------------------------------------------- /salt/ssh/init.sls: -------------------------------------------------------------------------------- 1 | {% set host_keys = salt["pillar.get"]("ssh_host_keys") %} 2 | 3 | 4 | ssh: 5 | service.running: 6 | - enable: True 7 | - restart: True 8 | - watch: 9 | - file: /etc/ssh/sshd_config 10 | {% for fn in host_keys %} 11 | - file: /etc/ssh/{{ fn }} 12 | {% endfor %} 13 | 14 | 15 | /etc/ssh/sshd_config: 16 | file.managed: 17 | - source: salt://ssh/configs/sshd_config.jinja 18 | - template: jinja 19 | - user: root 20 | - group: root 21 | - mode: "0644" 22 | 23 | 24 | /usr/lib/tmpfiles.d/sshd-priv-sep.conf: 25 | file.managed: 26 | - contents: | 27 | d /run/sshd 0755 root root 28 | - user: root 29 | - group: root 30 | - mode: "0644" 31 | 32 | 33 | # If we have defined host keys for this server, then we want to drop them here 34 | # instead of whatever is here by default. 35 | {% for fn in host_keys %} 36 | /etc/ssh/{{ fn }}: 37 | file.managed: 38 | - contents_pillar: ssh_host_keys:{{ fn }} 39 | - owner: root 40 | - group: root 41 | {% if fn.endswith('.pub') %} 42 | - mode: "0644" 43 | {% else %} 44 | - mode: "0600" 45 | - show_diff: False 46 | {% endif %} 47 | {% endfor %} 48 | -------------------------------------------------------------------------------- /salt/sudoers/config/salt.jinja: -------------------------------------------------------------------------------- 1 | {% for sudoer_group in sudoers.split(',') %} 2 | {% for command in pillar['sudoer_groups'][sudoer_group]['commands'] %} 3 | %{{sudoer_group}} {{command}} 4 | {% endfor %} 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /salt/sudoers/init.sls: -------------------------------------------------------------------------------- 1 | {% if 'sudoer_groups' in pillar %} 2 | {% for group in pillar.get('sudoer_groups', {}) %} 3 | {{ group }}-sudoer_group: 4 | group.present: 5 | - name: {{ group }} 6 | {% endfor %} 7 | /etc/sudoers.d/salt: 8 | file.managed: 9 | - source: salt://sudoers/config/salt.jinja 10 | - template: jinja 11 | - context: 12 | sudoers: {{ pillar.get('sudoer_groups', {}).keys()|join(',') }} 13 | - user: root 14 | - group: root 15 | - mode: "0640" 16 | {% endif %} 17 | -------------------------------------------------------------------------------- /salt/tls/config/lego.conf.jinja: -------------------------------------------------------------------------------- 1 | ssl_certificate /etc/lego/certificates/{{ grains['fqdn'] }}.crt; 2 | ssl_certificate_key /etc/lego/certificates/{{ grains['fqdn'] }}.key; 3 | 4 | 5 | ssl_protocols TLSv1.2; 6 | ssl_dhparam /etc/ssl/private/dhparams.pem; 7 | ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:ECDH+AESG; 8 | ssl_prefer_server_ciphers on; 9 | 10 | ssl_session_timeout 60m; 11 | ssl_session_cache shared:SSL:32m; 12 | ssl_buffer_size 8k; 13 | 14 | ssl_stapling on; 15 | ssl_stapling_verify on; 16 | resolver 8.8.8.8 8.8.4.4 valid=300s; 17 | resolver_timeout 1s; 18 | -------------------------------------------------------------------------------- /salt/tls/config/pebble-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "pebble": { 3 | "listenAddress": "0.0.0.0:14000", 4 | "managementListenAddress": "0.0.0.0:15000", 5 | "certificate": "/etc/ssl/private/salt-master.vagrant.psf.io.pem", 6 | "privateKey": "/etc/ssl/private/salt-master.vagrant.psf.io.pem", 7 | "httpPort": 80, 8 | "tlsPort": 443, 9 | "ocspResponderURL": "", 10 | "externalAccountBindingRequired": false, 11 | "retryAfter": { 12 | "authz": 3, 13 | "order": 5 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /salt/tls/config/pebble.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Pebble 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | Environment=PEBBLE_VA_ALWAYS_VALID=1 8 | ExecStart=/usr/local/bin/pebble -config /etc/pebble-config.json 9 | KillMode=process 10 | User=root 11 | Group=root 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /salt/tls/init.sls: -------------------------------------------------------------------------------- 1 | ssl-cert: 2 | pkg.installed 3 | 4 | 5 | {% for name in salt["pillar.get"]("tls:ca", {}) %} # " Syntax Hack 6 | /etc/ssl/certs/{{ name }}.pem: 7 | file.managed: 8 | - contents_pillar: tls:ca:{{ name }} 9 | - user: root 10 | - group: ssl-cert 11 | - mode: "0644" 12 | - require: 13 | - pkg: ssl-cert 14 | {% endfor %} 15 | 16 | 17 | {% for name in salt["pillar.get"]("tls:certs", {}) %} # " Syntax Hack 18 | /etc/ssl/private/{{ name }}.pem: 19 | file.managed: 20 | - contents_pillar: tls:certs:{{ name }} 21 | - user: root 22 | - group: ssl-cert 23 | - mode: "0640" 24 | - show_diff: False 25 | - require: 26 | - pkg: ssl-cert 27 | {% endfor %} 28 | -------------------------------------------------------------------------------- /salt/tls/lego.sls: -------------------------------------------------------------------------------- 1 | include: 2 | - nginx 3 | 4 | {% if pillar["dc"] == "vagrant" %} 5 | salt-master-vagrant-host-entry: 6 | host.present: 7 | - ip: 192.168.50.2 8 | - names: 9 | - salt-master.vagrant.psf.io 10 | - salt-master 11 | {% endif %} 12 | 13 | crypto_packages: 14 | pkg.installed: 15 | - pkgs: 16 | - openssl 17 | 18 | generate_dhparams: 19 | cmd.run: 20 | - name: openssl dhparam -out /etc/ssl/private/dhparams.pem 4096 21 | - creates: /etc/ssl/private/dhparams.pem 22 | - require: 23 | - pkg: crypto_packages 24 | 25 | lego_extract: 26 | archive.extracted: 27 | - name: /usr/local/bin/ 28 | - if_missing: /usr/local/bin/lego 29 | {% if grains.osarch == 'amd64' %} 30 | - source: https://github.com/go-acme/lego/releases/download/v4.8.0/lego_v4.8.0_linux_amd64.tar.gz 31 | - source_hash: sha256=e8a0d808721af53f64977d4c4811e596cb273e1b950fadd5bf39b6781d2c311c 32 | {% elif grains.osarch == 'arm64' %} 33 | - source: https://github.com/go-acme/lego/releases/download/v4.8.0/lego_v4.8.0_linux_arm64.tar.gz 34 | - source_hash: sha256=b2f43fdccdd434e00547750f40e4203f1a5fdcd5186764d3c52a05635600a220 35 | {% endif %} 36 | - archive_format: tar 37 | - tar_options: -J --strip-components=1 lego 38 | - enforce_toplevel: False 39 | 40 | /etc/lego: 41 | file.directory: 42 | - user: root 43 | - group: root 44 | - mode: "0755" 45 | 46 | /etc/lego/.well-known/acme-challenge: 47 | file.directory: 48 | - user: nginx 49 | - group: root 50 | - mode: "0750" 51 | - makedirs: True 52 | - require: 53 | - file: /etc/lego 54 | -------------------------------------------------------------------------------- /salt/tls/pebble.sls: -------------------------------------------------------------------------------- 1 | {% if pillar.get('pebble', {'enabled': False}).enabled %} 2 | pebble-build-deps: 3 | pkg.installed: 4 | - pkgs: 5 | - golang 6 | - git 7 | 8 | pebble-golang-workspace: 9 | file.directory: 10 | - name: /usr/local/golang/pebble 11 | - makedirs: True 12 | 13 | pebble-source: 14 | git.latest: 15 | - name: https://github.com/letsencrypt/pebble.git 16 | - rev: v2.4.0 17 | - force_reset: remote-changes 18 | - target: /usr/local/src/pebble 19 | - require: 20 | - pkg: pebble-build-deps 21 | 22 | pebble-build: 23 | cmd.run: 24 | - creates: /usr/local/golang/pebble/bin/pebble 25 | - name: go install ./cmd/pebble 26 | - cwd: /usr/local/src/pebble 27 | - env: 28 | - GOPATH: /usr/local/golang/pebble 29 | - require: 30 | - git: pebble-source 31 | - file: pebble-golang-workspace 32 | 33 | pebble-install: 34 | file.copy: 35 | - name: /usr/local/bin/pebble 36 | - source: /usr/local/golang/pebble/bin/pebble 37 | - mode: "0755" 38 | 39 | pebble-config: 40 | file.managed: 41 | - name: /etc/pebble-config.json 42 | - source: salt://tls/config/pebble-config.json 43 | 44 | pebble-service: 45 | file.managed: 46 | - name: /lib/systemd/system/pebble.service 47 | - source: salt://tls/config/pebble.service 48 | - mode: "0644" 49 | 50 | service.running: 51 | - name: pebble 52 | - enable: True 53 | - restart: True 54 | - require: 55 | - file: pebble-install 56 | - file: /etc/pebble-config.json 57 | - file: /etc/ssl/private/salt-master.vagrant.psf.io.pem 58 | - watch: 59 | - file: /etc/pebble-config.json 60 | - file: /etc/ssl/certs/PSF_CA.pem 61 | - file: /etc/ssl/private/salt-master.vagrant.psf.io.pem 62 | {% endif %} 63 | -------------------------------------------------------------------------------- /salt/top.sls: -------------------------------------------------------------------------------- 1 | base: 2 | '*': 3 | - base.auto-highstate 4 | - base.harden 5 | - base.mail 6 | - base.repo 7 | - base.salt 8 | - base.sanity 9 | - consul 10 | - groups 11 | - users 12 | - ssh 13 | - firewall 14 | - sudoers 15 | - backup.client 16 | - unattended-upgrades 17 | - tls 18 | - rsyslog 19 | - datadog 20 | - base.motd 21 | - base.swap 22 | 23 | 'backup-server': 24 | - match: nodegroup 25 | - backup.server 26 | 27 | 'bugs': 28 | - match: nodegroup 29 | - bugs 30 | - bugs.cpython 31 | - bugs.jython 32 | - bugs.roundup 33 | 34 | 'buildbot': 35 | - match: nodegroup 36 | - pgbouncer 37 | - buildbot 38 | 39 | 'cdn-logs': 40 | - match: nodegroup 41 | - cdn-logs 42 | 43 | 'codespeed': 44 | - match: nodegroup 45 | - pgbouncer 46 | - codespeed 47 | 48 | 'docs': 49 | - match: nodegroup 50 | - docs 51 | 52 | 'downloads': 53 | - match: nodegroup 54 | - downloads 55 | 56 | 'elasticsearch': 57 | - match: nodegroup 58 | - elasticsearch 59 | 60 | 'hg': 61 | - match: nodegroup 62 | - hg 63 | 64 | 'loadbalancer': 65 | - match: nodegroup 66 | - haproxy 67 | 68 | 'moin': 69 | - match: nodegroup 70 | - moin 71 | 72 | 'planet': 73 | - match: nodegroup 74 | - planet 75 | 76 | 'postgresql': 77 | - match: nodegroup 78 | - postgresql.server 79 | - postgresql.admin 80 | 81 | 'pythontest': 82 | - match: nodegroup 83 | - pythontest 84 | 85 | 'salt-master': 86 | - match: nodegroup 87 | - postgresql.admin 88 | - dns 89 | - tls.pebble 90 | -------------------------------------------------------------------------------- /salt/unattended-upgrades/config/10periodic: -------------------------------------------------------------------------------- 1 | APT::Periodic::Update-Package-Lists "1"; 2 | APT::Periodic::Download-Upgradeable-Packages "1"; 3 | APT::Periodic::AutocleanInterval "7"; 4 | APT::Periodic::Unattended-Upgrade "1"; 5 | -------------------------------------------------------------------------------- /salt/unattended-upgrades/init.sls: -------------------------------------------------------------------------------- 1 | unattended-upgrades: 2 | pkg.installed 3 | 4 | 5 | # Originally this file was used, however it was moved to 10periodic to make it 6 | # more clear that it is configuring the APT::Periodic and not the actual 7 | # automated upgrades. 8 | /etc/apt/apt.conf.d/20auto-upgrades: 9 | file.absent 10 | 11 | 12 | /etc/apt/apt.conf.d/10periodic: 13 | file.managed: 14 | - source: salt://unattended-upgrades/config/10periodic 15 | - user: root 16 | - group: root 17 | - mode: "0644" 18 | 19 | 20 | /etc/apt/apt.conf.d/50unattended-upgrades: 21 | file.managed: 22 | - source: salt://unattended-upgrades/config/50unattended-upgrades 23 | - user: root 24 | - group: root 25 | - mode: "0644" 26 | - require: 27 | - pkg: unattended-upgrades 28 | -------------------------------------------------------------------------------- /salt/users/config/authorized_keys.jinja: -------------------------------------------------------------------------------- 1 | {% for key in ssh_keys %} 2 | {{key}}{% endfor %} 3 | -------------------------------------------------------------------------------- /salt/users/dotfiles/dstufft.sls: -------------------------------------------------------------------------------- 1 | dstufft-git: 2 | pkg.installed: 3 | - name: git 4 | 5 | https://github.com/dstufft/dotfiles.git: 6 | git.latest: 7 | - target: /home/psf-users/dstufft/.dotfiles 8 | - user: dstufft 9 | - force_clone: True 10 | - force_checkout: True 11 | - force_reset: True 12 | - require: 13 | - pkg: dstufft-git 14 | - user: dstufft 15 | 16 | /home/psf-users/dstufft/.zshenv: 17 | file.symlink: 18 | - target: /home/psf-users/dstufft/.dotfiles/zsh/.zshenv 19 | - user: dstufft 20 | - group: dstufft 21 | - require: 22 | - git: https://github.com/dstufft/dotfiles.git 23 | -------------------------------------------------------------------------------- /salt/users/dotfiles/init.sls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/python/psf-salt/fe2896e7d5b0a651db89a037b1c3aa7c9b5ff6df/salt/users/dotfiles/init.sls -------------------------------------------------------------------------------- /tasks/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, print_function 2 | 3 | import invoke 4 | 5 | from . import salt 6 | 7 | ns = invoke.Collection(salt) 8 | -------------------------------------------------------------------------------- /tasks/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, print_function 2 | 3 | import contextlib 4 | import os 5 | 6 | import fabric.api 7 | 8 | 9 | @contextlib.contextmanager 10 | def cd(path): 11 | current_path = os.path.abspath(os.curdir) 12 | os.chdir(path) 13 | try: 14 | yield 15 | finally: 16 | os.chdir(current_path) 17 | 18 | 19 | @contextlib.contextmanager 20 | def ssh_host(host): 21 | current_value = fabric.api.env.host_string 22 | fabric.api.env.host_string = host 23 | try: 24 | yield 25 | finally: 26 | fabric.api.env.host_string = current_value 27 | -------------------------------------------------------------------------------- /tests/docs-redirects/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 10000; 3 | include docs-redirects.conf; 4 | } 5 | -------------------------------------------------------------------------------- /tests/docs-redirects/specs/default-root.hurl: -------------------------------------------------------------------------------- 1 | # Assert that Python 3 is the default at the root. 2 | 3 | GET {{host}}/ 4 | HTTP 302 5 | [Asserts] 6 | header "Location" == "http://localhost/3/" 7 | 8 | 9 | # Assert that Python 3 is the default at the root of each translation. 10 | 11 | GET {{host}}/es/ 12 | HTTP 302 13 | [Asserts] 14 | header "Location" == "http://localhost/es/3/" 15 | 16 | GET {{host}}/fr/ 17 | HTTP 302 18 | [Asserts] 19 | header "Location" == "http://localhost/fr/3/" 20 | 21 | GET {{host}}/id/ 22 | HTTP 302 23 | [Asserts] 24 | header "Location" == "http://localhost/id/3/" 25 | 26 | GET {{host}}/it/ 27 | HTTP 302 28 | [Asserts] 29 | header "Location" == "http://localhost/it/3/" 30 | 31 | GET {{host}}/ja/ 32 | HTTP 302 33 | [Asserts] 34 | header "Location" == "http://localhost/ja/3/" 35 | 36 | GET {{host}}/ko/ 37 | HTTP 302 38 | [Asserts] 39 | header "Location" == "http://localhost/ko/3/" 40 | 41 | GET {{host}}/pl/ 42 | HTTP 302 43 | [Asserts] 44 | header "Location" == "http://localhost/pl/3/" 45 | 46 | GET {{host}}/pt-br/ 47 | HTTP 302 48 | [Asserts] 49 | header "Location" == "http://localhost/pt-br/3/" 50 | 51 | GET {{host}}/tr/ 52 | HTTP 302 53 | [Asserts] 54 | header "Location" == "http://localhost/tr/3/" 55 | 56 | GET {{host}}/uk/ 57 | HTTP 302 58 | [Asserts] 59 | header "Location" == "http://localhost/uk/3/" 60 | 61 | GET {{host}}/zh-cn/ 62 | HTTP 302 63 | [Asserts] 64 | header "Location" == "http://localhost/zh-cn/3/" 65 | 66 | GET {{host}}/zh-tw/ 67 | HTTP 302 68 | [Asserts] 69 | header "Location" == "http://localhost/zh-tw/3/" 70 | -------------------------------------------------------------------------------- /tests/docs-redirects/specs/devguide.hurl: -------------------------------------------------------------------------------- 1 | # Assert that /devguide/ redirects to the Developer's Guide. 2 | 3 | GET {{host}}/devguide/ 4 | HTTP 301 5 | [Asserts] 6 | header "Location" == "https://devguide.python.org/" 7 | 8 | GET {{host}}/devguide/index.html 9 | HTTP 301 10 | [Asserts] 11 | header "Location" == "https://devguide.python.org/index.html" 12 | 13 | 14 | # Assert that /documenting/ redirects to the Developer's Guide. 15 | 16 | GET {{host}}/documenting/ 17 | HTTP 301 18 | [Asserts] 19 | header "Location" == "https://devguide.python.org/documentation/start-documenting/" 20 | 21 | GET {{host}}/documenting/index.html 22 | HTTP 301 23 | [Asserts] 24 | header "Location" == "https://devguide.python.org/documentation/start-documenting/" 25 | 26 | GET {{host}}/documenting/intro.html 27 | HTTP 301 28 | [Asserts] 29 | header "Location" == "https://devguide.python.org/documentation/start-documenting/#introduction" 30 | 31 | GET {{host}}/documenting/style.html 32 | HTTP 301 33 | [Asserts] 34 | header "Location" == "https://devguide.python.org/documentation/style-guide/" 35 | 36 | GET {{host}}/documenting/rest.html 37 | HTTP 301 38 | [Asserts] 39 | header "Location" == "https://devguide.python.org/documentation/markup/" 40 | 41 | GET {{host}}/documenting/markup.html 42 | HTTP 301 43 | [Asserts] 44 | header "Location" == "https://devguide.python.org/documentation/markup/" 45 | 46 | GET {{host}}/documenting/fromlatex.html 47 | HTTP 301 48 | [Asserts] 49 | header "Location" == "https://devguide.python.org/documentation/markup/" 50 | 51 | GET {{host}}/documenting/building.html 52 | HTTP 301 53 | [Asserts] 54 | header "Location" == "https://devguide.python.org/documentation/start-documenting/#building-the-documentation" 55 | -------------------------------------------------------------------------------- /tests/docs-redirects/specs/ftp-download.hurl: -------------------------------------------------------------------------------- 1 | # Assert that /ftp/ redirects to www.python.org/ftp 2 | 3 | GET {{host}}/ftp/python/doc 4 | HTTP 301 5 | [Asserts] 6 | header "Location" == "https://www.python.org/ftp/python/doc" 7 | 8 | GET {{host}}/ftp/python/doc/3.4.5/python-3.4.5-docs-text.zip 9 | HTTP 301 10 | [Asserts] 11 | header "Location" == "https://www.python.org/ftp/python/doc/3.4.5/python-3.4.5-docs-text.zip" 12 | -------------------------------------------------------------------------------- /tests/docs-redirects/specs/py2.5.hurl: -------------------------------------------------------------------------------- 1 | # Assert that pre-Python 2.5 URIs are redirected to their 2 | # Python 2.6-and-later locations. 3 | 4 | GET {{host}}/lib/ 5 | HTTP 301 6 | [Asserts] 7 | header "Location" == "https://localhost/3/library/" 8 | 9 | GET {{host}}/lib/module-base64.html 10 | HTTP 301 11 | [Asserts] 12 | header "Location" == "https://localhost/3/library/base64.html" 13 | 14 | GET {{host}}/lib/module-sys.html 15 | HTTP 301 16 | [Asserts] 17 | header "Location" == "https://localhost/3/library/sys.html" 18 | 19 | GET {{host}}/tut/ 20 | HTTP 301 21 | [Asserts] 22 | header "Location" == "https://localhost/3/tutorial/" 23 | 24 | GET {{host}}/tut/tut.html 25 | HTTP 301 26 | [Asserts] 27 | header "Location" == "https://localhost/3/tutorial/" 28 | 29 | GET {{host}}/api/ 30 | HTTP 301 31 | [Asserts] 32 | header "Location" == "https://localhost/3/c-api/" 33 | 34 | GET {{host}}/ext/ 35 | HTTP 301 36 | [Asserts] 37 | header "Location" == "https://localhost/3/extending/" 38 | 39 | GET {{host}}/dist/ 40 | HTTP 301 41 | [Asserts] 42 | header "Location" == "https://localhost/3/" 43 | 44 | GET {{host}}/inst/ 45 | HTTP 301 46 | [Asserts] 47 | header "Location" == "https://localhost/3/" 48 | 49 | GET {{host}}/doc/ 50 | HTTP 301 51 | [Asserts] 52 | header "Location" == "https://devguide.python.org/documentation/start-documenting/" 53 | 54 | GET {{host}}/ref/ 55 | HTTP 301 56 | [Asserts] 57 | header "Location" == "https://localhost/3/reference/" 58 | -------------------------------------------------------------------------------- /tests/docs-redirects/specs/py3k.hurl: -------------------------------------------------------------------------------- 1 | # Assert that Py3k is Python 3. 2 | 3 | GET {{host}}/py3k 4 | HTTP 301 5 | [Asserts] 6 | header "Location" == "https://localhost/3" 7 | 8 | GET {{host}}/py3k/whatsnew/3.0.html 9 | HTTP 301 10 | [Asserts] 11 | header "Location" == "https://localhost/3/whatsnew/3.0.html" 12 | -------------------------------------------------------------------------------- /tests/docs-redirects/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | # Test the docs redirects. This script must be run from the repository root. 5 | 6 | docker stop docs-redirects-nginx || true 7 | 8 | docker run --name docs-redirects-nginx --detach --quiet --rm --tty \ 9 | --mount type=bind,source=./tests/docs-redirects/nginx.conf,target=/etc/nginx/conf.d/docs.conf,readonly \ 10 | --mount type=bind,source=./salt/docs/config/nginx.docs-redirects.conf,target=/etc/nginx/docs-redirects.conf,readonly \ 11 | -p 10000:10000 \ 12 | nginx:1.26.1-alpine 13 | 14 | # Wait for the nginx container to start… 15 | sleep 1 16 | 17 | hurl --color --continue-on-error --variable host=http://localhost:10000 --test ./tests/docs-redirects/specs/*.hurl 18 | 19 | docker stop docs-redirects-nginx 20 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = docs, lint 3 | skipsdist = true 4 | 5 | [testenv:docs] 6 | deps = 7 | -rdocs/requirements.txt 8 | basepython = python3 9 | commands = 10 | sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html 11 | 12 | [testenv:lint] 13 | deps = 14 | salt-lint 15 | allowlist_externals = 16 | /bin/bash 17 | /usr/bin/bash 18 | basepython = python3 19 | commands = 20 | bash -exc "salt-lint $(find . -type f -name *.sls | xargs)" 21 | --------------------------------------------------------------------------------Error 410 - Page disabled
8 |The resources necessary to render annotate on
9 |Misc/NEWS
forcpython
andcpython-fullhistory
lead to poor performance for all repositories hosted at hg.python.org.If you are reliant on this feature, please contact The Infrastructure Staff to help us understand and support your usecase.
10 |