| author | wenzelm | 
| Thu, 14 Nov 2019 22:59:20 +0100 | |
| changeset 71135 | 781b15f53098 | 
| parent 71131 | 1579a9160c7f | 
| child 71265 | 6ca561001244 | 
| permissions | -rw-r--r-- | 
| 70967 | 1 | /* Title: Pure/Tools/phabricator.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 4 | Support for Phabricator server, notably for Ubuntu 18.04 LTS. | 
| 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 5 | |
| 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 6 | See also: | 
| 70967 | 7 | - https://www.phacility.com/phabricator | 
| 8 | - https://secure.phabricator.com/book/phabricator | |
| 9 | */ | |
| 10 | ||
| 11 | package isabelle | |
| 12 | ||
| 13 | ||
| 70969 | 14 | import scala.util.matching.Regex | 
| 15 | ||
| 16 | ||
| 70967 | 17 | object Phabricator | 
| 18 | {
 | |
| 19 | /** defaults **/ | |
| 20 | ||
| 71049 | 21 | /* required packages */ | 
| 22 | ||
| 23 | val packages: List[String] = | |
| 24 | Build_Docker.packages ::: | |
| 25 | List( | |
| 26 | // https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61 | |
| 27 | "git", "mysql-server", "apache2", "libapache2-mod-php", "php", "php-mysql", | |
| 28 | "php-gd", "php-curl", "php-apcu", "php-cli", "php-json", "php-mbstring", | |
| 29 | // more packages | |
| 71135 | 30 | "php-zip", "python-pygments", "ssh", "subversion", "mercurial") | 
| 71049 | 31 | |
| 32 | ||
| 33 | /* global system resources */ | |
| 34 | ||
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 35 | val www_user = "www-data" | 
| 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 36 | |
| 71049 | 37 | val daemon_user = "phabricator" | 
| 38 | ||
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 39 |   val sshd_config = Path.explode("/etc/ssh/sshd_config")
 | 
| 71049 | 40 | |
| 41 | ||
| 42 | /* installation parameters */ | |
| 43 | ||
| 70967 | 44 | val default_name = "vcs" | 
| 45 | ||
| 71052 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 46 | def phabricator_name(name: String = "", ext: String = ""): String = | 
| 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 47 | "phabricator" + (if (name.isEmpty) "" else "-" + name) + (if (ext.isEmpty) "" else "." + ext) | 
| 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 48 | |
| 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 49 | def isabelle_phabricator_name(name: String = "", ext: String = ""): String = | 
| 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 50 | "isabelle-" + phabricator_name(name = name, ext = ext) | 
| 70967 | 51 | |
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 52 | def default_root(name: String): Path = | 
| 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 53 |     Path.explode("/var/www") + Path.basic(phabricator_name(name = name))
 | 
| 70967 | 54 | |
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 55 |   def default_repo(name: String): Path = default_root(name) + Path.basic("repo")
 | 
| 70967 | 56 | |
| 71072 | 57 |   val default_mailers: Path = Path.explode("mailers.json")
 | 
| 71066 | 58 | |
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 59 | val default_system_port = 22 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 60 | val alternative_system_port = 222 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 61 | val default_server_port = 2222 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 62 | |
| 70967 | 63 | |
| 64 | ||
| 65 | /** global configuration **/ | |
| 66 | ||
| 71052 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 67 |   val global_config = Path.explode("/etc/" + isabelle_phabricator_name(ext = "conf"))
 | 
| 70967 | 68 | |
| 71122 | 69 | def global_config_script( | 
| 70 | header: Boolean = false, | |
| 71 | init: String = "", | |
| 72 | body: String = "", | |
| 73 | exit: String = ""): String = | |
| 74 |   {
 | |
| 75 | (if (header) "#!/bin/bash\n" else "") + | |
| 76 | """ | |
| 77 | {""" + (if (init.nonEmpty) "\n" + Library.prefix_lines("  ", init) else "") + """
 | |
| 78 |   while { unset REPLY; read -r; test "$?" = 0 -o -n "$REPLY"; }
 | |
| 79 | do | |
| 80 | NAME="$(echo "$REPLY" | cut -d: -f1)" | |
| 81 | ROOT="$(echo "$REPLY" | cut -d: -f2)" | |
| 82 | """ + Library.prefix_lines("    ", body) + """
 | |
| 83 | done""" + | |
| 84 |     (if (exit.nonEmpty) "\n" + Library.prefix_lines("  ", exit) else "") + """
 | |
| 85 | } < """ + File.bash_path(global_config) + """ | |
| 86 | """ | |
| 87 | } | |
| 88 | ||
| 70967 | 89 | sealed case class Config(name: String, root: Path) | 
| 70968 | 90 |   {
 | 
| 71052 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 91 | def home: Path = root + Path.explode(phabricator_name()) | 
| 70969 | 92 | |
| 93 | def execute(command: String): Process_Result = | |
| 71102 | 94 |       Isabelle_System.bash("bin/" + command, cwd = home.file, redirect = true).check
 | 
| 70968 | 95 | } | 
| 70967 | 96 | |
| 97 | def read_config(): List[Config] = | |
| 98 |   {
 | |
| 99 |     if (global_config.is_file) {
 | |
| 100 | for (entry <- Library.trim_split_lines(File.read(global_config)) if entry.nonEmpty) | |
| 101 |       yield {
 | |
| 102 |         space_explode(':', entry) match {
 | |
| 103 | case List(name, root) => Config(name, Path.explode(root)) | |
| 104 |           case _ => error("Malformed config file " + global_config + "\nentry " + quote(entry))
 | |
| 105 | } | |
| 106 | } | |
| 107 | } | |
| 108 | else Nil | |
| 109 | } | |
| 110 | ||
| 111 | def write_config(configs: List[Config]) | |
| 112 |   {
 | |
| 113 | File.write(global_config, | |
| 114 |       configs.map(config => config.name + ":" + config.root.implode).mkString("", "\n", "\n"))
 | |
| 115 | } | |
| 116 | ||
| 117 | def get_config(name: String): Config = | |
| 118 | read_config().find(config => config.name == name) getOrElse | |
| 119 |       error("Bad Isabelle/Phabricator installation " + quote(name))
 | |
| 120 | ||
| 121 | ||
| 122 | ||
| 71097 | 123 | /** command-line tools **/ | 
| 124 | ||
| 125 | /* Isabelle tool wrapper */ | |
| 126 | ||
| 127 | val isabelle_tool1 = | |
| 128 |     Isabelle_Tool("phabricator", "invoke command-line tool within Phabricator home directory", args =>
 | |
| 129 |     {
 | |
| 71101 | 130 | var list = false | 
| 71097 | 131 | var name = default_name | 
| 132 | ||
| 133 | val getopts = | |
| 134 |         Getopts("""
 | |
| 135 | Usage: isabelle phabricator [OPTIONS] COMMAND [ARGS...] | |
| 136 | ||
| 137 | Options are: | |
| 71101 | 138 | -l list available Phabricator installations | 
| 71097 | 139 | -n NAME Phabricator installation name (default: """ + quote(default_name) + """) | 
| 140 | ||
| 71103 | 141 | Invoke a command-line tool within the home directory of the named | 
| 142 | Phabricator installation. | |
| 71097 | 143 | """, | 
| 71101 | 144 | "l" -> (_ => list = true), | 
| 71097 | 145 | "n:" -> (arg => name = arg)) | 
| 146 | ||
| 147 | val more_args = getopts(args) | |
| 71101 | 148 | if (more_args.isEmpty && !list) getopts.usage() | 
| 71097 | 149 | |
| 150 | val progress = new Console_Progress | |
| 151 | ||
| 71101 | 152 |       if (list) {
 | 
| 153 |         for (config <- read_config()) {
 | |
| 71103 | 154 |           progress.echo("phabricator " + quote(config.name) + " root " + config.root)
 | 
| 71101 | 155 | } | 
| 156 | } | |
| 157 | ||
| 71097 | 158 | val config = get_config(name) | 
| 159 | ||
| 71098 | 160 | val result = progress.bash(Bash.strings(more_args), cwd = config.home.file, echo = true) | 
| 161 |       if (!result.ok) error("Return code: " + result.rc.toString)
 | |
| 71097 | 162 | }) | 
| 163 | ||
| 164 | ||
| 165 | ||
| 70967 | 166 | /** setup **/ | 
| 167 | ||
| 71049 | 168 | def user_setup(name: String, description: String, ssh_setup: Boolean = false) | 
| 169 |   {
 | |
| 170 |     if (!Linux.user_exists(name)) {
 | |
| 71054 
b64fc38327ae
prefer system user setup, e.g. avoid occurrence on login screen;
 wenzelm parents: 
71053diff
changeset | 171 | Linux.user_add(name, description = description, system = true, ssh_setup = ssh_setup) | 
| 71049 | 172 | } | 
| 173 |     else if (Linux.user_description(name) != description) {
 | |
| 174 |       error("User " + quote(name) + " already exists --" +
 | |
| 175 | " for Phabricator it should have the description:\n " + quote(description)) | |
| 176 | } | |
| 177 | } | |
| 178 | ||
| 70967 | 179 | def phabricator_setup( | 
| 180 | name: String = default_name, | |
| 181 | root: String = "", | |
| 182 | repo: String = "", | |
| 71047 | 183 | package_update: Boolean = false, | 
| 70967 | 184 | progress: Progress = No_Progress) | 
| 185 |   {
 | |
| 186 | /* system environment */ | |
| 187 | ||
| 188 | Linux.check_system_root() | |
| 189 | ||
| 71079 | 190 |     progress.echo("System packages ...")
 | 
| 191 | ||
| 71047 | 192 |     if (package_update) {
 | 
| 193 | Linux.package_update(progress = progress) | |
| 194 | Linux.check_reboot_required() | |
| 195 | } | |
| 70967 | 196 | |
| 197 | Linux.package_install(packages, progress = progress) | |
| 198 | Linux.check_reboot_required() | |
| 199 | ||
| 200 | ||
| 71049 | 201 | /* users */ | 
| 202 | ||
| 71125 | 203 | if (name.contains((c: Char) => !(Symbol.is_ascii_letter(c) || Symbol.is_ascii_digit(c))) || | 
| 204 |         Set("", "ssh", "phd", daemon_user).contains(name)) {
 | |
| 205 |       error("Bad installation name: " + quote(name))
 | |
| 71049 | 206 | } | 
| 207 | ||
| 208 | user_setup(daemon_user, "Phabricator Daemon User", ssh_setup = true) | |
| 209 | user_setup(name, "Phabricator SSH User") | |
| 210 | ||
| 211 | ||
| 70967 | 212 | /* basic installation */ | 
| 213 | ||
| 71079 | 214 |     progress.echo("\nPhabricator installation ...")
 | 
| 71076 | 215 | |
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 216 | val root_path = if (root.nonEmpty) Path.explode(root) else default_root(name) | 
| 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 217 | val repo_path = if (repo.nonEmpty) Path.explode(repo) else default_repo(name) | 
| 70967 | 218 | |
| 219 | val configs = read_config() | |
| 220 | ||
| 221 |     for (config <- configs if config.name == name) {
 | |
| 222 |       error("Duplicate Phabricator installation " + quote(name) + " in " + config.root)
 | |
| 223 | } | |
| 224 | ||
| 225 |     if (!Isabelle_System.bash("mkdir -p " + File.bash_path(root_path)).ok) {
 | |
| 226 |       error("Failed to create root directory " + root_path)
 | |
| 227 | } | |
| 228 | ||
| 71116 | 229 | Isabelle_System.chown(Bash.string(www_user) + ":" + Bash.string(www_user), root_path) | 
| 230 |     Isabelle_System.chmod("755", root_path)
 | |
| 231 | ||
| 70967 | 232 | progress.bash(cwd = root_path.file, echo = true, | 
| 233 | script = """ | |
| 234 | set -e | |
| 71126 | 235 | echo "Cloning distribution repositories:" | 
| 70967 | 236 | git clone https://github.com/phacility/libphutil.git | 
| 237 | git clone https://github.com/phacility/arcanist.git | |
| 238 | git clone https://github.com/phacility/phabricator.git | |
| 239 | """).check | |
| 240 | ||
| 241 | val config = Config(name, root_path) | |
| 242 | write_config(configs ::: List(config)) | |
| 70968 | 243 | |
| 71051 | 244 |     config.execute("config set pygments.enabled true")
 | 
| 245 | ||
| 70968 | 246 | |
| 71050 | 247 | /* local repository directory */ | 
| 248 | ||
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 249 |     progress.echo("\nRepository hosting setup ...")
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 250 | |
| 71050 | 251 |     if (!Isabelle_System.bash("mkdir -p " + File.bash_path(repo_path)).ok) {
 | 
| 252 |       error("Failed to create local repository directory " + repo_path)
 | |
| 253 | } | |
| 254 | ||
| 71114 | 255 | Isabelle_System.chown( | 
| 256 | "-R " + Bash.string(daemon_user) + ":" + Bash.string(daemon_user), repo_path) | |
| 257 |     Isabelle_System.chmod("755", repo_path)
 | |
| 71050 | 258 | |
| 259 |     config.execute("config set repository.default-local-path " + File.bash_path(repo_path))
 | |
| 260 | ||
| 261 | ||
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 262 |     val sudoers_file = Path.explode("/etc/sudoers.d") + Path.basic(isabelle_phabricator_name())
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 263 | File.write(sudoers_file, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 264 |       www_user + " ALL=(" + daemon_user + ") SETENV: NOPASSWD: /usr/bin/git, /usr/bin/hg, /usr/bin/ssh, /usr/bin/id\n" +
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 265 |       name + " ALL=(" + daemon_user + ") SETENV: NOPASSWD: /usr/bin/git, /usr/bin/git-upload-pack, /usr/bin/git-receive-pack, /usr/bin/hg, /usr/bin/svnserve, /usr/bin/ssh, /usr/bin/id\n")
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 266 | |
| 71115 | 267 |     Isabelle_System.chmod("440", sudoers_file)
 | 
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 268 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 269 |     config.execute("config set diffusion.ssh-user " + Bash.string(config.name))
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 270 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 271 | |
| 70969 | 272 | /* MySQL setup */ | 
| 273 | ||
| 71079 | 274 |     progress.echo("\nMySQL setup ...")
 | 
| 70969 | 275 | |
| 71055 
27a998cdc0f4
back to plain name, to have it accepted my mysql;
 wenzelm parents: 
71054diff
changeset | 276 |     File.write(Path.explode("/etc/mysql/mysql.conf.d/" + phabricator_name(ext = "cnf")),
 | 
| 71051 | 277 | """[mysqld] | 
| 278 | max_allowed_packet = 32M | |
| 279 | innodb_buffer_pool_size = 1600M | |
| 280 | local_infile = 0 | |
| 281 | """) | |
| 282 | ||
| 283 |     Linux.service_restart("mysql")
 | |
| 284 | ||
| 285 | ||
| 70969 | 286 | def mysql_conf(R: Regex): Option[String] = | 
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 287 |       split_lines(File.read(Path.explode("/etc/mysql/debian.cnf"))).collectFirst({ case R(a) => a })
 | 
| 70969 | 288 | |
| 289 |     for (user <- mysql_conf("""^user\s*=\s*(\S*)\s*$""".r)) {
 | |
| 290 |       config.execute("config set mysql.user " + Bash.string(user))
 | |
| 291 | } | |
| 292 | ||
| 293 |     for (pass <- mysql_conf("""^password\s*=\s*(\S*)\s*$""".r)) {
 | |
| 294 |       config.execute("config set mysql.pass " + Bash.string(pass))
 | |
| 295 | } | |
| 296 | ||
| 297 |     config.execute("config set storage.default-namespace " +
 | |
| 71052 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 298 |       Bash.string(phabricator_name(name = name).replace("-", "_")))
 | 
| 70969 | 299 | |
| 71051 | 300 |     config.execute("config set storage.mysql-engine.max-size 8388608")
 | 
| 301 | ||
| 71102 | 302 |     progress.bash("bin/storage upgrade --force", cwd = config.home.file, echo = true).check
 | 
| 70969 | 303 | |
| 304 | ||
| 71051 | 305 | /* PHP setup */ | 
| 306 | ||
| 307 | val php_version = | |
| 308 |       Isabelle_System.bash("""php --run 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;'""")
 | |
| 309 | .check.out | |
| 310 | ||
| 311 | val php_conf = | |
| 312 |       Path.explode("/etc/php") + Path.basic(php_version) +  // educated guess
 | |
| 71052 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 313 |         Path.explode("apache2/conf.d") +
 | 
| 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 314 | Path.basic(isabelle_phabricator_name(ext = "ini")) | 
| 71051 | 315 | |
| 316 | File.write(php_conf, | |
| 317 | "post_max_size = 32M\n" + | |
| 318 | "opcache.validate_timestamps = 0\n" + | |
| 71129 | 319 | "memory_limit = 512M\n" + | 
| 320 | "max_execution_time = 120\n") | |
| 71051 | 321 | |
| 322 | ||
| 70968 | 323 | /* Apache setup */ | 
| 324 | ||
| 71079 | 325 |     progress.echo("Apache setup ...")
 | 
| 70968 | 326 | |
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 327 |     val apache_root = Path.explode("/etc/apache2")
 | 
| 70968 | 328 |     val apache_sites = apache_root + Path.explode("sites-available")
 | 
| 329 | ||
| 330 |     if (!apache_sites.is_dir) error("Bad Apache sites directory " + apache_sites)
 | |
| 331 | ||
| 71058 | 332 | val server_name = phabricator_name(name = name, ext = "lvh.me") // alias for "localhost" for testing | 
| 71052 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 333 | val server_url = "http://" + server_name | 
| 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 334 | |
| 71058 | 335 | File.write(apache_sites + Path.basic(isabelle_phabricator_name(name = name, ext = "conf")), | 
| 70968 | 336 | """<VirtualHost *:80> | 
| 71052 
6bf53035baf0
clarified name prefixes: global config always uses "isabelle-phabricator";
 wenzelm parents: 
71051diff
changeset | 337 | ServerName """ + server_name + """ | 
| 70968 | 338 | ServerAdmin webmaster@localhost | 
| 70969 | 339 | DocumentRoot """ + config.home.implode + """/webroot | 
| 70968 | 340 | |
| 341 |     ErrorLog ${APACHE_LOG_DIR}/error.log
 | |
| 342 | RewriteEngine on | |
| 343 | RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA] | |
| 344 | </VirtualHost> | |
| 345 | ||
| 346 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet | |
| 347 | """) | |
| 348 | ||
| 71051 | 349 | Isabelle_System.bash( """ | 
| 70968 | 350 | set -e | 
| 351 | a2enmod rewrite | |
| 71058 | 352 | a2ensite """ + Bash.string(isabelle_phabricator_name(name = name))).check | 
| 71051 | 353 | |
| 71057 | 354 |     config.execute("config set phabricator.base-uri " + Bash.string(server_url))
 | 
| 355 | ||
| 71051 | 356 |     Linux.service_restart("apache2")
 | 
| 70968 | 357 | |
| 71128 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 358 |     progress.echo("\nWeb configuration via " + server_url)
 | 
| 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 359 | |
| 71053 | 360 | |
| 361 | /* PHP daemon */ | |
| 362 | ||
| 71128 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 363 |     progress.echo("\nPHP daemon setup ...")
 | 
| 71053 | 364 | |
| 365 |     config.execute("config set phd.user " + Bash.string(daemon_user))
 | |
| 71112 | 366 |     config.execute("config set phd.log-directory /var/tmp/phd/" +
 | 
| 367 | isabelle_phabricator_name(name = name) + "/log") | |
| 71053 | 368 | |
| 71124 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 369 | val phd_name = isabelle_phabricator_name(name = "phd") | 
| 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 370 |     val phd_command = Path.explode("/usr/local/bin") + Path.basic(phd_name)
 | 
| 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 371 | |
| 71127 | 372 | Linux.service_shutdown(phd_name) | 
| 373 | ||
| 71124 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 374 | File.write(phd_command, | 
| 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 375 | global_config_script(header = true, body = """"$ROOT/phabricator/bin/phd" "$@" """)) | 
| 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 376 |     Isabelle_System.chmod("755", phd_command)
 | 
| 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 377 |     Isabelle_System.chown("root:root", phd_command)
 | 
| 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 378 | |
| 71128 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 379 |     try {
 | 
| 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 380 | Linux.service_install(phd_name, | 
| 71053 | 381 | """[Unit] | 
| 71124 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 382 | Description=PHP daemon manager for Isabelle/Phabricator | 
| 71053 | 383 | After=syslog.target network.target apache2.service mysql.service | 
| 384 | ||
| 385 | [Service] | |
| 386 | Type=oneshot | |
| 387 | User=""" + daemon_user + """ | |
| 388 | Group=""" + daemon_user + """ | |
| 389 | Environment=PATH=/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin | |
| 71124 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 390 | ExecStart=""" + phd_command.implode + """ start --force | 
| 
7dbadecdc118
just one isabelle-phabricator-phd service, which manages all processes uniformly (NB: "bin/phd stop" affects all installations);
 wenzelm parents: 
71122diff
changeset | 391 | ExecStop=""" + phd_command.implode + """ stop | 
| 71053 | 392 | RemainAfterExit=yes | 
| 393 | ||
| 394 | [Install] | |
| 395 | WantedBy=multi-user.target | |
| 396 | """) | |
| 71128 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 397 | } | 
| 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 398 |     catch {
 | 
| 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 399 | case ERROR(msg) => | 
| 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 400 |         progress.bash("bin/phd status", cwd = config.home.file, echo = true).check
 | 
| 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 401 | error(msg) | 
| 
f79006c533b0
clarified errors: PHP daemon can fail under odd circumstances;
 wenzelm parents: 
71127diff
changeset | 402 | } | 
| 70967 | 403 | } | 
| 404 | ||
| 405 | ||
| 406 | /* Isabelle tool wrapper */ | |
| 407 | ||
| 71097 | 408 | val isabelle_tool2 = | 
| 70967 | 409 |     Isabelle_Tool("phabricator_setup", "setup Phabricator server on Ubuntu Linux", args =>
 | 
| 410 |     {
 | |
| 71047 | 411 | var repo = "" | 
| 412 | var package_update = false | |
| 71078 | 413 | var name = default_name | 
| 70967 | 414 | var root = "" | 
| 415 | ||
| 416 | val getopts = | |
| 417 |         Getopts("""
 | |
| 71078 | 418 | Usage: isabelle phabricator_setup [OPTIONS] | 
| 70967 | 419 | |
| 420 | Options are: | |
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 421 |     -R DIR       repository directory (default: """ + default_repo("NAME") + """)
 | 
| 71047 | 422 | -U full update of system packages before installation | 
| 71078 | 423 | -n NAME Phabricator installation name (default: """ + quote(default_name) + """) | 
| 71068 
510b89906d86
discontinued somewhat pointless Isabelle options: setup implicitly assumes Ubuntu 18.04;
 wenzelm parents: 
71066diff
changeset | 424 |     -r DIR       installation root directory (default: """ + default_root("NAME") + """)
 | 
| 70967 | 425 | |
| 71103 | 426 | Install Phabricator as LAMP application (Linux, Apache, MySQL, PHP). | 
| 70967 | 427 | |
| 71078 | 428 | The installation name (default: """ + quote(default_name) + """) is mapped to a regular | 
| 429 | Unix user; this is relevant for public SSH access. | |
| 70967 | 430 | """, | 
| 431 | "R:" -> (arg => repo = arg), | |
| 71047 | 432 | "U" -> (_ => package_update = true), | 
| 71078 | 433 | "n:" -> (arg => name = arg), | 
| 70967 | 434 | "r:" -> (arg => root = arg)) | 
| 435 | ||
| 436 | val more_args = getopts(args) | |
| 71078 | 437 | if (more_args.nonEmpty) getopts.usage() | 
| 70967 | 438 | |
| 439 | val progress = new Console_Progress | |
| 440 | ||
| 71078 | 441 | phabricator_setup(name = name, root = root, repo = repo, | 
| 71047 | 442 | package_update = package_update, progress = progress) | 
| 70967 | 443 | }) | 
| 444 | ||
| 445 | ||
| 446 | ||
| 71066 | 447 | /** setup mail **/ | 
| 70967 | 448 | |
| 71072 | 449 | val mailers_template: String = | 
| 450 | """[ | |
| 451 |   {
 | |
| 452 | "key": "example.org", | |
| 453 | "type": "smtp", | |
| 454 |     "options": {
 | |
| 455 | "host": "mail.example.org", | |
| 456 | "port": 465, | |
| 457 | "user": "phabricator@example.org", | |
| 458 | "password": "********", | |
| 459 | "protocol": "ssl", | |
| 460 | "message-id": true | |
| 461 | } | |
| 462 | } | |
| 463 | ]""" | |
| 464 | ||
| 71066 | 465 | def phabricator_setup_mail( | 
| 466 | name: String = default_name, | |
| 467 | config_file: Option[Path] = None, | |
| 468 | test_user: String = "", | |
| 469 | progress: Progress = No_Progress) | |
| 70967 | 470 |   {
 | 
| 471 | Linux.check_system_root() | |
| 472 | ||
| 71066 | 473 | val config = get_config(name) | 
| 71073 | 474 | val default_config_file = config.root + default_mailers | 
| 71066 | 475 | |
| 476 | val mail_config = config_file getOrElse default_config_file | |
| 477 | ||
| 478 | def setup_mail | |
| 479 |     {
 | |
| 480 |       progress.echo("Using mail configuration from " + mail_config)
 | |
| 481 |       config.execute("config set cluster.mailers --stdin < " + File.bash_path(mail_config))
 | |
| 482 | ||
| 483 |       if (test_user.nonEmpty) {
 | |
| 484 |         progress.echo("Sending test mail to " + quote(test_user))
 | |
| 485 | progress.bash(cwd = config.home.file, echo = true, | |
| 71102 | 486 | script = """echo "Test from Phabricator ($(date))" | bin/mail send-test --subject "Test" --to """ + | 
| 71066 | 487 | Bash.string(test_user)).check | 
| 488 | } | |
| 489 | } | |
| 490 | ||
| 491 |     if (config_file.isEmpty) {
 | |
| 71070 | 492 |       if (!default_config_file.is_file) {
 | 
| 493 | File.write(default_config_file, mailers_template) | |
| 71114 | 494 |         Isabelle_System.chmod("600", default_config_file)
 | 
| 71070 | 495 | } | 
| 71066 | 496 |       if (File.read(default_config_file) == mailers_template) {
 | 
| 71131 | 497 |         progress.echo("Please invoke the tool again, after providing details in\n  " +
 | 
| 498 | default_config_file.implode + "\n") | |
| 71066 | 499 | } | 
| 500 | else setup_mail | |
| 501 | } | |
| 502 | else setup_mail | |
| 70967 | 503 | } | 
| 504 | ||
| 505 | ||
| 506 | /* Isabelle tool wrapper */ | |
| 507 | ||
| 71097 | 508 | val isabelle_tool3 = | 
| 71066 | 509 |     Isabelle_Tool("phabricator_setup_mail",
 | 
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 510 | "setup mail for one Phabricator installation", args => | 
| 70967 | 511 |     {
 | 
| 71066 | 512 | var test_user = "" | 
| 513 | var name = default_name | |
| 514 | var config_file: Option[Path] = None | |
| 515 | ||
| 70967 | 516 | val getopts = | 
| 517 |         Getopts("""
 | |
| 71066 | 518 | Usage: isabelle phabricator_setup_mail [OPTIONS] | 
| 519 | ||
| 520 | Options are: | |
| 521 | -T USER send test mail to Phabricator user | |
| 71103 | 522 | -f FILE config file (default: """ + default_mailers + """ within Phabricator root) | 
| 71066 | 523 | -n NAME Phabricator installation name (default: """ + quote(default_name) + """) | 
| 70967 | 524 | |
| 71077 | 525 | Provide mail configuration for existing Phabricator installation. | 
| 71066 | 526 | """, | 
| 527 | "T:" -> (arg => test_user = arg), | |
| 528 | "f:" -> (arg => config_file = Some(Path.explode(arg))), | |
| 529 | "n:" -> (arg => name = arg)) | |
| 70967 | 530 | |
| 531 | val more_args = getopts(args) | |
| 71066 | 532 | if (more_args.nonEmpty) getopts.usage() | 
| 70967 | 533 | |
| 534 | val progress = new Console_Progress | |
| 535 | ||
| 71066 | 536 | phabricator_setup_mail(name = name, config_file = config_file, | 
| 537 | test_user = test_user, progress = progress) | |
| 70967 | 538 | }) | 
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 539 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 540 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 541 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 542 | /** setup ssh **/ | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 543 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 544 | /* sshd config */ | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 545 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 546 | private val Port = """^\s*Port\s+(\d+)\s*$""".r | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 547 | private val No_Port = """^#\s*Port\b.*$""".r | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 548 | private val Any_Port = """^#?\s*Port\b.*$""".r | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 549 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 550 | def conf_ssh_port(port: Int): String = | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 551 | if (port == 22) "#Port 22" else "Port " + port | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 552 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 553 | def read_ssh_port(conf: Path): Int = | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 554 |   {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 555 | val lines = split_lines(File.read(conf)) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 556 | val ports = | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 557 |       lines.flatMap({
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 558 | case Port(Value.Int(p)) => Some(p) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 559 | case No_Port() => Some(22) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 560 | case _ => None | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 561 | }) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 562 |     ports match {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 563 | case List(port) => port | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 564 |       case Nil => error("Missing Port specification in " + conf)
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 565 |       case _ => error("Multiple Port specifications in " + conf)
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 566 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 567 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 568 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 569 | def write_ssh_port(conf: Path, port: Int): Boolean = | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 570 |   {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 571 | val old_port = read_ssh_port(conf) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 572 | if (old_port == port) false | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 573 |     else {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 574 | val lines = split_lines(File.read(conf)) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 575 |       val lines1 = lines.map({ case Any_Port() => conf_ssh_port(port) case line => line })
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 576 | File.write(conf, cat_lines(lines1)) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 577 | true | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 578 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 579 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 580 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 581 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 582 | /* phabricator_setup_ssh */ | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 583 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 584 | def phabricator_setup_ssh( | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 585 | server_port: Int = default_server_port, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 586 | system_port: Int = default_system_port, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 587 | test_server: Boolean = false, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 588 | progress: Progress = No_Progress) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 589 |   {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 590 | Linux.check_system_root() | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 591 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 592 | val configs = read_config() | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 593 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 594 |     if (server_port == system_port) {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 595 |       error("Port for Phabricator sshd coincides with system port: " + system_port)
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 596 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 597 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 598 |     val sshd_conf_system = Path.explode("/etc/ssh/sshd_config")
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 599 | val sshd_conf_server = sshd_conf_system.ext(isabelle_phabricator_name()) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 600 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 601 | val ssh_name = isabelle_phabricator_name(name = "ssh") | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 602 |     val ssh_command = Path.explode("/usr/local/bin") + Path.basic(ssh_name)
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 603 | |
| 71111 
cd166c3904dd
more robust: system ssh service is required for Phabricator ssh service;
 wenzelm parents: 
71109diff
changeset | 604 | Linux.service_shutdown(ssh_name) | 
| 
cd166c3904dd
more robust: system ssh service is required for Phabricator ssh service;
 wenzelm parents: 
71109diff
changeset | 605 | |
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 606 | val old_system_port = read_ssh_port(sshd_conf_system) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 607 |     if (old_system_port != system_port) {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 608 |       progress.echo("Reconfigurig system ssh service")
 | 
| 71111 
cd166c3904dd
more robust: system ssh service is required for Phabricator ssh service;
 wenzelm parents: 
71109diff
changeset | 609 |       Linux.service_shutdown("ssh")
 | 
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 610 | write_ssh_port(sshd_conf_system, system_port) | 
| 71111 
cd166c3904dd
more robust: system ssh service is required for Phabricator ssh service;
 wenzelm parents: 
71109diff
changeset | 611 |       Linux.service_start("ssh")
 | 
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 612 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 613 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 614 |     progress.echo("Configuring " + ssh_name + " service")
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 615 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 616 | File.write(ssh_command, | 
| 71122 | 617 | global_config_script( | 
| 618 | header = true, | |
| 619 | body = | |
| 620 | """if [ "$1" = "$NAME" ] | |
| 621 | then | |
| 622 | exec "$ROOT/phabricator/bin/ssh-auth" "$@" | |
| 623 | fi""", | |
| 624 | exit = "exit 1")) | |
| 71114 | 625 |     Isabelle_System.chmod("755", ssh_command)
 | 
| 626 |     Isabelle_System.chown("root:root", ssh_command)
 | |
| 71109 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 627 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 628 | File.write(sshd_conf_server, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 629 | """# OpenBSD Secure Shell server for Isabelle/Phabricator | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 630 | AuthorizedKeysCommand """ + ssh_command.implode + """ | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 631 | AuthorizedKeysCommandUser """ + daemon_user + """ | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 632 | AuthorizedKeysFile none | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 633 | AllowUsers """ + configs.map(_.name).mkString(" ") + """
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 634 | Port """ + server_port + """ | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 635 | Protocol 2 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 636 | PermitRootLogin no | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 637 | AllowAgentForwarding no | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 638 | AllowTcpForwarding no | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 639 | PrintMotd no | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 640 | PrintLastLog no | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 641 | PasswordAuthentication no | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 642 | ChallengeResponseAuthentication no | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 643 | PidFile /var/run/""" + ssh_name + """.pid | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 644 | """) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 645 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 646 | Linux.service_install(ssh_name, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 647 | """[Unit] | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 648 | Description=OpenBSD Secure Shell server for Isabelle/Phabricator | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 649 | After=network.target auditd.service | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 650 | ConditionPathExists=!/etc/ssh/sshd_not_to_be_run | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 651 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 652 | [Service] | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 653 | EnvironmentFile=-/etc/default/ssh | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 654 | ExecStartPre=/usr/sbin/sshd -f """ + sshd_conf_server.implode + """ -t | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 655 | ExecStart=/usr/sbin/sshd -f """ + sshd_conf_server.implode + """ -D $SSHD_OPTS | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 656 | ExecReload=/usr/sbin/sshd -f """ + sshd_conf_server.implode + """ -t | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 657 | ExecReload=/bin/kill -HUP $MAINPID | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 658 | KillMode=process | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 659 | Restart=on-failure | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 660 | RestartPreventExitStatus=255 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 661 | Type=notify | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 662 | RuntimeDirectory=sshd-phabricator | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 663 | RuntimeDirectoryMode=0755 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 664 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 665 | [Install] | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 666 | WantedBy=multi-user.target | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 667 | Alias=""" + ssh_name + """.service | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 668 | """) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 669 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 670 |     for (config <- configs) {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 671 |       progress.echo("phabricator " + quote(config.name) + " port " +  server_port)
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 672 |       config.execute("config set diffusion.ssh-port " + Bash.string(server_port.toString))
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 673 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 674 |       if (test_server) {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 675 | progress.bash( | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 676 | """unset DISPLAY | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 677 |           echo "{}" | ssh -p """ + Bash.string(server_port.toString) +
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 678 | " -o StrictHostKeyChecking=false " + | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 679 | Bash.string(config.name) + """@localhost conduit conduit.ping""").print | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 680 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 681 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 682 | } | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 683 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 684 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 685 | /* Isabelle tool wrapper */ | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 686 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 687 | val isabelle_tool4 = | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 688 |     Isabelle_Tool("phabricator_setup_ssh",
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 689 | "setup ssh service for all Phabricator installations", args => | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 690 |     {
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 691 | var server_port = default_server_port | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 692 | var system_port = default_system_port | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 693 | var test_server = false | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 694 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 695 | val getopts = | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 696 |         Getopts("""
 | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 697 | Usage: isabelle phabricator_setup_ssh [OPTIONS] | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 698 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 699 | Options are: | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 700 | -p PORT sshd port for Phabricator servers (default: """ + default_server_port + """) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 701 | -q PORT sshd port for the operating system (default: """ + default_system_port + """) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 702 | -T test the ssh service for each Phabricator installation | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 703 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 704 | Configure ssh service for all Phabricator installations: a separate sshd | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 705 | is run in addition to the one of the operating system, and ports need to | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 706 | be distinct. | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 707 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 708 | A particular Phabricator installation is addressed by using its | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 709 | name as the ssh user; the actual Phabricator user is determined via | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 710 | stored ssh keys. | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 711 | """, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 712 | "p:" -> (arg => server_port = Value.Int.parse(arg)), | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 713 | "q:" -> (arg => system_port = Value.Int.parse(arg)), | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 714 | "T" -> (_ => test_server = true)) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 715 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 716 | val more_args = getopts(args) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 717 | if (more_args.nonEmpty) getopts.usage() | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 718 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 719 | val progress = new Console_Progress | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 720 | |
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 721 | phabricator_setup_ssh( | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 722 | server_port = server_port, system_port = system_port, test_server = test_server, | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 723 | progress = progress) | 
| 
8c1c717a830b
configure SSH hosting via "isabelle phabricator_setup_ssh";
 wenzelm parents: 
71103diff
changeset | 724 | }) | 
| 70967 | 725 | } |