diff --git a/.forgejo/workflows/docker.yaml b/.forgejo/workflows/docker.yaml index a8c493d..dfbdb95 100644 --- a/.forgejo/workflows/docker.yaml +++ b/.forgejo/workflows/docker.yaml @@ -4,7 +4,6 @@ on: push: branches: ["main"] paths: - - "Cargo.toml" - ".forgejo/workflows/docker.yaml" - "nix/image/**" @@ -17,9 +16,10 @@ jobs: strategy: matrix: - php-version: ["8.0", "8.1", "8.2", "8.3", "8.4", "8.5"] + php-version: ["8.2", "8.3", "8.4"] + variant: [""] - name: haze-${{ matrix.php-version }} + name: haze-${{ matrix.php-version }}${{ matrix.variant }} steps: - name: Checkout repository diff --git a/Cargo.lock b/Cargo.lock index 821ff04..d73ab8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures 0.2.17", + "cpufeatures", ] [[package]] @@ -147,7 +147,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", - "axum-macros", "bytes", "form_urlencoded", "futures-util", @@ -193,17 +192,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "backtrace" version = "0.3.74" @@ -266,9 +254,9 @@ dependencies = [ [[package]] name = "bollard" -version = "0.21.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d0a013e3d3ee4edd61e779adf117944c08902d375f18630a0c5b8f95659734" +checksum = "227aa051deec8d16bd9c34605e7aaf153f240e35483dd42f6f78903847934738" dependencies = [ "base64", "bollard-stubs", @@ -298,9 +286,9 @@ dependencies = [ [[package]] name = "bollard-stubs" -version = "1.53.1-rc.29.3.1" +version = "1.52.1-rc.29.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce412eb6f7096743011dc3cb5c674caeb24ced61d8c498fe07cf7998a4fea889" +checksum = "0f0a8ca8799131c1837d1282c3f81f31e76ceb0ce426e04a7fe1ccee3287c066" dependencies = [ "serde", "serde_json", @@ -384,17 +372,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chacha20" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.1", -] - [[package]] name = "cipher" version = "0.4.4" @@ -520,15 +497,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -538,31 +506,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - [[package]] name = "crypto-common" version = "0.1.7" @@ -917,7 +860,6 @@ dependencies = [ "js-sys", "libc", "r-efi", - "rand_core 0.10.1", "wasip2", "wasip3", "wasm-bindgen", @@ -943,14 +885,34 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git2" -version = "0.21.0" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddddbf932745a6be37109b6112d3ee09696106f848449069d3a57bba937ab82e" +checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" dependencies = [ "bitflags", "libc", "libgit2-sys", "log", + "url", +] + +[[package]] +name = "h2" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] @@ -970,7 +932,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "haze" -version = "2.3.0" +version = "2.1.6" dependencies = [ "async-trait", "atty", @@ -994,7 +956,6 @@ dependencies = [ "opener", "owo-colors", "petname", - "rayon", "reqwest", "serde", "serde_json", @@ -1004,7 +965,6 @@ dependencies = [ "tar", "termion", "tokio", - "tokio-stream", "toml", "tracing", "tracing-subscriber", @@ -1112,6 +1072,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", @@ -1142,9 +1103,8 @@ dependencies = [ [[package]] name = "hyper-reverse-proxy" version = "0.5.2-dev" -source = "git+https://code.betamike.com/micropelago/hyper-reverse-proxy.git?rev=d5a6f799189360d9449ae47ab3cdde511f02cf39#d5a6f799189360d9449ae47ab3cdde511f02cf39" +source = "git+https://github.com/chpio/hyper-reverse-proxy?rev=6934877eb74465204f605cc1c05ca5a9772db7c0#6934877eb74465204f605cc1c05ca5a9772db7c0" dependencies = [ - "http-body-util", "hyper", "hyper-util", "tokio", @@ -1511,9 +1471,9 @@ checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libgit2-sys" -version = "0.18.5+1.9.4" +version = "0.18.3+1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005d6ae6eac1912906073e069f7db60b1fa98e052a68227824afe3e3a1c59ca2" +checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" dependencies = [ "cc", "libc", @@ -1814,24 +1774,16 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petname" -version = "3.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce610bff48dd7b6a127e45631795fbb0b302b99a39bef7e6da3d297e8eb2b6b" +checksum = "9cd31dcfdbbd7431a807ef4df6edd6473228e94d5c805e8cf671227a21bad068" dependencies = [ + "anyhow", "clap", - "petname-macros", - "rand 0.10.1", -] - -[[package]] -name = "petname-macros" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324239bd00dcf61f1a0e301d4d8f6f8c080a755248fc3fdc817ee1fdbbc27b8b" -dependencies = [ + "itertools", "proc-macro2", "quote", - "syn", + "rand 0.8.5", ] [[package]] @@ -1993,23 +1945,33 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.9.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_chacha", - "rand_core 0.9.5", + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", ] [[package]] name = "rand" -version = "0.10.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "chacha20", - "getrandom 0.4.1", - "rand_core 0.10.1", + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -2022,6 +1984,15 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + [[package]] name = "rand_core" version = "0.9.5" @@ -2031,32 +2002,6 @@ dependencies = [ "getrandom 0.3.4", ] -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - -[[package]] -name = "rayon" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "redox_syscall" version = "0.5.10" @@ -2389,7 +2334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures", "digest 0.10.7", ] @@ -2400,7 +2345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures", "digest 0.10.7", ] @@ -2411,7 +2356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures", "digest 0.11.1", ] @@ -2750,17 +2695,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.13" diff --git a/Cargo.toml b/Cargo.toml index 631f10f..5760bd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "haze" -version = "2.3.0" +version = "2.1.6" authors = ["Robin Appelman "] edition = "2021" repository = "https://codeberg.org/icewind/haze" @@ -8,11 +8,10 @@ license = "MIT" description = "Easy setup and management of Nextcloud test instances using docker" [dependencies] -bollard = "0.21.0" +bollard = "0.20.1" maplit = "1.0.2" camino = { version = "1.2.2", features = ["serde1"] } tokio = { version = "1.49.0", features = ["fs", "macros", "signal", "rt-multi-thread"] } -tokio-stream = { version = "0.1.18", features = ["net"] } futures-util = "0.3.32" termion = "4.0.6" opener = "0.8.4" @@ -20,7 +19,7 @@ toml = "1.0.3" directories-next = "2.0.0" serde = "1.0.228" serde_json = "1.0.149" -petname = "3.0.0" +petname = "2.0.2" reqwest = { version = "0.13.2", default-features = false, features = ["rustls"] } tar = "0.4.44" flate2 = "1.1.9" @@ -31,7 +30,7 @@ shell-words = "1.1.1" tracing = "0.1.44" tracing-subscriber = "0.3.22" atty = "0.2.14" -git2 = { version = "0.21.0", default-features = false } +git2 = { version = "0.20.4", default-features = false } itertools = { version = "0.14.0", features = ["use_alloc"] } local-ip-address = "0.6.10" strum = { version = "0.28.0", features = ["derive"] } @@ -40,12 +39,11 @@ zip = "8.1.0" sha2 = "0.11.0-rc.5" base16ct = { version = "1.0.0", features = ["alloc"] } indicatif = "0.18.4" -rayon = "1.12.0" -hyper-reverse-proxy = { version = "0.5.2-dev", git = "https://code.betamike.com/micropelago/hyper-reverse-proxy.git", rev = "d5a6f799189360d9449ae47ab3cdde511f02cf39" } +hyper-reverse-proxy = { version = "0.5.2-dev", git = "https://github.com/chpio/hyper-reverse-proxy", rev = "6934877eb74465204f605cc1c05ca5a9772db7c0" } hyper = "1.8.1" hyper-util = "0.1.20" -axum = { version = "0.8.8", features = ["tokio", "macros"] } +axum = { version = "0.8.8", features = ["tokio"] } [profile.release] lto = true diff --git a/README.md b/README.md index aa538d2..bda3823 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,13 @@ haze start [database] [php-version] [services] [vX.Y.Z] Where `database` is one of `sqlite`, `mysql`, `mariadb`, `pgsql` or `oracle` with an optional version (e.g. `pgsql:12`), defaults to `sqlite`. And -`php-version` is one of `8.0`, `8.1`, `8.2`, `8.3`, `8.4` or `8.5`, defaults to -the maximum version support by the current Nextcloud version. +`php-version` is one of `8.2`, `8.3` or `8.4`, defaults to the maximum version +support by the current Nextcloud version. `7.3` till `8.1` are still supported +but the docker images for those versions aren't being updated anymore so they +might be missing some newer features. + +Each php version also comes with a `-dbg` variant that has php compiled in debug +mode and can be used for debugging php itself with gdb. You can specify a version number (e.g. `v32.0.2`) to use the sources from a release instead of using the local sources. @@ -71,9 +76,9 @@ Additionally, you can use the following options when starting an instance: - `s3`: set up an S3 server and configure to Nextcloud to use it as primary storage. - - `s3s`: enable TLS for the S3 setup. - - `s3mb`: enable multi-bucket S3 setup. - - `s3m`: enable multi-instance S3 setup. +- ``: by specifying the path to an app package this package + will be extracted into the apps. directory of the new instance (overwriting + any existing app code). This can be used to quickly test a packaged app. - `ldap`: set up an LDAP server. - `office`: set up a Nextcloud Office server. - `onlyoffice` setup an onlyoffice document server. @@ -81,8 +86,6 @@ Additionally, you can use the following options when starting an instance: - `smb`: set up a samba server for external storage use. - `dav`: set up a WebDAV server for external storage use. - `sftp`: set up a SFTP server for external storage use. -- `sftp-key`: set up a SFTP server for external storage use with public key - authentication. - `kaspersky`: set up a kaspersky scan engine server in http mode. ( Requires [manually setting up the image](https://github.com/icewind1991/kaspersky-docker)) - `kaspersky-icap`: setup a kaspersky scan engine server in ICAP mode. @@ -95,13 +98,8 @@ Additionally, you can use the following options when starting an instance: generation. - `mail`: start a [smtp4dev](https://github.com/rnwood/smtp4dev) server and configure it the mail server. -- `webhook` start a - [webhook tester](https://github.com/tarampampam/webhook-tester) - `redis`: start a separate container for redis. - `redis-tls`: connect to redis over TLS. -- ``: by specifying the path to an app package this package - will be extracted into the apps. directory of the new instance (overwriting - any existing app code). This can be used to quickly test a packaged app. - The name of any configured preset. #### Run tests in a new instance @@ -151,14 +149,11 @@ haze [match] db #### Execute a command on an instance ```bash -haze [match] [service] [cmd] +haze [match] exec [cmd] ``` If no `cmd` is specified it will launch `bash` -If a service name or `db` is provided, the command will be in the container of -the service or database. - #### Create a new instance and run a command ```bash @@ -281,7 +276,8 @@ proxy to allow using a wildcard domain. ### Setup - Set a DNS record for `*.haze.exmaple.com` and `haze.example.com` pointing to - your development machine. + `127.0.0.1` or your development machine if you need to access it from other + devices. - Set the `proxy` configuration with your domain and desired listen endpoint. - Set up a service to run `haze proxy` in the background as your own user. A systemd user service is recommended (see [haze.service](./haze.service) for an @@ -300,12 +296,6 @@ subdomain of the configured domain, e.g. the `rolling-bees` instance will be available at `rolling-bees.haze.example.com`. Additionally, `haze.example.com` will automatically point to the last created instance. -Additionally, the proxy allows access to the server containers trough either -`-.haze.example.com` for a specific instance, or -`.haze.example.com` for the last created instance. For example -`rolling-bees-mail.haze.example.com` will give access to the smtp4dev web -interface of the `rolling-bees` instance. - ## Configuration Configuration is loaded from `~/.config/haze/haze.toml` and has the following @@ -313,7 +303,6 @@ options ```toml sources_root = "/path/to/sources" # path of the nextcloud sources. required -app_directories = ["/path/to/sources/more_app"] # paths to additional app directories. work_dir = "/path/to/temp/dir" # path to temporary directory. optional, defaults to "/tmp/haze" [auto_setup] # optional @@ -325,7 +314,6 @@ disable_apps = ["contacts"] # apps to disable after setup, defaults to [] post_setup = [# commands to execute after setup, defaults to [] "occ group:add test", ] -config = { "foo" = "bar" } # configuration options to set before install [[volume]] # optional source = "/tmp/haze-shared" diff --git a/certificates/s3/private.key b/certificates/s3/private.key deleted file mode 100644 index 939d93e..0000000 --- a/certificates/s3/private.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCQuTk+irdXRGbY -JUu+AFmMM4/CCtBIBBgGIG18tesgQUeHEPdRHbBypvFKhpXvlKQbVbiaZxFjtlvn -L2ReN7gYwjiTjLWuaDgOzGQyObwSJpedlcd5Q957WNlc5OjpoK8zZq9EGnmvjIqe -5VVBne85RZVw6+i4ljEiWoXCiy0iOPIL4jKO8kfO8EmTTh6ge2sLCT5jFT/V63/B -hjEobA7+vPbAmEo+Qs4adnBSrlX9nLtL1j4gqawAQMmGl/Ti75T0uQvNxdq2gddc -n0wyWhyERnZNeMv5sfkwCOTuetNNtGLf/lTkXNdaOCRvW5jJ0EjYYdpQG5R0do1U -XFLH1cZZAgMBAAECggEAR0xpTk2Ku5yASlY9dXK4qyCv3znymLgjmckaB4mcN7zR -X1JVdYn55tImJ8AcV/bTzn+xvaevYn9x0XiAqwYqVVBCDTcSPsUrcObzKedVp1+J -7GHg7vYnwn7oPyKrOIYoKluZVyTv9DN6C4QSN4x2UbHdSM+ATIf51uHf6hMk/ilv -4uw3csxSCpLOqqsYCQarES7SypcETjFpNnIfTPt7q2Y2DbIDttTTjzrm0/GBP0WE -OYNvzZZPZRPJfy3et3r9vJbqWzGHvOttzQ+EFHjwPTMfW4tsHcCsEKSGWwLpG4bN -FPNx0+QCqDiChesdiCHFNSk+u7pRZrHdjuDJEuKSzQKBgQDMDgdCGBQfgaNnkRz/ -aiv3V200/vXegnc0Jz49Dye5AxEVu0X1m2xZpJv+qEwbOx5B+1PV3gfVP/iRf+FK -MAwFbmb7hGcDE8AGNsSpQydjwzKoi/M67YXv7T8dgWKnwz0eyU4K2IOGInGxuFty -Ik7+DTqz+Ikh1RiAoGbKfw9yhwKBgQC1kKhjxB7r/uSLcfOSg1mLcR5lTrNDQAPQ -GnsIje0nD5Tv52/k6U4tk15vjL4t6KZUFo9SJ4O1kM1veyuOJuol2AfPXS+H/Izo -5BjmoZ0jOONOZZiRIB1moQSy1qhTAeZB9S1ORxQ3dIBPqm+oyADPTTsNV67Cwnt4 -woeZRUPYHwKBgQDE0AcKJcVK+jQMUXfBlrsfTvDjO8MTwYyN/gfWxsZOeXnCFyYM -FcO01sMrJVJ6tVOi2nFrB0NQ2Om8FLbMYnlFx82GbJca7bK5i5u1kjLs0zoKPSn1 -vWEBIDhPEhuAqhxKlGk0ps580r4MZz+0XwkHmuTy7xX9TtbaQVvDljflAwKBgDKy -3hJdpTTIzBCUFSuIOezR/WbUfwH8UhQ+ELTmzJ3nn/MNcRU+gHIBgJEtf71aBXfd -hM+v8Ps2H+dNQXBENYWzuRqSLr+OKdquNrXP0w0OyYoOnHeJvCv4MlOt1Pq4wQ8R -40DEYETL5zhXoy5CCtfX/PFQ1p/Tpp6l0y9dRACJAoGALwUbyyDy85b2xRQB6RtU -I+5Vz5cd/1eQdCkoU9mX4qWA/hWpgc7Z2Jd67LW/WWtVjlF9hva/WNDSfGsXo2ew -C8OofvlfIuFDOCXrodYdHE1Q4g5TZdESr0XAqopq+QzBs89qbIy05kM9iuE4yFUo -xeimCY9oDWTeGw/XrLdHZF4= ------END PRIVATE KEY----- diff --git a/certificates/s3/public.crt b/certificates/s3/public.crt deleted file mode 100644 index f31f379..0000000 --- a/certificates/s3/public.crt +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDXTCCAkWgAwIBAgIULiChaTwmVx6nRTHohmPuf55/4jUwDQYJKoZIhvcNAQEL -BQAwPjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAoM -BEhhemUxCzAJBgNVBAMMAnMzMB4XDTI2MDMwOTE3NTgwOVoXDTI3MDMwOTE3NTgw -OVowPjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAoM -BEhhemUxCzAJBgNVBAMMAnMzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAkLk5Poq3V0Rm2CVLvgBZjDOPwgrQSAQYBiBtfLXrIEFHhxD3UR2wcqbxSoaV -75SkG1W4mmcRY7Zb5y9kXje4GMI4k4y1rmg4DsxkMjm8EiaXnZXHeUPee1jZXOTo -6aCvM2avRBp5r4yKnuVVQZ3vOUWVcOvouJYxIlqFwostIjjyC+IyjvJHzvBJk04e -oHtrCwk+YxU/1et/wYYxKGwO/rz2wJhKPkLOGnZwUq5V/Zy7S9Y+IKmsAEDJhpf0 -4u+U9LkLzcXatoHXXJ9MMlochEZ2TXjL+bH5MAjk7nrTTbRi3/5U5FzXWjgkb1uY -ydBI2GHaUBuUdHaNVFxSx9XGWQIDAQABo1MwUTAdBgNVHQ4EFgQUJJ8HiT2zmuF5 -6WHHFsTHgkrayxYwHwYDVR0jBBgwFoAUJJ8HiT2zmuF56WHHFsTHgkrayxYwDwYD -VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAUF0lB/qIrxkgZ4sqNrw4 -CInHCK29XVaMoqk1QZyS/KhWDM+zgbA92OxxuhCKw4iJEajZvgg0S9RtGkBNmquU -l0rf0JdALd0jPkWr7+3OeqlcgOs2EH7PTqrrbXTGsR12D+Ot+OerQeWXmO28Zrl8 -4O67TwQtslXwZzeCrtiwAA2DrIYpSLzh+qDtwbY5hMG5zmqqjBM20Ysgxszh4rhl -KR6skXwZwkVVhKpK76qwnU02PIMr8auL1csx8/uBTd/UzX2veqlkOP5V/Gg6eEbI -4fTOzq7k+FyuzSkrEX4Vc9GbWcRvoVZh+qAKUKstqlE2iCrqmZ+Wal6GA8JA5SZ+ -bQ== ------END CERTIFICATE----- diff --git a/certificates/sftp/id_rsa b/certificates/sftp/id_rsa deleted file mode 100644 index c8dcc4d..0000000 --- a/certificates/sftp/id_rsa +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn -NhAAAAAwEAAQAAAYEA323aWqH6YwRLbCBO94UKOkfnJ2m6Zsic0dMt3TmDnjLU0JzpOt7w -t5+mMZrEKQTpefozyUHo3z+HkmllLAGOupNy3A+jG2O955UUgw0dGfu6j6OOb66Du9jpqt -8BQ6gr3cEYASplPI7B889/cVpJ5l1HiBUgyR7Z16v15qCDtmpFVIECAdICEmPosfmZutt3 -YYl9xLay5WCmUztWS/amPcGs0DOEGrWeCtdxGKWT3TywdBKyQ0PbdYMamgDIT7JV1ZSzZP -aly4sB7E+dpS5AgBFVXmZ61151KN1TJ8gyoUjFhY7ctYEIpncZmyT4PYvyIvxRsbJtvERi -eNH8DoX5DwtqcxbgHK0OwYtdl4ydRXToYo3l+qIidf+g8ADVea/mbkfTPegdToo3LOuThX -OwExDlukpM8obFDpz1Yl1L6rRJAVNO1KmHWhn6to23jtYjBhczA2nkemQXQbVSjc/hItjQ -DIFNMOsLW33P+Y2k9LkpI0TL09ogOxOFZzGZp2tNAAAFgIgMIZ+IDCGfAAAAB3NzaC1yc2 -EAAAGBAN9t2lqh+mMES2wgTveFCjpH5ydpumbInNHTLd05g54y1NCc6Tre8LefpjGaxCkE -6Xn6M8lB6N8/h5JpZSwBjrqTctwPoxtjveeVFIMNHRn7uo+jjm+ug7vY6arfAUOoK93BGA -EqZTyOwfPPf3FaSeZdR4gVIMke2der9eagg7ZqRVSBAgHSAhJj6LH5mbrbd2GJfcS2suVg -plM7Vkv2pj3BrNAzhBq1ngrXcRilk908sHQSskND23WDGpoAyE+yVdWUs2T2pcuLAexPna -UuQIARVV5metdedSjdUyfIMqFIxYWO3LWBCKZ3GZsk+D2L8iL8UbGybbxEYnjR/A6F+Q8L -anMW4BytDsGLXZeMnUV06GKN5fqiInX/oPAA1Xmv5m5H0z3oHU6KNyzrk4VzsBMQ5bpKTP -KGxQ6c9WJdS+q0SQFTTtSph1oZ+raNt47WIwYXMwNp5HpkF0G1Uo3P4SLY0AyBTTDrC1t9 -z/mNpPS5KSNEy9PaIDsThWcxmadrTQAAAAMBAAEAAAGAWCkM/TEnztU9e3M+JX253OhNRe -h6lB75ffOxh7avgAc3oP8hKkkYu6PDnJQgbb0R8T7wGywmGp0DPhrXQGd27ZjLvBhxeBfB -sbTJ7LIKdxu0cAQN6nR2Z3M+NF2dLpiXgn80HRWg76W20yDffRcuzLamyIPptWI2e9rPAw -r4HczOAXuMErLOfXotsbg22BvL/dEWLr4WVdruli32LbArxXd73IVPTYi3TTjYV+zRrPzK -9WoBK/iFClfKcdT4NTY82llQesuUNu640lEJtT2G3Iba8UZnohyzm/S+UbeU65z8DKD5co -P7+QehxQSV+kj2BZnTi0WEwsD+GTznJYR5rvUsJCCAzoISsWrncSSgOQhF2XeW/T4ewvH+ -njLZViEhdG8R3kkdDjJG91OrSgrEqlk6Qhz1xEsv1rCOR69En7EJP3TNNrymPXPASrAnuE -HQkrVgGUfGqyD1sw1e6nBfNWisuw+g99CieIB8EI9WwpxQdKqWNU9Hjx+SAdC3NrPjAAAA -wQCo0hUGjSf6xhcgeaNa0gWSKEVuFhxR/FaCPTKadV7Md0APW4toeQZDujzDFlCZbQTZjC -0723B4lKugDzXfsOgvOTKp4vEjZOu0YGruS00LFWM7Sutdzx68b/ZMFALzITt/myKVMdpv -WpaO+3+PyEYIQH44QrSWw7cKLzNiZ8kt2drPkPktub4o2h5TdIBluEQLJDPMejy8IqQEU8 -aOyJOMvYxAbGAWY7Ck9DGlcJgaFdORROW8d8ZGrHQkyRl41JQAAADBAPeUMsrbI17wPP/s -Tsrkms5ws5yTz0xle2Wn6HwDSzQRSdn5abnIDYb3QSy0nRBvczef6ssH65dl50+2V4BV2L -MwHcmKD6/UoFsWwP/RMf1EoacPFiEAWJGxFbOthNX+rx5BpbUHNoQd8xby+88saDI0e8W6 -36HPBZrAZhQljkMa4OJqZDDCpOJvSndXwkZ789E96uprKopJZGwlLmfMtikQpNXT9R+I0b -SQCJj4yNakcdOE/7UifkOR02u+pgux3wAAAMEA5wdelKwGQ0EdkIF2TM844uLPszo3ZSH+ -Heff/Lbxs1Y+oL0NTJQicwMF0d9WEwBoTZJpuzsQEA1zkfmW0gi2womIRmiY0ZhpxbBuhO -6XePMIhUfQmWWjaUbAkrNB0eJkSTuUGzwxVkMXehrMuj4gYe8GMC8GgULbP0A8FjH01fKk -jFwgg4WAg6zUTpck12bh49NZRFyXIbXNk/jjxJtb0p//5TRTUQ6mR5IloaNTM23EiF6tle -Y6CAchnyhHO0BTAAAACWhhemVAaGF6ZQE= ------END OPENSSH PRIVATE KEY----- diff --git a/certificates/sftp/id_rsa.pub b/certificates/sftp/id_rsa.pub deleted file mode 100644 index 81a5db6..0000000 --- a/certificates/sftp/id_rsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfbdpaofpjBEtsIE73hQo6R+cnabpmyJzR0y3dOYOeMtTQnOk63vC3n6YxmsQpBOl5+jPJQejfP4eSaWUsAY66k3LcD6MbY73nlRSDDR0Z+7qPo45vroO72Omq3wFDqCvdwRgBKmU8jsHzz39xWknmXUeIFSDJHtnXq/XmoIO2akVUgQIB0gISY+ix+Zm623dhiX3EtrLlYKZTO1ZL9qY9wazQM4QatZ4K13EYpZPdPLB0ErJDQ9t1gxqaAMhPslXVlLNk9qXLiwHsT52lLkCAEVVeZnrXXnUo3VMnyDKhSMWFjty1gQimdxmbJPg9i/Ii/FGxsm28RGJ40fwOhfkPC2pzFuAcrQ7Bi12XjJ1FdOhijeX6oiJ1/6DwANV5r+ZuR9M96B1Oijcs65OFc7ATEOW6SkzyhsUOnPViXUvqtEkBU07UqYdaGfq2jbeO1iMGFzMDaeR6ZBdBtVKNz+Ei2NAMgU0w6wtbfc/5jaT0uSkjRMvT2iA7E4VnMZmna00= haze@haze diff --git a/flake.lock b/flake.lock index a7766b8..81e86a7 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "crane": { "locked": { - "lastModified": 1763938834, - "narHash": "sha256-j8iB0Yr4zAvQLueCZ5abxfk6fnG/SJ5JnGUziETjwfg=", + "lastModified": 1760924934, + "narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=", "owner": "ipetkov", "repo": "crane", - "rev": "d9e753122e51cee64eb8d2dddfe11148f339f5a2", + "rev": "c6b4d5308293d0d04fcfeee92705017537cad02f", "type": "github" }, "original": { @@ -15,22 +15,6 @@ "type": "github" } }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1767039857, - "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", - "owner": "NixOS", - "repo": "flake-compat", - "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "flake-compat", - "type": "github" - } - }, "flakelight": { "inputs": { "nixpkgs": [ @@ -38,11 +22,11 @@ ] }, "locked": { - "lastModified": 1773062095, - "narHash": "sha256-u+cK9IoJokO4YzQwMc2s8Vti0RL/LVSrROOEn2opc5U=", + "lastModified": 1764593611, + "narHash": "sha256-6SdexcO69Dlu14YN2xuB1A6JHWSrcqMj7Na9oK7IT2M=", "owner": "nix-community", "repo": "flakelight", - "rev": "c99e4d5f40e578cb2d8f460ea2bbd5dc26316d24", + "rev": "0d63256401341f528dd628f1a8e96d3afecade7a", "type": "github" }, "original": { @@ -60,11 +44,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1772297202, - "narHash": "sha256-UEzHO/tCmhPhr8RpWtbm1MTa7ABobwt3nCjrcuDAPm0=", + "lastModified": 1763591898, + "narHash": "sha256-aHSMj7CIa9EJYxdf05wOWRGp0KRsT/TAox7uwVSdDb8=", "ref": "refs/heads/main", - "rev": "8690e1514863b934de12f2a503c9431d186ce30b", - "revCount": 68, + "rev": "2d9b2da2c9f384f93ef977c48f8ee35ce586529b", + "revCount": 66, "type": "git", "url": "https://codeberg.org/icewind/mill-scale.git" }, @@ -75,11 +59,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1772822230, - "narHash": "sha256-yf3iYLGbGVlIthlQIk5/4/EQDZNNEmuqKZkQssMljuw=", + "lastModified": 1764522689, + "narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "71caefce12ba78d84fe618cf61644dce01cf3a96", + "rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f", "type": "github" }, "original": { @@ -88,48 +72,11 @@ "type": "indirect" } }, - "nixpkgs_2": { - "locked": { - "lastModified": 1772173633, - "narHash": "sha256-MOH58F4AIbCkh6qlQcwMycyk5SWvsqnS/TCfnqDlpj4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c0f3d81a7ddbc2b1332be0d8481a672b4f6004d6", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "phps": { - "inputs": { - "flake-compat": "flake-compat", - "nixpkgs": "nixpkgs_2", - "utils": "utils" - }, - "locked": { - "lastModified": 1772365008, - "narHash": "sha256-/ynkWKeZ1dyRIUkQas0AB35semWAwCbTKXu+/q+8MGg=", - "owner": "fossar", - "repo": "nix-phps", - "rev": "f47eb877bf1c219809e4357eec2fdab8e3263b7b", - "type": "github" - }, - "original": { - "owner": "fossar", - "repo": "nix-phps", - "type": "github" - } - }, "root": { "inputs": { "flakelight": "flakelight", "mill-scale": "mill-scale", - "nixpkgs": "nixpkgs", - "phps": "phps" + "nixpkgs": "nixpkgs" } }, "rust-overlay": { @@ -141,11 +88,11 @@ ] }, "locked": { - "lastModified": 1764557621, - "narHash": "sha256-kX5PoY8hQZ80+amMQgOO9t8Tc1JZ70gYRnzaVD4AA+o=", + "lastModified": 1761964689, + "narHash": "sha256-Zo3LQQDz+64EQ9zor/WmeNTFLoZkjmhp0UY3G0D3seE=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "93316876c2229460a5d6f5f052766cc4cef538ce", + "rev": "63d22578600f70d293aede6bc737efef60ebd97f", "type": "github" }, "original": { @@ -153,39 +100,6 @@ "repo": "rust-overlay", "type": "github" } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 9934eb7..641c5fc 100644 --- a/flake.nix +++ b/flake.nix @@ -9,15 +9,8 @@ url = "git+https://codeberg.org/icewind/mill-scale.git"; inputs.flakelight.follows = "flakelight"; }; - phps = { - url = "github:fossar/nix-phps"; - }; }; - outputs = { - mill-scale, - phps, - ... - }: + outputs = {mill-scale, ...}: mill-scale ./. { crossTargets = [ "x86_64-unknown-linux-gnu" @@ -31,23 +24,17 @@ }; extraPaths = [ - ./certificates + ./redis-certificates ]; withOverlays = [ (import ./nix/overlay.nix) - (prev: final: { - inherit (phps.packages.${prev.system}) php81 php80; - }) ]; packages = { - "haze-image-php-8.5" = pkgs: pkgs.haze-image-php-85; "haze-image-php-8.4" = pkgs: pkgs.haze-image-php-84; "haze-image-php-8.3" = pkgs: pkgs.haze-image-php-83; "haze-image-php-8.2" = pkgs: pkgs.haze-image-php-82; - "haze-image-php-8.1" = pkgs: pkgs.haze-image-php-81; - "haze-image-php-8.0" = pkgs: pkgs.haze-image-php-80; }; tools = pkgs: with pkgs; [cargo-edit bacon skopeo]; diff --git a/nix/hm-module.nix b/nix/hm-module.nix index 7fe684d..096d853 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -9,10 +9,9 @@ with lib; let format = pkgs.formats.toml {}; configFile = format.generate "haze.toml" ({ sources_root = cfg.sourcesRoot; - app_directories = cfg.appDirectories; work_dir = cfg.workDir; auto_setup = { - inherit (cfg.autoSetup) enable config; + enabled = cfg.autoSetup.enable; post_setup = cfg.autoSetup.postSetup; enable_apps = cfg.autoSetup.enableApps; disable_apps = cfg.autoSetup.disableApps; @@ -62,12 +61,6 @@ in { description = "Directory to store instance data"; }; - appDirectories = mkOption { - type = types.listOf types.str; - default = []; - description = "Paths to additional app directories"; - }; - autoSetup = mkOption { type = types.submodule { options = { @@ -91,13 +84,6 @@ in { default = []; description = "Commands to run post-setup"; }; - config = mkOption { - type = types.submodule { - freeformType = format.type; - }; - description = "Configuration options to set before install"; - default = {}; - }; }; }; }; diff --git a/nix/image/bootstrap b/nix/image/bootstrap deleted file mode 100755 index 2c9dcff..0000000 --- a/nix/image/bootstrap +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/nu - -touch /var/log/nginx/access.log -touch /var/log/nginx/error.log -touch /var/log/cron/owncloud.log - -mkdir /config -echo "# Options in here overwrite the builtin php.ini\n" | save /config/php.ini -echo "# xdebug.mode = debug\n" | save -a /config/php.ini -echo "# xdebug.start_with_request = yes\n\n" | save -a /config/php.ini -chmod 0777 /config/php.ini -let PHP_INI_DIR = php --ini | grep 'Scan' | cut -d ' ' -f7 | tr -d '"' -ln -s /config/php.ini $"($PHP_INI_DIR)/zz_extra.ini" - -let HAZE_UID = $env.HAZE_UID | default "1000" -let HAZE_GID = $env.HAZE_GID | default "1000" - -nc-auto-config -shadow-setup - -echo $"Running as ($HAZE_UID):($HAZE_GID)" - -mkdir /var/www/html/core/skeleton /var/www/html/build/integration/vendor /var/www/html/build/integration/output /var/www/html/build/integration/work /var/www/html/core/skeleton /var/www/.composer/cache /var/www/html/apps/spreed/tests/integration/vendor/composer -chown -R $"($HAZE_UID):($HAZE_GID)" /var/www/html/data /var/www/html/config -chown $"($HAZE_UID):($HAZE_GID)" /var/www/html/core/skeleton /var/www/html/build/integration/vendor /var/www/html/build/integration/composer.lock /var/www/html/build/integration/output /var/www/html/build/integration/work /var/www/html/core/skeleton /var/www/.composer/cache /var/www/html/apps/spreed/tests/integration/vendor/composer - -echo "{}\n" | save -f /var/www/html/build/integration/composer.lock - -echo $"Starting server using ($env.SQL) database…" - -chmod +sx /sbin/sudo - -mkdir /var/log/nginx /tmp /var/run/blackfire -touch /var/log/nginx/access.log -touch /var/log/nginx/error.log - -if ((getent group $HAZE_GID | length) > 0) { - groupadd haze - useradd -u $HAZE_UID -g $HAZE_GID -G haze haze -} else { - groupadd -g $HAZE_GID haze - useradd -u $HAZE_UID -g $HAZE_GID haze -} -chown -R $"haze:($HAZE_GID)" /home/haze -ls -af /etc/home | each {|file| ln -s $file.name $"/home/haze/($file.name | path basename)" } - -if ("/var/run/docker.sock" | path exists) { - let dockerGid = stat --format "%g" /var/run/docker.sock - groupadd docker -g $dockerGid - usermod -a -G docker haze -} - -if ("REDIS_TLS" in $env) { - cp /etc/supervisor/redis-tls.conf /etc/supervisor/enabled/ -} else { - cp /etc/supervisor/redis-plain.conf /etc/supervisor/enabled/ -} - -if ("BLACKFIRE_SERVER_ID" in $env) { - blackfire agent:config --server-id $env.BLACKFIRE_SERVER_ID --server-token $env.BLACKFIRE_SERVER_TOKEN - cp /etc/supervisor/blackfire.conf /etc/supervisor/enabled/ -} - -if ("PROXY_BASE" in $env) { - let UPSTREAM_DNS = cat /etc/resolv.conf | grep nameserver | cut -d' ' -f 2 - let RC = sed '/nameserver/d' /etc/resolv.conf - echo $RC | save -f /etc/resolv.conf - - echo "\nnameserver 127.0.0.22\n" | save -a /etc/resolv.conf - - echo $"s/UPSTREAM_DNS/($UPSTREAM_DNS)" - sed -i $"s/UPSTREAM_DNS/($UPSTREAM_DNS)/" /etc/dnsmasq.conf - echo $"s/PROXY_BASE/($env.PROXY_BASE)" - sed -i $"s/PROXY_BASE/($env.PROXY_BASE)/" /etc/dnsmasq.conf - echo $"s/HOST_IP/($env.HOST_IP)" - sed -i $"s/HOST_IP/($env.HOST_IP)/" /etc/dnsmasq.conf - - cp /etc/supervisor/dnsmasq.conf /etc/supervisor/enabled/ -} - -if ("FRANKENPHP" in $env) { - cp /etc/supervisor/frankenphp.conf /etc/supervisor/enabled/ -} else { - cp /etc/supervisor/php-fpm.conf /etc/supervisor/enabled/ - cp /etc/supervisor/nginx.conf /etc/supervisor/enabled/ -} - -exec supervisord -c /etc/supervisor/supervisord.conf diff --git a/nix/image/bootstrap.sh b/nix/image/bootstrap.sh new file mode 100755 index 0000000..5f85777 --- /dev/null +++ b/nix/image/bootstrap.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +touch /var/log/nginx/access.log +touch /var/log/nginx/error.log +touch /var/log/cron/owncloud.log + +mkdir -p /config +echo "# Options in here overwrite the builtin php.ini" > /config/php.ini +echo "# xdebug.mode = debug" >> /config/php.ini +echo "# xdebug.start_with_request = yes" >> /config/php.ini +chmod 0777 /config/php.ini +PHP_INI_DIR="$(php --ini | grep 'Scan' | cut -d ' ' -f7)" +ln -s /config/php.ini "$PHP_INI_DIR/zz_extra.ini" + +HAZE_UID=${HAZE_UID:-www-data} +HAZE_GID=${HAZE_GID:-www-data} + +nc-auto-config +shadow-setup + +echo "Running as $HAZE_UID:$HAZE_GID" + +mkdir -p /var/www/html/core/skeleton /var/www/html/build/integration/vendor /var/www/html/build/integration/output /var/www/html/build/integration/work /var/www/html/core/skeleton /var/www/.composer/cache /var/www/html/apps/spreed/tests/integration/vendor/composer +chown -R "$HAZE_UID":"$HAZE_GID" /var/www/html/data /var/www/html/config +chown "$HAZE_UID":"$HAZE_GID" /var/www/html/core/skeleton /var/www/html/build/integration/vendor /var/www/html/build/integration/composer.lock /var/www/html/build/integration/output /var/www/html/build/integration/work /var/www/html/core/skeleton /var/www/.composer/cache /var/www/html/apps/spreed/tests/integration/vendor/composer + +echo "{}" > /var/www/html/build/integration/composer.lock + +echo "Starting server using $SQL database…" + +# tail --follow --retry /var/log/nginx/*.log /var/log/cron/owncloud.log & + +chmod +sx /sbin/sudo + +mkdir -p /var/log/nginx /tmp /var/run/blackfire +touch /var/log/nginx/access.log +touch /var/log/nginx/error.log + +HAZE_UID=${HAZE_UID:-1000} +HAZE_GID=${HAZE_GID:-1000} + +if [ "$(getent group "$HAZE_GID")" ]; then + groupadd haze + EXTRA_GROUP=" -G haze" +else + groupadd -g "$HAZE_GID" haze + EXTRA_GROUP="" +fi + +useradd -u "$HAZE_UID" -g "$HAZE_GID""$EXTRA_GROUP" haze +chown -R haze:"$HAZE_GID" /home/haze + +if [ -f "/var/run/docker.sock" ]; then + groupadd docker -g "$(stat --format "%g" /var/run/docker.sock)" + usermod -a -G docker haze +fi + +if [ -n "${REDIS_TLS:-}" ] +then + redis-server --protected-mode no \ + --tls-port 6379 --port 0 \ + --tls-cert-file /redis-certificates/server.crt \ + --tls-key-file /redis-certificates/server.key \ + --tls-ca-cert-file /redis-certificates/ca.crt & +else + redis-server --protected-mode no & +fi + +if [ -n "${BLACKFIRE_SERVER_ID:-}" ] +then + sh -c ' + yes | blackfire agent:config --server-id=$BLACKFIRE_SERVER_ID --server-token=$BLACKFIRE_SERVER_TOKEN + BLACKFIRE_LOG_LEVEL=4 BLACKFIRE_LOG_FILE=/var/log/agent.log blackfire agent & + '& +fi + +php-fpm --fpm-config /etc/php-fpm.conf& + +nginx -c /etc/nginx.conf \ No newline at end of file diff --git a/nix/image/configs.nix b/nix/image/configs.nix index afa06c7..1b90bc8 100644 --- a/nix/image/configs.nix +++ b/nix/image/configs.nix @@ -1,7 +1,12 @@ {runCommand}: runCommand "configs" {} '' - mkdir -p $out - cp -r ${./configs} $out/etc - chmod -R +w $out/etc - mkdir $out/etc/supervisor/enabled/ + mkdir -p $out/etc + mkdir -p $out/etc/sudoers.d + mkdir -p $out/conf + cp ${./configs/cron.conf} $out/etc/oc-cron.conf + cp ${./configs/nginx-app.conf} $out/conf/nginx-app.conf + cp ${./configs/sudoers} $out/etc/sudoers.d/haze + cp -r ${./configs/nc} $out/etc/nc + cp ${./php-fpm.conf} $out/etc/php-fpm.conf + cp ${./nginx.conf} $out/etc/nginx.conf '' diff --git a/nix/image/configs/oc-cron.conf b/nix/image/configs/cron.conf similarity index 100% rename from nix/image/configs/oc-cron.conf rename to nix/image/configs/cron.conf diff --git a/nix/image/configs/dnsmasq.conf b/nix/image/configs/dnsmasq.conf deleted file mode 100644 index 2b1afc5..0000000 --- a/nix/image/configs/dnsmasq.conf +++ /dev/null @@ -1,6 +0,0 @@ -listen-address=127.0.0.22 -no-resolv - -address=/PROXY_BASE/HOST_IP - -server=UPSTREAM_DNS \ No newline at end of file diff --git a/nix/image/configs/home/.sqliterc b/nix/image/configs/home/.sqliterc deleted file mode 100644 index 0d5fe04..0000000 --- a/nix/image/configs/home/.sqliterc +++ /dev/null @@ -1 +0,0 @@ -.mode table diff --git a/nix/image/configs/nc/config.php b/nix/image/configs/nc/config.php index 06de6db..e8dc0af 100644 --- a/nix/image/configs/nc/config.php +++ b/nix/image/configs/nc/config.php @@ -1,19 +1,12 @@ - true, + 'appstoreenabled' => false, 'memcache.local' => '\\OC\\Memcache\\APCu', - 'memcache.distributed' => '\\OC\\Memcache\\Redis', - 'memcache.locking' => '\\OC\\Memcache\\Redis', + 'memcache.distributed' => '\\OC\\Memcache\\APCu', + 'memcache.locking' => '\\OC\\Memcache\\APCu', 'allow_local_remote_servers' => true, 'trusted_domains' => ['cloud'], 'profiling.secret' => 'haze', 'profiling.path' => '/tmp/profiling', //PLACEHOLDER -]); +]; diff --git a/nix/image/configs/nc/redis-default.php b/nix/image/configs/nc/redis-default.php index 71b18a8..2ba24aa 100644 --- a/nix/image/configs/nc/redis-default.php +++ b/nix/image/configs/nc/redis-default.php @@ -1 +1,2 @@ 'redis' => ['host' => 'localhost'], +//PLACEHOLDER diff --git a/nix/image/configs/nc/redis-tls.php b/nix/image/configs/nc/redis-tls.php index c3b9abe..fecc760 100644 --- a/nix/image/configs/nc/redis-tls.php +++ b/nix/image/configs/nc/redis-tls.php @@ -2,9 +2,10 @@ 'host' => 'tls://127.0.0.1', 'port' => 6379, 'ssl_context' => [ - 'local_cert' => '/certificates/redis/client.crt', - 'local_pk' => '/certificates/redis/client.key', - 'cafile' => '/certificates/redis/ca.crt', + 'local_cert' => '/redis-certificates/client.crt', + 'local_pk' => '/redis-certificates/client.key', + 'cafile' => '/redis-certificates/ca.crt', 'verify_peer_name' => false, ], ], +//PLACEHOLDER diff --git a/nix/image/configs/nc/s3s.php b/nix/image/configs/nc/s3s.php deleted file mode 100644 index cfbf186..0000000 --- a/nix/image/configs/nc/s3s.php +++ /dev/null @@ -1,15 +0,0 @@ - 'objectstore' => [ - 'class' => 'OC\Files\ObjectStore\S3', - 'arguments' => [ - 'bucket' => 'nextcloud', - 'autocreate' => true, - 'key' => 'minio', - 'secret' => 'minio123', - 'hostname' => 's3', - 'port' => 9000, - 'use_ssl' => true, - 'use_path_style' => true, - 'uploadPartSize' => 52428800, - 'use_nextcloud_bundle' => true, - ], - ], diff --git a/nix/image/configs/sudoers.d/haze b/nix/image/configs/sudoers similarity index 100% rename from nix/image/configs/sudoers.d/haze rename to nix/image/configs/sudoers diff --git a/nix/image/configs/supervisor/blackfire.conf b/nix/image/configs/supervisor/blackfire.conf deleted file mode 100644 index ca6cd89..0000000 --- a/nix/image/configs/supervisor/blackfire.conf +++ /dev/null @@ -1,2 +0,0 @@ -[program:blackfire] -command = blackfire agent \ No newline at end of file diff --git a/nix/image/configs/supervisor/dnsmasq.conf b/nix/image/configs/supervisor/dnsmasq.conf deleted file mode 100644 index d57ed09..0000000 --- a/nix/image/configs/supervisor/dnsmasq.conf +++ /dev/null @@ -1,2 +0,0 @@ -[program:dnsmasq] -command = /bin/dnsmasq --keep-in-foreground -u root \ No newline at end of file diff --git a/nix/image/configs/supervisor/frankenphp.conf b/nix/image/configs/supervisor/frankenphp.conf deleted file mode 100644 index 8c1b1e5..0000000 --- a/nix/image/configs/supervisor/frankenphp.conf +++ /dev/null @@ -1,3 +0,0 @@ -[program:frankenphp] -command = /bin/frankenphp php-server -directory = /var/www/html \ No newline at end of file diff --git a/nix/image/configs/supervisor/nginx.conf b/nix/image/configs/supervisor/nginx.conf deleted file mode 100644 index 957e4b3..0000000 --- a/nix/image/configs/supervisor/nginx.conf +++ /dev/null @@ -1,2 +0,0 @@ -[program:nginx] -command = /bin/nginx -c /etc/nginx.conf diff --git a/nix/image/configs/supervisor/php-fpm.conf b/nix/image/configs/supervisor/php-fpm.conf deleted file mode 100644 index 69418c7..0000000 --- a/nix/image/configs/supervisor/php-fpm.conf +++ /dev/null @@ -1,2 +0,0 @@ -[program:php-fpm] -command = /bin/php-fpm --fpm-config /etc/php-fpm.conf diff --git a/nix/image/configs/supervisor/redis-plain.conf b/nix/image/configs/supervisor/redis-plain.conf deleted file mode 100644 index e9284cc..0000000 --- a/nix/image/configs/supervisor/redis-plain.conf +++ /dev/null @@ -1,2 +0,0 @@ -[program:redis] -command = /bin/redis-server --protected-mode no \ No newline at end of file diff --git a/nix/image/configs/supervisor/redis-tls.conf b/nix/image/configs/supervisor/redis-tls.conf deleted file mode 100644 index d9f86bd..0000000 --- a/nix/image/configs/supervisor/redis-tls.conf +++ /dev/null @@ -1,2 +0,0 @@ -[program:redis-tls] -command = /bin/redis-server --protected-mode no --tls-port 6379 --port 0 --tls-cert-file /certificates/redis/server.crt --tls-key-file /certificates/redis/server.key --tls-ca-cert-file /certificates/redis/ca.crt \ No newline at end of file diff --git a/nix/image/configs/supervisor/supervisord.conf b/nix/image/configs/supervisor/supervisord.conf deleted file mode 100644 index bed7885..0000000 --- a/nix/image/configs/supervisor/supervisord.conf +++ /dev/null @@ -1,19 +0,0 @@ -[supervisord] -logfile = /dev/stdout -logfile_maxbytes = 0 -nodaemon = true -pidfile = /var/run/supervisord.pid -user = root - -[unix_http_server] -file = /var/run/supervisor.sock -chmod = 0777 - -[rpcinterface:supervisor] -supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface - -[supervisorctl] -serverurl = unix:///var/run/supervisor.sock - -[include] -files = enabled/* diff --git a/nix/image/haze.nix b/nix/image/haze.nix index 5ce1051..38bc8f9 100644 --- a/nix/image/haze.nix +++ b/nix/image/haze.nix @@ -7,9 +7,10 @@ blackfire, coreutils, getent, - writers, shadow, + buildEnv, runCommand, + cacert, callPackage, cronie, redis, @@ -32,20 +33,18 @@ writeShellApplication, vim, helix, - python3Packages, - dnsmasq, - frankenphp, - nushell, }: let - inherit (builtins) toString compareVersions; - inherit (lib) readFile getExe concatStringsSep splitString take optionals; - - version = (fromTOML (readFile ../../Cargo.toml)).package.version; + inherit (builtins) toString; + inherit (lib) readFile getExe concatStringsSep splitString take; phpVersion = concatStringsSep "." (take 2 (splitString "." php.version)); phpEnv = callPackage ./php.nix {inherit debug php;}; - bootstrap = writers.writeNuBin "bootstrap" (readFile ./bootstrap); + bootstrap = writeShellApplication { + name = "bootstrap"; + runtimeInputs = [getent]; + text = readFile ./bootstrap.sh; + }; shadowSetupScript = writeShellApplication { name = "shadow-setup"; text = dockerTools.shadowSetup; @@ -71,6 +70,14 @@ php = phpEnv; }; + phpunitWrapped = majorVersion: + writeShellApplication { + name = "phpunit${toString majorVersion}"; + text = '' + ${phpunitUnwrapped (toString majorVersion)}/bin/phpunit "$@" + ''; + }; + phpunit = writeShellApplication { name = "phpunit"; runtimeInputs = [jq]; @@ -97,9 +104,9 @@ ''; }; - certificates = runCommand "scripts" {} '' + redis-certificates = runCommand "scripts" {} '' mkdir -p $out - cp -r ${../../certificates} $out/certificates + cp -r ${../../redis-certificates} $out/redis-certificates ''; clamav-data = runCommand "scripts" {} '' mkdir -p $out/etc @@ -138,10 +145,6 @@ oracle-instantclient vim helix - python3Packages.supervisor - dnsmasq - nushell - getent ]; }; @@ -150,20 +153,11 @@ tag = phpVersion; fromImage = baseImage; - copyToRoot = - [ - phpEnv - phpEnv.packages.composer - phpunit - ] - ++ optionals ((compareVersions phpVersion "8.2") == 1) [ - (frankenphp.override { - php = php.withExtensions (import ./php-ext.nix { - inherit lib php; - enableBlackfire = false; - }); - }) - ]; + copyToRoot = [ + phpEnv + phpEnv.packages.composer + phpunit + ]; }; in dockerTools.buildLayeredImage { @@ -176,7 +170,7 @@ in bootstrap configs scripts - certificates + redis-certificates clamav-data shadowSetupScript ]; @@ -191,14 +185,7 @@ in ''; config = { Cmd = [(getExe bootstrap)]; - Env = [ - "EDITOR=hx" - "WEBROOT=/var/www/html" - "HAZE_IMAGE_VERSION=${toString version}" - ]; + Env = ["EDITOR=hx" "WEBROOT=/var/www/html"]; WorkingDir = "/var/www/html"; - Labels = { - "nl.icewind.haze.version" = toString version; - }; }; } diff --git a/nix/image/configs/nginx.conf b/nix/image/nginx.conf similarity index 76% rename from nix/image/configs/nginx.conf rename to nix/image/nginx.conf index 15a57c3..3de81ca 100644 --- a/nix/image/configs/nginx.conf +++ b/nix/image/nginx.conf @@ -69,17 +69,7 @@ http { access_log off; } - location ^~ /store_apps { - root /var/www; - try_files $uri /index.php$request_uri; - access_log off; # Optional: Don't log access to assets - - location ~ \.wasm$ { - default_type application/wasm; - } - } - - include /etc/nginx-app.conf; + include /conf/nginx-app.conf; location ~ \.php(?:$|/) { rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri; @@ -109,16 +99,5 @@ http { expires 7d; # Cache-Control policy borrowed from `.htaccess` access_log off; # Optional: Don't log access to assets } - - location /fpm-status { - include /conf/fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_pass php-handler; - fastcgi_read_timeout 3600; - proxy_request_buffering off; - fastcgi_request_buffering off; - fastcgi_buffering off; - } } } diff --git a/nix/image/php-ext.nix b/nix/image/php-ext.nix deleted file mode 100644 index 0a7e53e..0000000 --- a/nix/image/php-ext.nix +++ /dev/null @@ -1,45 +0,0 @@ -{ - lib, - php, - debug ? false, - enableBlackfire ? true, -}: let - inherit (builtins) compareVersions; - inherit (lib) optionals; - withBlackfire = enableBlackfire && !debug && ((compareVersions php.version "8.1.0") == 1); -in - { - enabled, - all, - }: - enabled - ++ (with all; - [ - xdebug - excimer - inotify - redis - oci8 - zip - pdo - pdo_pgsql - pdo_sqlite - pdo_mysql - pgsql - intl - curl - mbstring - pcntl - ldap - exif - gmp - apcu - ffi - imagick - ] - ++ optionals (!debug) [ - # smbclient # this breaks the build for no apparent reason - ] - ++ optionals withBlackfire [ - blackfire - ]) diff --git a/nix/image/configs/php-fpm.conf b/nix/image/php-fpm.conf similarity index 77% rename from nix/image/configs/php-fpm.conf rename to nix/image/php-fpm.conf index 89379d8..e6292fb 100644 --- a/nix/image/configs/php-fpm.conf +++ b/nix/image/php-fpm.conf @@ -1,11 +1,11 @@ [global] -error_log = /var/log/php-fpm-error.log +error_log = /proc/self/fd/2 daemonize = no [www] -access.log =/var/log/php-fpm-access.log +access.log = /proc/self/fd/2 user = haze group = haze @@ -21,7 +21,6 @@ pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 -pm.status_path = /fpm-status clear_env = no diff --git a/nix/image/php.nix b/nix/image/php.nix index 8ef3d31..852b478 100644 --- a/nix/image/php.nix +++ b/nix/image/php.nix @@ -2,23 +2,56 @@ lib, php, debug ? false, -}: -php.buildEnv { - extensions = import ./php-ext.nix {inherit lib php debug;}; - extraConfig = '' - xdebug.mode=debug,trace,profile - xdebug.start_with_request=trigger - xdebug.discover_client_host=false - xdebug.client_host=hazehost - xdebug.log_level=0 - xdebug.output_dir=/tmp/xdebug +}: let + inherit (lib) optionals; +in + php.buildEnv { + extensions = { + enabled, + all, + }: + enabled + ++ (with all; + [ + xdebug + excimer + inotify + redis + oci8 + zip + pdo + pdo_pgsql + pdo_sqlite + pdo_mysql + pgsql + intl + curl + mbstring + pcntl + ldap + exif + gmp + apcu + ffi + ] + ++ optionals (!debug) [ + smbclient # this breaks the build for no apparent reason + blackfire + ]); + extraConfig = '' + xdebug.mode=debug,trace,profile + xdebug.start_with_request=trigger + xdebug.discover_client_host=false + xdebug.client_host=hazehost + xdebug.log_level=0 + xdebug.output_dir=/tmp/xdebug - memory_limit=512M + memory_limit=512M - post_max_size 10G - upload_max_filesize 10G + post_max_size 10G + upload_max_filesize 10G - apc.enable_cli=1 - opcache.enable_cli=1 - ''; -} + apc.enable_cli=1 + opcache.enable_cli=1 + ''; + } diff --git a/nix/image/scripts/install b/nix/image/scripts/install index 35d3f00..d216118 100755 --- a/nix/image/scripts/install +++ b/nix/image/scripts/install @@ -1,22 +1,20 @@ -#!/bin/nu +#!/bin/sh -def main [username: string, password: string] { - cd $env.WEBROOT; - let sql = match $env.SQL { - "oracle" => "oci" - "mariadb" => "mysql" - _ => $env.SQL - } - let dbName = match $env.SQL { - "oracle" => "xe" - _ => "haze" - } - let dbUser = match $env.SQL { - "oracle" => "system" - _ => "haze" - } - let dbPass = "haze" - let dbHost = $env.SQL +USER=$1 +PASSWORD=$2 - occ maintenance:install --admin-user $username --admin-pass $password --database $sql --database-name $dbName --database-host $dbHost --database-user $dbUser --database-pass $dbPass -} +if [ -z "$USER" ] || [ -z "$PASSWORD" ]; then + echo "Usage: install \$USER \$PASSWORD" + exit; +fi + +cd $WEBROOT + +if [ "$SQL" = "oci" ]; then + # oracle is a special snowflake + occ maintenance:install --admin-user=$USER --admin-pass=$PASSWORD --database=$SQL --database-name=xe --database-host=$SQL --database-user=system --database-pass=haze +elif [ "$SQL" = "mariadb" ]; then + occ maintenance:install --admin-user=$USER --admin-pass=$PASSWORD --database=mysql --database-name=haze --database-host=$SQL --database-user=haze --database-pass=haze +else + occ maintenance:install --admin-user=$USER --admin-pass=$PASSWORD --database=$SQL --database-name=haze --database-host=$SQL --database-user=haze --database-pass=haze +fi; diff --git a/nix/image/scripts/integration b/nix/image/scripts/integration index d8187d9..4f73aef 100755 --- a/nix/image/scripts/integration +++ b/nix/image/scripts/integration @@ -1,22 +1,4 @@ -#!/bin/nu +#!/bin/sh -def --wrapped main [feature: path, ...rest] { - mut feature = $feature; - mut workdir = $"($env.WEBROOT)/build/integration" - if ($feature | str starts-with "apps/") { - let parts = $feature | split row '/' - occ app:enable $parts.1 - let parts = $feature | split row -n 2 '/features/' - $workdir = $parts.0 - $feature = $"features/($parts.1)" - } else if ($feature | str starts-with "build/integration/") { - $feature = $feature | str replace "build/integration/" "" - } - - # don't use the proxy urls for generated urls - occ config:system:delete overwritehost - occ config:system:delete overwriteprotocol - - cd $workdir - bash run.sh $feature ...$rest -} +cd $WEBROOT/build/integration +./run.sh "$@" diff --git a/nix/image/scripts/nc-auto-config b/nix/image/scripts/nc-auto-config index b7a2c07..6a803d9 100755 --- a/nix/image/scripts/nc-auto-config +++ b/nix/image/scripts/nc-auto-config @@ -1,4 +1,4 @@ -#!/bin/nu +#!/usr/bin/env bash touch /var/log/nginx/access.log touch /var/log/nginx/error.log @@ -7,30 +7,59 @@ touch /var/log/cron/owncloud.log cp /etc/nc/config.php /var/www/html/config/config.php chmod 0755 /var/www/html/config/config.php -let configName = match $env.SQL { - "oracle" => "oci" - _ => $env.SQL +if [ "$SQL" = "mysql" ] +then + cp /etc/nc/autoconfig_mysql.php /var/www/html/config/autoconfig.php +fi -} -let configPath = $"/etc/nc/autoconfig_($configName).php" +if [ "$SQL" = "mariadb" ] +then + cp /etc/nc/autoconfig_mariadb.php /var/www/html/config/autoconfig.php +fi -if ($configPath | path exists) { - cp $configPath /var/www/html/config/autoconfig.php -} +if [ "$SQL" = "pgsql" ] +then + cp /etc/nc/autoconfig_pgsql.php /var/www/html/config/autoconfig.php +fi -def loadExtraConfig [name: string] { - sed -i $'/\/\/PLACEHOLDER/ r /etc/nc/($name).php' /var/www/html/config/config.php -} +if [ "$SQL" = "oci" ] +then + cp /etc/nc/autoconfig_oci.php /var/www/html/config/autoconfig.php +fi -let extraConfigs = ["S3", "S3S", "S3MB", "S3M", "SWIFT", "SWIFTV3", "AZURE"]; -$extraConfigs | each { - if ($in in $env) { - loadExtraConfig ($in | str downcase) - } -} +if [ -n "${S3:-}" ] +then + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/s3.php' /var/www/html/config/config.php +fi -if ("REDIS_TLS" in $env) { - loadExtraConfig "redis-tls" -} else { - loadExtraConfig "redis-default" -} +if [ -n "${S3MB:-}" ] +then + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/s3mb.php' /var/www/html/config/config.php +fi + +if [ -n "${S3M:-}" ] +then + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/s3m.php' /var/www/html/config/config.php +fi + +if [ -n "${SWIFT:-}" ] +then + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/swift.php' /var/www/html/config/config.php +fi + +if [ -n "${SWIFTV3:-}" ] +then + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/swiftv3.php' /var/www/html/config/config.php +fi + +if [ -n "${AZURE:-}" ] +then + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/azure.php' /var/www/html/config/config.php +fi + +if [ -n "${REDIS_TLS:-}" ] +then + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/redis-tls.php' /var/www/html/config/config.php +else + sed -i '/\/\/PLACEHOLDER/ r /etc/nc/redis-default.php' /var/www/html/config/config.php +fi diff --git a/nix/image/scripts/occ b/nix/image/scripts/occ index 07a443b..cf7d6fa 100755 --- a/nix/image/scripts/occ +++ b/nix/image/scripts/occ @@ -1,5 +1,5 @@ -#!/bin/nu +#!/bin/sh -def --wrapped main [...rest] { - XDEBUG_SESSION=haze php $"($env.WEBROOT)/occ" ...$rest -} +export XDEBUG_SESSION=haze + +php $WEBROOT/occ "$@" diff --git a/nix/image/scripts/tests b/nix/image/scripts/tests index 868f225..70691c0 100755 --- a/nix/image/scripts/tests +++ b/nix/image/scripts/tests @@ -1,7 +1,7 @@ -#!/bin/nu +#!/bin/sh -def --wrapped main [...rest] { - cd $env.WEBROOT +cd $WEBROOT - XDEBUG_SESSION=haze phpunit --configuration $"($env.WEBROOT)/tests/phpunit-autotest.xml" ...$rest -} +export XDEBUG_SESSION=haze + +phpunit --configuration $WEBROOT/tests/phpunit-autotest.xml $@ diff --git a/nix/overlay.nix b/nix/overlay.nix index 276b70e..b08daca 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -1,9 +1,7 @@ final: prev: { haze = final.callPackage ./package.nix {}; - haze-image-php-85 = final.callPackage ./image/haze.nix {php = final.php85;}; haze-image-php-84 = final.callPackage ./image/haze.nix {php = final.php84;}; haze-image-php-83 = final.callPackage ./image/haze.nix {php = final.php83;}; haze-image-php-82 = final.callPackage ./image/haze.nix {php = final.php82;}; haze-image-php-81 = final.callPackage ./image/haze.nix {php = final.php81;}; - haze-image-php-80 = final.callPackage ./image/haze.nix {php = final.php80;}; } diff --git a/nix/package.nix b/nix/package.nix index c6166f0..d79a216 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,15 +1,16 @@ { rustPlatform, + pkg-config, lib, git, }: let inherit (lib) getExe; inherit (lib.sources) sourceByRegex; inherit (builtins) fromTOML readFile; - src = sourceByRegex ../. ["Cargo.*" "(src|certificates)(/.*)?"]; + src = sourceByRegex ../. ["Cargo.*" "(src|redis-certificates)(/.*)?"]; version = (fromTOML (readFile ../Cargo.toml)).package.version; in - rustPlatform.buildRustPackage { + rustPlatform.buildRustPackage rec { pname = "haze"; inherit src version; @@ -19,7 +20,7 @@ in cargoLock = { lockFile = ../Cargo.lock; outputHashes = { - "hyper-reverse-proxy-0.5.2-dev" = "sha256-awmj5aLFTea+kj81cwmfP1HWlWezwEKfyQSUJWjtamk="; + "hyper-reverse-proxy-0.5.2-dev" = "sha256-+ebi4FVVkiOpf75e8K5oGkHJBYQjLNJhUPNj+78zd7Q="; }; }; } diff --git a/certificates/redis/ca.crt b/redis-certificates/ca.crt similarity index 100% rename from certificates/redis/ca.crt rename to redis-certificates/ca.crt diff --git a/certificates/redis/ca.key b/redis-certificates/ca.key similarity index 100% rename from certificates/redis/ca.key rename to redis-certificates/ca.key diff --git a/certificates/redis/ca.txt b/redis-certificates/ca.txt similarity index 100% rename from certificates/redis/ca.txt rename to redis-certificates/ca.txt diff --git a/certificates/redis/client.crt b/redis-certificates/client.crt similarity index 100% rename from certificates/redis/client.crt rename to redis-certificates/client.crt diff --git a/certificates/redis/client.key b/redis-certificates/client.key similarity index 100% rename from certificates/redis/client.key rename to redis-certificates/client.key diff --git a/certificates/redis/openssl.cnf b/redis-certificates/openssl.cnf similarity index 100% rename from certificates/redis/openssl.cnf rename to redis-certificates/openssl.cnf diff --git a/certificates/redis/redis.crt b/redis-certificates/redis.crt similarity index 100% rename from certificates/redis/redis.crt rename to redis-certificates/redis.crt diff --git a/certificates/redis/redis.dh b/redis-certificates/redis.dh similarity index 100% rename from certificates/redis/redis.dh rename to redis-certificates/redis.dh diff --git a/certificates/redis/redis.key b/redis-certificates/redis.key similarity index 100% rename from certificates/redis/redis.key rename to redis-certificates/redis.key diff --git a/certificates/redis/server.crt b/redis-certificates/server.crt similarity index 100% rename from certificates/redis/server.crt rename to redis-certificates/server.crt diff --git a/certificates/redis/server.key b/redis-certificates/server.key similarity index 100% rename from certificates/redis/server.key rename to redis-certificates/server.key diff --git a/src/args.rs b/src/args.rs index 59bca87..f5434ca 100644 --- a/src/args.rs +++ b/src/args.rs @@ -124,12 +124,9 @@ pub enum GitOperation { /// /// "main" and "master" can be used interchangeably. #[strum(props( - Args = "[branch] branch to checkout, defaults to the branch matching the current server version [-v] verbose" + Args = "[branch] branch to checkout, defaults to the branch matching the current server version" ))] - Checkout { - branch: Option, - verbose: bool, - }, + Checkout { branch: Option }, } impl SubCommand for GitOperation { @@ -165,7 +162,6 @@ impl LogService { #[derive(Debug, Clone, Eq, PartialEq)] pub enum ExecService { Db, - Service(Service), } impl HazeArgs { @@ -233,14 +229,6 @@ impl HazeArgs { args.next(); Some(ExecService::Db) } - Some(arg) => Service::from_type(&[], arg.as_ref()) - .into_iter() - .filter_map(|services| services.into_iter().next()) - .next() - .map(|service| { - args.next(); - ExecService::Service(service) - }), _ => None, }; @@ -332,24 +320,18 @@ impl HazeArgs { HazeCommand::Checkout => { let branch = args.next().map(S::into); Ok(HazeArgs::Git { - operation: GitOperation::Checkout { - branch, - verbose: false, - }, + operation: GitOperation::Checkout { branch }, }) } HazeCommand::Git => { - let mut args = args.peekable(); let operation = args .next() .ok_or_else(|| Report::msg("No git operation provided"))?; match operation.as_ref() { "checkout" => { - let verbose = args.next_if(|arg| arg.as_ref() == "-v").is_some(); let branch = args.next().map(S::into); - let verbose = verbose | args.next_if(|arg| arg.as_ref() == "-v").is_some(); Ok(HazeArgs::Git { - operation: GitOperation::Checkout { branch, verbose }, + operation: GitOperation::Checkout { branch }, }) } "pull" => Ok(HazeArgs::Git { @@ -523,7 +505,6 @@ impl SubCommand for HazeCommand { fn test_arg_parse() { let config = HazeConfig { sources_root: Default::default(), - app_directories: Default::default(), work_dir: Default::default(), auto_setup: Default::default(), volume: vec![], diff --git a/src/cloud.rs b/src/cloud.rs index afa01cf..79d298c 100644 --- a/src/cloud.rs +++ b/src/cloud.rs @@ -1,7 +1,7 @@ use crate::config::{HazeConfig, HazeVolumeConfig}; use crate::database::Database; use crate::exec::{exec, exec_io, exec_tty, ExitCode}; -use crate::mapping::{for_config, Mapping}; +use crate::mapping::{default_mappings, Mapping}; use crate::php::{PhpVersion, PHP_MEMORY_LIMIT}; use crate::service::Service; use crate::service::ServiceTrait; @@ -20,9 +20,9 @@ use std::borrow::Cow; use std::collections::HashMap; use std::fmt::Display; use std::fs; -use std::fs::{read_to_string, write}; +use std::fs::read_to_string; use std::io::{stdout, Cursor, Read, Stdout, Write}; -use std::iter::{once, Peekable}; +use std::iter::Peekable; use std::net::IpAddr; use std::os::unix::fs::MetadataExt; use std::str::FromStr; @@ -152,44 +152,44 @@ fn test_option_parse() { ..Default::default() } ); - let mut args = vec!["8"].into_iter().peekable(); + let mut args = vec!["7"].into_iter().peekable(); assert_eq!( CloudOptions::parse(&config, &mut args).unwrap(), CloudOptions { - php: PhpVersion::Php80, + php: PhpVersion::Php74, ..Default::default() } ); - let mut args = vec!["8.1", "pgsql", "rest"].into_iter().peekable(); + let mut args = vec!["7", "pgsql", "rest"].into_iter().peekable(); assert_eq!( CloudOptions::parse(&config, &mut args).unwrap(), CloudOptions { - php: PhpVersion::Php81, + php: PhpVersion::Php74, db: Database::Postgres, ..Default::default() } ); - let mut args = vec!["8", "ldap", "pgsql"].into_iter().peekable(); + let mut args = vec!["7", "ldap", "pgsql"].into_iter().peekable(); assert_eq!( CloudOptions::parse(&config, &mut args).unwrap(), CloudOptions { - php: PhpVersion::Php80, + php: PhpVersion::Php74, db: Database::Postgres, services: vec![Service::Ldap(Ldap), Service::LdapAdmin(LdapAdmin)], ..Default::default() } ); - let mut args = vec!["8", "pgsql", "ldap"].into_iter().peekable(); + let mut args = vec!["7", "pgsql", "ldap"].into_iter().peekable(); assert_eq!( CloudOptions::parse(&config, &mut args).unwrap(), CloudOptions { - php: PhpVersion::Php80, + php: PhpVersion::Php74, db: Database::Postgres, services: vec![Service::Ldap(Ldap), Service::LdapAdmin(LdapAdmin)], ..Default::default() } ); - let mut args = vec!["8", "pgsql", "ldap", "mypreset"] + let mut args = vec!["7", "pgsql", "ldap", "mypreset"] .into_iter() .peekable(); @@ -206,7 +206,7 @@ fn test_option_parse() { assert_eq!( CloudOptions::parse(&config, &mut args).unwrap(), CloudOptions { - php: PhpVersion::Php80, + php: PhpVersion::Php74, db: Database::Postgres, services: vec![ Service::Ldap(Ldap), @@ -218,7 +218,7 @@ fn test_option_parse() { ); } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Cloud { pub id: String, pub network: String, @@ -286,8 +286,11 @@ impl Cloud { }) }) .collect::>>()?; - - let mappings = for_config(config) + let mappings = config + .volume + .iter() + .map(Mapping::from) + .chain(default_mappings()) .chain(app_volumes.iter().map(Mapping::from)) .collect::>(); for mapping in &mappings { @@ -297,53 +300,6 @@ impl Cloud { .wrap_err_with(|| format!("Failed to setup work directory {}", mapping.source))?; } - let mut nc_config = Value::Object( - config - .auto_setup - .config - .clone() - .into_iter() - .map(|(key, value)| (key, serde_json::to_value(value).unwrap())) - .collect(), - ); - nc_config["apps_paths"] = Value::Array( - once("apps") - .chain( - config - .app_directories - .iter() - .filter_map(|dir| dir.file_name()), - ) - .map(|name| { - [ - ( - String::from("path"), - Value::from(format!("/var/www/html/{}", name)), - ), - (String::from("url"), Value::from(format!("/{}", name))), - (String::from("writable"), Value::from(false)), - ] - .into_iter() - .collect() - }) - .chain(once( - [ - (String::from("path"), Value::from("/var/www/store_apps")), - (String::from("url"), Value::from("/store_apps")), - (String::from("writable"), Value::from(true)), - ] - .into_iter() - .collect(), - )) - .collect(), - ); - write( - workdir.join("config/nextcloud.json"), - serde_json::to_string_pretty(&nc_config).unwrap(), - ) - .into_diagnostic() - .wrap_err("Failed to write config json")?; - let network = docker .create_network(NetworkCreateRequest { name: id.clone(), @@ -498,26 +454,9 @@ impl Cloud { } }; - for pre_setup in options - .services - .iter() - .flat_map(|service| service.pre_setup(docker, &id, config).into_iter().flatten()) - { - exec( - docker, - &container, - &uid.to_string(), - pre_setup, - vec!["NC_IS_CONFIG_READ_ONLY=1"], - Some(stdout()), - ) - .await?; - } - containers.push(container); let options_clone = options.clone(); - let proxy_config = config.proxy.clone(); let cloud_id = id.clone(); let docker_clone = docker.clone(); spawn(async move { @@ -531,10 +470,7 @@ impl Cloud { return; } for service in options_clone.services { - match service - .start_message(&docker_clone, &cloud_id, &proxy_config) - .await - { + match service.start_message(&docker_clone, &cloud_id).await { Ok(Some(msg)) => { println!("{}", msg); } @@ -563,9 +499,6 @@ impl Cloud { pub async fn destroy(self, docker: &Docker) -> Result<()> { for container in self.containers { - let _ = docker - .kill_container(container.trim_start_matches('/'), None) - .await; docker .remove_container( container.trim_start_matches('/'), @@ -861,7 +794,12 @@ impl Cloud { format!("/var/www/html/{path}").into() }; - let mut mappings = for_config(config).collect::>(); + let mut mappings = config + .volume + .iter() + .map(Mapping::from) + .chain(default_mappings()) + .collect::>(); mappings.sort_by_key(|mapping| usize::MAX - mapping.target.as_str().len()); for mapping in mappings { @@ -877,9 +815,3 @@ impl Cloud { None } } - -impl PartialEq for Cloud { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} diff --git a/src/config.rs b/src/config.rs index 9e4548f..07cfcef 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,17 +4,15 @@ use miette::{IntoDiagnostic, Report, Result, WrapErr}; use serde::Deserialize; use std::collections::HashMap; use std::convert::TryFrom; -use std::env::home_dir; +use std::env::var; use std::fs::read_to_string; use std::net::IpAddr; -use toml::map::Map; use toml::Value; #[derive(Debug, Deserialize, Default)] #[serde(from = "RawHazeConfig")] pub struct HazeConfig { pub sources_root: Utf8PathBuf, - pub app_directories: Vec, pub work_dir: Utf8PathBuf, pub auto_setup: HazeAutoSetupConfig, pub volume: Vec, @@ -29,8 +27,6 @@ pub struct RawHazeConfig { #[serde(default = "default_work_dir")] pub work_dir: Utf8PathBuf, #[serde(default)] - pub app_directories: Vec, - #[serde(default)] pub auto_setup: HazeAutoSetupConfig, #[serde(default)] pub volume: Vec, @@ -46,11 +42,7 @@ impl From for HazeConfig { fn from(raw: RawHazeConfig) -> Self { fn normalize_path(path: Utf8PathBuf) -> Utf8PathBuf { if path.starts_with("~") { - let home = home_dir().expect("can't detect home directory"); - let home = home - .into_os_string() - .into_string() - .expect("non-utf8 home directory"); + let home = var("HOME").expect("HOME not set"); format!("{}{}", home, &path.as_str()[1..]).into() } else { path @@ -59,11 +51,6 @@ impl From for HazeConfig { HazeConfig { sources_root: normalize_path(raw.sources_root), - app_directories: raw - .app_directories - .into_iter() - .map(normalize_path) - .collect(), work_dir: normalize_path(raw.work_dir), auto_setup: raw.auto_setup, volume: raw.volume, @@ -88,8 +75,6 @@ pub struct HazeAutoSetupConfig { pub disable_apps: Vec, #[serde(default)] pub post_setup: Vec, - #[serde(default)] - pub config: Map, } impl Default for HazeAutoSetupConfig { @@ -101,7 +86,6 @@ impl Default for HazeAutoSetupConfig { enable_apps: Vec::default(), disable_apps: Vec::default(), post_setup: Vec::default(), - config: Map::default(), } } } @@ -185,7 +169,7 @@ fn load_secret(name: &str, path: Option, raw: Option) -> Result< } } -#[derive(Default, Deserialize, Debug, Clone)] +#[derive(Default, Deserialize, Debug)] pub struct ProxyConfig { pub listen: String, #[serde(default)] diff --git a/src/database.rs b/src/database.rs index 0bc31d7..ff969a3 100644 --- a/src/database.rs +++ b/src/database.rs @@ -219,6 +219,14 @@ impl Database { } }), }), + cmd: if self.image() == "mysql:8" { + Some(vec![ + "--default-authentication-plugin".into(), + "mysql_native_password".into(), + ]) + } else { + None + }, ..Default::default() }; let id = docker diff --git a/src/git.rs b/src/git.rs index fc31255..d08f2f3 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,33 +1,22 @@ -use crate::config::HazeConfig; use crate::Result; use git2::build::CheckoutBuilder; use git2::{Branch, BranchType, Repository, RepositoryState}; -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use miette::{Context, IntoDiagnostic}; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; -use rayon::ThreadPoolBuilder; use std::fs::read_dir; -use std::iter::once; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::Command; -use std::time::Duration; -fn find_app_repos(config: &HazeConfig) -> Result> { - let apps_dirs = once(config.sources_root.as_path().join("apps")) - .chain(config.app_directories.iter().cloned()); - let dir_handles = apps_dirs - .map(|dir| read_dir(dir).into_diagnostic()) - .collect::>>()?; - Ok(dir_handles - .into_iter() - .flatten() +fn find_app_repos(root: impl AsRef) -> Result> { + let apps_dir = root.as_ref().join("apps"); + Ok(read_dir(apps_dir) + .into_diagnostic()? .flatten() .filter(|app| app.path().join(".git").is_dir()) .map(|app| app.path())) } -fn longest_app_branch(config: &HazeConfig) -> Result<(usize, usize)> { - Ok(find_app_repos(config)? +fn longest_app_branch(root: impl AsRef) -> Result<(usize, usize)> { + Ok(find_app_repos(root)? .filter_map(|app_dir| { let app_name = app_dir.file_name()?.to_str()?; let repo = Repository::init(&app_dir).ok()?; @@ -38,32 +27,27 @@ fn longest_app_branch(config: &HazeConfig) -> Result<(usize, usize)> { .unwrap_or_default()) } -pub fn checkout_all(config: &HazeConfig, mut name: &str, verbose: bool) -> Result<()> { +pub fn checkout_all>(sources_root: P, mut name: &str) -> Result<()> { // "main" and "master" are interchangeable if name == "main" { name = "master"; } - for app_dir in find_app_repos(config)? { + for app_dir in find_app_repos(sources_root)? { let repo = Repository::init(&app_dir) .into_diagnostic() .wrap_err_with(|| format!("Failed to open repository {}", app_dir.display()))?; - let app_name = app_dir.file_name().unwrap().to_string_lossy(); if let Some(branch) = get_branch(&repo, name)? { if !branch.is_head() { let is_remote = branch.get().is_remote(); - print!("{app_name}"); + print!("{}", app_dir.file_name().unwrap().to_string_lossy()); if let Err(e) = checkout(&repo, &branch, is_remote.then_some(name)) { println!(": {:#} ❌", e); } else { println!(" ✓"); } - } else if verbose { - println!("{app_name} -"); } - } else if verbose { - println!("{app_name} 🛇 Branch not found"); }; } Ok(()) @@ -84,69 +68,42 @@ const GIT_BINARY: &str = match option_env!("GIT_BINARY") { None => "git", }; -pub fn pull_all(config: &HazeConfig) -> Result<()> { - let (max_app, max_branch) = longest_app_branch(config)?; +pub fn pull_all>(sources_root: P) -> Result<()> { + let sources_root = sources_root.as_ref(); + let (max_app, max_branch) = longest_app_branch(sources_root)?; - let progress = MultiProgress::new(); - let pull_style = ProgressStyle::with_template("{spinner:.green} {msg}").unwrap(); + for app_dir in find_app_repos(sources_root)? { + let app_name = app_dir.file_name().unwrap().to_string_lossy(); + let repo = Repository::init(&app_dir) + .into_diagnostic() + .wrap_err_with(|| format!("Failed to open repository {}", app_dir.display()))?; + let branch_name = current_branch_name(&repo).unwrap_or("unknown".into()); - let pool = ThreadPoolBuilder::new() - .num_threads(8) - .build() - .into_diagnostic()?; - let repos = find_app_repos(config)?.collect::>(); + print!( + "{app_name: output, - Err(error) => { - bar.set_message(msg(&format!(" ⨯ {error}"))); - return; - } - }; - - if output.status.success() { - bar.set_message(msg(" ✓")); - } else { - let err = String::from_utf8_lossy(&output.stderr); - let err_line = err.lines().next().unwrap(); - bar.set_message(msg(&format!(" ⨯ {err_line}"))); - } - bar.finish(); - }); - }); + let output = Command::new(GIT_BINARY) + .arg("pull") + .current_dir(&app_dir) + .output() + .into_diagnostic() + .wrap_err_with(|| format!("Failed to run git pull for {}", app_dir.display()))?; + if output.status.success() { + println!(" ✓"); + } else { + println!(" ❌"); + eprintln!("{}", String::from_utf8_lossy(&output.stderr)) + } + } Ok(()) } diff --git a/src/image.rs b/src/image.rs index e24abfd..94da352 100644 --- a/src/image.rs +++ b/src/image.rs @@ -5,48 +5,11 @@ use futures_util::StreamExt; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use miette::{IntoDiagnostic, Result, WrapErr}; use std::collections::HashMap; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; - -#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)] -pub struct ImageVersion { - pub major: u8, - pub minor: u8, - pub patch: u8, -} - -impl FromStr for ImageVersion { - type Err = (); - - fn from_str(s: &str) -> std::result::Result { - let mut parts = s.split('.'); - let major = parts.next().ok_or(())?.parse().map_err(|_| ())?; - let minor = parts.next().ok_or(())?.parse().map_err(|_| ())?; - let patch = parts.next().ok_or(())?.parse().map_err(|_| ())?; - Ok(ImageVersion { - major, - minor, - patch, - }) - } -} - -impl Display for ImageVersion { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}.{}.{}", self.major, self.minor, self.patch) - } -} pub async fn image_exists(docker: &Docker, image: &str) -> bool { docker.inspect_image(image).await.is_ok() } -pub async fn image_version(docker: &Docker, image: &str) -> Option { - let labels = docker.inspect_image(image).await.ok()?.config?.labels?; - let label = labels.get("nl.icewind.haze.version")?; - ImageVersion::from_str(label).ok() -} - pub async fn update_image(docker: &Docker, image: &str) -> Result<()> { if image_exists(docker, image).await { force_pull_image(docker, image).await?; diff --git a/src/main.rs b/src/main.rs index d999b7c..5deb172 100644 --- a/src/main.rs +++ b/src/main.rs @@ -148,9 +148,6 @@ async fn main() -> Result { root, } => { let cloud = Cloud::get_by_filter(&docker, filter, &config).await?; - let env = get_forward_env(); - let tty = atty::is(atty::Stream::Stdout); - match service { None => { let command = if command.is_empty() { @@ -158,7 +155,8 @@ async fn main() -> Result { } else { command }; - + let env = get_forward_env(); + let tty = atty::is(atty::Stream::Stdout); let user = if root { "root" } else { "haze" }; if tty { exec_tty(&docker, &cloud.id, user, command, env).await?; @@ -167,42 +165,19 @@ async fn main() -> Result { } } Some(ExecService::Db) => { - let command = if command.is_empty() { - vec!["bash".to_string()] - } else { - command - }; - - cloud.db().exec_sh(&docker, &cloud.id, command, tty).await?; - } - Some(ExecService::Service(service)) => { - let Some(container) = service.container_name(&cloud.id) else { - eprintln!( - "Service {} can't be exec'ed as it has no associated container", - service.name() - ); - return Ok(ExitCode::FAILURE); - }; - if service.exec_shell() == "" && command.is_empty() { - eprintln!( - "Service {} can't be exec'ed as it has no shell", - service.name() - ); - return Ok(ExitCode::FAILURE); - } - - let command = if command.is_empty() { - vec![service.exec_shell().to_string()] - } else { - command - }; - - let user = if root { "root" } else { service.exec_user() }; - if tty { - exec_tty(&docker, &container, user, command, env).await?; - } else { - exec(&docker, &container, user, command, env, Some(stdout())).await?; - } + cloud + .db() + .exec_sh( + &docker, + &cloud.id, + if command.is_empty() { + vec!["bash".to_string()] + } else { + command + }, + atty::is(atty::Stream::Stdout), + ) + .await?; } } } @@ -398,16 +373,15 @@ async fn main() -> Result { proxy(docker, config).await?; } HazeArgs::Git { operation } => match operation { - GitOperation::Checkout { branch, verbose } => { + GitOperation::Checkout { branch } => { let sources = Sources::new(&config.sources_root)?; checkout_all( - &config, + &config.sources_root, &branch.unwrap_or_else(|| sources.get_server_version_branch()), - verbose, )?; } GitOperation::Pull => { - pull_all(&config)?; + pull_all(&config.sources_root)?; } }, HazeArgs::Env { @@ -446,16 +420,16 @@ async fn main() -> Result { ); if cloud.services().contains(&Service::RedisTls(RedisTls)) { - create_dir_all(config.work_dir.join("certificates/redis")) + create_dir_all(config.work_dir.join("redis_certificates")) .into_diagnostic() .wrap_err("Failed to create redis certificate directory")?; - let redis_cert_path = config.work_dir.join("certificates/redis/client.cert"); - let redis_key_path = config.work_dir.join("certificates/redis/client.key"); - let redis_ca_path = config.work_dir.join("certificates/redis/ca.cert"); + let redis_cert_path = config.work_dir.join("redis_certificates/client.cert"); + let redis_key_path = config.work_dir.join("redis_certificates/client.key"); + let redis_ca_path = config.work_dir.join("redis_certificates/ca.cert"); if !redis_cert_path.exists() { write( &redis_cert_path, - include_bytes!("../certificates/redis/client.crt"), + include_bytes!("../redis-certificates/client.crt"), ) .into_diagnostic() .wrap_err("Failed to write redis client certificate")?; @@ -463,7 +437,7 @@ async fn main() -> Result { if !redis_key_path.exists() { write( &redis_key_path, - include_bytes!("../certificates/redis/client.key"), + include_bytes!("../redis-certificates/client.key"), ) .into_diagnostic() .wrap_err("Failed to write redis client key")?; @@ -471,7 +445,7 @@ async fn main() -> Result { if !redis_ca_path.exists() { write( &redis_ca_path, - include_bytes!("../certificates/redis/ca.crt"), + include_bytes!("../redis-certificates/ca.crt"), ) .into_diagnostic() .wrap_err("Failed to write redis ca certificate")?; @@ -658,7 +632,12 @@ async fn setup(docker: &Docker, options: CloudOptions, config: &HazeConfig) -> R for service in cloud.services() { for cmd in service.post_setup(docker, &cloud.id, config).await? { cloud - .exec(docker, cmd, false, Vec::::default()) + .exec( + docker, + shell_words::split(&cmd).into_diagnostic()?, + false, + Vec::::default(), + ) .await?; } } diff --git a/src/mapping.rs b/src/mapping.rs index 9c01da0..4061100 100644 --- a/src/mapping.rs +++ b/src/mapping.rs @@ -1,14 +1,13 @@ use crate::config::{HazeConfig, HazeVolumeConfig}; use camino::{Utf8Path, Utf8PathBuf}; use miette::{IntoDiagnostic, Result}; -use std::borrow::Cow; use tokio::fs::{create_dir_all, write}; #[derive(Debug)] pub struct Mapping<'a> { source_type: MappingSourceType, - pub source: Cow<'a, Utf8Path>, - pub target: Cow<'a, Utf8Path>, + pub source: &'a Utf8Path, + pub target: &'a Utf8Path, mapping_type: MappingType, read_only: bool, map: bool, @@ -24,26 +23,6 @@ impl<'a> Mapping<'a> { where Target: Into<&'a Utf8Path>, Source: Into<&'a Utf8Path>, - { - Mapping { - source_type, - source: Cow::Borrowed(source.into()), - target: Cow::Borrowed(target.into()), - mapping_type: MappingType::Folder, - read_only: false, - map: true, - create: true, - } - } - - pub fn owned( - source_type: MappingSourceType, - source: Source, - target: Target, - ) -> Self - where - Target: Into>, - Source: Into>, { Mapping { source_type, @@ -86,10 +65,10 @@ impl<'a> Mapping<'a> { return Ok(()); } let source = match self.source_type { - MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source.as_ref()), - MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source.as_ref()), + MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source), + MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source), MappingSourceType::Sources => return Ok(()), - MappingSourceType::Absolute => self.source.as_ref().into(), + MappingSourceType::Absolute => self.source.into(), }; match self.mapping_type { MappingType::Folder => create_dir_all(source).await.into_diagnostic()?, @@ -101,10 +80,10 @@ impl<'a> Mapping<'a> { pub fn source(&self, id: &str, config: &HazeConfig, source_root: &Utf8Path) -> Utf8PathBuf { match self.source_type { - MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source.as_ref()), - MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source.as_ref()), - MappingSourceType::Sources => source_root.join(self.source.as_ref()), - MappingSourceType::Absolute => self.source.as_ref().into(), + MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source), + MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source), + MappingSourceType::Sources => source_root.join(self.source), + MappingSourceType::Absolute => self.source.into(), } } @@ -133,7 +112,6 @@ pub fn default_mappings<'a>() -> impl IntoIterator> { Mapping::new(Sources, "", "/var/www/html"), Mapping::new(WorkDir, "data", "/var/www/html/data"), Mapping::new(WorkDir, "config", "/var/www/html/config"), - Mapping::new(WorkDir, "store_apps", "/var/www/store_apps"), Mapping::new(WorkDir, "data-autotest", "/var/www/html/data-autotest"), Mapping::new(WorkDir, "skeleton", "/var/www/html/core/skeleton"), Mapping::new( @@ -190,30 +168,9 @@ pub fn default_mappings<'a>() -> impl IntoIterator> { Mapping::new(WorkDir, "profiling", "/tmp/profiling"), Mapping::new(WorkDir, "php-config", "/config"), ]; - IntoIterator::into_iter(mappings) } -pub fn for_config<'a>(config: &'a HazeConfig) -> impl Iterator> { - let app_dir_mappings = config.app_directories.iter().map(|dir| { - Mapping::owned( - MappingSourceType::Absolute, - dir.as_path(), - Cow::Owned(Utf8PathBuf::from(format!( - "/var/www/html/{}", - dir.file_name().unwrap() - ))), - ) - }); - - config - .volume - .iter() - .map(Mapping::from) - .chain(app_dir_mappings) - .chain(default_mappings()) -} - #[derive(Debug, Copy, Clone)] pub enum MappingSourceType { Sources, @@ -237,8 +194,8 @@ impl<'a> From<&'a HazeVolumeConfig> for Mapping<'a> { }; Mapping { source_type: MappingSourceType::Absolute, - source: Cow::Borrowed(config.source.as_path()), - target: Cow::Borrowed(config.target.as_path()), + source: config.source.as_path(), + target: config.target.as_path(), mapping_type: ty, read_only: config.read_only, map: true, diff --git a/src/php.rs b/src/php.rs index d1abaa2..0842ec2 100644 --- a/src/php.rs +++ b/src/php.rs @@ -1,7 +1,6 @@ -use owo_colors::OwoColorize; use crate::config::ProxyConfig; use crate::database::Database; -use crate::image::{image_version, pull_image, ImageVersion}; +use crate::image::pull_image; use crate::network::ensure_network_exists; use crate::service::Service; use crate::service::ServiceTrait; @@ -22,12 +21,20 @@ use tokio::time::{sleep, timeout}; #[allow(dead_code)] pub enum PhpVersion { #[default] - Php85, Php84, Php83, Php82, Php81, Php80, + Php74, + Php73, + Php84Dbg, + Php83Dbg, + Php82Dbg, + Php81Dbg, + Php80Dbg, + Php74Dbg, + Php73Dbg, } pub const PHP_MEMORY_LIMIT: i64 = 2 * 1024 * 1024 * 1024; @@ -37,13 +44,24 @@ impl FromStr for PhpVersion { fn from_str(s: &str) -> Result { match s { - "8" => Ok(PhpVersion::Php80), + "7" => Ok(PhpVersion::Php74), + "7.3" => Ok(PhpVersion::Php73), + "7.4" => Ok(PhpVersion::Php74), + "8" => Ok(PhpVersion::Php81), "8.0" => Ok(PhpVersion::Php80), "8.1" => Ok(PhpVersion::Php81), "8.2" => Ok(PhpVersion::Php82), "8.3" => Ok(PhpVersion::Php83), "8.4" => Ok(PhpVersion::Php84), - "8.5" => Ok(PhpVersion::Php85), + "7-dbg" => Ok(PhpVersion::Php74Dbg), + "7.3-dbg" => Ok(PhpVersion::Php73Dbg), + "7.4-dbg" => Ok(PhpVersion::Php74Dbg), + "8-dbg" => Ok(PhpVersion::Php80Dbg), + "8.0-dbg" => Ok(PhpVersion::Php80Dbg), + "8.1-dbg" => Ok(PhpVersion::Php81Dbg), + "8.2-dbg" => Ok(PhpVersion::Php82Dbg), + "8.3-dbg" => Ok(PhpVersion::Php83Dbg), + "8.4-dbg" => Ok(PhpVersion::Php84Dbg), _ => Err(()), } } @@ -55,35 +73,53 @@ impl PhpVersion { } pub fn image(&self) -> &'static str { + // for now only 7.4 match self { + PhpVersion::Php73 => "icewind1991/haze:7.3", + PhpVersion::Php74 => "icewind1991/haze:7.4", PhpVersion::Php80 => "icewind1991/haze:8.0", PhpVersion::Php81 => "icewind1991/haze:8.1", PhpVersion::Php82 => "icewind1991/haze:8.2", PhpVersion::Php83 => "icewind1991/haze:8.3", PhpVersion::Php84 => "icewind1991/haze:8.4", - PhpVersion::Php85 => "icewind1991/haze:8.5", + PhpVersion::Php73Dbg => "icewind1991/haze:7.3-dbg", + PhpVersion::Php74Dbg => "icewind1991/haze:7.4-dbg", + PhpVersion::Php80Dbg => "icewind1991/haze:8.0-dbg", + PhpVersion::Php81Dbg => "icewind1991/haze:8.1-dbg", + PhpVersion::Php82Dbg => "icewind1991/haze:8.2-dbg", + PhpVersion::Php83Dbg => "icewind1991/haze:8.3-dbg", + PhpVersion::Php84Dbg => "icewind1991/haze:8.4-dbg", } } pub fn name(&self) -> &'static str { match self { + PhpVersion::Php73 => "7.3", + PhpVersion::Php74 => "7.4", PhpVersion::Php80 => "8.0", PhpVersion::Php81 => "8.1", PhpVersion::Php82 => "8.2", PhpVersion::Php83 => "8.3", PhpVersion::Php84 => "8.4", - PhpVersion::Php85 => "8.4", + PhpVersion::Php73Dbg => "7.3-dbg", + PhpVersion::Php74Dbg => "7.4-dbg", + PhpVersion::Php80Dbg => "8.0-dbg", + PhpVersion::Php81Dbg => "8.1-dbg", + PhpVersion::Php82Dbg => "8.2-dbg", + PhpVersion::Php83Dbg => "8.3-dbg", + PhpVersion::Php84Dbg => "8.4-dbg", } } pub fn from_number(major: u8, minor: u8) -> Option { match (major, minor) { + (7, 3) => Some(PhpVersion::Php73), + (7, 4) => Some(PhpVersion::Php74), (8, 0) => Some(PhpVersion::Php80), (8, 1) => Some(PhpVersion::Php81), (8, 2) => Some(PhpVersion::Php82), (8, 3) => Some(PhpVersion::Php83), (8, 4) => Some(PhpVersion::Php84), - (8, 5) => Some(PhpVersion::Php85), _ => None, } } @@ -91,19 +127,27 @@ impl PhpVersion { pub fn max_minor(major: u8) -> u8 { match major { 7 => 4, - 8 => 5, + 8 => 4, _ => 0, } } pub fn all() -> impl Iterator { [ + PhpVersion::Php73, + PhpVersion::Php74, PhpVersion::Php80, PhpVersion::Php81, PhpVersion::Php82, PhpVersion::Php83, PhpVersion::Php84, - PhpVersion::Php85, + PhpVersion::Php73Dbg, + PhpVersion::Php74Dbg, + PhpVersion::Php80Dbg, + PhpVersion::Php81Dbg, + PhpVersion::Php82Dbg, + PhpVersion::Php83Dbg, + PhpVersion::Php84Dbg, ] .into_iter() } @@ -124,17 +168,6 @@ impl PhpVersion { ) -> Result { ensure_network_exists(docker, "haze").await?; pull_image(docker, self.image()).await?; - - let image_version = image_version(docker, self.image()).await; - let haze_version = ImageVersion::from_str(env!("CARGO_PKG_VERSION")); - if let (Some(image_version), Ok(haze_version)) = (image_version, haze_version) { - if image_version < haze_version { - eprintln!("{}: image version is out of date, run {} to update.", "Warning".red(), "haze update".blue()); - eprintln!(" Haze version: {}", haze_version.bright_yellow()); - eprintln!(" Image version: {}", image_version.bright_yellow()); - } - } - let options = Some(CreateContainerOptions { name: Some(id.to_string()), ..CreateContainerOptions::default() @@ -160,11 +193,6 @@ impl PhpVersion { proxy_config.addr(id, IpAddr::V4(Ipv4Addr::LOCALHOST)) )); - env.push(format!("HOST_IP={host}")); - if !proxy_config.address.is_empty() { - env.push(format!("PROXY_BASE={}", proxy_config.address)); - } - let mut labels = hashmap! { "haze-type".to_string() => "cloud".to_string(), "haze-db".to_string() => db.name().to_string(), diff --git a/src/proxy.rs b/src/proxy.rs index 4784a18..ee867c9 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -1,43 +1,34 @@ -use crate::service::{ServiceTrait, ServiceType}; +use crate::service::ServiceTrait; use crate::Result; use crate::{Cloud, HazeConfig}; use axum::http::header::HOST; use axum::http::HeaderValue; use axum::{ body::Body, - extract::Request, + extract::{Request, State}, response::{IntoResponse, Response}, + Router, }; use bollard::Docker; -use futures_util::StreamExt; -use hyper::body::Incoming; -use hyper::server::conn::http1; -use hyper::service::service_fn; use hyper::StatusCode; -use hyper_util::rt::TokioIo; use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; use miette::{miette, IntoDiagnostic}; use std::collections::HashMap; -use std::convert::Infallible; use std::fs::{create_dir_all, set_permissions}; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; -use std::pin::pin; -use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::Duration; -use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::UnixListener; use tokio::signal::ctrl_c; use tokio::spawn; use tokio::time::sleep; -use tokio_stream::wrappers::{TcpListenerStream, UnixListenerStream}; use tracing::{debug, error, info}; struct ActiveInstances { known: Mutex>, - last: Mutex>, + last: Mutex>, docker: Docker, config: HazeConfig, } @@ -57,9 +48,15 @@ impl ActiveInstances { return Some(ip); } - let addr = if ServiceType::from_str(name).is_ok() { - let cloud = self.last()?; - let service = cloud.services().find(|service| service.name() == name)?; + // service proxy + let addr = if name.matches('-').count() == 2 { + let (name, service_name) = name.rsplit_once('-').unwrap(); + let cloud = Cloud::get_by_filter(&self.docker, Some(name.into()), &self.config) + .await + .ok()?; + let service = cloud + .services() + .find(|service| service.name() == service_name)?; let ip = service .get_ips(&self.docker, &cloud.id) .await @@ -67,34 +64,13 @@ impl ActiveInstances { .next()?; SocketAddr::new(ip, service.proxy_port()) } else { - match name.matches('-').count() { - // instance - 1 => SocketAddr::new( - Cloud::get_by_filter(&self.docker, Some(name.into()), &self.config) - .await - .ok()? - .ip?, - 80, - ), - // service with instance - 2.. => { - let service_name = name.splitn(3, '-').last()?; - let name = &name[0..(name.len() - service_name.len() - 1)]; - let cloud = Cloud::get_by_filter(&self.docker, Some(name.into()), &self.config) - .await - .ok()?; - let service = cloud - .services() - .find(|service| service.name() == service_name)?; - let ip = service - .get_ips(&self.docker, &cloud.id) - .await - .ok()? - .next()?; - SocketAddr::new(ip, service.proxy_port()) - } - _ => return None, - } + SocketAddr::new( + Cloud::get_by_filter(&self.docker, Some(name.into()), &self.config) + .await + .ok()? + .ip?, + 80, + ) }; println!("{name} => {addr}"); @@ -103,31 +79,18 @@ impl ActiveInstances { Some(addr) } - pub fn last_addr(&self) -> Option { - self.last - .lock() - .unwrap() - .as_ref() - .and_then(|cloud| Some(SocketAddr::new(cloud.ip?, 80))) - } - - pub fn last(&self) -> Option { - self.last.lock().unwrap().clone() + pub fn last(&self) -> Option { + *self.last.lock().unwrap() } async fn update_last(&self) { let last = Cloud::get_by_filter(&self.docker, None, &self.config) .await - .ok(); + .ok() + .and_then(|cloud| Some(SocketAddr::new(cloud.ip?, 80))); let mut old = self.last.lock().unwrap(); if old.as_ref() != last.as_ref() { info!(instance = ?last, "Found new instance"); - - // remove cached base-service mappings - self.known - .lock() - .unwrap() - .retain(|key, _| ServiceType::from_str(key).is_err()); *old = last; } } @@ -171,26 +134,20 @@ async fn serve(instances: ActiveInstances, listen: String, base_address: String) ctrl_c().await.ok(); }; - let state = AppState { + let app = Router::new().fallback(handler).with_state(AppState { instances: instances.clone(), base_address: base_address.clone(), proxy_client: Arc::new(proxy_client), - }; + }); if !listen.starts_with('/') { let addr: SocketAddr = listen.parse().into_diagnostic()?; let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); println!("listening on {}", listener.local_addr().unwrap()); - let mut connections = pin!(TcpListenerStream::new(listener).take_until(cancel)); - - while let Some(stream) = connections.next().await { - match stream { - Ok(stream) => handle_connection(state.clone(), stream), - Err(error) => { - error!(%error, "connection failed"); - } - } - } + axum::serve(listener, app) + .with_graceful_shutdown(cancel) + .await + .unwrap(); } else { let listen: PathBuf = listen.into(); if let Some(parent) = listen.parent() { @@ -201,42 +158,18 @@ async fn serve(instances: ActiveInstances, listen: String, base_address: String) } let _ = tokio::fs::remove_file(&listen).await; - let listener = UnixListener::bind(&listen).unwrap(); - println!("listening on {}", listen.display()); + let uds = UnixListener::bind(&listen).unwrap(); set_permissions(&listen, PermissionsExt::from_mode(0o666)).into_diagnostic()?; - let mut connections = pin!(UnixListenerStream::new(listener).take_until(cancel)); - - while let Some(stream) = connections.next().await { - match stream { - Ok(stream) => handle_connection(state.clone(), stream), - Err(error) => { - error!(%error, "connection failed"); - } - } - } + axum::serve(uds, app) + .with_graceful_shutdown(cancel) + .await + .unwrap(); } Ok(()) } -fn handle_connection( - state: AppState, - stream: I, -) { - let io = TokioIo::new(stream); - // Spawn a tokio task to serve multiple connections concurrently - tokio::task::spawn(async move { - if let Err(err) = http1::Builder::new() - .serve_connection(io, service_fn(move |req| handler(state.clone(), req))) - .with_upgrades() - .await - { - eprintln!("Error serving connection: {:?}", err); - } - }); -} - async fn get_remote( host: Option<&HeaderValue>, instances: &ActiveInstances, @@ -248,7 +181,7 @@ async fn get_remote( }; let ip = if host == base_address { instances - .last_addr() + .last() .ok_or_else(|| String::from("No running instance known")) } else { let requested_instance = host.split('.').next().unwrap(); @@ -270,9 +203,9 @@ async fn get_remote( } } -type Client = hyper_util::client::legacy::Client; +type Client = hyper_util::client::legacy::Client; -async fn handler(state: AppState, mut req: Request) -> Result { +async fn handler(State(state): State, mut req: Request) -> Result { let host = req.headers().get(HOST).cloned(); let remote = match get_remote(host.as_ref(), &state.instances, &state.base_address).await { Ok(remote) => remote, @@ -297,13 +230,13 @@ async fn handler(state: AppState, mut req: Request) -> Result Ok(response.map(Body::new)), Err(error) => { - error!(?error, "error while proxying request"); + error!(%error, "error while proxying request"); Ok(StatusCode::BAD_REQUEST.into_response()) } } diff --git a/src/service.rs b/src/service.rs index c514449..8874352 100644 --- a/src/service.rs +++ b/src/service.rs @@ -14,10 +14,9 @@ mod sftp; mod redis; mod sharded; mod smb; -mod webhook; use crate::cloud::CloudOptions; -use crate::config::{HazeConfig, Preset, ProxyConfig}; +use crate::config::{HazeConfig, Preset}; pub use crate::service::clam::{Clam, ClamIcap, ClamIcapTls, ClamSocket}; use crate::service::dav::Dav; use crate::service::imaginary::Imaginary; @@ -30,10 +29,9 @@ pub use crate::service::office::Office; pub use crate::service::onlyoffice::OnlyOffice; pub use crate::service::push::NotifyPush; use crate::service::redis::Redis; -use crate::service::sftp::{Sftp, SftpKey}; +use crate::service::sftp::Sftp; use crate::service::sharded::{Sharding, ShardingMigrate, ShardingMigrateUnset, SingleShard}; use crate::service::smb::Smb; -use crate::service::webhook::Webhook; use bollard::models::ContainerState; use bollard::Docker; use enum_dispatch::enum_dispatch; @@ -80,12 +78,7 @@ pub trait ServiceTrait { None } - async fn start_message( - &self, - _docker: &Docker, - _cloud_id: &str, - _proxy: &ProxyConfig, - ) -> Result> { + async fn start_message(&self, _docker: &Docker, _cloud_id: &str) -> Result> { Ok(None) } @@ -102,21 +95,12 @@ pub trait ServiceTrait { Ok(HashMap::default()) } - fn pre_setup( - &self, - _docker: &Docker, - _cloud_id: &str, - _config: &HazeConfig, - ) -> Result>> { - Ok(Vec::new()) - } - async fn post_setup( &self, _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(Vec::new()) } @@ -194,14 +178,6 @@ pub trait ServiceTrait { fn proxy_port(&self) -> u16 { 80 } - - fn exec_user(&self) -> &'static str { - "root" - } - - fn exec_shell(&self) -> &'static str { - "bash" - } } #[derive(Clone, Eq, PartialEq, Debug)] @@ -217,19 +193,6 @@ impl ServiceTrait for RedisTls { } } -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct FrankenPhp; - -impl ServiceTrait for FrankenPhp { - fn name(&self) -> &str { - "franken-php" - } - - fn env(&self) -> &[&str] { - &["FRANKENPHP=1"] - } -} - #[derive( Copy, Clone, Debug, PartialEq, EnumString, EnumMessage, EnumIter, IntoStaticStr, Display, )] @@ -237,8 +200,6 @@ impl ServiceTrait for FrankenPhp { pub enum ServiceType { /// S3 Primary storage and external storage S3, - /// S3 Primary storage with TLS - S3s, /// S3 multi-object store Primary storage and external storage S3m, /// S3 multi-bucket Primary storage and external storage @@ -247,10 +208,7 @@ pub enum ServiceType { Azure, /// Ldap user backend Ldap, - /// Ldap admin interface - LdapAdmin, /// OnlyOffice - #[strum(serialize = "onlyoffice", serialize = "only-office")] OnlyOffice, /// Libre office online Office, @@ -276,8 +234,6 @@ pub enum ServiceType { Dav, /// Sftp external storage Sftp, - /// Sftp external storage with public key authentication - SftpKey, /// ownCloud instance for migration Oc, /// Imaginary for preview generation @@ -307,10 +263,6 @@ pub enum ServiceType { Redis, /// External redis instance with TLS RedisTls, - /// Use FrankenPHP instead of PHP-FPM - FrankenPhp, - /// Webhook test listener - Webhook, } #[enum_dispatch] @@ -329,7 +281,6 @@ pub enum Service { ShardingMigrate(ShardingMigrate), ShardingMigrateUnset(ShardingMigrateUnset), Sftp(Sftp), - SftpKey(SftpKey), Kaspersky(Kaspersky), KasperskyIcap(KasperskyIcap), Clam(Clam), @@ -341,8 +292,6 @@ pub enum Service { Mail(Mail), Redis(Redis), RedisTls(RedisTls), - FrankenPhp(FrankenPhp), - Webhook(Webhook), Preset(PresetService), } @@ -351,14 +300,10 @@ impl Service { if let Ok(ty) = ServiceType::from_str(ty) { match ty { ServiceType::S3 => Some(vec![Service::ObjectStore(ObjectStore::S3)]), - ServiceType::S3s => Some(vec![Service::ObjectStore(ObjectStore::S3s)]), ServiceType::S3m => Some(vec![Service::ObjectStore(ObjectStore::S3m)]), ServiceType::S3mb => Some(vec![Service::ObjectStore(ObjectStore::S3mb)]), ServiceType::Azure => Some(vec![Service::ObjectStore(ObjectStore::Azure)]), ServiceType::Ldap => Some(vec![Service::Ldap(Ldap), Service::LdapAdmin(LdapAdmin)]), - ServiceType::LdapAdmin => { - Some(vec![Service::Ldap(Ldap), Service::LdapAdmin(LdapAdmin)]) - } ServiceType::OnlyOffice => Some(vec![Service::OnlyOffice(OnlyOffice)]), ServiceType::Office => Some(vec![Service::Office(Office)]), ServiceType::Push => Some(vec![Service::Push(NotifyPush)]), @@ -373,7 +318,6 @@ impl Service { } ServiceType::Dav => Some(vec![Service::Dav(Dav)]), ServiceType::Sftp => Some(vec![Service::Sftp(Sftp)]), - ServiceType::SftpKey => Some(vec![Service::SftpKey(SftpKey)]), ServiceType::Oc => Some(vec![Service::Oc(Oc)]), ServiceType::Imaginary => Some(vec![Service::Imaginary(Imaginary)]), ServiceType::Kaspersky => Some(vec![Service::Kaspersky(Kaspersky)]), @@ -386,8 +330,6 @@ impl Service { ServiceType::Mail => Some(vec![Service::Mail(Mail)]), ServiceType::Redis => Some(vec![Service::Redis(Redis)]), ServiceType::RedisTls => Some(vec![Service::RedisTls(RedisTls)]), - ServiceType::FrankenPhp => Some(vec![Service::FrankenPhp(FrankenPhp)]), - ServiceType::Webhook => Some(vec![Service::Webhook(Webhook)]), } } else { presets @@ -450,29 +392,15 @@ impl ServiceTrait for PresetService { _docker: &Docker, _cloud_id: &str, config: &HazeConfig, - ) -> Result>> { + ) -> Result> { let preset = get_preset(&config.preset, &self.0).ok_or_else(|| Report::msg("invalid preset"))?; let mut commands: Vec<_> = preset .apps .iter() - .map(|app| { - vec![ - "occ".into(), - "app:enable".into(), - app.clone(), - "--force".into(), - ] - }) + .map(|app| format!("occ app:enable {app} --force")) .collect(); - for cmnd in &preset.commands { - commands.push(shell_words::split(cmnd).into_diagnostic()?); - } - + commands.extend_from_slice(&preset.commands); Ok(commands) } } - -fn split_cmnd(s: &str) -> Vec { - s.split(' ').map(String::from).collect() -} diff --git a/src/service/clam.rs b/src/service/clam.rs index 7221309..74b790d 100644 --- a/src/service/clam.rs +++ b/src/service/clam.rs @@ -2,7 +2,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::exec::exec; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig}; use bollard::query_parameters::CreateContainerOptions; @@ -85,13 +85,14 @@ impl ServiceTrait for ClamIcap { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ config:app:set files_antivirus av_mode --value=icap"), - split_cmnd("occ config:app:set files_antivirus av_host --value=clamav-icap"), - split_cmnd("occ config:app:set files_antivirus av_port --value=1344"), - split_cmnd("occ config:app:set files_antivirus av_icap_request_service --value=avscan"), - split_cmnd("occ config:app:set files_antivirus av_icap_response_header --value=X-Infection-Found"), + "occ config:app:set files_antivirus av_mode --value=icap".into(), + "occ config:app:set files_antivirus av_host --value=clamav-icap".into(), + "occ config:app:set files_antivirus av_port --value=1344".into(), + "occ config:app:set files_antivirus av_icap_request_service --value=avscan".into(), + "occ config:app:set files_antivirus av_icap_response_header --value=X-Infection-Found" + .into(), ]) } } @@ -170,7 +171,7 @@ impl ServiceTrait for ClamIcapTls { docker: &Docker, cloud_id: &str, config: &HazeConfig, - ) -> Result>> { + ) -> Result> { let mut cert = Vec::new(); exec( docker, @@ -190,13 +191,14 @@ impl ServiceTrait for ClamIcapTls { .wrap_err("Failed to write icap certificate")?; Ok(vec![ - split_cmnd("occ config:app:set files_antivirus av_mode --value=icap"), - split_cmnd("occ config:app:set files_antivirus av_icap_tls --value=1"), - split_cmnd("occ config:app:set files_antivirus av_host --value=clamav-icap-tls"), - split_cmnd("occ config:app:set files_antivirus av_port --value=1345"), - split_cmnd("occ config:app:set files_antivirus av_icap_request_service --value=avscan"), - split_cmnd("occ config:app:set files_antivirus av_icap_response_header --value=X-Infection-Found"), - split_cmnd("occ security:certificates:import data/icap-cert.pem"), + "occ config:app:set files_antivirus av_mode --value=icap".into(), + "occ config:app:set files_antivirus av_icap_tls --value=1".into(), + "occ config:app:set files_antivirus av_host --value=clamav-icap-tls".into(), + "occ config:app:set files_antivirus av_port --value=1345".into(), + "occ config:app:set files_antivirus av_icap_request_service --value=avscan".into(), + "occ config:app:set files_antivirus av_icap_response_header --value=X-Infection-Found" + .into(), + "occ security:certificates:import data/icap-cert.pem".into(), ]) } } @@ -219,10 +221,10 @@ impl ServiceTrait for Clam { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ config:app:set files_antivirus av_mode --value=executable"), - split_cmnd("occ config:app:set files_antivirus av_path --value=/bin/clamscan"), + "occ config:app:set files_antivirus av_mode --value=executable".into(), + "occ config:app:set files_antivirus av_path --value=/bin/clamscan".into(), ]) } } @@ -292,12 +294,10 @@ impl ServiceTrait for ClamSocket { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ config:app:set files_antivirus av_mode --value=socket"), - split_cmnd( - "occ config:app:set files_antivirus av_socket --value=tcp://clamav-socket:3310", - ), + "occ config:app:set files_antivirus av_mode --value=socket".into(), + "occ config:app:set files_antivirus av_socket --value=tcp://clamav-socket:3310".into(), ]) } } diff --git a/src/service/dav.rs b/src/service/dav.rs index e0b20f3..d328925 100644 --- a/src/service/dav.rs +++ b/src/service/dav.rs @@ -1,7 +1,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::config::ContainerCreateBody; use bollard::models::{EndpointSettings, HostConfig, NetworkingConfig}; @@ -76,12 +76,12 @@ impl ServiceTrait for Dav { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ files_external:create dav dav password::password"), - split_cmnd("occ files_external:config 1 host dav"), - split_cmnd("occ files_external:config 1 user test"), - split_cmnd("occ files_external:config 1 password test"), + "occ files_external:create dav dav password::password".into(), + "occ files_external:config 1 host dav".into(), + "occ files_external:config 1 user test".into(), + "occ files_external:config 1 password test".into(), ]) } } diff --git a/src/service/imaginary.rs b/src/service/imaginary.rs index 4ec4d96..693c173 100644 --- a/src/service/imaginary.rs +++ b/src/service/imaginary.rs @@ -1,7 +1,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::config::NetworkingConfig; use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig}; @@ -71,14 +71,11 @@ impl ServiceTrait for Imaginary { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd( - "occ config:system:set enabledPreviewProviders 0 --value='OC\\Preview\\Imaginary'", - ), - split_cmnd( - "occ config:system:set preview_imaginary_url --value='http://imaginary:9000'", - ), + "occ config:system:set enabledPreviewProviders 0 --value='OC\\Preview\\Imaginary'" + .into(), + "occ config:system:set preview_imaginary_url --value='http://imaginary:9000'".into(), ]) } } diff --git a/src/service/kaspersky.rs b/src/service/kaspersky.rs index 1c0a67f..bc4f08a 100644 --- a/src/service/kaspersky.rs +++ b/src/service/kaspersky.rs @@ -2,7 +2,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::exec::exec; use crate::image::{image_exists, pull_image}; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig}; use bollard::query_parameters::CreateContainerOptions; @@ -101,11 +101,11 @@ impl ServiceTrait for Kaspersky { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ config:app:set files_antivirus av_mode --value=kaspersky"), - split_cmnd("occ config:app:set files_antivirus av_host --value=kaspersky"), - split_cmnd("occ config:app:set files_antivirus av_port --value=80"), + "occ config:app:set files_antivirus av_mode --value=kaspersky".into(), + "occ config:app:set files_antivirus av_host --value=kaspersky".into(), + "occ config:app:set files_antivirus av_port --value=80".into(), ]) } } @@ -187,15 +187,13 @@ impl ServiceTrait for KasperskyIcap { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ config:app:set files_antivirus av_mode --value=icap"), - split_cmnd("occ config:app:set files_antivirus av_host --value=kaspersky-icap"), - split_cmnd("occ config:app:set files_antivirus av_port --value=1344"), - split_cmnd("occ config:app:set files_antivirus av_icap_request_service --value=req"), - split_cmnd( - "occ config:app:set files_antivirus av_icap_response_header --value=X-Virus-ID", - ), + "occ config:app:set files_antivirus av_mode --value=icap".into(), + "occ config:app:set files_antivirus av_host --value=kaspersky-icap".into(), + "occ config:app:set files_antivirus av_port --value=1344".into(), + "occ config:app:set files_antivirus av_icap_request_service --value=req".into(), + "occ config:app:set files_antivirus av_icap_response_header --value=X-Virus-ID".into(), ]) } } diff --git a/src/service/ldap.rs b/src/service/ldap.rs index 4f317e6..7526918 100644 --- a/src/service/ldap.rs +++ b/src/service/ldap.rs @@ -1,7 +1,7 @@ use crate::cloud::CloudOptions; -use crate::config::{HazeConfig, ProxyConfig}; +use crate::config::HazeConfig; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::config::NetworkingConfig; use bollard::models::{ContainerCreateBody, ContainerState, EndpointSettings, HostConfig}; @@ -9,8 +9,6 @@ use bollard::query_parameters::CreateContainerOptions; use bollard::Docker; use maplit::hashmap; use miette::{IntoDiagnostic, Report}; -use std::net::IpAddr; -use std::str::FromStr; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Ldap; @@ -86,46 +84,6 @@ impl ServiceTrait for Ldap { ) -> Result { self.is_running(docker, cloud_id).await } - - async fn post_setup( - &self, - _docker: &Docker, - _cloud_id: &str, - _config: &HazeConfig, - ) -> Result>> { - Ok(vec![ - split_cmnd("occ ldap:create-empty-config"), - split_cmnd("occ ldap:set-config s01 ldapHost ldap://ldap"), - split_cmnd("occ ldap:set-config s01 ldapPort 389"), - split_cmnd("occ ldap:set-config s01 ldapAgentName cn=admin,dc=example,dc=org"), - split_cmnd("occ ldap:set-config s01 ldapAgentPassword haze"), - split_cmnd("occ ldap:set-config s01 ldapBase dc=example,dc=org"), - split_cmnd("occ ldap:set-config s01 ldapBaseUsers dc=example,dc=org"), - split_cmnd("occ ldap:set-config s01 ldapBaseGroups dc=example,dc=org"), - split_cmnd("occ ldap:set-config s01 ldapLoginFilter (&(&(objectclass=inetOrgPerson))(uid=%uid))"), - split_cmnd("occ ldap:set-config s01 ldapUserFilter ((objectclass=inetOrgPerson))"), - split_cmnd("occ ldap:set-config s01 ldapUserFilterMode 0"), - split_cmnd("occ ldap:set-config s01 ldapUserDisplayName sn"), - split_cmnd("occ ldap:set-config s01 ldapUserFilterObjectclass inetOrgPerson"), - split_cmnd("occ ldap:set-config s01 ldapGroupFilter (&(|(objectclass=posixGroup)))"), - split_cmnd("occ ldap:set-config s01 ldapGroupFilterObjectclass posixGroup"), - split_cmnd("occ ldap:set-config s01 ldapEmailAttribute email"), - split_cmnd("occ ldap:set-config s01 ldapUuidUserAttribute email"), - split_cmnd("occ ldap:set-config s01 ldapUuidUserAttribute auto"), - split_cmnd("occ ldap:set-config s01 ldapUuidGroupAttribute auto"), - split_cmnd("occ ldap:set-config s01 ldapLoginFilterUsername 1"), - split_cmnd("occ ldap:set-config s01 ldapConfigurationActive 1"), - ]) - } - - async fn start_message( - &self, - _docker: &Docker, - _cloud_id: &str, - _proxy: &ProxyConfig, - ) -> Result> { - Ok(Some("\nLdap users provisioned:\n\t'cn=admin,dc=example,dc=org' and password 'haze'\n\t'cn=ldaptest,dc=example,dc=org' and password 'test'\n\nldaptest is available for login\n".into())) - } } #[derive(Debug, Clone, Eq, PartialEq)] @@ -157,10 +115,7 @@ impl ServiceTrait for LdapAdmin { }); let config = ContainerCreateBody { image: Some(image.into()), - env: Some(vec![ - "PHPLDAPADMIN_LDAP_HOSTS=ldap".into(), - "PHPLDAPADMIN_HTTPS=false".into(), - ]), + env: Some(vec!["PHPLDAPADMIN_LDAP_HOSTS=ldap".into()]), host_config: Some(HostConfig { network_mode: Some(network.to_string()), ..Default::default() @@ -193,15 +148,9 @@ impl ServiceTrait for LdapAdmin { Some(format!("{}-ldap-admin", cloud_id)) } - async fn start_message( - &self, - docker: &Docker, - cloud_id: &str, - proxy: &ProxyConfig, - ) -> Result> { - let id = self.container_name(cloud_id).unwrap(); + async fn start_message(&self, docker: &Docker, cloud_id: &str) -> Result> { let info = docker - .inspect_container(&id, None) + .inspect_container(&self.container_name(cloud_id).unwrap(), None) .await .into_diagnostic()?; let ip = if matches!( @@ -224,7 +173,9 @@ impl ServiceTrait for LdapAdmin { } else { return Err(Report::msg("ldap admin not started")); }; - let addr = proxy.addr(&id, IpAddr::from_str(&ip).unwrap()); - Ok(Some(format!("Ldap admin running at: {addr}"))) + Ok(Some(format!( + "Ldap admin running at: https://{} with 'cn=admin,dc=example,dc=org' and password 'haze'", + ip + ))) } } diff --git a/src/service/mail.rs b/src/service/mail.rs index ad40471..c52fdac 100644 --- a/src/service/mail.rs +++ b/src/service/mail.rs @@ -1,7 +1,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig}; use bollard::query_parameters::CreateContainerOptions; @@ -70,14 +70,14 @@ impl ServiceTrait for Mail { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ config:system:set mail_smtpmode --value smtp"), - split_cmnd("occ config:system:set mail_sendmailmode --value smtp"), - split_cmnd("occ config:system:set mail_domain --value haze"), - split_cmnd("occ config:system:set mail_smtphost --value mail"), - split_cmnd("occ config:system:set mail_smtpport --value 25"), - split_cmnd("occ user:setting admin settings email admin@haze"), + "occ config:system:set mail_smtpmode --value smtp".into(), + "occ config:system:set mail_sendmailmode --value smtp".into(), + "occ config:system:set mail_domain --value haze".into(), + "occ config:system:set mail_smtphost --value mail".into(), + "occ config:system:set mail_smtpport --value 25".into(), + "occ user:setting admin settings email admin@haze".into(), ]) } } diff --git a/src/service/objectstore.rs b/src/service/objectstore.rs index 20e586c..2225dca 100644 --- a/src/service/objectstore.rs +++ b/src/service/objectstore.rs @@ -2,7 +2,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::exec::exec; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ ContainerCreateBody, ContainerState, EndpointSettings, HostConfig, NetworkingConfig, @@ -10,15 +10,11 @@ use bollard::models::{ use bollard::query_parameters::CreateContainerOptions; use bollard::Docker; use maplit::hashmap; -use miette::{IntoDiagnostic, WrapErr}; -use serde_json::Value; -use std::collections::HashMap; -use std::fs::{create_dir_all, write}; +use miette::IntoDiagnostic; #[derive(Debug, Clone, Eq, PartialEq)] pub enum ObjectStore { S3, - S3s, S3m, S3mb, Azure, @@ -27,7 +23,7 @@ pub enum ObjectStore { impl ObjectStore { fn image(&self) -> &str { match self { - ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => { + ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb => { "minio/minio:RELEASE.2024-07-16T23-46-41Z" } ObjectStore::Azure => "arafato/azurite:2.6.5", @@ -36,7 +32,7 @@ impl ObjectStore { fn self_env(&self) -> Vec<&str> { match self { - ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => { + ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb => { vec!["MINIO_ACCESS_KEY=minio", "MINIO_SECRET_KEY=minio123"] } ObjectStore::Azure => vec![], @@ -45,54 +41,17 @@ impl ObjectStore { fn host_name(&self) -> &str { match self { - ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => "s3", + ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb => "s3", ObjectStore::Azure => "azure", } } fn args(&self) -> &[&str] { match self { - ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => { - &["server", "/data"] - } + ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb => &["server", "/data"], _ => &[], } } - - fn volumes(&self, config: &HazeConfig) -> Option> { - match self { - ObjectStore::S3s => { - let cert_dir = config.work_dir.join("certificates/s3"); - create_dir_all(&cert_dir) - .into_diagnostic() - .wrap_err("Failed to create redis certificate directory") - .unwrap(); - let s3_cert_path = config.work_dir.join("certificates/s3/public.crt"); - let s3_key_path = config.work_dir.join("certificates/s3/private.key"); - if !s3_cert_path.exists() { - write( - &s3_cert_path, - include_bytes!("../../certificates/s3/public.crt"), - ) - .into_diagnostic() - .wrap_err("Failed to write s3 certificate") - .unwrap(); - } - if !s3_key_path.exists() { - write( - &s3_key_path, - include_bytes!("../../certificates/s3/private.key"), - ) - .into_diagnostic() - .wrap_err("Failed to write s3 key") - .unwrap(); - } - - Some(vec![format!("{cert_dir}:/root/.minio/certs:ro")]) - } - _ => None, - } - } } #[async_trait::async_trait] @@ -100,7 +59,6 @@ impl ServiceTrait for ObjectStore { fn name(&self) -> &str { match self { ObjectStore::S3 => "s3", - ObjectStore::S3s => "s3s", ObjectStore::S3m => "s3m", ObjectStore::S3mb => "s3mb", ObjectStore::Azure => "azure", @@ -110,9 +68,8 @@ impl ServiceTrait for ObjectStore { fn env(&self) -> &[&str] { match self { ObjectStore::S3 => &["S3=1"], - ObjectStore::S3s => &["S3S=1"], ObjectStore::S3m => &["S3M=1"], - ObjectStore::S3mb => &["S3MB =1"], + ObjectStore::S3mb => &["S3MB=1"], ObjectStore::Azure => &["AZURE=1"], } } @@ -122,7 +79,7 @@ impl ServiceTrait for ObjectStore { docker: &Docker, cloud_id: &str, network: &str, - config: &HazeConfig, + _config: &HazeConfig, _options: &CloudOptions, ) -> Result> { pull_image(docker, self.image()).await?; @@ -135,7 +92,6 @@ impl ServiceTrait for ObjectStore { env: Some(self.self_env().into_iter().map(String::from).collect()), host_config: Some(HostConfig { network_mode: Some(network.to_string()), - binds: self.volumes(config), ..Default::default() }), labels: Some(hashmap! { @@ -209,76 +165,26 @@ impl ServiceTrait for ObjectStore { &["files_external"] } - fn config( - &self, - _docker: &Docker, - _cloud_id: &str, - _config: &HazeConfig, - ) -> Result> { - match self { - ObjectStore::S3s => Ok(hashmap![ - "default_certificates_bundle_path".into() => Value::String("/var/www/html/data/ca-bundle.crt".into()), - ]), - _ => Ok(HashMap::default()), - } - } - - fn pre_setup( - &self, - _docker: &Docker, - _cloud_id: &str, - _config: &HazeConfig, - ) -> Result>> { - match self { - ObjectStore::S3s => Ok(vec![ - vec!["mkdir".into(), "-p".into(), "/var/www/html/data".into()], - vec![ - "sh".into(), - "-c".into(), - "cat /var/www/html/resources/config/ca-bundle.crt /certificates/s3/public.crt > /var/www/html/data/ca-bundle.crt".into(), - ], - ]), - _ => Ok(Vec::new()), - } - } - async fn post_setup( &self, _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { - match self { - ObjectStore::S3 => Ok(vec![ - split_cmnd("occ files_external:create s3 amazons3 amazons3::accesskey"), - split_cmnd("occ files_external:config 1 bucket ext"), - split_cmnd("occ files_external:config 1 hostname s3"), - split_cmnd("occ files_external:config 1 port 9000"), - split_cmnd("occ files_external:config 1 use_ssl false"), - split_cmnd("occ files_external:config 1 use_path_style true"), - split_cmnd("occ files_external:config 1 key minio"), - split_cmnd("occ files_external:config 1 secret minio123"), - split_cmnd("mc alias set s3 http://s3:9000 minio minio123"), - ]), - // ObjectStore::S3s => Ok(vec![ - // "occ files_external:create s3 amazons3 amazons3::accesskey".into(), - // "occ files_external:config 1 bucket ext".into(), - // "occ files_external:config 1 hostname s3".into(), - // "occ files_external:config 1 port 9000".into(), - // "occ files_external:config 1 use_ssl true".into(), - // "occ files_external:config 1 use_path_style true".into(), - // "occ files_external:config 1 key minio".into(), - // "occ files_external:config 1 secret minio123".into(), - // "mc alias set s3 https://s3:9000 minio minio123".into(), - // ]), - _ => Ok(Vec::new()), - } - } - - fn proxy_port(&self) -> u16 { - match self { - ObjectStore::S3 | ObjectStore::S3m | ObjectStore::S3mb | ObjectStore::S3s => 9000, - ObjectStore::Azure => 10000, + ) -> Result> { + if *self == ObjectStore::S3 { + Ok(vec![ + "occ files_external:create s3 amazons3 amazons3::accesskey".into(), + "occ files_external:config 1 bucket ext".into(), + "occ files_external:config 1 hostname s3".into(), + "occ files_external:config 1 port 9000".into(), + "occ files_external:config 1 use_ssl false".into(), + "occ files_external:config 1 use_path_style true".into(), + "occ files_external:config 1 key minio".into(), + "occ files_external:config 1 secret minio123".into(), + "mc alias set s3 http://s3:9000 minio minio123".into(), + ]) + } else { + Ok(Vec::new()) } } } diff --git a/src/service/oc.rs b/src/service/oc.rs index 296b2a5..2eb3a22 100644 --- a/src/service/oc.rs +++ b/src/service/oc.rs @@ -83,7 +83,7 @@ impl ServiceTrait for Oc { docker: &Docker, cloud_id: &str, config: &HazeConfig, - ) -> Result>> { + ) -> Result> { if let Some(ip) = self.get_ips(docker, cloud_id).await?.next() { let container = self.container_name(cloud_id).unwrap(); let addr = config.proxy.addr(&container, ip); diff --git a/src/service/office.rs b/src/service/office.rs index e7db10d..4cd72c9 100644 --- a/src/service/office.rs +++ b/src/service/office.rs @@ -32,23 +32,6 @@ impl ServiceTrait for Office { config: &HazeConfig, _options: &CloudOptions, ) -> Result> { - let network_info = docker - .inspect_network(network, None) - .await - .into_diagnostic()?; - let gateway = network_info - .ipam - .as_ref() - .ok_or_else(|| Report::msg("Network has no ip info"))? - .config - .as_deref() - .ok_or_else(|| Report::msg("Network has no ip info"))? - .first() - .ok_or_else(|| Report::msg("Network has no ip info"))? - .gateway - .as_deref() - .ok_or_else(|| Report::msg("Network has no ip info"))?; - let image = "collabora/code"; pull_image(docker, image).await?; let container_id = self.container_name(cloud_id).unwrap(); @@ -56,31 +39,28 @@ impl ServiceTrait for Office { name: Some(container_id.clone()), ..CreateContainerOptions::default() }); - let mut env = - vec![r#"extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:net.frame_ancestors=*"#.to_string()]; + let mut env = vec!["extra_params=--o:ssl.enable=false --o:ssl.termination=true"]; - let proxy_base = &config.proxy.address; let clean_id = container_id.strip_prefix("haze-").unwrap_or(&container_id); - if !proxy_base.is_empty() { - env.push(format!("server_name={clean_id}.{}", config.proxy.address)); - } - - let clean_cloud_id = cloud_id.strip_prefix("haze-").unwrap_or(cloud_id); - let hosts = if proxy_base.is_empty() { - vec![] - } else { - vec![ - format!("{proxy_base}:{gateway}"), - format!("{clean_cloud_id}.{proxy_base}:{gateway}"), - ] + let server_name_opt = match (&config.proxy.address, config.proxy.https) { + (public, true) if !public.is_empty() => { + format!("server_name={clean_id}.{public}") + } + (public, false) if !public.is_empty() => { + format!("server_name={clean_id}.{public}") + } + _ => "".to_string(), }; + if !server_name_opt.is_empty() { + env.push(&server_name_opt); + } + let config = ContainerCreateBody { image: Some(image.into()), - env: Some(env), + env: Some(env.into_iter().map(String::from).collect()), host_config: Some(HostConfig { network_mode: Some(network.to_string()), - extra_hosts: Some(hosts), ..Default::default() }), labels: Some(hashmap! { @@ -119,7 +99,7 @@ impl ServiceTrait for Office { docker: &Docker, cloud_id: &str, config: &HazeConfig, - ) -> Result>> { + ) -> Result> { let container = &self.container_name(cloud_id).unwrap(); let info = docker .inspect_container(container, None) @@ -147,27 +127,19 @@ impl ServiceTrait for Office { } else { return Err(Report::msg("office not started")); }; - let public = config - .proxy - .addr_with_port(container, ip, self.proxy_port()); - Ok(vec![ - vec![ - "occ".into(), - "config:app:set".into(), - "richdocuments".into(), - "public_wopi_url".into(), - "--value".into(), - public, - ], - vec![ - "occ".into(), - "richdocuments:setup".into(), - "--wopi-url".into(), - "http://office:9980".into(), - "--callback-url".into(), - "http://cloud".into(), - ], + format!( + r#"occ config:app:set richdocuments wopi_url --value="http://{}:9980""#, + ip + ), + format!( + r#"occ config:app:set richdocuments public_wopi_url --value="{}""#, + config.proxy.addr_with_port(container, ip, 9980) + ), + format!( + r#"occ config:app:set richdocuments wopi_root --value="http://{}""#, + cloud_id + ), ]) } diff --git a/src/service/onlyoffice.rs b/src/service/onlyoffice.rs index fa12c2c..b7c8a14 100644 --- a/src/service/onlyoffice.rs +++ b/src/service/onlyoffice.rs @@ -2,7 +2,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::exec::exec; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ ContainerCreateBody, ContainerState, EndpointSettings, HostConfig, NetworkingConfig, @@ -82,7 +82,7 @@ impl ServiceTrait for OnlyOffice { docker: &Docker, cloud_id: &str, config: &HazeConfig, - ) -> Result>> { + ) -> Result> { let info = docker .inspect_container(&self.container_name(cloud_id).unwrap(), None) .await @@ -137,44 +137,16 @@ impl ServiceTrait for OnlyOffice { ); Ok(vec![ - vec![ - "occ".into(), - "config:app:set".into(), - "onlyoffice".into(), - "DocumentServerUrl".into(), - "--value".into(), - addr, - ], - vec![ - "occ".into(), - "config:app:set".into(), - "onlyoffice".into(), - "jwt_secret".into(), - "--value".into(), - secret.into(), - ], - split_cmnd("occ onlyoffice:documentserver --check"), + format!("occ config:app:set onlyoffice DocumentServerUrl --value {addr}/"), + format!("occ config:app:set onlyoffice jwt_secret --value {secret}"), + "occ onlyoffice:documentserver --check".into(), ]) } else { Ok(vec![ - vec![ - "occ".into(), - "config:app:set".into(), - "onlyoffice".into(), - "DocumentServerUrl".into(), - "--value".into(), - format!("https://{ip}/"), - ], - split_cmnd("occ config:app:set onlyoffice verify_peer_off --value true"), - vec![ - "occ".into(), - "config:app:set".into(), - "onlyoffice".into(), - "jwt_secret".into(), - "--value".into(), - secret.into(), - ], - split_cmnd("occ onlyoffice:documentserver --check"), + format!("occ config:app:set onlyoffice DocumentServerUrl --value https://{ip}/"), + "occ config:app:set onlyoffice verify_peer_off --value true".into(), + format!("occ config:app:set onlyoffice jwt_secret --value {secret}"), + "occ onlyoffice:documentserver --check".into(), ]) } } diff --git a/src/service/push.rs b/src/service/push.rs index b0bbab2..22b3ac2 100644 --- a/src/service/push.rs +++ b/src/service/push.rs @@ -87,7 +87,7 @@ impl ServiceTrait for NotifyPush { docker: &Docker, cloud_id: &str, config: &HazeConfig, - ) -> Result>> { + ) -> Result> { let mut ips: Vec<_> = self.get_ips(docker, cloud_id).await?.collect(); if let Ok(local_interfaces) = list_afinet_netifas() { ips.extend(local_interfaces.into_iter().map(|(_, ip)| ip)); @@ -97,14 +97,10 @@ impl ServiceTrait for NotifyPush { .iter() .enumerate() .map(|(i, ip)| { - vec![ - "occ".into(), - "config:system:set".into(), - "trusted_proxies".into(), - (i + 1).to_string(), - "--value".into(), - ip.to_string(), - ] + format!( + "occ config:system:set trusted_proxies {} --value {ip}", + i + 1 + ) }) .collect(); @@ -112,7 +108,7 @@ impl ServiceTrait for NotifyPush { config .proxy .addr_with_port(&self.container_name(cloud_id).unwrap(), ips[0], 7867); - commands.push(vec!["occ".into(), "notify_push:setup".into(), addr]); + commands.push(format!("occ notify_push:setup {}", addr)); Ok(commands) } diff --git a/src/service/redis.rs b/src/service/redis.rs index 6d5d5e6..29a22ee 100644 --- a/src/service/redis.rs +++ b/src/service/redis.rs @@ -1,7 +1,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig}; use bollard::query_parameters::CreateContainerOptions; @@ -70,13 +70,7 @@ impl ServiceTrait for Redis { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { - Ok(vec![split_cmnd( - "occ config:system:set redis host --value redis", - )]) - } - - fn exec_shell(&self) -> &'static str { - "sh" + ) -> Result> { + Ok(vec!["occ config:system:set redis host --value redis".into()]) } } diff --git a/src/service/sftp.rs b/src/service/sftp.rs index 1f47a40..80405e2 100644 --- a/src/service/sftp.rs +++ b/src/service/sftp.rs @@ -1,14 +1,13 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig}; use bollard::query_parameters::CreateContainerOptions; use bollard::Docker; use maplit::hashmap; -use miette::{Context, IntoDiagnostic}; -use std::fs::{create_dir_all, write}; +use miette::IntoDiagnostic; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Sftp; @@ -51,10 +50,7 @@ impl ServiceTrait for Sftp { } }), }), - cmd: Some(vec![ - "test:test:::data".into(), - "ldaptest:test:::data".into(), - ]), + cmd: Some(vec!["test:test:::data".into()]), ..Default::default() }; let id = docker @@ -79,119 +75,13 @@ impl ServiceTrait for Sftp { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { - Ok(vec![ - split_cmnd("occ files_external:create sftp sftp password::password"), - split_cmnd("occ files_external:config 1 host sftp"), - split_cmnd("occ files_external:config 1 user test"), - split_cmnd("occ files_external:config 1 root data"), - split_cmnd("occ files_external:config 1 password test"), - ]) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct SftpKey; - -#[async_trait::async_trait] -impl ServiceTrait for SftpKey { - fn name(&self) -> &str { - "sftp-key" - } - - async fn spawn( - &self, - docker: &Docker, - cloud_id: &str, - network: &str, - config: &HazeConfig, - _options: &CloudOptions, ) -> Result> { - let image = "atmoz/sftp:alpine"; - pull_image(docker, image).await?; - let options = Some(CreateContainerOptions { - name: self.container_name(cloud_id), - ..CreateContainerOptions::default() - }); - let key_dir = config.work_dir.join("certificates/sftp"); - create_dir_all(&key_dir) - .into_diagnostic() - .wrap_err("Failed to create sftp certificate directory")?; - let private_path = key_dir.join("id_rsa"); - let public_path = key_dir.join("id_rsa.pub"); - let private_key = include_str!("../../certificates/sftp/id_rsa"); - let public_key = include_str!("../../certificates/sftp/id_rsa.pub"); - if !private_path.exists() { - write(&private_path, private_key) - .into_diagnostic() - .wrap_err("Failed to write sftp client certificate")?; - } - if !public_path.exists() { - write(&public_path, public_key) - .into_diagnostic() - .wrap_err("Failed to write sftp client key")?; - } - - let volumes = vec![format!("{public_path}:/home/test/.ssh/keys/id_rsa:ro")]; - - let config = ContainerCreateBody { - image: Some(image.into()), - host_config: Some(HostConfig { - network_mode: Some(network.to_string()), - binds: Some(volumes), - ..Default::default() - }), - labels: Some(hashmap! { - "haze-type".into() => self.name().into(), - "haze-cloud-id".into() => cloud_id.into(), - }), - networking_config: Some(NetworkingConfig { - endpoints_config: Some(hashmap! { - network.into() => EndpointSettings { - aliases: Some(vec![self.name().to_string()]), - ..Default::default() - } - }), - }), - cmd: Some(vec!["test::::data".into()]), - ..Default::default() - }; - let id = docker - .create_container(options, config) - .await - .into_diagnostic()? - .id; - docker.start_container(&id, None).await.into_diagnostic()?; - Ok(vec![id]) - } - - fn container_name(&self, cloud_id: &str) -> Option { - Some(format!("{}-sftp-key", cloud_id)) - } - - fn apps(&self) -> &'static [&'static str] { - &["files_external"] - } - - async fn post_setup( - &self, - _docker: &Docker, - _cloud_id: &str, - _config: &HazeConfig, - ) -> Result>> { Ok(vec![ - split_cmnd("occ files_external:create sftp sftp publickey::rsa_private"), - split_cmnd("occ files_external:config 1 host sftp-key"), - split_cmnd("occ files_external:config 1 user test"), - split_cmnd("occ files_external:config 1 root data"), - vec![ - "occ".into(), - "files_external:config".into(), - "--value-from-file".into(), - "1".into(), - "private_key".into(), - "/certificates/sftp/id_rsa".into(), - ], + "occ files_external:create sftp sftp password::password".into(), + "occ files_external:config 1 host sftp".into(), + "occ files_external:config 1 user test".into(), + "occ files_external:config 1 root data".into(), + "occ files_external:config 1 password test".into(), ]) } } diff --git a/src/service/smb.rs b/src/service/smb.rs index 08f69bd..a40b105 100644 --- a/src/service/smb.rs +++ b/src/service/smb.rs @@ -1,7 +1,7 @@ use crate::cloud::CloudOptions; use crate::config::HazeConfig; use crate::image::pull_image; -use crate::service::{split_cmnd, ServiceTrait}; +use crate::service::ServiceTrait; use crate::Result; use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig}; use bollard::query_parameters::CreateContainerOptions; @@ -40,10 +40,8 @@ impl ServiceTrait for Smb { }), env: Some(vec![ "ACCOUNT_test=test".into(), - "ACCOUNT_ldaptest=test".into(), "UID_test=1000".into(), "SAMBA_VOLUME_CONFIG_test=[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes".into(), - "SAMBA_VOLUME_CONFIG_ldaptest=[ldaptest]; path=/tmp; valid users = ldaptest; guest ok = no; read only = no; browseable = yes".into(), ]), labels: Some(hashmap! { "haze-type".into() => self.name().into(), @@ -81,17 +79,13 @@ impl ServiceTrait for Smb { _docker: &Docker, _cloud_id: &str, _config: &HazeConfig, - ) -> Result>> { + ) -> Result> { Ok(vec![ - split_cmnd("occ files_external:create smb smb password::password"), - split_cmnd("occ files_external:config 1 host smb"), - split_cmnd("occ files_external:config 1 user test"), - split_cmnd("occ files_external:config 1 password test"), - split_cmnd("occ files_external:config 1 share test"), + "occ files_external:create smb smb password::password".into(), + "occ files_external:config 1 host smb".into(), + "occ files_external:config 1 user test".into(), + "occ files_external:config 1 password test".into(), + "occ files_external:config 1 share test".into(), ]) } - - fn exec_shell(&self) -> &'static str { - "sh" - } } diff --git a/src/service/webhook.rs b/src/service/webhook.rs deleted file mode 100644 index e7ebae0..0000000 --- a/src/service/webhook.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::cloud::CloudOptions; -use crate::config::HazeConfig; -use crate::image::pull_image; -use crate::service::ServiceTrait; -use crate::Result; -use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig}; -use bollard::query_parameters::CreateContainerOptions; -use bollard::Docker; -use maplit::hashmap; -use miette::IntoDiagnostic; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Webhook; - -#[async_trait::async_trait] -impl ServiceTrait for Webhook { - fn name(&self) -> &str { - "webhook" - } - - async fn spawn( - &self, - docker: &Docker, - cloud_id: &str, - network: &str, - _config: &HazeConfig, - _options: &CloudOptions, - ) -> Result> { - let image = "ghcr.io/tarampampam/webhook-tester"; - pull_image(docker, image).await?; - let options = Some(CreateContainerOptions { - name: self.container_name(cloud_id), - ..CreateContainerOptions::default() - }); - let config = ContainerCreateBody { - image: Some(image.into()), - host_config: Some(HostConfig { - network_mode: Some(network.to_string()), - ..Default::default() - }), - labels: Some(hashmap! { - "haze-type".into() => self.name().into(), - "haze-cloud-id".into() => cloud_id.into(), - }), - networking_config: Some(NetworkingConfig { - endpoints_config: Some(hashmap! { - network.into() => EndpointSettings { - aliases: Some(vec![self.name().to_string()]), - ..Default::default() - } - }), - }), - ..Default::default() - }; - let id = docker - .create_container(options, config) - .await - .into_diagnostic()? - .id; - docker.start_container(&id, None).await.into_diagnostic()?; - Ok(vec![id]) - } - - fn container_name(&self, cloud_id: &str) -> Option { - Some(format!("{}-webhook", cloud_id)) - } - - fn proxy_port(&self) -> u16 { - 8080 - } - - fn exec_shell(&self) -> &'static str { - "" - } -} diff --git a/src/sources.rs b/src/sources.rs index ccfe564..b99c54a 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -122,7 +122,7 @@ pub async fn download_nc(config: &HazeConfig, version: &str) -> Result