Creates a project from its files and deploys it. Waits for the deploy (wait_seconds) and answers with the operation and, once it ended, the project: its URL, its services' states, its problems. `violations` instead = nothing was created: change what each says, call again. SUCCEEDED says the containers run and listen, not what a page answers: open the URL once (401 = its password page).
Files, one of: the directory as it is on your disk, as an archive (CreateTransfer, then `upload_id`): nothing is retyped; `files`, text you send yourself, when there is no directory or no shell (never a file you have not read); `source.github`. /.env holds the secrets (`env_file: .env`). The compose file is the root's pethost.compose.yaml (so the repository's compose.yaml stays for development), else compose.yaml, compose.yml, docker-compose.yml or docker-compose.yaml; it becomes /compose.yaml, other compose and override files are dropped. Without one, a Dockerfile yields service `app` (reading /.env if any, its EXPOSE ports, a named volume per VOLUME of its last stage).
compose.yaml rules. Data lives in named volumes; all else a container writes is lost when it is recreated. Project files are bind-mounted read-only. HTTP comes through the proxy, to a host of a route in `x-pethost`, the one extension read, in the file or as `x_pethost`:
x-pethost:
metadata: {name: Recipe Box, emoji: "🥗", description: One line, notes: Free text}
routes:
- {host: recipes.sam.pethost.app, service: web, port: 3000}
- {host: recipes.sam.pethost.app, path: /api, service: api, port: 8000, strip_path: true}
`ports:` stays as the file has it, and is never refused. A TCP port it publishes that answers HTTP gets its route by itself and is not opened on the machine: at `<project>.<Machine.apps_domain>`, or `<project>-<service>.<apps_domain>` each when the project has several; `Project.url` has it when the call answers. Any other published port opens on the machine as written, at `<Machine.hostname>:<port>`, and one that is taken there fails the deploy; so does a web port once its route is removed. Never opened: a port bound to 127.0.0.1 (`ssh_command` tunnels to it), a machine port of the machine's own (80, 443, 22), and one nothing listens on within a minute of its start, until a later deploy finds it listening (`Service.published_ports` lists what is open). With `x_pethost.routes` the routes are yours and the machine names none. A project that publishes no port gets `<project>.<apps_domain>` in its first deploy, for the one port it listens on. A service with neither is private: the project's services reach it at `<service>:<port>`. A password for visitors goes only as `x_pethost.password`, never into the file: every route then answers 401 with a password page, over HTTPS only; nothing returns it (`Project.password_protected` says it is set); and `files` that write /compose.yaml keep the `password_hash` line the machine put in its `x-pethost`. All of compose.yaml is interpolated: $$ for $.
The file runs as written, or is refused: the machine corrects nothing in it, in any version. Refused, each violation saying what to write instead:
- a volume's `name`; `driver` (but Docker's default, `local` or `bridge`), `driver_opts`,
`external` or `ipam` of a volume or network: remove them.
- a writable bind mount of the whole project (`.:/app`): add `:ro`.
- a volume with no name (`- /data`): name it. Below a bind mount it is allowed, as scratch
space (`/app/node_modules`).
- `env_file` naming a file the files lack: write it, empty if it sets nothing, or give the
entry `required: false`.
- `privileged`, `cap_add`, `security_opt` (but `no-new-privileges`), `devices`, host
namespaces, the Docker socket, a path outside the directory; more than one replica;
`include` or `extends` from a URL; a git URL as a build context.
Not refused, and read the machine's way: a `container_name` and a network's `name` name nothing on the machine, so two projects may write the same (the project's services still reach the container by it); a service with `profiles` runs only while `COMPOSE_PROFILES` in /.env names one of them, and is no service of the project until then; a bind mount of a folder without `:ro` (`./data:/data`) mounts the project's volume named after the path (`data`), which deploys keep and backups hold, with none of the version's files in it, so project files take `:ro`, and data is plainer in a named volume (`data:/data`, with `data:` under `volumes:`); a bind mount of a file without `:ro` mounts it read-only. An image's VOLUME that no mount covers fails the deploy (UNCOVERED_IMAGE_VOLUME): mount a named volume or a tmpfs there.
ALREADY_EXISTS = the id is taken (a retry with its operation_id returns that operation). FAILED_PRECONDITION = the GitHub App cannot read the repository (see GetMachine.github), or no such branch or directory. A deleted project's id inherits its snapshots.
CreateProject