mirror of
https://codeberg.org/icewind/haze.git
synced 2026-10-01 16:54:08 +02:00
Compare commits
22 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e2e826817 | |||
| d973bca0b3 | |||
| 3398027ad2 | |||
| a73f4218b2 | |||
| eefffc3231 | |||
| 39b5370818 | |||
| fb4e65eef4 | |||
| 6c440952dc | |||
| 515fc60f49 | |||
| 0a74daf4fd | |||
| 6d8e026ec4 | |||
| eac08ac64c | |||
| 029f26bda6 | |||
| 5bab1b89bb | |||
| 99c3285f07 | |||
| 51d0279c41 | |||
|
|
08df5a11c0 | ||
| 307dba81ec | |||
| d027f17ec6 | |||
| 070972a316 | |||
| d615322449 | |||
| d398b9f9e1 |
66 changed files with 1681 additions and 687 deletions
61
.forgejo/workflows/book-pr.yaml
Normal file
61
.forgejo/workflows/book-pr.yaml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
name: "Book - PR"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
paths:
|
||||
- ".forgejo/workflows/book-pr.yaml"
|
||||
- "book/**"
|
||||
|
||||
concurrency:
|
||||
group: page-preview
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
createPreview:
|
||||
runs-on: nix
|
||||
env:
|
||||
SITE_ORIGIN:
|
||||
"https://${{ forge.event.repository.owner.username
|
||||
}}.preview.codeberg.page"
|
||||
SITE_BASEPATH:
|
||||
"/${{ forge.event.repository.name }}@${{ forge.event.number }}/"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: https://codeberg.org/icewind/attic-action@v1
|
||||
with:
|
||||
name: link
|
||||
instance: https://cache.icewind.link
|
||||
authToken: "${{ secrets.ATTIC_TOKEN }}"
|
||||
- name: Build
|
||||
run: |
|
||||
# git-pages/action doesn't like symlinks
|
||||
cp -r $(nix build .#haze-book --print-out-paths --no-link) dist
|
||||
- name: "Deploy Site"
|
||||
uses: https://code.forgejo.org/actions/git-pages@v2
|
||||
with:
|
||||
site: "${{ env.SITE_ORIGIN }}${{ env.SITE_BASEPATH }}" #
|
||||
token: "${{ forge.token }}" #
|
||||
source: "dist/" #
|
||||
- name: "Find comment"
|
||||
uses: "https://github.com/peter-evans/find-comment@v4" #
|
||||
id: comment
|
||||
with:
|
||||
issue-number: ${{ forge.event.number }} #
|
||||
body-includes: "<!-- preview-comment -->" #
|
||||
- name: "Create or update comment"
|
||||
uses: "https://github.com/peter-evans/create-or-update-comment@v5" #
|
||||
with:
|
||||
issue-number: ${{ forge.event.number }} #
|
||||
comment-id: "${{ steps.comment.outputs.comment-id }}" #
|
||||
edit-mode: "replace"
|
||||
body: |-
|
||||
# Pull request preview ready!
|
||||
|
||||
The Preview of commit ${{ forge.event.pull_request.head.sha }} has been created.
|
||||
You can find it here: ${{ env.SITE_ORIGIN }}${{ env.SITE_BASEPATH }}
|
||||
|
||||
<!-- preview-comment -->
|
||||
29
.forgejo/workflows/book.yaml
Normal file
29
.forgejo/workflows/book.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
name: "Book"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
runs-on: nix
|
||||
env:
|
||||
SITE_ORIGIN: "${{forge.event.repository.owner.username}}.codeberg.page"
|
||||
SITE_BASEPATH: "/${{forge.event.repository.name}}/"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: https://codeberg.org/icewind/attic-action@v1
|
||||
with:
|
||||
name: link
|
||||
instance: https://cache.icewind.link
|
||||
authToken: "${{ secrets.ATTIC_TOKEN }}"
|
||||
- name: Build
|
||||
run: |
|
||||
# git-pages/action doesn't like symlinks
|
||||
cp -r $(nix build .#haze-book --print-out-paths --no-link) dist
|
||||
- uses: https://codeberg.org/git-pages/action@v2
|
||||
with:
|
||||
site: https://${{ env.SITE_ORIGIN }}${{ env.SITE_BASEPATH }}
|
||||
token: ${{ forge.token }}
|
||||
source: dist/
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,3 +2,5 @@
|
|||
.direnv
|
||||
.env
|
||||
result
|
||||
.vale/*
|
||||
!.vale/config
|
||||
|
|
|
|||
13
.vale.ini
Normal file
13
.vale.ini
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
StylesPath = .vale
|
||||
MinAlertLevel = suggestion
|
||||
Vocab = haze
|
||||
|
||||
[formats]
|
||||
mdx = md
|
||||
|
||||
[*]
|
||||
BasedOnStyles = Vale
|
||||
|
||||
[*.{md,mdx}]
|
||||
BasedOnStyles = Vale
|
||||
Microsoft.Contractions = NO
|
||||
26
.vale/config/vocabularies/haze/accept.txt
Normal file
26
.vale/config/vocabularies/haze/accept.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Nextcloud
|
||||
ownCloud
|
||||
appstore
|
||||
Authentik
|
||||
Caddy
|
||||
cron
|
||||
FrankenPHP
|
||||
PHPUnit
|
||||
mdBook
|
||||
boolean
|
||||
Codeberg
|
||||
Kaspersky
|
||||
Redis
|
||||
Podman
|
||||
Xdebug
|
||||
occ
|
||||
dnsmasq
|
||||
notify_push
|
||||
sharding
|
||||
tokio
|
||||
worktree
|
||||
worktrees
|
||||
config
|
||||
stdin
|
||||
stdout
|
||||
direnv
|
||||
40
CHANGELOG.md
40
CHANGELOG.md
|
|
@ -1,9 +1,15 @@
|
|||
## 2.4.2
|
||||
|
||||
- Support having a `#!` inside a haze script to specify the interpreter to use
|
||||
- Add WebUI for accessing the database.
|
||||
- Allow opening services with `haze open [service]`
|
||||
|
||||
## 2.4.1
|
||||
|
||||
- Show database location on start
|
||||
- Direct TLS listening support for the proxy
|
||||
- Set `SERVER_NAME` for frankenphp
|
||||
- Expose Caddy admin endpoints when using frankenphp
|
||||
- Set `SERVER_NAME` for FrankenPHP
|
||||
- Expose Caddy admin endpoints when using FrankenPHP
|
||||
- Use cron for background jobs
|
||||
|
||||
## 2.4.0
|
||||
|
|
@ -12,34 +18,34 @@
|
|||
- Add option to start an instance with a detached worktree
|
||||
- Add "haze scripts" that bundle a setup configuration and script to run in the
|
||||
instance
|
||||
- Allow specifying phpunit version when running tests
|
||||
- Add SAML service using authentik
|
||||
- Add OIDC service using authentik
|
||||
- Add SCIM service using authentik
|
||||
- Add option to specify PHPUnit version when running tests
|
||||
- Add SAML service using Authentik
|
||||
- Add OIDC service using Authentik
|
||||
- Add SCIM service using Authentik
|
||||
- Fix using a single word as instance name
|
||||
- Fixed cleanup not removing some cache files
|
||||
- Remove memory and cpu limits from containers
|
||||
- Remove memory and CPU limits from containers
|
||||
- Fix max upload size not being set correctly
|
||||
|
||||
## 2.3.0
|
||||
|
||||
- Allow execing into service containers
|
||||
- Add sftp with key authentication service
|
||||
- Fix mysql 8 support
|
||||
- Add option to `exec` in service containers
|
||||
- Add SFTP with key authentication service
|
||||
- Fix MySQL 8 support
|
||||
|
||||
## 2.2.2
|
||||
|
||||
- parallelize `git pull`
|
||||
- add webhook tester
|
||||
- automatically configure ldap when enabled
|
||||
- improve compatibility with intergration tests
|
||||
- automatically configure LDAP when enabled
|
||||
- improve compatibility with integration tests
|
||||
- add `php-imagick` module
|
||||
|
||||
## 2.1.1
|
||||
|
||||
- Add basic [frankenphp](https://github.com/php/frankenphp) support
|
||||
- Add basic [FrankenPHP](https://github.com/php/frankenphp) support
|
||||
- Allow running integration tests from (some) apps
|
||||
- Support federation with proxy and using 127.0.0.1 as proxy ip
|
||||
- Support federation with proxy and using 127.0.0.1 as proxy IP
|
||||
- Fix office not working
|
||||
- Warn when using out-of-date images.
|
||||
|
||||
|
|
@ -49,8 +55,8 @@
|
|||
- Faster stopping of instances, by @provokateurin
|
||||
- Support extra app directories
|
||||
- Enable appstore
|
||||
- Allow setting config options pre-setup
|
||||
- Allow setting configuration options pre-setup
|
||||
- Improved access to service containers
|
||||
- Add S3 with TLS options
|
||||
- Updated php 8.0 and 8.1 images
|
||||
- Add php 8.5 support
|
||||
- Updated PHP 8.0 and 8.1 images
|
||||
- Add PHP 8.5 support
|
||||
|
|
|
|||
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -899,7 +899,7 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
|||
|
||||
[[package]]
|
||||
name = "haze"
|
||||
version = "2.4.1"
|
||||
version = "2.4.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"atty",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "haze"
|
||||
version = "2.4.1"
|
||||
version = "2.4.2"
|
||||
edition = "2024"
|
||||
description = "Easy setup and management of Nextcloud test instances using docker"
|
||||
repository = "https://codeberg.org/icewind/haze"
|
||||
|
|
|
|||
80
DEVELOPING.md
Normal file
80
DEVELOPING.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# Developing
|
||||
|
||||
## Setup
|
||||
|
||||
### Nix based development environment
|
||||
|
||||
The recommended way to setup the development environment is to use
|
||||
[Lix](https://lix.systems/install/)/[Nix](https://nixos.org/download/).
|
||||
|
||||
Once installed, you can enter the development shell using `nix develop` or,
|
||||
setup [direnv](https://direnv.net/) to automatically enter the development shell
|
||||
when you enter the folder.
|
||||
|
||||
The development shell provides all necessary tooling to develop haze.
|
||||
|
||||
### Without Nix
|
||||
|
||||
The fooling tools need to be setup to develop without using Nix to manage the
|
||||
development setup:
|
||||
|
||||
- [`cargo`](https://doc.rust-lang.org/cargo/getting-started/installation.html) -
|
||||
For building the program
|
||||
- [`mdbook`](https://github.com/rust-lang/mdBook) - For building the
|
||||
documentation
|
||||
- [`prettier`](https://prettier.io/) - For formatting the non-rust files
|
||||
- [`vale`](https://vale.sh/) - For checking documentation
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
The binary can then be found at `target/debug/haze`.
|
||||
|
||||
## Formatting
|
||||
|
||||
### With Nix
|
||||
|
||||
```bash
|
||||
nix fmt
|
||||
```
|
||||
|
||||
### Without Nix
|
||||
|
||||
#### Rust code
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
```
|
||||
|
||||
#### Documentation
|
||||
|
||||
```bash
|
||||
prettier --write '**/*.md'
|
||||
```
|
||||
|
||||
### Building documentation
|
||||
|
||||
```bash
|
||||
mdbook serve
|
||||
```
|
||||
|
||||
### Checking documentation
|
||||
|
||||
```bash
|
||||
vale src/ book/src/ book/README.md *.md
|
||||
```
|
||||
|
||||
### Run all checks
|
||||
|
||||
```bash
|
||||
nix flake check
|
||||
```
|
||||
|
||||
### Building docker images
|
||||
|
||||
```bash
|
||||
nix run .#'"haze-image-php-8.4"'.copyToDockerDaemon
|
||||
```
|
||||
521
README.md
521
README.md
|
|
@ -7,528 +7,35 @@ Easy setup and management of Nextcloud test instances using docker
|
|||
## What
|
||||
|
||||
`haze` provides an easy way to set up Nextcloud test instances with a choice of
|
||||
php version, database server, optional s3 or ldap setup and more.
|
||||
PHP version, database server, optional s3 or LDAP setup and more.
|
||||
|
||||
## Setup
|
||||
## Documentation
|
||||
|
||||
### Requirements
|
||||
Documentation for haze can be found in the
|
||||
[book](https://icewind.codeberg.page/haze/)
|
||||
|
||||
- Docker
|
||||
|
||||
### Installation
|
||||
## Quickstart
|
||||
|
||||
- Grab a binary from the
|
||||
[Codeberg releases](https://codeberg.org/icewind/haze/releases) and place it
|
||||
in your `$PATH`
|
||||
|
||||
### Config
|
||||
- Create a file `~/.config/haze/haze.toml` with the following content:
|
||||
|
||||
Create a file `~/.config/haze/haze.toml` with the following options:
|
||||
|
||||
```toml
|
||||
sources_root = "/path/to/nextcloud/sources"
|
||||
```
|
||||
|
||||
See the [configuration section](#configuration) for more options.
|
||||
|
||||
### Quick examples
|
||||
|
||||
- Start a Nextcloud instance with `postgresql`, and `s3` primary storage:
|
||||
|
||||
```bash
|
||||
haze start pgsql s3
|
||||
```toml
|
||||
sources_root = "/path/to/nextcloud/sources"
|
||||
```
|
||||
|
||||
- Start a Nextcloud instance with `sqlite`, `php 8.3` and an `smb` external
|
||||
storage:
|
||||
- Start a basic Nextcloud instance:
|
||||
|
||||
```bash
|
||||
haze start 8.3 smb
|
||||
haze start
|
||||
```
|
||||
|
||||
- Run specific units test against an `oracle` database
|
||||
```bash
|
||||
haze test oracle apps/dav/tests/unit/Connector/Sabre
|
||||
```
|
||||
- Navigate to the address that is provided in the output.
|
||||
|
||||
## Managing instances
|
||||
See the [book](https://icewind.codeberg.page/haze/) for more details.
|
||||
|
||||
#### Start an instance
|
||||
## Developing
|
||||
|
||||
```bash
|
||||
haze start [--name <name>] [--detach] [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.
|
||||
|
||||
You can specify a version number (e.g. `v32.0.2`) to use the sources from a
|
||||
release instead of using the local sources.
|
||||
|
||||
Use `--name <name>` to give the instance a specific name instead of a randomly
|
||||
generated one. For example:
|
||||
|
||||
Use `--detach` to give the instance
|
||||
[its own sources](#instances-with-their-own-sources) instead of sharing
|
||||
`sources_root` with all other instances.
|
||||
|
||||
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.
|
||||
- `ldap`: set up an LDAP server.
|
||||
- `saml`: set up authentik as a SAML IDP.
|
||||
- `oidc`: set up authentik as an OIDC IDP.
|
||||
- `scim`: set up authentik as a SCIM server.
|
||||
- `office`: set up a Nextcloud Office server.
|
||||
- `onlyoffice` setup an onlyoffice document server.
|
||||
- `push` set up [client push](https://github.com/nextcloud/notify_push).
|
||||
- `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.
|
||||
- `clamav`: set up a local clam av scanner in executable mode.
|
||||
- `clamav-socket`: set up a clam av scanner in socket mode.
|
||||
- `clamav-icap`: set up a clam av scanner in ICAP mode.
|
||||
- `clamav-icap-tls`: set up a clam av scanner in ICAP mode with TLS encryption.
|
||||
- `oc`: start an ownCloud instance in the same network.
|
||||
- `imaginary`: start an Imaginary service and configure it for preview
|
||||
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.
|
||||
- `<path to app.tar.gz>`: 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
|
||||
|
||||
```bash
|
||||
haze test [database] [php-version] [phpunit version] [path]
|
||||
```
|
||||
|
||||
Where `path` is a file or folder to run PHPUnit in, relative to the sources
|
||||
root.
|
||||
|
||||
### List running instances
|
||||
|
||||
```bash
|
||||
haze
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
haze list
|
||||
```
|
||||
|
||||
#### Remove all running instances
|
||||
|
||||
```bash
|
||||
haze clean
|
||||
```
|
||||
|
||||
### Instances with their own sources
|
||||
|
||||
By default every instance shares the sources configured as `sources_root`, so
|
||||
all instances always run the same code. An instance started with `--detach` gets
|
||||
its own `git worktree` of `sources_root` instead, created in `worktree_dir`,
|
||||
which lets you run several instances on different branches at the same time.
|
||||
|
||||
```bash
|
||||
haze start --name my-fix --detach
|
||||
```
|
||||
|
||||
The worktree is checked out with a detached head. Every app in one of the
|
||||
`app_directories` that gets enabled during setup receives its own worktree as
|
||||
well, other apps keep running from the shared app directory.
|
||||
|
||||
The worktrees are removed together with the instance, by `haze stop` or
|
||||
`haze clean`.
|
||||
|
||||
## Controlling running instances
|
||||
|
||||
The following commands run against the most recently started instance and allow
|
||||
optionally providing a `match` to select a specific instance by its name.
|
||||
|
||||
#### Open an instance
|
||||
|
||||
```bash
|
||||
haze [match] open
|
||||
```
|
||||
|
||||
#### Open the database of an instance
|
||||
|
||||
```bash
|
||||
haze [match] db
|
||||
```
|
||||
|
||||
#### Execute a command on an instance
|
||||
|
||||
```bash
|
||||
haze [match] [service] [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
|
||||
haze [match] shell [cmd]
|
||||
```
|
||||
|
||||
If no `cmd` is specified it will launch `bash`
|
||||
|
||||
#### Execute an occ command on an instance
|
||||
|
||||
```bash
|
||||
haze [match] occ [cmd]
|
||||
```
|
||||
|
||||
#### Connect to the database on an instance
|
||||
|
||||
```bash
|
||||
haze [match] db
|
||||
```
|
||||
|
||||
#### Show the logs of an instance
|
||||
|
||||
```bash
|
||||
haze [match] logs
|
||||
```
|
||||
|
||||
#### Stop an instance
|
||||
|
||||
```bash
|
||||
haze [match] stop
|
||||
```
|
||||
|
||||
#### Pin an instance
|
||||
|
||||
```bash
|
||||
haze [match] pin
|
||||
```
|
||||
|
||||
Pinned instances will not be removed by `haze clean`.
|
||||
|
||||
#### Unpin an instance
|
||||
|
||||
```bash
|
||||
haze [match] unpin
|
||||
```
|
||||
|
||||
#### Run a command with instance environment variables set
|
||||
|
||||
```bash
|
||||
haze [match] env <cmd> [args]
|
||||
```
|
||||
|
||||
Runs the provided command with `NEXTCLOUD_URL`, `DATABASE_URL` and `REDIS_URL`
|
||||
environment variables set for the matched instance.
|
||||
|
||||
This is intended to run a local
|
||||
[push daemon](https://github.com/nextcloud/notify_push) against an instance.
|
||||
|
||||
#### Update the container images
|
||||
|
||||
```bash
|
||||
haze update
|
||||
```
|
||||
|
||||
#### Edit a file in an instance with the local $EDITOR
|
||||
|
||||
```bash
|
||||
haze [match] edit <path>
|
||||
```
|
||||
|
||||
#### Reload the php config of an instance
|
||||
|
||||
```bash
|
||||
haze [match] reload
|
||||
```
|
||||
|
||||
The php configuration can edit changed with `haze edit /config/php.ini`
|
||||
|
||||
#### Checkout a branch for all local apps
|
||||
|
||||
```bash
|
||||
haze git checkout [branch]
|
||||
```
|
||||
|
||||
Checks out the branch in all git repositories within the apps folder.
|
||||
|
||||
Defaults to the branch matching the current checked out server versions (e.g.
|
||||
`master` or `stable33`).
|
||||
|
||||
`master` and `main` can be used interchangeably.
|
||||
|
||||
#### Pull remote changes for all local apps
|
||||
|
||||
```bash
|
||||
haze git pull
|
||||
```
|
||||
|
||||
Performs a pull in all git repositories within the apps folder.
|
||||
|
||||
## Federation
|
||||
|
||||
Multiple instances can reach each other by using their instance name as domain
|
||||
name to allow for testing federation between instances. Alternatively, you can
|
||||
set up the haze proxy and the proxied domains to get https support between
|
||||
instances.
|
||||
|
||||
## Proxy
|
||||
|
||||
By default, instances can be accessed by their IP. In order to get more
|
||||
memorable URLs and allow supporting https, haze comes with a builtin reverse
|
||||
proxy to allow using a wildcard domain.
|
||||
|
||||
### DNS Setup
|
||||
|
||||
#### Requirements
|
||||
|
||||
- A domain name you can set wildcard DNS records for
|
||||
- A reverse proxy like Nginx or Apache
|
||||
- (optionally) a wildcard ssl certificate (can be acquiring using letsencrypt
|
||||
and dns verification)
|
||||
|
||||
#### Steps
|
||||
|
||||
- Set a DNS record for `*.haze.example.com` and `haze.example.com` pointing to
|
||||
your development machine.
|
||||
- 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
|
||||
example).
|
||||
- Configure your reverse proxy of choice to proxy `*.haze.example.com` and
|
||||
`haze.example.com` to the proxy's listen endpoint
|
||||
- (optional) acquire a wildcard ssl certificate for your domain and set your
|
||||
reverse proxy to use it. This will be highly dependent on your DNS provider,
|
||||
[this](https://community.letsencrypt.org/t/dns-providers-who-easily-integrate-with-lets-encrypt-dns-validation/86438)
|
||||
lists some DNS providers and supported ACME clients.
|
||||
|
||||
### Local Setup
|
||||
|
||||
- Setup `dnsmasq` to resolve `*.haze.test` to your development machine.
|
||||
- Generate a wildcard ssl certificate for `*.haze.test` using `mkcert`:
|
||||
|
||||
```bash
|
||||
# Generate local wildcard certificate
|
||||
mkcert -cert-file <path-to-your-certificats>haze.test.crt -key-file <path-to-your-certificats>haze.test.key '*.haze.test'
|
||||
```
|
||||
|
||||
- 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
|
||||
example).
|
||||
- Either point haze at the certificate directly:
|
||||
|
||||
```toml
|
||||
[proxy]
|
||||
address = "haze.test"
|
||||
https = true
|
||||
listen = "127.0.0.1:443"
|
||||
cert = "<path-to-your-certificats>/haze.test.crt"
|
||||
key = "<path-to-your-certificats>/haze.test.key"
|
||||
```
|
||||
|
||||
Binding to port 443 as a regular user requires either
|
||||
`sudo setcap cap_net_bind_service=+ep $(which haze)` or
|
||||
`sysctl net.ipv4.ip_unprivileged_port_start=443`.
|
||||
|
||||
- Or, if you already have another web server, setup it up to proxy `*.haze.test`
|
||||
and `haze.test` to the `haze proxy`'s socket. Example for Nginx:
|
||||
|
||||
```nginx
|
||||
upstream haze-handler {
|
||||
server unix:/run/haze/haze.sock;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name *.haze.test;
|
||||
|
||||
ssl_certificate <path-to-your-certificats>/haze.test.crt;
|
||||
ssl_certificate_key <path-to-your-certificats>/haze.test.key;
|
||||
|
||||
location / {
|
||||
proxy_pass http://haze-handler;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
When the proxy is configured, generated URLs for the instances will use a
|
||||
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
|
||||
`<instance id>-<service id>.haze.example.com` for a specific instance, or
|
||||
`<service-id>.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.
|
||||
|
||||
## Haze scripts
|
||||
|
||||
Haze scripts combine a set of instance options and a script to run in the
|
||||
instance.
|
||||
|
||||
Haze scripts are intended to way to create automated ways of running more
|
||||
complex tests are setting up more complex instances.
|
||||
|
||||
A script contains of 3 paths
|
||||
|
||||
1. An optional shebang line setting `haze` as the interpreter, e.g.
|
||||
`#! /usr/bin/env -S haze script`
|
||||
2. A shebang line setting the options for the instance creation as the
|
||||
interpreter, e.g. `#! haze shell pgsql s3`
|
||||
3. The rest that is ran as a script inside the created instance.
|
||||
|
||||
The first sheband is set, the script can be ran directly. Else it needs to be
|
||||
run with `haze script [path-to-script]`.
|
||||
|
||||
For example, the following script will create an instance with `postgresql` and
|
||||
`s3` primary storage. Then creates a new file, gets the file id, read the object
|
||||
of the file from S3, validate that it contains the expected contents, and
|
||||
cleanup the instance.
|
||||
|
||||
```bash
|
||||
#! #! /usr/bin/env -S haze script
|
||||
#! haze shell pgsql s3
|
||||
|
||||
echo 'test' | occ file:put '-' /admin/files/test.txt
|
||||
FILE_ID=$(occ info:file /admin/files/test.txt | grep fileid: | grep -oE '[0-9]+')
|
||||
OBJECT_CONTENTS=$(occ file:object:get urn:oid:$FILE_ID -)
|
||||
if [ "$OBJECT_CONTENTS" == 'test' ]; then
|
||||
echo "object contains expected contents"
|
||||
else
|
||||
echo "object does not contains expected contents!"
|
||||
fi
|
||||
```
|
||||
|
||||
### Script modes
|
||||
|
||||
Scripts can be either `shell` or `start` scripts.
|
||||
|
||||
`shell` scripts will automatically remove the created instance once the script
|
||||
is done, just like `haze shell` will. The intended use case for this is
|
||||
performing some tests in the created instance without leaving state behind.
|
||||
|
||||
`start` scripts on the other hand will keep the instance, like `haze start`
|
||||
will. The intended use case for this is creating more complex instances without
|
||||
having to configure a dedicated preset.
|
||||
|
||||
The script mode is determined based on the shebang line. The mode set in a
|
||||
script can be overriden by running the script with
|
||||
`haze script [shell|start] path-to-script.sh`.
|
||||
|
||||
## Nushell scripts
|
||||
|
||||
By default, the script contents are executed as a `bash` script, you can instead
|
||||
execute the script as a `nushell` script by using `.nu` as the file extention.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration is loaded from `~/.config/haze/haze.toml` and has the following
|
||||
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"
|
||||
worktree_dir = "/path/to/worktrees" # where to create the worktrees of detached instances. optional, defaults to "<work_dir>/worktrees"
|
||||
|
||||
[auto_setup] # optional
|
||||
enabled = false # whether or not to automatically install nextcloud on `haze start`. enabled by default
|
||||
username = "foo" # username for admin user during auto setup. optional, defaults to "admin"
|
||||
password = "bar" # password for admin user during auto setup. optional, defaults to "admin"
|
||||
enable_apps = ["files_external"] # apps to enable after setup, defaults to []
|
||||
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"
|
||||
target = "/shared"
|
||||
create = true
|
||||
|
||||
[[volume]]
|
||||
source = "/home/me/Downloads"
|
||||
target = "/Downloads"
|
||||
read_only = true
|
||||
|
||||
[proxy] # optional
|
||||
address = "haze.example.com" # base domain
|
||||
https = true # Whether the instances are reachable over https
|
||||
listen = "/run/haze/haze.sock" # either a unix socket path
|
||||
#listen = "127.0.0.1:8080" # or a socket address
|
||||
cert = "/path/to/haze.test.crt" # optional - PEM encoded certificate chain
|
||||
key = "/path/to/haze.test.key" # optional - PEM encoded private key
|
||||
|
||||
# presets allow for easy usage of commonly used setups
|
||||
[[preset]]
|
||||
name = "groupfolders" # name of the preset
|
||||
apps = ["groupfolders"] # app to enable
|
||||
commands = ["occ groupfolders:create gf", "occ groupfolders:group 1 admin read write share delete"] # commands to run post-setup
|
||||
```
|
||||
|
||||
## Xdebug
|
||||
|
||||
Haze Xdebug is running in a docker container, you need to tell you IDE how to
|
||||
properly map the path. The IDE debugger config usually looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"label": "PHP: Debug server within docker",
|
||||
"adapter": "Xdebug",
|
||||
"request": "launch",
|
||||
"port": 9003,
|
||||
"pathMappings": {
|
||||
"/var/www/html": "<sources_root_configured_in_haze.toml>",
|
||||
"/var/www/html/apps-extra": "<app_directories_configured_in_haze.toml>",
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
This would have to be adapted for detached instances.
|
||||
|
||||
To enable Xdebug for all requests:
|
||||
|
||||
- Uncomment the lines in `haze <cloud-id> edit /config/php.ini`
|
||||
- Then run `haze reload <cloud-id>`
|
||||
|
||||
## FrankenPHP (experimental)
|
||||
|
||||
You can have Nextcloud run on FrankenPHP.
|
||||
|
||||
Caddy's admin metrics are then accessible through
|
||||
`http://<cloud-id>-franken-php.haze.test`. With ember you can run:
|
||||
|
||||
```bash
|
||||
ember --addr http://<cloud-id>-franken-php.haze.test
|
||||
```
|
||||
See [DEVELOPING.md](./DEVELOPING.md) for information on how to work on `haze`.
|
||||
|
|
|
|||
1
book/.gitignore
vendored
Normal file
1
book/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
book
|
||||
9
book/README.md
Normal file
9
book/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
## Build requirements
|
||||
|
||||
- [mdBook](https://github.com/rust-lang/mdBook)
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
mdbook serve
|
||||
```
|
||||
4
book/book.toml
Normal file
4
book/book.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[book]
|
||||
title = "Haze"
|
||||
authors = ["Robin Appelman"]
|
||||
language = "en"
|
||||
30
book/src/README.md
Normal file
30
book/src/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Haze
|
||||
|
||||
Hazy with a chance of clouds.
|
||||
|
||||
`haze` is a tool that provides an easy way to set up Nextcloud test instances
|
||||
with a choice of PHP version, database server, optional s3 or LDAP setup and
|
||||
much more.
|
||||
|
||||
## Quickstart
|
||||
|
||||
- Grab a binary from the
|
||||
[Codeberg releases](https://codeberg.org/icewind/haze/releases) and place it
|
||||
in your `$PATH`
|
||||
|
||||
- Create a file `~/.config/haze/haze.toml` with the following content:
|
||||
|
||||
```toml
|
||||
sources_root = "/path/to/nextcloud/sources"
|
||||
```
|
||||
|
||||
- Start a basic Nextcloud instance:
|
||||
|
||||
```bash
|
||||
haze start
|
||||
```
|
||||
|
||||
- Navigate to the address that is provided in the output.
|
||||
|
||||
See the [setup](./setup.html), [configuration](./configuration.html) and
|
||||
[usage](./usage.html) for a more details.
|
||||
16
book/src/SUMMARY.md
Normal file
16
book/src/SUMMARY.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Summary
|
||||
|
||||
[Introduction](README.md)
|
||||
|
||||
- [Setup](setup.md)
|
||||
- [Usage](usage.md)
|
||||
- [Configuration](configuration.md)
|
||||
- [Proxy](proxy/README.md)
|
||||
- [DNS](proxy/dns.md)
|
||||
- [HTTPS](proxy/https.md)
|
||||
- [Services](services.md)
|
||||
- [Database](database.md)
|
||||
- [Federation](federation.md)
|
||||
- [Haze scripts](scripts.md)
|
||||
- [Xdebug](xdebug.md)
|
||||
- [FrankenPHP (experimental)](frankenphp.md)
|
||||
271
book/src/configuration.md
Normal file
271
book/src/configuration.md
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
# Configuration
|
||||
|
||||
Configuration is loaded from `~/.config/haze/haze.toml`.
|
||||
|
||||
The minimum required configuration needed to get started is just the
|
||||
`sources_root` options.
|
||||
|
||||
The full list of supported options is:
|
||||
|
||||
### `sources_root`
|
||||
|
||||
The local path of the Nextcloud sources. This options is **required**.
|
||||
|
||||
Type: string
|
||||
|
||||
### `app_directories`
|
||||
|
||||
A list of additional app directory paths to look for apps into
|
||||
|
||||
Default `[]`
|
||||
|
||||
Type: list of strings
|
||||
|
||||
### `work_dir`
|
||||
|
||||
The location where haze keeps it's temporary files and caches
|
||||
|
||||
Default: `/tmp/haze`
|
||||
|
||||
Type: string
|
||||
|
||||
### `worktree_dir`
|
||||
|
||||
The location to store git worktrees when using instances with detached sources.
|
||||
|
||||
Default: `<work_dir>/worktrees`
|
||||
|
||||
Type: string
|
||||
|
||||
## `auto_setup`
|
||||
|
||||
Options for automatically setting up the newly created Nextcloud instance.
|
||||
|
||||
Examples:
|
||||
|
||||
```toml
|
||||
[auto_setup]
|
||||
username = "foo"
|
||||
password = "bar"
|
||||
enable_apps = ["files_external"]
|
||||
disable_apps = ["contacts"]
|
||||
post_setup = [
|
||||
"occ group:add test",
|
||||
]
|
||||
config = { "enforce_theme" = "dark" }
|
||||
```
|
||||
|
||||
```toml
|
||||
[auto_setup]
|
||||
enabled = false
|
||||
```
|
||||
|
||||
### `auto_setup.enabled`
|
||||
|
||||
Whether to automatically setup Nextcloud inside a created instance.
|
||||
|
||||
Default: `true`
|
||||
|
||||
Type: boolean
|
||||
|
||||
### `auto_setup.username`
|
||||
|
||||
The username to use for the admin account during auto setup.
|
||||
|
||||
Default: `admin`
|
||||
|
||||
Type: string
|
||||
|
||||
### `auto_setup.password`
|
||||
|
||||
The password to use for the admin account during auto setup.
|
||||
|
||||
Default: `admin`
|
||||
|
||||
Type: string
|
||||
|
||||
### `auto_setup.enabled_apps`
|
||||
|
||||
Extra apps to enable after auto setup
|
||||
|
||||
Default: `[]`
|
||||
|
||||
Type: list of strings
|
||||
|
||||
### `auto_setup.disabled_apps`
|
||||
|
||||
Apps to disabled after auto setup
|
||||
|
||||
Default: `[]`
|
||||
|
||||
Type: list of strings
|
||||
|
||||
### `auto_setup.post_setup`
|
||||
|
||||
Commands to execute after auto setup
|
||||
|
||||
Default: `[]`
|
||||
|
||||
Type: list of strings
|
||||
|
||||
### `auto_setup.config`
|
||||
|
||||
System configuration options to set before auto setup
|
||||
|
||||
Default: `{}`
|
||||
|
||||
Type: Object
|
||||
|
||||
## `volume`
|
||||
|
||||
Additional files or directories to bind-mount into instances.
|
||||
|
||||
Any number of volume options can be configured
|
||||
|
||||
Examples:
|
||||
|
||||
```toml
|
||||
[[volume]]
|
||||
source = "/tmp/haze-shared"
|
||||
target = "/shared"
|
||||
create = true
|
||||
```
|
||||
|
||||
```toml
|
||||
[[volume]]
|
||||
source = "/home/me/Downloads"
|
||||
target = "/Downloads"
|
||||
read_only = true
|
||||
```
|
||||
|
||||
### `volume.source`
|
||||
|
||||
The source path on the host
|
||||
|
||||
Type: string
|
||||
|
||||
### `volume.target`
|
||||
|
||||
The target path inside the container
|
||||
|
||||
Type: string
|
||||
|
||||
### `volume.create`
|
||||
|
||||
Create the source directory on the host if it doesn't exist already.
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: boolean
|
||||
|
||||
### `volume.read_only`
|
||||
|
||||
Whether to mount the file or directory as read only
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
### preset
|
||||
|
||||
Configured presets that can be used when creating instances.
|
||||
|
||||
Any number of presets can be configured.
|
||||
|
||||
Example:
|
||||
|
||||
```toml
|
||||
[[preset]]
|
||||
name = "groupfolders"
|
||||
apps = ["groupfolders"]
|
||||
commands = [
|
||||
"occ groupfolders:create gf",
|
||||
"occ groupfolders:group 1 admin read write share delete"
|
||||
]
|
||||
```
|
||||
|
||||
### `preset.name`
|
||||
|
||||
The name of the preset, this is used when creating instances to select the
|
||||
preset.
|
||||
|
||||
Type: string without whitespace
|
||||
|
||||
### `preset.apps`
|
||||
|
||||
A list of apps to enable when the preset is used.
|
||||
|
||||
Default: `[]`
|
||||
|
||||
Type: list of strings
|
||||
|
||||
### `preset.commands`
|
||||
|
||||
A list of commands to run post-setup when the preset is used.
|
||||
|
||||
Default: `[]`
|
||||
|
||||
Type: list of strings
|
||||
|
||||
## `proxy`
|
||||
|
||||
Configuration for the haze proxy. Only required when using the proxy.
|
||||
|
||||
```toml
|
||||
[proxy]
|
||||
address = "haze.example.com"
|
||||
listen = "/run/haze/haze.sock"
|
||||
https = true
|
||||
cert = "/path/to/haze.test.crt"
|
||||
key = "/path/to/haze.test.key"
|
||||
```
|
||||
|
||||
### `proxy.listen`
|
||||
|
||||
The IP and port or Unix socket for the proxy to listen on.
|
||||
|
||||
**Required** when the proxy is enabled.
|
||||
|
||||
Type: string
|
||||
|
||||
Examples:
|
||||
|
||||
```toml
|
||||
listen = "/run/haze/haze.sock"
|
||||
```
|
||||
|
||||
```toml
|
||||
listen = "127.0.0.1:8080"
|
||||
```
|
||||
|
||||
### `proxy.address`
|
||||
|
||||
The base domain the proxy is accessible on.
|
||||
|
||||
**Required** if the proxy is enabled.
|
||||
|
||||
Type: string
|
||||
|
||||
### `proxy.https`
|
||||
|
||||
Whether to enable built-in HTTPS support for the proxy.
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: boolean
|
||||
|
||||
### `proxy.cert`
|
||||
|
||||
The path of the PEM encoded certificate chain to use for HTTPS.
|
||||
|
||||
**Required** if HTTPS is enabled for the proxy.
|
||||
|
||||
Type: string.
|
||||
|
||||
### `proxy.cert`
|
||||
|
||||
The path of the PEM encoded private key to use for HTTPS.
|
||||
|
||||
**Required** if HTTPS is enabled for the proxy.
|
||||
|
||||
Type: string.
|
||||
33
book/src/database.md
Normal file
33
book/src/database.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Database
|
||||
|
||||
There are 3 ways of accessing the database of a haze instance.
|
||||
|
||||
## CLI
|
||||
|
||||
```bash
|
||||
haze [filter] db [query]
|
||||
```
|
||||
|
||||
Opens the command line client for the database. If a query is specified, it will
|
||||
be executed. If no query is specified, an interactive shell will be started.
|
||||
|
||||
Example
|
||||
|
||||
```
|
||||
haze db 'select fileid, storage, path from oc_filecache'
|
||||
```
|
||||
|
||||
## WebUI
|
||||
|
||||
A web UI (based on [DbGate](https://www.dbgate.io/)) is available with every
|
||||
instance.
|
||||
|
||||
It can be accessed by using `haze open db`, or, if the proxy is setup at
|
||||
`db.haze.example.com`.
|
||||
|
||||
## External tools
|
||||
|
||||
For usage with external tools, the database connection URL is printed when the
|
||||
instance is created.
|
||||
|
||||
Details on how to use the connection URL is dependent on the external tool.
|
||||
13
book/src/federation.md
Normal file
13
book/src/federation.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Federation
|
||||
|
||||
Multiple instances can reach each other by using their instance name as domain
|
||||
name to allow for testing federation between instances.
|
||||
|
||||
For example, if you have a `rover-beavers` and `splendid-couch` instance, you
|
||||
can create a federated share from the `rover-beavers` instance to
|
||||
`http://admin@splendid-couch`.
|
||||
|
||||
If the proxy is setup with HTTP, you can use HTTP between the instances by using
|
||||
the full proxy URLs.
|
||||
|
||||
For example sharing to `admin@splendid-couch.haze.example.com`.
|
||||
11
book/src/frankenphp.md
Normal file
11
book/src/frankenphp.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# FrankenPHP (experimental)
|
||||
|
||||
You can have Nextcloud run on FrankenPHP by starting the instance with the
|
||||
`franken-php` option.
|
||||
|
||||
Caddy's admin metrics are then accessible through
|
||||
`http://<cloud-id>-franken-php.haze.test`. With ember you can run:
|
||||
|
||||
```bash
|
||||
ember --addr http://<cloud-id>-franken-php.haze.test
|
||||
```
|
||||
91
book/src/proxy/README.md
Normal file
91
book/src/proxy/README.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Proxy
|
||||
|
||||
By default, instances can be accessed by their IP. In order to get more
|
||||
memorable URLs and allow supporting HTTPS. haze comes with a builtin reverse
|
||||
proxy to allow using a wildcard domain.
|
||||
|
||||
## Setup
|
||||
|
||||
- [Setup a DNS record](./dns.html) for `*.haze.example.com` and
|
||||
`haze.example.com` pointing to your development machine.
|
||||
- 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](https://codeberg.org/icewind/haze/src/branch/main/haze.service)>)
|
||||
for an example).
|
||||
- If you're already running a reverse proxy, configure your reverse proxy of
|
||||
choice to proxy `*.haze.example.com` and `haze.example.com` to the proxy's
|
||||
listen endpoint.
|
||||
- (Optionally) [setup HTTPS](./https.html) for the proxy.
|
||||
|
||||
### Configuration
|
||||
|
||||
Add the following configuration to the `haze.toml` configuration file:
|
||||
|
||||
```toml
|
||||
[proxy]
|
||||
address = "haze.example.com" # the base domain for the proxy to use
|
||||
listen = "127.0.0.1:8080" # the port+ip to listen on
|
||||
# listen = "/var/run/haze/haze.sock" # or a unix socket path
|
||||
```
|
||||
|
||||
### Without a reverse proxy
|
||||
|
||||
If you have no other http(s) servers on your development machine, you can setup
|
||||
things without a reverse proxy.
|
||||
|
||||
Simply configure the proxy to listen on port `80` (or `443` when using HTTPS).
|
||||
|
||||
Binding to port 80 or443 as a regular user requires either giving the haze
|
||||
binary the `net_bind_service` capability with
|
||||
`sudo setcap cap_net_bind_service=+ep $(which haze)` (this will have to be done
|
||||
every time your upgrade haze) or configure your system to allow unprivileged
|
||||
users to bind on the low port numbers. Using
|
||||
`sysctl net.ipv4.ip_unprivileged_port_start=80` and writing
|
||||
|
||||
```
|
||||
net.ipv4.ip_unprivileged_port_start=80
|
||||
```
|
||||
|
||||
to `/etc/sysctl.d/bind.conf` to make it persistent across reboot.
|
||||
|
||||
### With a reverse proxy
|
||||
|
||||
If you're already have other http(s) services listening on your machine, you'll
|
||||
probably want to setup a reverse proxy to allow them to all be served on your
|
||||
machine.
|
||||
|
||||
The setup for this will depend on your reverse proxy of the choice, the
|
||||
following example configuration is for `nginx`.
|
||||
|
||||
```nginx
|
||||
upstream haze-handler {
|
||||
server unix:/var/run/haze/haze.sock;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name *.haze.example.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://haze-handler;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
When the proxy is configured, generated URLs for the instances will use a
|
||||
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 service containers trough either
|
||||
`<instance id>-<service id>.haze.example.com` for a specific instance, or
|
||||
`<service-id>.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.
|
||||
27
book/src/proxy/dns.md
Normal file
27
book/src/proxy/dns.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# DNS
|
||||
|
||||
Since the domain name used for the instance is dynamic, a wildcard DNS record is
|
||||
required.
|
||||
|
||||
## With your domain's DNS provider
|
||||
|
||||
If you own a domain you would like to use, you can create a wildcard domain
|
||||
within the DNS settings of your DNS provider. For example creating a record an
|
||||
`A` record for `*.haze.example.com` with a value of `127.0.0.1` and a similar
|
||||
one for `haze.example.com`.
|
||||
|
||||
## With a local dnsmasq
|
||||
|
||||
If you do not own a "real" domain for using with haze, you can setup `dnsmasq`
|
||||
locally to achieve the same goal instead.
|
||||
|
||||
How to install and enable `dnsmasq` will depend on your Linux distribution of
|
||||
choice and should be documented by it's documentation.
|
||||
|
||||
Once setup, a configuration line like
|
||||
|
||||
```
|
||||
address=/haze.local/172.0.0.1
|
||||
```
|
||||
|
||||
should be enough to point `haze.local` and `*.haze.local` to your local host.
|
||||
78
book/src/proxy/https.md
Normal file
78
book/src/proxy/https.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# HTTPS
|
||||
|
||||
The proxy can be setup to enable using HTTPS to access the running instances.
|
||||
Besides the warm and fuzzy feeling of knowing that nobody can snoop on the
|
||||
traffic that is happening completely local inside your machine. Accessing the
|
||||
page over HTTPS is required for some JavaScript features (such as service
|
||||
workers), as they are only available in "secure contexts".
|
||||
|
||||
## Getting a wildcard certificate
|
||||
|
||||
Since the domain name used for the instance is dynamic, a wildcard certificate
|
||||
is required.
|
||||
|
||||
## Let's encrypt
|
||||
|
||||
Let's encrypt allows getting trusted wildcard certificates for free if you can
|
||||
use DNS validation.
|
||||
|
||||
How to setup DNS validation will depend on the specifics of the DNS provider and
|
||||
ACME client.
|
||||
[This](https://community.letsencrypt.org/t/dns-providers-who-easily-integrate-with-lets-encrypt-dns-validation/86438)
|
||||
lists some DNS providers and supported ACME clients.
|
||||
|
||||
## Self signed
|
||||
|
||||
You can also create a self-signed wildcard certificate using a tool like
|
||||
`mkcert`. This certificate will not be trusted by your browser and tools like
|
||||
curl, but you can add manually add it to the trusted certificates on your
|
||||
system, or bypass the certificates warning in the browser/curl every time.
|
||||
|
||||
```bash
|
||||
# Generate local wildcard certificate
|
||||
mkcert -cert-file <path-to-your-certificates>haze.example.com.crt -key-file <path-to-your-certificates>haze.example.com.key '*.haze.example.com'
|
||||
```
|
||||
|
||||
## Using the certificate
|
||||
|
||||
### Without reverse proxy
|
||||
|
||||
The haze proxy can serve over HTTPS directly, to enable that add the following
|
||||
to the `[proxy]` section of your `haze.toml`.
|
||||
|
||||
```toml
|
||||
https = true
|
||||
cert = "/path/to/haze.example.com.crt"
|
||||
key = "/path/to/haze.example.com.key"
|
||||
```
|
||||
|
||||
You might also want to change the port it's listening on to `443`.
|
||||
|
||||
### With a reverse proxy
|
||||
|
||||
This depends on what reverse proxy you have setup. The following example is for
|
||||
`nginx`.
|
||||
|
||||
```nginx
|
||||
upstream haze-handler {
|
||||
server unix:/run/haze/haze.sock;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name *.haze.example.com;
|
||||
|
||||
ssl_certificate <path-to-your-certificates>/haze.example.com.crt;
|
||||
ssl_certificate_key <path-to-your-certificates>/haze.example.com.key;
|
||||
|
||||
location / {
|
||||
proxy_pass http://haze-handler;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
72
book/src/scripts.md
Normal file
72
book/src/scripts.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# Haze scripts
|
||||
|
||||
Haze scripts combine a set of instance options and a script to run in the
|
||||
instance.
|
||||
|
||||
Haze scripts are intended to way to create automated ways of running more
|
||||
complex tests are setting up more complex instances.
|
||||
|
||||
A script contains of 3 paths
|
||||
|
||||
1. An optional shebang line setting `haze` as the interpreter, e.g.
|
||||
`#! /usr/bin/env -S haze script`
|
||||
2. A shebang line setting the options for the instance creation as the
|
||||
interpreter, e.g. `#! haze shell pgsql s3`
|
||||
3. The rest that is ran as a script inside the created instance.
|
||||
|
||||
The first shebang is set, the script can be ran directly. Else it needs to be
|
||||
run with `haze script [path-to-script]`.
|
||||
|
||||
For example, the following script will create an instance with `postgresql` and
|
||||
`s3` primary storage. Then creates a new file, gets the file id, read the object
|
||||
of the file from S3, validate that it contains the expected contents, and
|
||||
cleanup the instance.
|
||||
|
||||
```bash
|
||||
#! #! /usr/bin/env -S haze script
|
||||
#! haze shell pgsql s3
|
||||
|
||||
echo 'test' | occ file:put '-' /admin/files/test.txt
|
||||
FILE_ID=$(occ info:file /admin/files/test.txt | grep fileid: | grep -oE '[0-9]+')
|
||||
OBJECT_CONTENTS=$(occ file:object:get urn:oid:$FILE_ID -)
|
||||
if [ "$OBJECT_CONTENTS" == 'test' ]; then
|
||||
echo "object contains expected contents"
|
||||
else
|
||||
echo "object does not contains expected contents!"
|
||||
fi
|
||||
```
|
||||
|
||||
### Script modes
|
||||
|
||||
Scripts can be either `shell` or `start` scripts.
|
||||
|
||||
`shell` scripts will automatically remove the created instance once the script
|
||||
is done, just like `haze shell` will. The intended use case for this is
|
||||
performing some tests in the created instance without leaving state behind.
|
||||
|
||||
`start` scripts on the other hand will keep the instance, like `haze start`
|
||||
will. The intended use case for this is creating more complex instances without
|
||||
having to configure a dedicated preset.
|
||||
|
||||
The script mode is determined based on the shebang line. The mode set in a
|
||||
script can be overridden by running the script with
|
||||
`haze script [shell|start] path-to-script.sh`.
|
||||
|
||||
## Using different interpreters
|
||||
|
||||
By default, the script contents are executed as either `bash` script, or `nu`
|
||||
script based on the extension.
|
||||
|
||||
You can overwrite the interpreter used to execute the script by adding an extra
|
||||
`#!` line to the script, for example:
|
||||
|
||||
```bash
|
||||
#! /usr/bin/env -S haze script
|
||||
#! haze shell pgsql s3
|
||||
#! php -f
|
||||
<?php
|
||||
print("Hello");
|
||||
```
|
||||
|
||||
Note that the interpreter used needs to already be available inside the haze
|
||||
container.
|
||||
41
book/src/services.md
Normal file
41
book/src/services.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Services
|
||||
|
||||
The following service options are available:
|
||||
|
||||
- `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.
|
||||
- `ldap`: set up an LDAP server.
|
||||
- `saml`: set up Authentik as a SAML IDP.
|
||||
- `oidc`: set up Authentik as an OIDC IDP.
|
||||
- `scim`: set up Authentik as a SCIM server.
|
||||
- `office`: set up a Nextcloud Office server.
|
||||
- `onlyoffice` setup an OnlyOffice document server.
|
||||
- `push` set up [client push](https://github.com/nextcloud/notify_push).
|
||||
- `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.
|
||||
- `clamav`: set up a local clam av scanner in executable mode.
|
||||
- `clamav-socket`: set up a clam av scanner in socket mode.
|
||||
- `clamav-icap`: set up a clam av scanner in ICAP mode.
|
||||
- `clamav-icap-tls`: set up a clam av scanner in ICAP mode with TLS encryption.
|
||||
- `oc`: start an ownCloud instance in the same network.
|
||||
- `imaginary`: start an Imaginary service and configure it for preview
|
||||
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.
|
||||
- `<path to app.tar.gz>`: 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.
|
||||
36
book/src/setup.md
Normal file
36
book/src/setup.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Setup
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker
|
||||
|
||||
haze is built around docker containers and manages containers using the docker
|
||||
socket. Using Podman with docker compatibility might also work, but is untested.
|
||||
|
||||
## Installation
|
||||
|
||||
- Grab a binary from the
|
||||
[Codeberg releases](https://codeberg.org/icewind/haze/releases) and place it
|
||||
in your `$PATH`
|
||||
|
||||
## Configuration
|
||||
|
||||
Create a file `~/.config/haze/haze.toml` with the following options:
|
||||
|
||||
```toml
|
||||
sources_root = "/path/to/nextcloud/sources"
|
||||
```
|
||||
|
||||
See the [configuration section](./configuration.html) for more options.
|
||||
|
||||
## Test the Setup
|
||||
|
||||
### Quick examples
|
||||
|
||||
- Start a basic Nextcloud instance:
|
||||
|
||||
```bash
|
||||
haze start
|
||||
```
|
||||
|
||||
- Navigate to the address that is provided in the output.
|
||||
230
book/src/usage.md
Normal file
230
book/src/usage.md
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
# Usage
|
||||
|
||||
## Quick examples
|
||||
|
||||
- Start a Nextcloud instance with `postgresql`, and `s3` primary storage:
|
||||
|
||||
```bash
|
||||
haze start pgsql s3
|
||||
```
|
||||
|
||||
- Start a Nextcloud instance with `sqlite`, `php 8.3` and an `smb` external
|
||||
storage:
|
||||
|
||||
```bash
|
||||
haze start 8.3 smb
|
||||
```
|
||||
|
||||
- Run specific units test against an `oracle` database
|
||||
```bash
|
||||
haze test oracle apps/dav/tests/unit/Connector/Sabre
|
||||
```
|
||||
|
||||
## Managing instances
|
||||
|
||||
### Starting an instance
|
||||
|
||||
```bash
|
||||
haze start [--name <name>] [--detach] [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.
|
||||
|
||||
You can specify a version number (e.g. `v32.0.2`) to use the sources from a
|
||||
release instead of using the local sources.
|
||||
|
||||
Use `--name <name>` to give the instance a specific name instead of a randomly
|
||||
generated one. For example:
|
||||
|
||||
Use `--detach` to give the instance
|
||||
[its own sources](#instances-with-their-own-sources) instead of sharing
|
||||
`sources_root` with all other instances.
|
||||
|
||||
See the [services documentation](./services.html) for a list of available
|
||||
services.
|
||||
|
||||
### List running instances
|
||||
|
||||
```bash
|
||||
haze
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
haze list
|
||||
```
|
||||
|
||||
### Stop an instance
|
||||
|
||||
```bash
|
||||
haze [match] stop
|
||||
```
|
||||
|
||||
### Remove all unpinned running instances
|
||||
|
||||
```bash
|
||||
haze clean
|
||||
```
|
||||
|
||||
### Pin an instance
|
||||
|
||||
```bash
|
||||
haze [match] pin
|
||||
```
|
||||
|
||||
Pinned instances will not be removed by `haze clean`.
|
||||
|
||||
### Unpin an instance
|
||||
|
||||
```bash
|
||||
haze [match] unpin
|
||||
```
|
||||
|
||||
## Run commands in a temporary instance
|
||||
|
||||
```bash
|
||||
haze shell [database] [php-version] [services] [cmd]
|
||||
```
|
||||
|
||||
This will create an instance, run the provided command, and cleanup the
|
||||
instance.
|
||||
|
||||
If no `cmd` is specified it will launch `bash`
|
||||
|
||||
## Run tests in a new instance
|
||||
|
||||
```bash
|
||||
haze test [database] [php-version] [services] [phpunit version] [path]
|
||||
```
|
||||
|
||||
Where `path` is a file or folder to run PHPUnit in, relative to the sources
|
||||
root.
|
||||
|
||||
This will create a fresh instance, run the PHPUnit tests, and clean up the
|
||||
created instance.
|
||||
|
||||
## Interacting with running instances
|
||||
|
||||
The following commands run against the most recently started instance by default
|
||||
and allow optionally providing a `match` to select a specific instance by its
|
||||
name.
|
||||
|
||||
### Open an instance in the browser
|
||||
|
||||
```bash
|
||||
haze [match] open
|
||||
```
|
||||
|
||||
### Execute a command on an instance
|
||||
|
||||
```bash
|
||||
haze [match] [service] [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.
|
||||
|
||||
If no `cmd` is specified it will launch `bash`
|
||||
|
||||
### Execute an occ command on an instance
|
||||
|
||||
```bash
|
||||
haze [match] occ [cmd]
|
||||
```
|
||||
|
||||
### Connect to the database on an instance
|
||||
|
||||
```bash
|
||||
haze [match] db
|
||||
```
|
||||
|
||||
### Show the logs of an instance
|
||||
|
||||
```bash
|
||||
haze [match] logs
|
||||
```
|
||||
|
||||
### Edit a file in an instance with the local $EDITOR
|
||||
|
||||
```bash
|
||||
haze [match] edit <path>
|
||||
```
|
||||
|
||||
Where `<path>` is the path of a file inside the container, for example
|
||||
`config/config.php`.
|
||||
|
||||
### Reload the PHP configuration of an instance
|
||||
|
||||
```bash
|
||||
haze [match] reload
|
||||
```
|
||||
|
||||
The PHP configuration can edit changed with `haze edit /config/php.ini`
|
||||
|
||||
### Run a command with instance environment variables set
|
||||
|
||||
```bash
|
||||
haze [match] env <cmd> [args]
|
||||
```
|
||||
|
||||
Runs the provided command with `NEXTCLOUD_URL`, `DATABASE_URL` and `REDIS_URL`
|
||||
environment variables set for the matched instance.
|
||||
|
||||
This is intended to run a local
|
||||
[push daemon](https://github.com/nextcloud/notify_push) against an instance.
|
||||
|
||||
## Git tools
|
||||
|
||||
Haze provides a couple of utilities to make working with many git repositories
|
||||
for apps easier.
|
||||
|
||||
### Checkout a branch for all local apps
|
||||
|
||||
```bash
|
||||
haze git checkout [branch]
|
||||
```
|
||||
|
||||
Checks out the branch in all git repositories within the apps folder.
|
||||
|
||||
Defaults to the branch matching the current checked out server versions (e.g.
|
||||
`master` or `stable33`).
|
||||
|
||||
`master` and `main` can be used interchangeably.
|
||||
|
||||
### Pull remote changes for all local apps
|
||||
|
||||
```bash
|
||||
haze git pull
|
||||
```
|
||||
|
||||
Performs a pull in all git repositories within the apps folder.
|
||||
|
||||
## Update the container images
|
||||
|
||||
```bash
|
||||
haze update
|
||||
```
|
||||
|
||||
## Instances with their own sources
|
||||
|
||||
By default every instance shares the sources configured as `sources_root`, so
|
||||
all instances always run the same code. An instance started with `--detach` gets
|
||||
its own `git worktree` of `sources_root` instead, created in `worktree_dir`,
|
||||
which lets you run several instances on different branches at the same time.
|
||||
|
||||
```bash
|
||||
haze start --name my-fix --detach
|
||||
```
|
||||
|
||||
The worktree is checked out with a detached head. Every app in one of the
|
||||
`app_directories` that gets enabled during setup receives its own worktree as
|
||||
well, other apps keep running from the shared app directory.
|
||||
|
||||
The worktrees are removed together with the instance, by `haze stop` or
|
||||
`haze clean`.
|
||||
36
book/src/xdebug.md
Normal file
36
book/src/xdebug.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Xdebug
|
||||
|
||||
To use Xdebug running in a haze instance with your IDE for debugging, you need
|
||||
to tell you IDE how to properly map the path from the container to the host. The
|
||||
IDE debugger configuration usually looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"label": "PHP: Debug server within docker",
|
||||
"adapter": "Xdebug",
|
||||
"request": "launch",
|
||||
"port": 9003,
|
||||
"pathMappings": {
|
||||
"/var/www/html": "<sources_root_configured_in_haze.toml>",
|
||||
"/var/www/html/apps-extra": "<app_directories_configured_in_haze.toml>",
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
This would have to be adapted for detached instances.
|
||||
|
||||
## Debugging all requests
|
||||
|
||||
By default, Xdebug is configured to only run for requests that containing the
|
||||
trigger (e.g. from using the Xdebug browser extension, or adding
|
||||
`?XDEBUG_SESSION_START=1` to the URL).
|
||||
|
||||
To enable Xdebug for all requests:
|
||||
|
||||
- Un-comment the lines in `haze [cloud-id] edit /config/php.ini`
|
||||
- Then run `haze reload [cloud-id]`
|
||||
|
||||
## Xdebug profile and trace files
|
||||
|
||||
When enabling Xdebug trace or profile mode, the generated files can be found in
|
||||
`<work-dir>/<instance id>/xdebug`.
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#! /usr/bin/env -S haze script
|
||||
#! haze shell pgsql s3
|
||||
#! /usr/bin/env nu
|
||||
|
||||
echo 'test' | occ file:put '-' /admin/files/test.txt
|
||||
FILE_ID=$(occ info:file /admin/files/test.txt | grep fileid: | grep -oE '[0-9]+')
|
||||
|
|
|
|||
30
flake.lock
generated
30
flake.lock
generated
|
|
@ -38,11 +38,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1789408620,
|
||||
"narHash": "sha256-ZymN+wNsIs0rMw9ydP5Yp5GIUKZoA8b8IDsCnz30VfE=",
|
||||
"lastModified": 1790013821,
|
||||
"narHash": "sha256-0OrPYAGfGF5BGPPtzEzeMNhNcvGyQBWRRfvcE0xY750=",
|
||||
"owner": "nix-community",
|
||||
"repo": "flakelight",
|
||||
"rev": "1d9163b9abf315129e912f3157e03b265f104838",
|
||||
"rev": "a57b0af9d0da4c5389ccf19e310daf0e5518312a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -80,11 +80,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1788758950,
|
||||
"narHash": "sha256-b3zONUcYXZHeoeYwDZdSDCzMj0s6ubmD6NT3D7sS+jU=",
|
||||
"lastModified": 1790258944,
|
||||
"narHash": "sha256-3bwtAiifsfGXVLIopwhJ/RNIkDABcLg6DxnlbaiE2xc=",
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"rev": "b6ac40ef110c12ab1651fce5ea563f7837236439",
|
||||
"rev": "08d8889b6d2528acfce6e2616b0cd41983dedb02",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -95,11 +95,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1789749394,
|
||||
"narHash": "sha256-cFTsMQz8Hzn8MT49oaeLSHg62tE86NykugCWkeM2ypk=",
|
||||
"lastModified": 1790218706,
|
||||
"narHash": "sha256-6e4Na3z008XpdVyOXgfasXIn1aN+z8AXFG+jXdQSyuI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "cf9d2fb3e50fa1cd5114c47505ea9177f7ff5f49",
|
||||
"rev": "c508844df6c28fa6dabc1b6af70f3ccbd65c5201",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -110,11 +110,11 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1788953386,
|
||||
"narHash": "sha256-dIqD4NX3Uldk29CBqKt9dRdSxh/+Ba8lVPu2xEsLTJo=",
|
||||
"lastModified": 1789370336,
|
||||
"narHash": "sha256-6RSEDHIWQtesQKWSu5qRai8L2h4KgCgMEfJHstW99G4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "19a27817106f9449970edb3a398ab5349666466f",
|
||||
"rev": "c7def046b9a883d46974757852106483d741586f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -130,11 +130,11 @@
|
|||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1789262846,
|
||||
"narHash": "sha256-IrgEYbj5LY4EskP8lvYRexPp0jI2KBy3NJZBBgSqrpg=",
|
||||
"lastModified": 1790337121,
|
||||
"narHash": "sha256-phqixEWMLjvdlUpo6uBCYbVYuGCk0FjiIoC0zPTCu3c=",
|
||||
"owner": "fossar",
|
||||
"repo": "nix-phps",
|
||||
"rev": "af15d3f84460bfa8cd15278795347e4661e0a199",
|
||||
"rev": "2a7ca28d4634890d2b07a63847cd6d26da9c2cb4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
"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;
|
||||
haze-book = pkgs: pkgs.haze-book;
|
||||
};
|
||||
|
||||
tools = pkgs:
|
||||
|
|
@ -63,8 +64,14 @@
|
|||
bacon
|
||||
skopeo
|
||||
dive
|
||||
mdbook
|
||||
vale
|
||||
];
|
||||
|
||||
checks = {
|
||||
vale = {vale, ...}: "${vale}/bin/vale src/ book/src/ book/README.md *.md";
|
||||
};
|
||||
|
||||
homeModules = {
|
||||
default = {
|
||||
pkgs,
|
||||
|
|
|
|||
20
nix/book.nix
Normal file
20
nix/book.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
mdbook,
|
||||
stdenv,
|
||||
...
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
name = "haze-book";
|
||||
src = ../book;
|
||||
|
||||
nativeBuildInputs = [mdbook];
|
||||
|
||||
buildPhase = ''
|
||||
mdbook build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -r book/* $out/
|
||||
'';
|
||||
}
|
||||
|
|
@ -6,4 +6,5 @@ final: prev: {
|
|||
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;};
|
||||
haze-book = final.callPackage ./book.nix {};
|
||||
}
|
||||
|
|
|
|||
19
src/args.rs
19
src/args.rs
|
|
@ -64,6 +64,7 @@ pub enum HazeArgs {
|
|||
},
|
||||
Open {
|
||||
filter: Option<String>,
|
||||
service: Option<Service>,
|
||||
},
|
||||
Fmt {
|
||||
path: String,
|
||||
|
|
@ -317,7 +318,20 @@ impl HazeArgs {
|
|||
.into_diagnostic()?,
|
||||
})
|
||||
}
|
||||
HazeCommand::Open => Ok(HazeArgs::Open { filter }),
|
||||
HazeCommand::Open => {
|
||||
let mut args = args.peekable();
|
||||
let service = match args.peek() {
|
||||
Some(arg) => Service::from_type(&[], arg.as_ref())
|
||||
.into_iter()
|
||||
.filter_map(|services| services.into_iter().next())
|
||||
.next()
|
||||
.inspect(|_| {
|
||||
args.next();
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
Ok(HazeArgs::Open { filter, service })
|
||||
}
|
||||
HazeCommand::Fmt => {
|
||||
let path = args
|
||||
.next()
|
||||
|
|
@ -472,6 +486,7 @@ pub enum HazeCommand {
|
|||
))]
|
||||
Logs,
|
||||
/// Open an instance in the browser
|
||||
#[strum(props(Args = "[service] service to open, instead of the Nextcloud instance"))]
|
||||
Open,
|
||||
/// Run code formatting from a new instance
|
||||
#[strum(props(Args = "[path] path to format"))]
|
||||
|
|
@ -507,7 +522,7 @@ pub enum HazeCommand {
|
|||
/// Edit a file in the instance with $EDITOR on the host
|
||||
#[strum(props(Args = "[path] file to edit"))]
|
||||
Edit,
|
||||
/// Reload the php configuration in the instance
|
||||
/// Reload the PHP configuration in the instance
|
||||
#[strum(props(
|
||||
Details = "note: you can overwrite <yellow>php.ini</yellow> settings with <literal>haze</literal> <arg>[filter]</arg> <literal>edit /config/php.ini</literal>"
|
||||
))]
|
||||
|
|
|
|||
11
src/cloud.rs
11
src/cloud.rs
|
|
@ -4,9 +4,9 @@ use crate::exec::{ExitCode, exec, exec_io, exec_tty};
|
|||
use crate::git::{create_worktree, find_app_repo, init_submodules, remove_worktree};
|
||||
use crate::mapping::{Mapping, for_config};
|
||||
use crate::php::PhpVersion;
|
||||
use crate::service::Service;
|
||||
use crate::service::ServiceTrait;
|
||||
use crate::service::deduplicate_services;
|
||||
use crate::service::{DbGate, Service};
|
||||
use crate::sources::download_nc;
|
||||
use bollard::Docker;
|
||||
use bollard::config::NetworkCreateRequest;
|
||||
|
|
@ -347,6 +347,8 @@ fn test_option_parse() {
|
|||
);
|
||||
}
|
||||
|
||||
static DEFAULT_SERVICES: &[Service] = &[Service::DbGate(DbGate)];
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Cloud {
|
||||
pub id: String,
|
||||
|
|
@ -539,6 +541,8 @@ impl Cloud {
|
|||
options
|
||||
.services
|
||||
.iter()
|
||||
.filter(|service| !service.hidden())
|
||||
.chain(DEFAULT_SERVICES.iter())
|
||||
.map(|service| service.spawn(docker, &id, &network, config, &options)),
|
||||
)
|
||||
.await?;
|
||||
|
|
@ -808,7 +812,8 @@ impl Cloud {
|
|||
&& match filter.as_ref() {
|
||||
Some(filter) => cloud_id.contains(filter),
|
||||
None => true,
|
||||
} {
|
||||
}
|
||||
{
|
||||
let entry = containers_by_id.entry(cloud_id.to_string()).or_default();
|
||||
if labels.get("haze-type").map(String::as_str) == Some("cloud") {
|
||||
entry.0 = Some(container);
|
||||
|
|
@ -969,7 +974,7 @@ impl Cloud {
|
|||
}
|
||||
|
||||
pub fn services(&self) -> impl Iterator<Item = &Service> {
|
||||
self.options.services.iter()
|
||||
self.options.services.iter().chain(DEFAULT_SERVICES.iter())
|
||||
}
|
||||
|
||||
pub fn db(&self) -> &Database {
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ pub struct ProxyConfig {
|
|||
}
|
||||
|
||||
impl ProxyConfig {
|
||||
/// Get a public address for a service, either with direct ip or through the proxy
|
||||
/// Get a public address for a service, either with direct IP or through the proxy
|
||||
pub fn addr(&self, id: &str, ip: IpAddr) -> String {
|
||||
let clean_id = id.strip_prefix("haze-").unwrap_or(id);
|
||||
match (&self.address, self.https) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use crate::config::HazeConfig;
|
||||
use crate::exec::{exec, exec_tty, ExitCode};
|
||||
use crate::exec::{ExitCode, exec, exec_tty};
|
||||
use crate::image::pull_image;
|
||||
use bollard::Docker;
|
||||
use bollard::config::ContainerCreateBody;
|
||||
use bollard::models::{EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, Report, Result, WrapErr};
|
||||
use std::io::{stdout, Stdout};
|
||||
use std::io::{Stdout, stdout};
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
|
@ -32,6 +32,39 @@ impl DatabaseFamily {
|
|||
pub fn name(&self) -> &'static str {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn db_gate_driver(&self) -> &'static str {
|
||||
match self {
|
||||
DatabaseFamily::Mysql => "mysql@dbgate-plugin-mysql",
|
||||
DatabaseFamily::MariaDB => "mariadb@dbgate-plugin-mysql",
|
||||
DatabaseFamily::Postgres => "postgres@dbgate-plugin-postgres",
|
||||
DatabaseFamily::Oracle => "oracle@dbgate-plugin-oracle",
|
||||
DatabaseFamily::Sqlite => "sqlite@dbgate-plugin-sqlite",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn port(&self) -> u16 {
|
||||
match self {
|
||||
DatabaseFamily::Mysql | DatabaseFamily::MariaDB => 3306,
|
||||
DatabaseFamily::Postgres => 5432,
|
||||
DatabaseFamily::Oracle => 1521,
|
||||
DatabaseFamily::Sqlite => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn username(&self) -> &'static str {
|
||||
match self {
|
||||
DatabaseFamily::Oracle => "system",
|
||||
_ => "haze",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn db(&self) -> &'static str {
|
||||
match self {
|
||||
DatabaseFamily::Oracle => "SYSTEM",
|
||||
_ => "haze",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ pub async fn exec_tty<S1: AsRef<str>, S2: Into<String>, Env: Into<String>>(
|
|||
}
|
||||
});
|
||||
|
||||
// set stdout in raw mode so we can do tty stuff
|
||||
// set stdout in raw mode so we can do TTY stuff
|
||||
let mut stdout = stdout.lock().into_raw_mode().into_diagnostic()?;
|
||||
|
||||
// pipe docker exec output into stdout
|
||||
|
|
|
|||
|
|
@ -151,13 +151,15 @@ fn subcommand_help(command: &dyn SubCommand) {
|
|||
for service in ServiceType::iter() {
|
||||
let service: ServiceType = service;
|
||||
let service_str: &'static str = service.into();
|
||||
if let Some(doc) = service.get_documentation() {
|
||||
println!(
|
||||
" {}{} {}",
|
||||
service.blue(),
|
||||
" ".repeat(max_service_len - service_str.len()),
|
||||
service.get_documentation().unwrap_or_default(),
|
||||
doc,
|
||||
);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
|
||||
println!("{}", "Options:".yellow().bold());
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use bollard::Docker;
|
||||
use bollard::models::CreateImageInfo;
|
||||
use bollard::query_parameters::CreateImageOptions;
|
||||
use bollard::Docker;
|
||||
use futures_util::StreamExt;
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
use miette::{IntoDiagnostic, Result, WrapErr};
|
||||
|
|
|
|||
25
src/main.rs
25
src/main.rs
|
|
@ -129,7 +129,11 @@ async fn main() -> Result<ExitCode> {
|
|||
HazeArgs::List { filter } => {
|
||||
let list = Cloud::list(&docker, filter, &config).await?;
|
||||
for cloud in list {
|
||||
let mut services: Vec<_> = cloud.services().map(Service::name).collect();
|
||||
let mut services: Vec<_> = cloud
|
||||
.services()
|
||||
.filter(|service| !service.hidden())
|
||||
.map(Service::name)
|
||||
.collect();
|
||||
services.push(cloud.db().name());
|
||||
let services = services.join(", ");
|
||||
let pin = if cloud.is_pinned(&docker).await.unwrap_or(false) {
|
||||
|
|
@ -282,11 +286,26 @@ async fn main() -> Result<ExitCode> {
|
|||
.await?;
|
||||
}
|
||||
}
|
||||
HazeArgs::Open { filter } => {
|
||||
HazeArgs::Open { filter, service } => {
|
||||
let cloud = Cloud::get_by_filter(&docker, filter, &config).await?;
|
||||
match cloud.ip {
|
||||
match service {
|
||||
Some(service) => {
|
||||
let Some(ip) = service.get_ips(&docker, &cloud.id).await?.next() else {
|
||||
eprintln!(
|
||||
"Service {} can't be opened as it has no associated IP",
|
||||
service.name()
|
||||
);
|
||||
return Ok(ExitCode::FAILURE);
|
||||
};
|
||||
let addr = config
|
||||
.proxy
|
||||
.addr(&format!("{}-{}", cloud.id, service.name()), ip);
|
||||
opener::open(addr).into_diagnostic()?;
|
||||
}
|
||||
None => match cloud.ip {
|
||||
Some(_) => opener::open(cloud.address).into_diagnostic()?,
|
||||
None => eprintln!("{} is not running", cloud.id),
|
||||
},
|
||||
}
|
||||
}
|
||||
HazeArgs::Test { options, mut args } => {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ impl<'a> Mapping<'a> {
|
|||
.wrap_err("Failed to create source file")?,
|
||||
}
|
||||
|
||||
// For worktrees, pre-create mountpoints within /var/www/html to prevent docker from creating them as root.
|
||||
// For worktrees, pre-create mount points within /var/www/html to prevent docker from creating them as root.
|
||||
if self.target.starts_with("/var/www/html") {
|
||||
let local_target = source_root.join(
|
||||
self.target
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::cloud::Cloud;
|
||||
use bollard::config::NetworkCreateRequest;
|
||||
use bollard::Docker;
|
||||
use bollard::config::NetworkCreateRequest;
|
||||
use miette::{IntoDiagnostic, Result, WrapErr};
|
||||
|
||||
pub async fn clear_networks(docker: &Docker, instances: &[Cloud]) -> Result<()> {
|
||||
|
|
@ -12,7 +12,8 @@ pub async fn clear_networks(docker: &Docker, instances: &[Cloud]) -> Result<()>
|
|||
for network in networks {
|
||||
if let Some(name) = network.name.as_deref()
|
||||
&& let Some(id) = name.strip_prefix("haze-")
|
||||
&& !instances.iter().any(|cloud| cloud.id == id) {
|
||||
&& !instances.iter().any(|cloud| cloud.id == id)
|
||||
{
|
||||
docker.remove_network(name).await.ok();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use crate::config::ProxyConfig;
|
||||
use crate::database::Database;
|
||||
use crate::image::{image_version, pull_image, ImageVersion};
|
||||
use crate::image::{ImageVersion, image_version, pull_image};
|
||||
use crate::network::ensure_network_exists;
|
||||
use crate::service::Service;
|
||||
use crate::service::ServiceTrait;
|
||||
use bollard::Docker;
|
||||
use bollard::config::{ContainerCreateBody, NetworkConnectRequest, NetworkingConfig};
|
||||
use bollard::models::{EndpointSettings, HostConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use itertools::Itertools;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, Report, Result, WrapErr};
|
||||
|
|
@ -127,7 +127,8 @@ impl PhpVersion {
|
|||
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)
|
||||
&& image_version < haze_version {
|
||||
&& image_version < haze_version
|
||||
{
|
||||
eprintln!(
|
||||
"{}: image version is out of date, run {} to update.",
|
||||
"Warning".red(),
|
||||
|
|
|
|||
13
src/proxy.rs
13
src/proxy.rs
|
|
@ -1,8 +1,8 @@
|
|||
use crate::service::{ServiceTrait, ServiceType};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, ServiceType};
|
||||
use crate::{Cloud, HazeConfig};
|
||||
use axum::http::header::HOST;
|
||||
use axum::http::HeaderValue;
|
||||
use axum::http::header::HOST;
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::Request,
|
||||
|
|
@ -10,13 +10,13 @@ use axum::{
|
|||
};
|
||||
use bollard::Docker;
|
||||
use futures_util::StreamExt;
|
||||
use hyper::StatusCode;
|
||||
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 miette::{IntoDiagnostic, miette};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::Infallible;
|
||||
use std::fs::{create_dir_all, set_permissions};
|
||||
|
|
@ -237,7 +237,8 @@ async fn serve(
|
|||
} else {
|
||||
let listen: PathBuf = listen.into();
|
||||
if let Some(parent) = listen.parent()
|
||||
&& !parent.exists() {
|
||||
&& !parent.exists()
|
||||
{
|
||||
create_dir_all(parent).into_diagnostic()?;
|
||||
set_permissions(parent, PermissionsExt::from_mode(0o755)).into_diagnostic()?;
|
||||
}
|
||||
|
|
@ -337,7 +338,7 @@ async fn handler(state: AppState, mut req: Request<Incoming>) -> Result<Response
|
|||
return Ok(hyper::Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(e.into())
|
||||
.unwrap())
|
||||
.unwrap());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::fs::read_to_string;
|
||||
use std::{fs::read_to_string, iter::once};
|
||||
|
||||
use bollard::Docker;
|
||||
use camino::Utf8PathBuf;
|
||||
|
|
@ -36,15 +36,17 @@ pub async fn run_script(
|
|||
let contents = read_to_string(&path)
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to read script file {path}"))?;
|
||||
let (mut options, mode) = parse_script(&contents, config)
|
||||
let script = parse_script(&contents, config)
|
||||
.wrap_err_with(|| format!("Failed to parse script file {path}"))?;
|
||||
let mode = mode_override.unwrap_or(mode);
|
||||
|
||||
let mode = mode_override.unwrap_or(script.mode);
|
||||
let mut options = script.options;
|
||||
|
||||
let target_path = Utf8PathBuf::from(format!("/{}", path.file_name().unwrap()));
|
||||
let shell = if path.extension() == Some("nu") {
|
||||
"nu"
|
||||
} else {
|
||||
"bash"
|
||||
let shell = match (script.shell, path.extension()) {
|
||||
(Some(shell), _) => shell,
|
||||
(None, Some("nu")) => vec!["nu".into()],
|
||||
_ => vec!["bash".into()],
|
||||
};
|
||||
|
||||
options.mappings.push(
|
||||
|
|
@ -61,7 +63,10 @@ pub async fn run_script(
|
|||
cloud
|
||||
.exec(
|
||||
docker,
|
||||
vec![shell.to_string(), target_path.into_string()],
|
||||
shell
|
||||
.into_iter()
|
||||
.chain(once(target_path.into_string()))
|
||||
.collect(),
|
||||
true,
|
||||
get_forward_env(),
|
||||
)
|
||||
|
|
@ -74,14 +79,22 @@ pub async fn run_script(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_script(script: &str, config: &HazeConfig) -> Result<(CloudOptions, ScriptMode)> {
|
||||
let (options, mode) = script
|
||||
#[derive(Debug)]
|
||||
struct Script {
|
||||
options: CloudOptions,
|
||||
mode: ScriptMode,
|
||||
shell: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
fn parse_script(script: &str, config: &HazeConfig) -> Result<Script> {
|
||||
let (options, mode, line_num) = script
|
||||
.lines()
|
||||
.find_map(|line| line.strip_prefix("#! haze "))
|
||||
.enumerate()
|
||||
.find_map(|(i, line)| Some((i, line.strip_prefix("#! haze ")?)))
|
||||
.and_then(
|
||||
|line| match (line.strip_prefix("shell"), line.strip_prefix("start")) {
|
||||
(Some(shell_options), None) => Some((shell_options.trim(), ScriptMode::Shell)),
|
||||
(None, Some(script_options)) => Some((script_options.trim(), ScriptMode::Start)),
|
||||
|(i, line)| match (line.strip_prefix("shell"), line.strip_prefix("start")) {
|
||||
(Some(shell_options), None) => Some((shell_options.trim(), ScriptMode::Shell, i)),
|
||||
(None, Some(script_options)) => Some((script_options.trim(), ScriptMode::Start, i)),
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
|
|
@ -90,5 +103,19 @@ fn parse_script(script: &str, config: &HazeConfig) -> Result<(CloudOptions, Scri
|
|||
|
||||
let options =
|
||||
CloudOptions::parse(config, &mut options).wrap_err("Failed to parse shell options")?;
|
||||
Ok((options, mode))
|
||||
|
||||
let first_content_line = script.lines().nth(line_num + 1).unwrap_or_default();
|
||||
let shell = first_content_line.strip_prefix("#!").map(|bang| {
|
||||
bang.split(" ")
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(String::from)
|
||||
.collect()
|
||||
});
|
||||
|
||||
Ok(Script {
|
||||
options,
|
||||
mode,
|
||||
shell,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
mod authentik;
|
||||
mod clam;
|
||||
mod dav;
|
||||
mod dbgate;
|
||||
mod imaginary;
|
||||
mod kaspersky;
|
||||
mod ldap;
|
||||
|
|
@ -22,6 +23,7 @@ use crate::config::{HazeConfig, Preset, ProxyConfig};
|
|||
pub use crate::service::authentik::{Authentik, AuthentikOidc, AuthentikSaml, AuthentikScim};
|
||||
pub use crate::service::clam::{Clam, ClamIcap, ClamIcapTls, ClamSocket};
|
||||
use crate::service::dav::Dav;
|
||||
pub use crate::service::dbgate::DbGate;
|
||||
use crate::service::imaginary::Imaginary;
|
||||
use crate::service::kaspersky::{Kaspersky, KasperskyIcap};
|
||||
pub use crate::service::ldap::{Ldap, LdapAdmin};
|
||||
|
|
@ -59,6 +61,10 @@ pub trait ServiceTrait {
|
|||
&[]
|
||||
}
|
||||
|
||||
fn hidden(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
async fn spawn(
|
||||
&self,
|
||||
_docker: &Docker,
|
||||
|
|
@ -206,7 +212,7 @@ pub trait ServiceTrait {
|
|||
"bash"
|
||||
}
|
||||
|
||||
/// Allow services to delay the completion of the `start` command untill they are fully setup
|
||||
/// Allow services to delay the completion of the `start` command until they are fully setup
|
||||
///
|
||||
/// This is not for services which are critical for the running of the instance (use `is_healthy` for that)
|
||||
/// But instead for cases where the instance is mostly usable, but might have some missing features
|
||||
|
|
@ -264,18 +270,18 @@ pub enum ServiceType {
|
|||
S3mb,
|
||||
/// Azure Primary storage and external storage
|
||||
Azure,
|
||||
/// Ldap user backend
|
||||
/// LDAP user backend
|
||||
Ldap,
|
||||
/// Ldap admin interface
|
||||
/// LDAP admin interface
|
||||
LdapAdmin,
|
||||
/// OnlyOffice
|
||||
#[strum(serialize = "onlyoffice", serialize = "only-office")]
|
||||
OnlyOffice,
|
||||
/// Libre office online
|
||||
/// LibreOffice online
|
||||
Office,
|
||||
/// notify_push
|
||||
Push,
|
||||
/// Smb external storage
|
||||
/// SMB external storage
|
||||
Smb,
|
||||
/// Database sharding
|
||||
#[strum(serialize = "sharding", serialize = "sharded")]
|
||||
|
|
@ -293,17 +299,17 @@ pub enum ServiceType {
|
|||
SingleShard,
|
||||
/// WebDav external storage
|
||||
Dav,
|
||||
/// Sftp external storage
|
||||
/// SFTP external storage
|
||||
Sftp,
|
||||
/// Sftp external storage with public key authentication
|
||||
/// SFTP external storage with public key authentication
|
||||
SftpKey,
|
||||
/// ownCloud instance for migration
|
||||
Oc,
|
||||
/// Imaginary for preview generation
|
||||
Imaginary,
|
||||
/// Kaspersky antivirus in http mode
|
||||
/// Kaspersky antivirus in HTTP mode
|
||||
Kaspersky,
|
||||
/// Kaspersky antivirus in icap mode
|
||||
/// Kaspersky antivirus in ICAP mode
|
||||
KasperskyIcap,
|
||||
/// Kaspersky antivirus in local binary
|
||||
#[strum(serialize = "clamav", serialize = "clam")]
|
||||
|
|
@ -314,23 +320,23 @@ pub enum ServiceType {
|
|||
/// Kaspersky antivirus in local socket mode
|
||||
#[strum(serialize = "clamav-socket", serialize = "clam-socket")]
|
||||
ClamAvSocket,
|
||||
/// Kaspersky antivirus in icap mode
|
||||
/// Kaspersky antivirus in ICAP mode
|
||||
#[strum(serialize = "clamav-icap", serialize = "clam-icap")]
|
||||
ClamAvIcap,
|
||||
/// Kaspersky antivirus in icap mode with TLS
|
||||
/// Kaspersky antivirus in ICAP mode with TLS
|
||||
#[strum(serialize = "clamav-icap-tls", serialize = "clam-icap-tls")]
|
||||
ClamAvIcapTls,
|
||||
/// Mail server
|
||||
Mail,
|
||||
/// External redis instance
|
||||
/// External Redis instance
|
||||
Redis,
|
||||
/// External redis instance with TLS
|
||||
/// External Redis instance with TLS
|
||||
RedisTls,
|
||||
/// Use FrankenPHP instead of PHP-FPM
|
||||
FrankenPhp,
|
||||
/// Webhook test listener
|
||||
Webhook,
|
||||
/// Enable DB partitioning for mariadb
|
||||
/// Enable DB partitioning for MariaDB
|
||||
Partitioning,
|
||||
/// Authentik identity provider
|
||||
Authentik,
|
||||
|
|
@ -340,6 +346,8 @@ pub enum ServiceType {
|
|||
Oidc,
|
||||
/// Configure Authentik as a SCIM server for Nextcloud
|
||||
Scim,
|
||||
#[strum(serialize = "db", serialize = "db-gate")]
|
||||
DbGate,
|
||||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
|
|
@ -377,6 +385,7 @@ pub enum Service {
|
|||
AuthentikSaml(AuthentikSaml),
|
||||
AuthentikOidc(AuthentikOidc),
|
||||
AuthentikScim(AuthentikScim),
|
||||
DbGate(DbGate),
|
||||
Preset(PresetService),
|
||||
}
|
||||
|
||||
|
|
@ -436,6 +445,7 @@ impl Service {
|
|||
Service::Authentik(Authentik),
|
||||
Service::AuthentikScim(AuthentikScim),
|
||||
]),
|
||||
ServiceType::DbGate => Some(vec![Service::DbGate(DbGate)]),
|
||||
}
|
||||
} else {
|
||||
presets
|
||||
|
|
@ -465,7 +475,7 @@ impl Service {
|
|||
}
|
||||
|
||||
// Remove duplicate services.
|
||||
// Useful for Authentik as it is needed by saml and oidc.
|
||||
// Useful for Authentik as it is needed by SAML and OIDC.
|
||||
pub fn deduplicate_services(services: impl IntoIterator<Item = Service>) -> Vec<Service> {
|
||||
let mut collected = Vec::new();
|
||||
for service in services {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ async fn spawn_authentik(
|
|||
if !config.proxy.address.is_empty() {
|
||||
let url = config.proxy.addr_with_port(
|
||||
&container_name(cloud_id, "server"),
|
||||
IpAddr::V4(Ipv4Addr::LOCALHOST), // ip arg is unused when a proxy is configured
|
||||
IpAddr::V4(Ipv4Addr::LOCALHOST), // IP argument is unused when a proxy is configured
|
||||
AUTHENTIK_PORT,
|
||||
);
|
||||
env.push(format!("AUTHENTIK_WEB__BASE_URL={url}"));
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use crate::Result;
|
||||
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::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, WrapErr};
|
||||
use tokio::fs::write;
|
||||
|
|
@ -92,7 +92,9 @@ impl ServiceTrait for ClamIcap {
|
|||
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"),
|
||||
split_cmnd(
|
||||
"occ config:app:set files_antivirus av_icap_response_header --value=X-Infection-Found",
|
||||
),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
@ -196,7 +198,9 @@ impl ServiceTrait for ClamIcapTls {
|
|||
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 config:app:set files_antivirus av_icap_response_header --value=X-Infection-Found",
|
||||
),
|
||||
split_cmnd("occ security:certificates:import data/icap-cert.pem"),
|
||||
])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::{split_cmnd, ServiceTrait};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::config::ContainerCreateBody;
|
||||
use bollard::models::{EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
|
||||
|
|
|
|||
133
src/service/dbgate.rs
Normal file
133
src/service/dbgate.rs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
use std::io::Stdout;
|
||||
|
||||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::database::DatabaseFamily;
|
||||
use crate::exec::exec;
|
||||
use crate::image::pull_image;
|
||||
use crate::mapping::Mapping;
|
||||
use crate::service::ServiceTrait;
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct DbGate;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ServiceTrait for DbGate {
|
||||
fn name(&self) -> &str {
|
||||
"db"
|
||||
}
|
||||
|
||||
fn hidden(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
async fn spawn(
|
||||
&self,
|
||||
docker: &Docker,
|
||||
cloud_id: &str,
|
||||
network: &str,
|
||||
config: &HazeConfig,
|
||||
options: &CloudOptions,
|
||||
) -> Result<Vec<String>> {
|
||||
let image = "dbgate/dbgate:7.3.1";
|
||||
pull_image(docker, image).await?;
|
||||
let container_options = Some(CreateContainerOptions {
|
||||
name: self.container_name(cloud_id),
|
||||
..CreateContainerOptions::default()
|
||||
});
|
||||
|
||||
let db_family = options.db.family();
|
||||
|
||||
let mut env = vec![
|
||||
"CONNECTIONS=con1".into(),
|
||||
"USAGE_ANALYTICS=false".into(),
|
||||
"LOCAL_DBGATE_CLOUD=1".into(),
|
||||
"LABEL_con1=haze".into(),
|
||||
format!("ENGINE_con1={}", db_family.db_gate_driver()),
|
||||
];
|
||||
|
||||
if db_family == DatabaseFamily::Sqlite {
|
||||
env.extend(["FILE_con1=/haze-data/haze.db".into()]);
|
||||
} else {
|
||||
env.extend([
|
||||
"SERVER_con1=db".into(),
|
||||
format!("USER_con1={}", db_family.username()),
|
||||
format!("PORT_con1={}", db_family.port()),
|
||||
format!("DATABASE_con1={}", db_family.db()),
|
||||
"PASSWORD_con1=haze".into(),
|
||||
]);
|
||||
}
|
||||
|
||||
if db_family == DatabaseFamily::Oracle {
|
||||
env.push("SERVICE_NAME_con1=xe".into());
|
||||
}
|
||||
|
||||
let mapping = Mapping::new(
|
||||
crate::mapping::MappingSourceType::WorkDir,
|
||||
"data",
|
||||
"/haze-data",
|
||||
);
|
||||
|
||||
let config = ContainerCreateBody {
|
||||
image: Some(image.into()),
|
||||
host_config: Some(HostConfig {
|
||||
network_mode: Some(network.to_string()),
|
||||
binds: Some(vec![
|
||||
mapping
|
||||
.get_volume_arg(cloud_id, config, &config.sources_root)
|
||||
.unwrap(),
|
||||
]),
|
||||
..Default::default()
|
||||
}),
|
||||
env: Some(env),
|
||||
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(container_options, config)
|
||||
.await
|
||||
.into_diagnostic()?
|
||||
.id;
|
||||
docker.start_container(&id, None).await.into_diagnostic()?;
|
||||
exec(
|
||||
docker,
|
||||
&id,
|
||||
"root",
|
||||
vec![
|
||||
"sed",
|
||||
"-i",
|
||||
"s/attr(t,`title`,`Upgrade to Premium`)/attr(t,`style`,`display:none`)/",
|
||||
"public/build/bundle.js",
|
||||
],
|
||||
Vec::<String>::new(),
|
||||
None::<Stdout>,
|
||||
)
|
||||
.await?;
|
||||
Ok(vec![id])
|
||||
}
|
||||
|
||||
fn container_name(&self, cloud_id: &str) -> Option<String> {
|
||||
Some(format!("{}-db-gate", cloud_id))
|
||||
}
|
||||
|
||||
fn proxy_port(&self) -> u16 {
|
||||
3000
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::{split_cmnd, ServiceTrait};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::config::NetworkingConfig;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::Result;
|
||||
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::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::{bail, IntoDiagnostic};
|
||||
use miette::{IntoDiagnostic, bail};
|
||||
use std::io::Stdout;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::{HazeConfig, ProxyConfig};
|
||||
use crate::image::pull_image;
|
||||
use crate::service::{split_cmnd, ServiceTrait};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::config::NetworkingConfig;
|
||||
use bollard::models::{ContainerCreateBody, ContainerState, EndpointSettings, HostConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, Report};
|
||||
use std::net::IpAddr;
|
||||
|
|
@ -102,7 +102,9 @@ impl ServiceTrait for Ldap {
|
|||
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 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"),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::{split_cmnd, ServiceTrait};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::Result;
|
||||
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::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::models::{
|
||||
ContainerCreateBody, ContainerState, EndpointSettings, HostConfig, NetworkingConfig,
|
||||
};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, WrapErr};
|
||||
use serde_json::Value;
|
||||
|
|
@ -260,17 +260,6 @@ impl ServiceTrait for ObjectStore {
|
|||
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()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::exec::exec;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::ServiceTrait;
|
||||
use crate::Result;
|
||||
use bollard::Docker;
|
||||
use bollard::config::NetworkingConfig;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
use std::io::Stdout;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::ServiceTrait;
|
||||
use crate::Result;
|
||||
use bollard::Docker;
|
||||
use bollard::models::{
|
||||
ContainerCreateBody, ContainerState, EndpointSettings, HostConfig, NetworkingConfig,
|
||||
};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, Report};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::Result;
|
||||
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::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::models::{
|
||||
ContainerCreateBody, ContainerState, EndpointSettings, HostConfig, NetworkingConfig,
|
||||
};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, Report};
|
||||
use std::net::Ipv4Addr;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use std::io::stdout;
|
||||
|
||||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::database::DatabaseFamily;
|
||||
use crate::exec::exec;
|
||||
use crate::service::ServiceTrait;
|
||||
use crate::Result;
|
||||
use bollard::Docker;
|
||||
use miette::Report;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use crate::cloud::CloudOptions;
|
|||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::ServiceTrait;
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use local_ip_address::list_afinet_netifas;
|
||||
use maplit::hashmap;
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::{split_cmnd, ServiceTrait};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::{split_cmnd, ServiceTrait};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
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};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::database::DatabaseFamily;
|
||||
use crate::service::ServiceTrait;
|
||||
use crate::Result;
|
||||
use bollard::Docker;
|
||||
use futures_util::future::try_join_all;
|
||||
use maplit::hashmap;
|
||||
use miette::Report;
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::identity;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::{split_cmnd, ServiceTrait};
|
||||
use crate::Result;
|
||||
use crate::service::{ServiceTrait, split_cmnd};
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Result;
|
||||
use crate::cloud::CloudOptions;
|
||||
use crate::config::HazeConfig;
|
||||
use crate::image::pull_image;
|
||||
use crate::service::ServiceTrait;
|
||||
use crate::Result;
|
||||
use bollard::Docker;
|
||||
use bollard::models::{ContainerCreateBody, EndpointSettings, HostConfig, NetworkingConfig};
|
||||
use bollard::query_parameters::CreateContainerOptions;
|
||||
use bollard::Docker;
|
||||
use maplit::hashmap;
|
||||
use miette::IntoDiagnostic;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use std::io::Cursor;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use tokio::fs::create_dir_all;
|
||||
use zip::read::root_dir_common_filter;
|
||||
use zip::ZipArchive;
|
||||
use zip::read::root_dir_common_filter;
|
||||
|
||||
pub struct Sources {
|
||||
#[allow(dead_code)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue