mirror of
https://github.com/containers/podman-compose.git
synced 2025-07-04 06:30:10 +02:00
Compare commits
241 Commits
Author | SHA1 | Date | |
---|---|---|---|
406596e1db | |||
b3fd55047b | |||
c1ca9166c6 | |||
256b51c8ee | |||
2ed50b9538 | |||
e97d446a04 | |||
9fe6e7f284 | |||
764efd360c | |||
b06224389e | |||
0e37b31e45 | |||
3918f7e5f8 | |||
d7cd02e3e9 | |||
05f341b3c5 | |||
f8d05babd7 | |||
8eb55735e9 | |||
1c0c63aaf2 | |||
2f8dbdcd09 | |||
e789d98bf0 | |||
0de04b32bb | |||
d864e195ce | |||
96ec9617f1 | |||
b48317c22b | |||
0cbf70a4e9 | |||
7105198ae1 | |||
8f9f6d0657 | |||
61392e9cba | |||
dd471c8918 | |||
1113c833da | |||
4177bae807 | |||
fa2252801a | |||
6635b8b570 | |||
8f55227167 | |||
9cde3993f2 | |||
04155d0d09 | |||
605495233e | |||
3e579f65f0 | |||
034b86ea73 | |||
bbdb63604e | |||
93371b0f4e | |||
27d1fc67a0 | |||
77bc9c5602 | |||
82dd0acab2 | |||
0e4f686f4b | |||
0491269f53 | |||
ee90712843 | |||
82d7622c45 | |||
4c6df85efa | |||
7b3276e5d7 | |||
fc6bfc9931 | |||
949af2a50c | |||
b650efbb33 | |||
0b8b483cb7 | |||
0dcc864fdd | |||
56238b10e3 | |||
d4ebf62e0e | |||
83c7e9462e | |||
835e3abe95 | |||
248a63ebb0 | |||
efea0ee652 | |||
3c2978c9ca | |||
5765e5306b | |||
0be50ffdfb | |||
1eae76ddca | |||
6c46678082 | |||
a3f48f830d | |||
dedb081550 | |||
ea22227625 | |||
6b2665683c | |||
58df8497aa | |||
741cb008c8 | |||
39e21d8c11 | |||
02166f584a | |||
8aeeafb98c | |||
9162fe6438 | |||
cc10a61017 | |||
08d06df0f2 | |||
c26e188991 | |||
a983129e88 | |||
76b3055934 | |||
f5e3162e91 | |||
225999eab1 | |||
b86f8b1d61 | |||
3d47849d28 | |||
bfaf77a506 | |||
0c1c4ffea9 | |||
98f065b3e2 | |||
6e30673260 | |||
9c09789948 | |||
01214fa013 | |||
bd29caa797 | |||
f0928dd399 | |||
6c9c09197a | |||
cda84f439f | |||
67616bdaac | |||
7497692b19 | |||
782c44d4c3 | |||
d7762a54f0 | |||
eba2ca2695 | |||
abe5965c9a | |||
9e0da82726 | |||
6acdafd5b1 | |||
8638eb9b6d | |||
e1d938ffa6 | |||
d532e09d7d | |||
1dab256cdd | |||
2a33ef5c79 | |||
5ab734026c | |||
35dc395483 | |||
38a9263424 | |||
cbe9587973 | |||
8bb43100b1 | |||
98f166d2e4 | |||
150ab02446 | |||
ff58a0bff0 | |||
8d899ebb65 | |||
342a39dcfe | |||
d6b8476573 | |||
ae41ef08c3 | |||
da46ee3910 | |||
d80c31f578 | |||
cefa68dc75 | |||
2e46ff0db2 | |||
fbc4c7da80 | |||
11879d3e94 | |||
27cf8da06f | |||
10a30ba24a | |||
a1be62fd31 | |||
15bf02a004 | |||
e45b5d5063 | |||
c46ecb226b | |||
e04b8f3a60 | |||
815450aba9 | |||
92f0a8583a | |||
5f4fc4618c | |||
4d899edeb3 | |||
f9489afaf5 | |||
7d7533772b | |||
65b455f081 | |||
1aa750bacf | |||
98b9bb9f8e | |||
170411de8b | |||
0cf1378cb5 | |||
f5a6df6dc4 | |||
f106ea0c01 | |||
b748c2666c | |||
3973c476c4 | |||
8b1bd0123c | |||
2e7d83f7f0 | |||
52e2912e0b | |||
8ef537e247 | |||
04fcc26a79 | |||
d4760712b7 | |||
7c61f24467 | |||
202c3771a9 | |||
a54f0fa573 | |||
3353697402 | |||
ca1b59c449 | |||
b9f27795c0 | |||
4cd1642be0 | |||
fd401331e5 | |||
37b27fa233 | |||
976847ef9b | |||
c6b3d497d6 | |||
10ad739746 | |||
784d798dac | |||
dd01d039bf | |||
81a0a5933e | |||
c289a3b827 | |||
baccce4f3f | |||
07af8488db | |||
cbc5a8c8b3 | |||
aeaceed7ba | |||
b1eb558b41 | |||
1cdc9e6552 | |||
2f8ed2137c | |||
838957b902 | |||
15380a809d | |||
d4e5859370 | |||
593d7c825e | |||
bfba7ba32d | |||
fe9be2d98f | |||
43a2f1d01f | |||
aa47a373ca | |||
eaec19336f | |||
34bee28bb8 | |||
bfea139362 | |||
4a81bce2a5 | |||
e626f15eff | |||
974250caa5 | |||
29404af723 | |||
d1ba2f4c7d | |||
e03d675b9b | |||
51d180d2d0 | |||
9c905f9012 | |||
bdb3e4e984 | |||
105e390f6b | |||
d79ff01e77 | |||
d9ef3d2cc6 | |||
d23ef4f481 | |||
b685bce400 | |||
7d5bf645f6 | |||
9f7ae38bac | |||
3cee4e015c | |||
498a1994ce | |||
488908f809 | |||
f7bcc4221e | |||
a73df712cc | |||
50dc19f5f8 | |||
9029dce0f6 | |||
a8282c77d6 | |||
f4b775c7e4 | |||
adf30e0475 | |||
41675c3916 | |||
6caf2eae42 | |||
3093b00326 | |||
1c21d655ba | |||
18e5fd64f3 | |||
24bdfd1e17 | |||
c2d3e156c2 | |||
ba95100cff | |||
6022669991 | |||
e29df71d42 | |||
21b9d385b2 | |||
4c17ce2434 | |||
09d54e9dcc | |||
f1dd9b374e | |||
87af67fe94 | |||
f1d663874e | |||
69ffff33f6 | |||
f376700972 | |||
9be3ec985f | |||
6e642dca1f | |||
0f2c717655 | |||
2aa042b9c7 | |||
a177603661 | |||
bc4177fbdc | |||
8206cc3ea2 | |||
60ac5e43b3 | |||
48c6c38fcd | |||
84f1fbd622 | |||
ac5291e10b |
9
.github/workflows/static-checks.yml
vendored
9
.github/workflows/static-checks.yml
vendored
@ -14,12 +14,19 @@ jobs:
|
|||||||
options: --privileged --cgroupns=host
|
options: --privileged --cgroupns=host
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Analysing the code with ruff
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
pip install -r test-requirements.txt
|
pip install -r test-requirements.txt
|
||||||
|
- name: Analysing the code using ruff
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
ruff format --check
|
ruff format --check
|
||||||
ruff check
|
ruff check
|
||||||
|
- name: Analysing the code using mypy
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
mypy .
|
||||||
- name: Analysing the code with pylint
|
- name: Analysing the code with pylint
|
||||||
run: |
|
run: |
|
||||||
pylint podman_compose.py
|
pylint podman_compose.py
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
|
default_install_hook_types: [pre-commit, commit-msg]
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: 23.3.0
|
rev: v0.9.6
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: ruff
|
||||||
# It is recommended to specify the latest version of Python
|
|
||||||
# supported by your project here, or alternatively use
|
|
||||||
# pre-commit's default_language_version, see
|
|
||||||
# https://pre-commit.com/#top_level-default_language_version
|
|
||||||
language_version: python3.10
|
|
||||||
types: [python]
|
types: [python]
|
||||||
args: [
|
|
||||||
"--check", # Don't apply changes automatically
|
|
||||||
]
|
|
||||||
- repo: https://github.com/pycqa/flake8
|
- repo: https://github.com/pycqa/flake8
|
||||||
rev: 6.0.0
|
rev: 6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
@ -34,3 +27,8 @@ repos:
|
|||||||
rev: v2.2.5
|
rev: v2.2.5
|
||||||
hooks:
|
hooks:
|
||||||
- id: codespell
|
- id: codespell
|
||||||
|
|
||||||
|
- repo: https://github.com/gklein/check_signoff
|
||||||
|
rev: v1.0.5
|
||||||
|
hooks:
|
||||||
|
- id: check-signoff
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[MESSAGES CONTROL]
|
[MESSAGES CONTROL]
|
||||||
# C0111 missing-docstring: missing-class-docstring, missing-function-docstring, missing-method-docstring, missing-module-docstrin
|
# C0111 missing-docstring: missing-class-docstring, missing-function-docstring, missing-method-docstring, missing-module-docstrin
|
||||||
# consider-using-with: we need it for color formatter pipe
|
# consider-using-with: we need it for color formatter pipe
|
||||||
disable=too-many-lines,too-many-branches,too-many-locals,too-many-statements,too-many-arguments,too-many-instance-attributes,fixme,multiple-statements,missing-docstring,line-too-long,consider-using-f-string,consider-using-with,unnecessary-lambda-assignment
|
disable=too-many-lines,too-many-branches,too-many-locals,too-many-statements,too-many-arguments,too-many-instance-attributes,fixme,multiple-statements,missing-docstring,line-too-long,consider-using-f-string,consider-using-with,unnecessary-lambda-assignment,broad-exception-caught
|
||||||
# allow _ for ignored variables
|
# allow _ for ignored variables
|
||||||
# allow generic names like a,b,c and i,j,k,l,m,n and x,y,z
|
# allow generic names like a,b,c and i,j,k,l,m,n and x,y,z
|
||||||
# allow k,v for key/value
|
# allow k,v for key/value
|
||||||
|
@ -19,11 +19,12 @@ Note: Some steps are OPTIONAL but all are RECOMMENDED.
|
|||||||
$ cd podman-compose
|
$ cd podman-compose
|
||||||
```
|
```
|
||||||
|
|
||||||
2. (OPTIONAL) Create a Python virtual environment. Example using
|
2. (OPTIONAL) Create a Python virtual environment. Example using python builtin
|
||||||
[virtualenv wrapper](https://virtualenvwrapper.readthedocs.io/en/latest/):
|
`venv` module:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ mkvirtualenv podman-compose
|
$ python3 -m venv .venv
|
||||||
|
$ . .venv/bin/activate
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Install the project runtime and development requirements:
|
3. Install the project runtime and development requirements:
|
||||||
@ -60,9 +61,25 @@ Note: Some steps are OPTIONAL but all are RECOMMENDED.
|
|||||||
- Make sure you include a `Signed-off-by` message in your commits.
|
- Make sure you include a `Signed-off-by` message in your commits.
|
||||||
Read [this guide](https://github.com/containers/common/blob/main/CONTRIBUTING.md#sign-your-prs)
|
Read [this guide](https://github.com/containers/common/blob/main/CONTRIBUTING.md#sign-your-prs)
|
||||||
to learn how to sign your commits.
|
to learn how to sign your commits.
|
||||||
- In the commit message, reference the Issue ID that your code fixes and a brief description of
|
- In the commit message body, reference the Issue ID that your code fixes and a brief description of the changes.
|
||||||
the changes.
|
Example:
|
||||||
Example: `Fixes #516: Allow empty network`
|
```
|
||||||
|
Allow empty network
|
||||||
|
|
||||||
|
<description, such as links to the compose spec and so on>
|
||||||
|
|
||||||
|
Fixes https://github.com/containers/podman-compose/issues/516
|
||||||
|
```
|
||||||
|
- If your commit requires a refactoring, first do the refactoring and
|
||||||
|
commit it separately before starting feature work. This makes the
|
||||||
|
pull request easier to review. Additionally, pull request will be
|
||||||
|
less risky, because if it breaks something, it's way easier to
|
||||||
|
isolate the offending code, understand what's broken and fix it.
|
||||||
|
Due to the latter reason it's best to commit in as many independent
|
||||||
|
commits as reasonable.
|
||||||
|
|
||||||
|
This will result in pull requests being merged much faster.
|
||||||
|
|
||||||
9. Open a pull request to `containers/podman-compose` and wait for a maintainer to review your work.
|
9. Open a pull request to `containers/podman-compose` and wait for a maintainer to review your work.
|
||||||
|
|
||||||
## Adding new commands
|
## Adding new commands
|
||||||
|
63
README.md
63
README.md
@ -68,7 +68,23 @@ Or latest development version from GitHub:
|
|||||||
pip3 install https://github.com/containers/podman-compose/archive/main.tar.gz
|
pip3 install https://github.com/containers/podman-compose/archive/main.tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
### Homebrew
|
### Package repositories
|
||||||
|
|
||||||
|
podman-compose is available from the following package repositories:
|
||||||
|
|
||||||
|
Debian:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install podman-compose
|
||||||
|
```
|
||||||
|
|
||||||
|
Fedora (starting from f31) repositories:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install podman-compose
|
||||||
|
```
|
||||||
|
|
||||||
|
Homebrew:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install podman-compose
|
brew install podman-compose
|
||||||
@ -94,51 +110,22 @@ curl -o ~/.local/bin/podman-compose https://raw.githubusercontent.com/containers
|
|||||||
chmod +x ~/.local/bin/podman-compose
|
chmod +x ~/.local/bin/podman-compose
|
||||||
```
|
```
|
||||||
|
|
||||||
or install from Fedora (starting from f31) repositories:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo dnf install podman-compose
|
|
||||||
```
|
|
||||||
|
|
||||||
## Basic Usage
|
|
||||||
|
|
||||||
We have included fully functional sample stacks inside `examples/` directory.
|
|
||||||
You can get more examples from [awesome-compose](https://github.com/docker/awesome-compose).
|
|
||||||
|
|
||||||
A quick example would be
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd examples/busybox
|
|
||||||
podman-compose --help
|
|
||||||
podman-compose up --help
|
|
||||||
podman-compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
A more rich example can be found in [examples/awx3](examples/awx3)
|
|
||||||
which have
|
|
||||||
|
|
||||||
- A Postgres Database
|
|
||||||
- RabbitMQ server
|
|
||||||
- MemCached server
|
|
||||||
- a django web server
|
|
||||||
- a django tasks
|
|
||||||
|
|
||||||
|
|
||||||
When testing the `AWX3` example, if you got errors, just wait for db migrations to end.
|
|
||||||
There is also AWX 17.1.0
|
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
Inside `tests/` directory we have many useless docker-compose stacks
|
podman-compose is tested via unit and integration tests.
|
||||||
that are meant to test as many cases as we can to make sure we are compatible
|
|
||||||
|
|
||||||
### Unit tests with unittest
|
Unit tests can be run via the following:
|
||||||
run a unittest with following command
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python3 -m unittest discover tests/unit
|
python3 -m unittest discover tests/unit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Integration tests can be run via the following:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
python3 -m unittest discover tests/integration
|
||||||
|
```
|
||||||
|
|
||||||
# Contributing guide
|
# Contributing guide
|
||||||
|
|
||||||
If you are a user or a developer and want to contribute please check the [CONTRIBUTING](CONTRIBUTING.md) section
|
If you are a user or a developer and want to contribute please check the [CONTRIBUTING](CONTRIBUTING.md) section
|
||||||
|
@ -35,7 +35,7 @@ Pull the merge commit created on the `main` branch during the step 2.
|
|||||||
Then run:
|
Then run:
|
||||||
|
|
||||||
```
|
```
|
||||||
./scripts/make_release.sh
|
./scripts/make_release.sh $VERSION
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create release commit, tag and push everything.
|
This will create release commit, tag and push everything.
|
||||||
|
39
docs/Changelog-1.4.0.md
Normal file
39
docs/Changelog-1.4.0.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
Version 1.4.0 (2025-05-10)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- Fixed handling of relative includes and extends in compose files
|
||||||
|
- Fixed error when merging arguments in list and dictionary syntax
|
||||||
|
- Fixed issue where short-lived containers could execute twice when using `up` in detached mode
|
||||||
|
- Fixed `up` command hanging on Podman versions earlier than 4.6.0
|
||||||
|
- Fixed issue where `service_healthy` conditions weren't enforced during `up` command
|
||||||
|
- Fixed support for the `--scale` flag
|
||||||
|
- Fixed bug causing dependent containers to start despite `--no-deps` flag
|
||||||
|
- Fixed port command behavior for dynamic host ports
|
||||||
|
- Fixed interpolation of `COMPOSE_PROJECT_NAME` when set from top-level `name` in compose file
|
||||||
|
- Fixed project name evaluation order to match compose spec
|
||||||
|
- Fixed build context when using git URLs
|
||||||
|
- Fixed `KeyError` when `down` is called with non-existent service
|
||||||
|
- Skip `down` during `up` when no active containers exist
|
||||||
|
- Fixed non-zero exit code on failure when using `up -d`
|
||||||
|
- Fixed SIGINT handling during `up` command for graceful shutdown
|
||||||
|
- Fixed `NotImplementedError` when interrupted on Windows
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Added `--quiet` flag to `config` command to suppress output
|
||||||
|
- Added support for `pids_limit` and `deploy.resources.limits.pids`
|
||||||
|
- Added `--abort-on-container-failure` option
|
||||||
|
- Added `--rmi` argument to `down` command for image removal
|
||||||
|
- Added support for `x-podman.disable-dns` to disable DNS plugin on defined networks
|
||||||
|
- Added support for `x-podman.dns` to set DNS nameservers for defined networks
|
||||||
|
- Improved file descriptor handling - no longer closes externally created descriptors.
|
||||||
|
This allows descriptors created e.g. via systemd socket activation to be passed to
|
||||||
|
containers.
|
||||||
|
- Added support for `cpuset` configuration
|
||||||
|
- Added support for `reset` and `override` tags when merging compose files
|
||||||
|
- Added support for `x-podman.interface_name` to set network interface names
|
||||||
|
- Added support for `x-podman.pod_args` to override default `--pod-args`
|
7
docs/Changelog-1.4.1.md
Normal file
7
docs/Changelog-1.4.1.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Version 1.4.1 (2025-06-05)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- Fixed relative host path resolution for volume bind mount source
|
@ -27,6 +27,42 @@ services:
|
|||||||
|
|
||||||
For explanations of these extensions, please refer to the [Podman Documentation](https://docs.podman.io/).
|
For explanations of these extensions, please refer to the [Podman Documentation](https://docs.podman.io/).
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
The following extension keys are available under `secret` configuration:
|
||||||
|
|
||||||
|
x-podman.relabel - Configure SELinux relabeling
|
||||||
|
|
||||||
|
For example, the following configures custom-secret to use mount with private and unshared content.
|
||||||
|
Only the current container can use a private volume.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
secrets:
|
||||||
|
custom-secret:
|
||||||
|
x-podman.relabel: Z
|
||||||
|
```
|
||||||
|
|
||||||
|
For explanations of these extensions, please refer to the [podman-run --volume documentation](https://docs.podman.io/en/latest/markdown/podman-run.1.html#volume-v-source-volume-host-dir-container-dir-options)).
|
||||||
|
|
||||||
|
## Network management
|
||||||
|
|
||||||
|
The following extension keys are available under network configuration:
|
||||||
|
|
||||||
|
* `x-podman.disable-dns` - Disable the DNS plugin for the network when set to 'true'.
|
||||||
|
* `x-podman.dns` - Set nameservers for the network using supplied addresses (cannot be used with x-podman.disable-dns`).
|
||||||
|
|
||||||
|
For example, the following docker-compose.yml allows all containers on the same network to use the
|
||||||
|
specified nameservers:
|
||||||
|
```yml
|
||||||
|
version: "3"
|
||||||
|
network:
|
||||||
|
my_network:
|
||||||
|
x-podman.dns:
|
||||||
|
- "10.1.2.3"
|
||||||
|
- "10.1.2.4"
|
||||||
|
```
|
||||||
|
|
||||||
|
For explanations of these extensions, please refer to the
|
||||||
|
[Podman network create command Documentation](https://docs.podman.io/en/latest/markdown/podman-network-create.1.html).
|
||||||
|
|
||||||
## Per-network MAC-addresses
|
## Per-network MAC-addresses
|
||||||
|
|
||||||
@ -66,7 +102,7 @@ networks:
|
|||||||
- subnet: "192.168.1.0/24"
|
- subnet: "192.168.1.0/24"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
webserver
|
webserver:
|
||||||
image: "busybox"
|
image: "busybox"
|
||||||
command: ["/bin/busybox", "httpd", "-f", "-h", "/etc", "-p", "8001"]
|
command: ["/bin/busybox", "httpd", "-f", "-h", "/etc", "-p", "8001"]
|
||||||
networks:
|
networks:
|
||||||
@ -78,6 +114,10 @@ services:
|
|||||||
mac_address: "02:bb:bb:bb:bb:bb" # mac_address is supported
|
mac_address: "02:bb:bb:bb:bb:bb" # mac_address is supported
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Per-network interface name
|
||||||
|
|
||||||
|
Using `x-podman.interface_name` within a containers network config you can specify the interface name inside the container.
|
||||||
|
|
||||||
## Podman-specific network modes
|
## Podman-specific network modes
|
||||||
|
|
||||||
Generic docker-compose supports the following values for `network-mode` for a container:
|
Generic docker-compose supports the following values for `network-mode` for a container:
|
||||||
@ -99,6 +139,44 @@ The options to the network modes are passed to the `--network` option of the `po
|
|||||||
as-is.
|
as-is.
|
||||||
|
|
||||||
|
|
||||||
|
## Docker Compose Compatibility
|
||||||
|
|
||||||
|
podman-compose aims to be compatible with docker-compose, but there are some differences in
|
||||||
|
behavior and features. The following sections describe how to enable compatibility with docker-compose
|
||||||
|
and how to handle some of the differences.
|
||||||
|
|
||||||
|
Compatibility settings can either be set explicitly as described below, or by setting the `docker_compose_compat` meta
|
||||||
|
settings to `true` under the global `x-podman` key:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
x-podman:
|
||||||
|
docker_compose_compat: true
|
||||||
|
```
|
||||||
|
|
||||||
|
This will enable all compatibility settings described below, and is equivalent to setting each of them to `true`.
|
||||||
|
|
||||||
|
This setting can also be changed by setting the `PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT` environment variable.
|
||||||
|
|
||||||
|
## Compatibility of name separators between docker-compose and podman-compose
|
||||||
|
|
||||||
|
Currently, podman-compose is using underscores (`_` character) as a separator in names of
|
||||||
|
containers, images, etc., while docker-compose has switched to hyphens (`-` character). This setting
|
||||||
|
allows to switch podman-compose to use hyphens as well.
|
||||||
|
|
||||||
|
To enable compatibility between docker-compose and podman-compose, specify
|
||||||
|
`name_separator_compat: true` under global `x-podman` key:
|
||||||
|
|
||||||
|
```
|
||||||
|
x-podman:
|
||||||
|
name_separator_compat: true
|
||||||
|
```
|
||||||
|
|
||||||
|
By default `name_separator_compat` is `false`. This will change to `true` at some point and the
|
||||||
|
setting will be removed.
|
||||||
|
|
||||||
|
This setting can also be changed by setting `PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT` environment
|
||||||
|
variable.
|
||||||
|
|
||||||
## Compatibility of default network names between docker-compose and podman-compose
|
## Compatibility of default network names between docker-compose and podman-compose
|
||||||
|
|
||||||
Current versions of podman-compose may produce different default external network names than
|
Current versions of podman-compose may produce different default external network names than
|
||||||
@ -116,6 +194,9 @@ x-podman:
|
|||||||
By default `default_net_name_compat` is `false`. This will change to `true` at some point and the
|
By default `default_net_name_compat` is `false`. This will change to `true` at some point and the
|
||||||
setting will be removed.
|
setting will be removed.
|
||||||
|
|
||||||
|
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_NAME_COMPAT` environment
|
||||||
|
variable.
|
||||||
|
|
||||||
## Compatibility of default network behavior between docker-compose and podman-compose
|
## Compatibility of default network behavior between docker-compose and podman-compose
|
||||||
|
|
||||||
When there is no network defined (neither network-mode nor networks) in service,
|
When there is no network defined (neither network-mode nor networks) in service,
|
||||||
@ -136,6 +217,9 @@ x-podman:
|
|||||||
default_net_behavior_compat: true
|
default_net_behavior_compat: true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This setting can also be changed by setting `PODMAN_COMPOSE_DEFAULT_NET_BEHAVIOR_COMPAT` environment
|
||||||
|
variable.
|
||||||
|
|
||||||
## Custom pods management
|
## Custom pods management
|
||||||
|
|
||||||
Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod.
|
Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod.
|
||||||
@ -154,3 +238,23 @@ services:
|
|||||||
x-podman:
|
x-podman:
|
||||||
in_pod: false
|
in_pod: false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This setting can also be changed by setting `PODMAN_COMPOSE_IN_POD` environment
|
||||||
|
variable.
|
||||||
|
|
||||||
|
It is also possible to override the default arguments for pod creation that are
|
||||||
|
used when --pod-args is not passed on the command line:
|
||||||
|
```yml
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
cont:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"]
|
||||||
|
x-podman:
|
||||||
|
pod_args: ["--infra=false", "--share=", "--cpus=1"]
|
||||||
|
```
|
||||||
|
When not set in docker-compose.yml or on the command line, the pod args default
|
||||||
|
to `["--infra=false", "--share="]`.
|
||||||
|
|
||||||
|
This setting can also be changed by setting `PODMAN_COMPOSE_POD_ARGS` environment
|
||||||
|
variable.
|
9
examples/docker-inline/docker-compose.yml
Normal file
9
examples/docker-inline/docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
dummy:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile_inline: |
|
||||||
|
FROM alpine
|
||||||
|
RUN echo "hello world"
|
@ -3,8 +3,8 @@
|
|||||||
import asyncio # noqa: F401
|
import asyncio # noqa: F401
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import aioredis
|
import aioredis # type: ignore[import-not-found]
|
||||||
from aiohttp import web
|
from aiohttp import web # type: ignore[import-not-found]
|
||||||
|
|
||||||
REDIS_HOST = os.environ.get("REDIS_HOST", "localhost")
|
REDIS_HOST = os.environ.get("REDIS_HOST", "localhost")
|
||||||
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
|
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
|
||||||
@ -16,13 +16,13 @@ routes = web.RouteTableDef()
|
|||||||
|
|
||||||
|
|
||||||
@routes.get("/")
|
@routes.get("/")
|
||||||
async def hello(request): # pylint: disable=unused-argument
|
async def hello(request: web.Request) -> web.Response: # pylint: disable=unused-argument
|
||||||
counter = await redis.incr("mycounter")
|
counter = await redis.incr("mycounter")
|
||||||
return web.Response(text=f"counter={counter}")
|
return web.Response(text=f"counter={counter}")
|
||||||
|
|
||||||
|
|
||||||
@routes.get("/hello.json")
|
@routes.get("/hello.json")
|
||||||
async def hello_json(request): # pylint: disable=unused-argument
|
async def hello_json(request: web.Request) -> web.Response: # pylint: disable=unused-argument
|
||||||
counter = await redis.incr("mycounter")
|
counter = await redis.incr("mycounter")
|
||||||
data = {"counter": counter}
|
data = {"counter": counter}
|
||||||
return web.json_response(data)
|
return web.json_response(data)
|
||||||
@ -31,7 +31,7 @@ async def hello_json(request): # pylint: disable=unused-argument
|
|||||||
app.add_routes(routes)
|
app.add_routes(routes)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
web.run_app(app, port=8080)
|
web.run_app(app, port=8080)
|
||||||
|
|
||||||
|
|
||||||
|
1
newsfragments/compose-systemd-unregister.feature
Normal file
1
newsfragments/compose-systemd-unregister.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
- Add unregister command to remove systemd service registration (`podman-compose systemd -a unregister`)
|
1
newsfragments/custom-pod-name-argument.change
Normal file
1
newsfragments/custom-pod-name-argument.change
Normal file
@ -0,0 +1 @@
|
|||||||
|
- Change behaviour of `--in-pod` to handle custom pod names instead of only disabling pod feature
|
1
newsfragments/docker-compose-compat.feature
Normal file
1
newsfragments/docker-compose-compat.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
- Add new docker_compose_compat x-podman meta setting to enable all Docker Compose compatibility settings
|
1
newsfragments/env-var-interpolation-for-keys.feature
Normal file
1
newsfragments/env-var-interpolation-for-keys.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Add support for environment variable interpolation for YAML keys.
|
1
newsfragments/fix-build-ssh-path-to-be-relative.bugfix
Normal file
1
newsfragments/fix-build-ssh-path-to-be-relative.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Fixed build ssh path to a local SSH key, to be relative to the directory of compose file.
|
1
newsfragments/fix-cmd-healtchecks.bugfix
Normal file
1
newsfragments/fix-cmd-healtchecks.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Fixed support for CMD healthchecks to run using the given command directly and not using `/bin/sh -c`.
|
@ -0,0 +1 @@
|
|||||||
|
Fixed regression of dockerfile definition if working directory name ends with ".git".
|
@ -0,0 +1 @@
|
|||||||
|
Implemented forwarding failure exit code from `push` command.
|
1
newsfragments/fix-short-syntax-env-variables.bugfix
Normal file
1
newsfragments/fix-short-syntax-env-variables.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Implemented short syntax for environment variables set in `.env` for compose.yml "environment:" section.
|
@ -0,0 +1 @@
|
|||||||
|
Fixed regression of log output including "text" in detached mode.
|
1
newsfragments/hide-stack-trace-yaml-parse-error.change
Normal file
1
newsfragments/hide-stack-trace-yaml-parse-error.change
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hide the stack trace on a YAML parse error.
|
1
newsfragments/io-podman-compose-service-label.feature
Normal file
1
newsfragments/io-podman-compose-service-label.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Added `io.podman.compose.service` label to created containers. It contains the same value as com.docker.compose.service.
|
1
newsfragments/name-separator-compat.feature
Normal file
1
newsfragments/name-separator-compat.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
- Add new name_separator_compat x-podman setting to change name separator to hyphen, same as Docker Compose
|
1
newsfragments/secret-selinux-relabel-option.feature
Normal file
1
newsfragments/secret-selinux-relabel-option.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
- Add relabel option to secret to make possible to read the secret file by the contained process.
|
1
newsfragments/x-podman-env-vars.feature
Normal file
1
newsfragments/x-podman-env-vars.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
- Add support for setting x-podman values using PODMAN_COMPOSE_* environment variables.
|
1312
podman_compose.py
1312
podman_compose.py
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,59 @@
|
|||||||
|
[build-system]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
requires = ["setuptools"]
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "podman-compose"
|
||||||
|
authors = [
|
||||||
|
{ email = "alsadi@gmail.com", name = "Muayyad Alsadi" },
|
||||||
|
]
|
||||||
|
description = "A script to run docker-compose.yml using podman"
|
||||||
|
dependencies = [
|
||||||
|
"python-dotenv",
|
||||||
|
"pyyaml",
|
||||||
|
]
|
||||||
|
requires-python = ">=3.9"
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 3 - Alpha",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Topic :: Software Development :: Build Tools",
|
||||||
|
]
|
||||||
|
keywords = [
|
||||||
|
"podman",
|
||||||
|
"podman-compose",
|
||||||
|
]
|
||||||
|
license = "GPL-2.0-only"
|
||||||
|
dynamic = ["version", "readme"]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
homepage = "https://github.com/containers/podman-compose"
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
devel = [
|
||||||
|
"coverage",
|
||||||
|
"parameterized",
|
||||||
|
"pre-commit",
|
||||||
|
"ruff",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
podman-compose = "podman_compose:main"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
py-modules = ["podman_compose"]
|
||||||
|
|
||||||
|
[tool.setuptools.dynamic]
|
||||||
|
readme = {file = ["README.md"], content-type = "text/markdown"}
|
||||||
|
version = {attr = "podman_compose.__version__"}
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 100
|
line-length = 100
|
||||||
target-version = "py38"
|
target-version = "py38"
|
||||||
@ -53,3 +109,21 @@ quote-style = "preserve"
|
|||||||
directory = "misc"
|
directory = "misc"
|
||||||
name = "Misc"
|
name = "Misc"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
python_version = "3.9"
|
||||||
|
namespace_packages = true
|
||||||
|
explicit_package_bases = true
|
||||||
|
pretty = true
|
||||||
|
warn_redundant_casts = true
|
||||||
|
disallow_untyped_calls = false
|
||||||
|
disallow_untyped_defs = true
|
||||||
|
no_implicit_optional = true
|
||||||
|
mypy_path = "$MYPY_CONFIG_FILE_DIR"
|
||||||
|
exclude = "build"
|
||||||
|
|
||||||
|
[[tool.mypy.overrides]]
|
||||||
|
module = [
|
||||||
|
"parameterized.*",
|
||||||
|
]
|
||||||
|
ignore_missing_imports = true
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
./scripts/uninstall.sh
|
./scripts/uninstall.sh
|
||||||
./scripts/clean_up.sh
|
./scripts/clean_up.sh
|
||||||
python3 setup.py register
|
pyproject-build
|
||||||
python3 setup.py sdist bdist_wheel
|
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
[bdist_wheel]
|
|
||||||
universal = 1
|
|
||||||
|
|
||||||
[metadata]
|
|
||||||
version = attr: podman_compose.__version__
|
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
# The GitHub editor is 127 chars wide
|
# The GitHub editor is 127 chars wide
|
||||||
max-line-length=127
|
max-line-length=127
|
||||||
|
# These are not being followed yet
|
||||||
|
ignore=E222,E231,E272,E713,W503
|
||||||
|
49
setup.py
49
setup.py
@ -1,49 +0,0 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from setuptools import setup
|
|
||||||
|
|
||||||
try:
|
|
||||||
README = open(os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8").read()
|
|
||||||
except: # noqa: E722 # pylint: disable=bare-except
|
|
||||||
README = ""
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="podman-compose",
|
|
||||||
description="A script to run docker-compose.yml using podman",
|
|
||||||
long_description=README,
|
|
||||||
long_description_content_type="text/markdown",
|
|
||||||
classifiers=[
|
|
||||||
"Programming Language :: Python",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: 3.12",
|
|
||||||
"Programming Language :: Python :: 3.13",
|
|
||||||
"Intended Audience :: Developers",
|
|
||||||
"Operating System :: OS Independent",
|
|
||||||
"Development Status :: 3 - Alpha",
|
|
||||||
"Topic :: Software Development :: Build Tools",
|
|
||||||
"License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
|
|
||||||
],
|
|
||||||
keywords="podman, podman-compose",
|
|
||||||
author="Muayyad Alsadi",
|
|
||||||
author_email="alsadi@gmail.com",
|
|
||||||
url="https://github.com/containers/podman-compose",
|
|
||||||
py_modules=["podman_compose"],
|
|
||||||
entry_points={"console_scripts": ["podman-compose = podman_compose:main"]},
|
|
||||||
include_package_data=True,
|
|
||||||
license="GPL-2.0-only",
|
|
||||||
install_requires=[
|
|
||||||
"pyyaml",
|
|
||||||
"python-dotenv",
|
|
||||||
],
|
|
||||||
extras_require={"devel": ["ruff", "pre-commit", "coverage", "parameterized"]},
|
|
||||||
# test_suite='tests',
|
|
||||||
# tests_require=[
|
|
||||||
# 'coverage',
|
|
||||||
# 'tox',
|
|
||||||
# ]
|
|
||||||
)
|
|
@ -1,10 +1,15 @@
|
|||||||
-e .
|
-e .
|
||||||
coverage==7.4.3
|
coverage==7.4.3
|
||||||
|
cryptography==44.0.3
|
||||||
parameterized==0.9.0
|
parameterized==0.9.0
|
||||||
pytest==8.0.2
|
pytest==8.0.2
|
||||||
tox==4.13.0
|
tox==4.13.0
|
||||||
ruff==0.3.1
|
mypy==1.15.0
|
||||||
|
ruff==0.11.11
|
||||||
pylint==3.1.0
|
pylint==3.1.0
|
||||||
|
types-PyYAML==6.0.12.20250402
|
||||||
|
types-requests==2.32.0.20250328
|
||||||
|
types-setuptools==80.7.0.20250516
|
||||||
|
|
||||||
# The packages below are transitive dependencies of the packages above and are included here
|
# The packages below are transitive dependencies of the packages above and are included here
|
||||||
# to make testing reproducible.
|
# to make testing reproducible.
|
||||||
@ -23,6 +28,7 @@ filelock==3.13.1
|
|||||||
iniconfig==2.0.0
|
iniconfig==2.0.0
|
||||||
isort==5.13.2
|
isort==5.13.2
|
||||||
mccabe==0.7.0
|
mccabe==0.7.0
|
||||||
|
mypy_extensions==1.1.0
|
||||||
packaging==23.2
|
packaging==23.2
|
||||||
platformdirs==4.2.0
|
platformdirs==4.2.0
|
||||||
pluggy==1.4.0
|
pluggy==1.4.0
|
||||||
@ -31,4 +37,5 @@ python-dotenv==1.0.1
|
|||||||
PyYAML==6.0.1
|
PyYAML==6.0.1
|
||||||
requests
|
requests
|
||||||
tomlkit==0.12.4
|
tomlkit==0.12.4
|
||||||
virtualenv==20.25.1
|
typing_extensions==4.13.2
|
||||||
|
virtualenv==20.26.6
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
def create_base_test_image():
|
def create_base_test_image() -> None:
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
['podman', 'build', '-t', 'nopush/podman-compose-test', '.'],
|
['podman', 'build', '-t', 'nopush/podman-compose-test', '.'],
|
||||||
cwd=os.path.join(os.path.dirname(__file__), "base_image"),
|
cwd=os.path.join(os.path.dirname(__file__), "base_image"),
|
||||||
|
0
tests/integration/abort/__init__.py
Normal file
0
tests/integration/abort/__init__.py
Normal file
11
tests/integration/abort/docker-compose-fail-first.yaml
Normal file
11
tests/integration/abort/docker-compose-fail-first.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 1"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]
|
11
tests/integration/abort/docker-compose-fail-none.yaml
Normal file
11
tests/integration/abort/docker-compose-fail-none.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]
|
11
tests/integration/abort/docker-compose-fail-second.yaml
Normal file
11
tests/integration/abort/docker-compose-fail-second.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 1"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3; exit 0"]
|
@ -0,0 +1,11 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
sh1:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 1"]
|
||||||
|
sh2:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 1; exit 0"]
|
||||||
|
sh3:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 2; exit 0"]
|
46
tests/integration/abort/test_podman_compose_abort.py
Normal file
46
tests/integration/abort/test_podman_compose_abort.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from parameterized import parameterized
|
||||||
|
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
|
def compose_yaml_path(failure_order: str) -> str:
|
||||||
|
return os.path.join(test_path(), "abort", f"docker-compose-fail-{failure_order}.yaml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeAbort(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
@parameterized.expand([
|
||||||
|
("exit", "first", 0),
|
||||||
|
("failure", "first", 1),
|
||||||
|
("exit", "second", 0),
|
||||||
|
("failure", "second", 1),
|
||||||
|
("exit", "simultaneous", 0),
|
||||||
|
("failure", "simultaneous", 1),
|
||||||
|
("exit", "none", 0),
|
||||||
|
("failure", "none", 0),
|
||||||
|
])
|
||||||
|
def test_abort(self, abort_type: str, failure_order: str, expected_exit_code: int) -> None:
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(failure_order),
|
||||||
|
"up",
|
||||||
|
f"--abort-on-container-{abort_type}",
|
||||||
|
],
|
||||||
|
expected_exit_code,
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(failure_order),
|
||||||
|
"down",
|
||||||
|
])
|
1
tests/integration/additional_contexts/__init__.py
Normal file
1
tests/integration/additional_contexts/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -7,17 +7,17 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
from tests.integration.test_utils import podman_compose_path
|
||||||
from tests.integration.test_podman_compose import test_path
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_yaml_path():
|
def compose_yaml_path() -> str:
|
||||||
""" "Returns the path to the compose file used for this test module"""
|
""" "Returns the path to the compose file used for this test module"""
|
||||||
return os.path.join(test_path(), "additional_contexts", "project")
|
return os.path.join(test_path(), "additional_contexts", "project")
|
||||||
|
|
||||||
|
|
||||||
class TestComposeBuildAdditionalContexts(unittest.TestCase):
|
class TestComposeBuildAdditionalContexts(unittest.TestCase):
|
||||||
def test_build_additional_context(self):
|
def test_build_additional_context(self) -> None:
|
||||||
"""podman build should receive additional contexts as --build-context
|
"""podman build should receive additional contexts as --build-context
|
||||||
|
|
||||||
See additional_context/project/docker-compose.yaml for context paths
|
See additional_context/project/docker-compose.yaml for context paths
|
1
tests/integration/build/__init__.py
Normal file
1
tests/integration/build/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
tests/integration/build/git_url_context/__init__.py
Normal file
1
tests/integration/build/git_url_context/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
test_context:
|
||||||
|
build:
|
||||||
|
context: https://github.com/mokibit/test-git-url-as-context.git
|
||||||
|
image: test-git-url-as-context
|
||||||
|
test_context_inline:
|
||||||
|
build: https://github.com/mokibit/test-git-url-as-context.git
|
||||||
|
image: test-git-url-as-context-inline
|
@ -0,0 +1,55 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
from parameterized import parameterized
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
|
||||||
|
|
||||||
|
def compose_yaml_path():
|
||||||
|
""" "Returns the path to the compose file used for this test module"""
|
||||||
|
base_path = os.path.join(test_path(), "build/git_url_context")
|
||||||
|
return os.path.join(base_path, "docker-compose.yml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeBuildGitUrlAsContext(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
@parameterized.expand([
|
||||||
|
("git_url_context_test_context_1", "data_1.txt", b'test1\r\n'),
|
||||||
|
("git_url_context_test_context_1", "data_2.txt", b'test2\r\n'),
|
||||||
|
("git_url_context_test_context_inline_1", "data_1.txt", b'test1\r\n'),
|
||||||
|
("git_url_context_test_context_inline_1", "data_2.txt", b'test2\r\n'),
|
||||||
|
])
|
||||||
|
def test_build_git_url_as_context(self, container_name, file_name, output):
|
||||||
|
# test if container can access specific files from git repository when git url is used as
|
||||||
|
# a build context
|
||||||
|
try:
|
||||||
|
out, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"up",
|
||||||
|
"-d",
|
||||||
|
])
|
||||||
|
|
||||||
|
out, _ = self.run_subprocess_assert_returncode([
|
||||||
|
"podman",
|
||||||
|
"exec",
|
||||||
|
"-ti",
|
||||||
|
f"{container_name}",
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
f"cat {file_name}",
|
||||||
|
])
|
||||||
|
self.assertEqual(out, output)
|
||||||
|
finally:
|
||||||
|
out, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
"-t",
|
||||||
|
"0",
|
||||||
|
])
|
@ -5,8 +5,8 @@ import unittest
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
from tests.integration.test_utils import podman_compose_path
|
||||||
from tests.integration.test_podman_compose import test_path
|
from tests.integration.test_utils import test_path
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
|
||||||
|
|
1
tests/integration/build_fail/__init__.py
Normal file
1
tests/integration/build_fail/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
test
|
@ -3,3 +3,12 @@ services:
|
|||||||
test:
|
test:
|
||||||
build: ./context
|
build: ./context
|
||||||
image: build-fail-img
|
image: build-fail-img
|
||||||
|
test_no_dockerfile:
|
||||||
|
build:
|
||||||
|
context: ./context_no_file
|
||||||
|
image: busybox
|
||||||
|
test_no_custom_dockerfile:
|
||||||
|
build:
|
||||||
|
context: ./context_no_file
|
||||||
|
dockerfile: Dockerfile-alt
|
||||||
|
image: busybox
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
|
def compose_yaml_path():
|
||||||
|
""" "Returns the path to the compose file used for this test module"""
|
||||||
|
base_path = os.path.join(test_path(), "build_fail")
|
||||||
|
return os.path.join(base_path, "docker-compose.yml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeBuildFail(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
def test_build_fail(self):
|
||||||
|
output, error = self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"build",
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
expected_returncode=127,
|
||||||
|
)
|
||||||
|
self.assertIn("RUN this_command_does_not_exist", str(output))
|
||||||
|
self.assertIn("this_command_does_not_exist: not found", str(error))
|
||||||
|
self.assertIn("while running runtime: exit status 127", str(error))
|
||||||
|
|
||||||
|
def test_dockerfile_does_not_exist(self):
|
||||||
|
out, error = self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"build",
|
||||||
|
"test_no_dockerfile",
|
||||||
|
],
|
||||||
|
expected_returncode=1,
|
||||||
|
)
|
||||||
|
error = error.decode('utf-8')
|
||||||
|
result = '\n'.join(error.splitlines()[-1:])
|
||||||
|
|
||||||
|
expected_path = os.path.join(os.path.dirname(__file__), "context_no_file")
|
||||||
|
expected = f'OSError: Dockerfile not found in {expected_path}'
|
||||||
|
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_custom_dockerfile_does_not_exist(self):
|
||||||
|
out, error = self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"build",
|
||||||
|
"test_no_custom_dockerfile",
|
||||||
|
],
|
||||||
|
expected_returncode=1,
|
||||||
|
)
|
||||||
|
error = error.decode('utf-8')
|
||||||
|
result = '\n'.join(error.splitlines()[-1:])
|
||||||
|
|
||||||
|
expected_path = os.path.join(os.path.dirname(__file__), "context_no_file/Dockerfile-alt")
|
||||||
|
expected = f'OSError: Dockerfile not found in {expected_path}'
|
||||||
|
|
||||||
|
self.assertEqual(expected, result)
|
0
tests/integration/build_labels/__init__.py
Normal file
0
tests/integration/build_labels/__init__.py
Normal file
@ -5,9 +5,9 @@ import json
|
|||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
class TestBuildLabels(unittest.TestCase, RunSubprocessMixin):
|
class TestBuildLabels(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
1
tests/integration/build_secrets/__init__.py
Normal file
1
tests/integration/build_secrets/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -7,8 +7,8 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
from tests.integration.test_utils import podman_compose_path
|
||||||
from tests.integration.test_podman_compose import test_path
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_yaml_path():
|
def compose_yaml_path():
|
1
tests/integration/build_ssh/__init__.py
Normal file
1
tests/integration/build_ssh/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -9,9 +9,9 @@ import unittest
|
|||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
expected_lines = [
|
expected_lines = [
|
||||||
"default: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFYQvN9a+toIB6jSs4zY7FMapZnHt80EKCUr/WhLwUum",
|
"default: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFYQvN9a+toIB6jSs4zY7FMapZnHt80EKCUr/WhLwUum",
|
||||||
|
3
tests/integration/commands_fail_exit_code/bad/Dockerfile
Normal file
3
tests/integration/commands_fail_exit_code/bad/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM busybox
|
||||||
|
|
||||||
|
RUN false
|
@ -0,0 +1,8 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
bad:
|
||||||
|
build:
|
||||||
|
context: bad
|
||||||
|
good:
|
||||||
|
build:
|
||||||
|
context: good
|
@ -0,0 +1,3 @@
|
|||||||
|
FROM busybox
|
||||||
|
#ensure that this build finishes second so that it has a chance to overwrite the return code
|
||||||
|
RUN sleep 0.5
|
@ -0,0 +1,76 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
|
def compose_yaml_path() -> str:
|
||||||
|
""" "Returns the path to the compose file used for this test module"""
|
||||||
|
base_path = os.path.join(test_path(), "commands_fail_exit_code")
|
||||||
|
return os.path.join(base_path, "docker-compose.yml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeCommandsFailExitCodes(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
def test_build_command_fail(self) -> None:
|
||||||
|
output, error = self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"build",
|
||||||
|
# prevent the successful build from being cached to ensure it runs long enough
|
||||||
|
"--no-cache",
|
||||||
|
],
|
||||||
|
expected_returncode=1,
|
||||||
|
)
|
||||||
|
self.assertIn("RUN false", str(output))
|
||||||
|
self.assertIn("while running runtime: exit status 1", str(error))
|
||||||
|
|
||||||
|
def test_push_command_fail(self) -> None:
|
||||||
|
# test that push command is able to return other than "0" return code
|
||||||
|
# "push" command fails due to several steps missing before running it (logging, tagging)
|
||||||
|
try:
|
||||||
|
output, error = self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"push",
|
||||||
|
"good",
|
||||||
|
],
|
||||||
|
expected_returncode=125,
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_run_command_fail(self) -> None:
|
||||||
|
# test that run command is able to return other than "0" return code
|
||||||
|
try:
|
||||||
|
output, error = self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"run",
|
||||||
|
"bad",
|
||||||
|
],
|
||||||
|
expected_returncode=125,
|
||||||
|
)
|
||||||
|
self.assertIn("RUN false", str(output))
|
||||||
|
self.assertIn("while running runtime: exit status 1", str(error))
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
1
tests/integration/default_net_behavior/__init__.py
Normal file
1
tests/integration/default_net_behavior/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -5,12 +5,12 @@ import unittest
|
|||||||
|
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_yaml_path(scenario):
|
def compose_yaml_path(scenario: str) -> str:
|
||||||
return os.path.join(
|
return os.path.join(
|
||||||
os.path.join(test_path(), "default_net_behavior"), f"docker-compose_{scenario}.yaml"
|
os.path.join(test_path(), "default_net_behavior"), f"docker-compose_{scenario}.yaml"
|
||||||
)
|
)
|
||||||
@ -27,13 +27,13 @@ class TestComposeDefaultNetBehavior(unittest.TestCase, RunSubprocessMixin):
|
|||||||
('two_nets_compat', 'default_net_behavior_default'),
|
('two_nets_compat', 'default_net_behavior_default'),
|
||||||
('with_default_compat', 'default_net_behavior_default'),
|
('with_default_compat', 'default_net_behavior_default'),
|
||||||
])
|
])
|
||||||
def test_nethost(self, scenario, default_net):
|
def test_nethost(self, scenario: str, default_net: str) -> None:
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(
|
self.run_subprocess_assert_returncode(
|
||||||
[podman_compose_path(), "-f", compose_yaml_path(scenario), "up", "-d"],
|
[podman_compose_path(), "-f", compose_yaml_path(scenario), "up", "-d"],
|
||||||
)
|
)
|
||||||
|
|
||||||
container_id, _ = self.run_subprocess_assert_returncode(
|
container_id_out, _ = self.run_subprocess_assert_returncode(
|
||||||
[
|
[
|
||||||
podman_compose_path(),
|
podman_compose_path(),
|
||||||
"-f",
|
"-f",
|
||||||
@ -43,7 +43,7 @@ class TestComposeDefaultNetBehavior(unittest.TestCase, RunSubprocessMixin):
|
|||||||
'{{.ID}}',
|
'{{.ID}}',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
container_id = container_id.decode('utf-8').split('\n')[0]
|
container_id = container_id_out.decode('utf-8').split('\n')[0]
|
||||||
output, _ = self.run_subprocess_assert_returncode(
|
output, _ = self.run_subprocess_assert_returncode(
|
||||||
[
|
[
|
||||||
"podman",
|
"podman",
|
1
tests/integration/deps/__init__.py
Normal file
1
tests/integration/deps/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
version: "3.7"
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-h", "/etc/", "-p", "8000"]
|
||||||
|
tmpfs:
|
||||||
|
- /run
|
||||||
|
- /tmp
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://localhost:8000/hosts"]
|
||||||
|
start_period: 10s # initialization time for containers that need time to bootstrap
|
||||||
|
interval: 10s # Time between health checks
|
||||||
|
timeout: 5s # Time to wait for a response
|
||||||
|
retries: 3 # Number of consecutive failures before marking as unhealthy
|
||||||
|
sleep:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "sh", "-c", "sleep 3600"]
|
||||||
|
depends_on:
|
||||||
|
web:
|
||||||
|
condition: service_healthy
|
||||||
|
tmpfs:
|
||||||
|
- /run
|
||||||
|
- /tmp
|
266
tests/integration/deps/test_podman_compose_deps.py
Normal file
266
tests/integration/deps/test_podman_compose_deps.py
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from tests.integration.test_utils import PodmanAwareRunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import is_systemd_available
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
|
def compose_yaml_path(suffix: str = "") -> str:
|
||||||
|
return os.path.join(os.path.join(test_path(), "deps"), f"docker-compose{suffix}.yaml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeBaseDeps(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
def test_deps(self) -> None:
|
||||||
|
try:
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"sleep",
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
"wget -O - http://web:8000/hosts",
|
||||||
|
])
|
||||||
|
self.assertIn(b"HTTP request sent, awaiting response... 200 OK", output)
|
||||||
|
self.assertIn(b"deps_web_1", output)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_run_nodeps(self) -> None:
|
||||||
|
try:
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"--no-deps",
|
||||||
|
"sleep",
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
"wget -O - http://web:8000/hosts || echo Failed to connect",
|
||||||
|
])
|
||||||
|
self.assertNotIn(b"HTTP request sent, awaiting response... 200 OK", output)
|
||||||
|
self.assertNotIn(b"deps_web_1", output)
|
||||||
|
self.assertIn(b"Failed to connect", output)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_up_nodeps(self) -> None:
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"up",
|
||||||
|
"--no-deps",
|
||||||
|
"--detach",
|
||||||
|
"sleep",
|
||||||
|
])
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"ps",
|
||||||
|
])
|
||||||
|
self.assertNotIn(b"deps_web_1", output)
|
||||||
|
self.assertIn(b"deps_sleep_1", output)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_podman_compose_run(self) -> None:
|
||||||
|
"""
|
||||||
|
This will test depends_on as well
|
||||||
|
"""
|
||||||
|
run_cmd = [
|
||||||
|
"coverage",
|
||||||
|
"run",
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
os.path.join(test_path(), "deps", "docker-compose.yaml"),
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"sleep",
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
"wget -q -O - http://web:8000/hosts",
|
||||||
|
]
|
||||||
|
|
||||||
|
out, _ = self.run_subprocess_assert_returncode(run_cmd)
|
||||||
|
self.assertIn(b"127.0.0.1\tlocalhost", out)
|
||||||
|
|
||||||
|
# Run it again to make sure we can run it twice. I saw an issue where a second run, with
|
||||||
|
# the container left up, would fail
|
||||||
|
run_cmd = [
|
||||||
|
"coverage",
|
||||||
|
"run",
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
os.path.join(test_path(), "deps", "docker-compose.yaml"),
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"sleep",
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
"wget -q -O - http://web:8000/hosts",
|
||||||
|
]
|
||||||
|
|
||||||
|
out, _ = self.run_subprocess_assert_returncode(run_cmd)
|
||||||
|
self.assertIn(b"127.0.0.1\tlocalhost", out)
|
||||||
|
|
||||||
|
# This leaves a container running. Not sure it's intended, but it matches docker-compose
|
||||||
|
down_cmd = [
|
||||||
|
"coverage",
|
||||||
|
"run",
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
os.path.join(test_path(), "deps", "docker-compose.yaml"),
|
||||||
|
"down",
|
||||||
|
]
|
||||||
|
|
||||||
|
self.run_subprocess_assert_returncode(down_cmd)
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeConditionalDeps(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
def test_deps_succeeds(self) -> None:
|
||||||
|
suffix = "-conditional-succeeds"
|
||||||
|
try:
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(suffix),
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"sleep",
|
||||||
|
"/bin/sh",
|
||||||
|
"-c",
|
||||||
|
"wget -O - http://web:8000/hosts",
|
||||||
|
])
|
||||||
|
self.assertIn(b"HTTP request sent, awaiting response... 200 OK", output)
|
||||||
|
self.assertIn(b"deps_web_1", output)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(suffix),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_deps_fails(self) -> None:
|
||||||
|
suffix = "-conditional-fails"
|
||||||
|
try:
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(suffix),
|
||||||
|
"ps",
|
||||||
|
])
|
||||||
|
self.assertNotIn(b"HTTP request sent, awaiting response... 200 OK", output)
|
||||||
|
self.assertNotIn(b"deps_web_1", output)
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(suffix),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeConditionalDepsHealthy(unittest.TestCase, PodmanAwareRunSubprocessMixin):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.podman_version = self.retrieve_podman_version()
|
||||||
|
|
||||||
|
def test_up_deps_healthy(self) -> None:
|
||||||
|
suffix = "-conditional-healthy"
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(suffix),
|
||||||
|
"up",
|
||||||
|
"sleep",
|
||||||
|
"--detach",
|
||||||
|
])
|
||||||
|
|
||||||
|
# Since the command `podman wait --condition=healthy` is invalid prior to 4.6.0,
|
||||||
|
# we only validate healthy status for podman 4.6.0+, which won't be tested in the
|
||||||
|
# CI pipeline of the podman-compose project where podman 4.3.1 is employed.
|
||||||
|
podman_ver_major, podman_ver_minor, podman_ver_patch = self.podman_version
|
||||||
|
if podman_ver_major >= 4 and podman_ver_minor >= 6 and podman_ver_patch >= 0:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
"podman",
|
||||||
|
"wait",
|
||||||
|
"--condition=running",
|
||||||
|
"deps_web_1",
|
||||||
|
"deps_sleep_1",
|
||||||
|
])
|
||||||
|
|
||||||
|
# check both web and sleep are running
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"ps",
|
||||||
|
"--format",
|
||||||
|
"{{.ID}}\t{{.Names}}\t{{.Status}}\t{{.StartedAt}}",
|
||||||
|
])
|
||||||
|
|
||||||
|
# extract container id of web
|
||||||
|
decoded_out = output.decode('utf-8')
|
||||||
|
lines = decoded_out.split("\n")
|
||||||
|
|
||||||
|
web_lines = [line for line in lines if "web" in line]
|
||||||
|
self.assertTrue(web_lines)
|
||||||
|
self.assertEqual(1, len(web_lines))
|
||||||
|
web_cnt_id, web_cnt_name, web_cnt_status, web_cnt_started = web_lines[0].split("\t")
|
||||||
|
self.assertNotEqual("", web_cnt_id)
|
||||||
|
self.assertEqual("deps_web_1", web_cnt_name)
|
||||||
|
|
||||||
|
sleep_lines = [line for line in lines if "sleep" in line]
|
||||||
|
self.assertTrue(sleep_lines)
|
||||||
|
self.assertEqual(1, len(sleep_lines))
|
||||||
|
sleep_cnt_id, sleep_cnt_name, _, sleep_cnt_started = sleep_lines[0].split("\t")
|
||||||
|
self.assertNotEqual("", sleep_cnt_id)
|
||||||
|
self.assertEqual("deps_sleep_1", sleep_cnt_name)
|
||||||
|
|
||||||
|
# When test case is executed inside container like github actions, the absence of
|
||||||
|
# systemd prevents health check from working properly, resulting in failure to
|
||||||
|
# transit to healthy state. As a result, we only assert the `healthy` state where
|
||||||
|
# systemd is functioning.
|
||||||
|
if (
|
||||||
|
is_systemd_available()
|
||||||
|
and podman_ver_major >= 4
|
||||||
|
and podman_ver_minor >= 6
|
||||||
|
and podman_ver_patch >= 0
|
||||||
|
):
|
||||||
|
self.assertIn("healthy", web_cnt_status)
|
||||||
|
self.assertGreaterEqual(int(sleep_cnt_started), int(web_cnt_started))
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(suffix),
|
||||||
|
"down",
|
||||||
|
])
|
@ -1,2 +0,0 @@
|
|||||||
ZZVAR1='This value is overwritten by env-file-tests/.env'
|
|
||||||
ZZVAR3='This value is loaded from env-file-tests/.env'
|
|
2
tests/integration/env_file_tests/.env
Normal file
2
tests/integration/env_file_tests/.env
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ZZVAR1='This value is overwritten by env_file_tests/.env'
|
||||||
|
ZZVAR3='This value is loaded from env_file_tests/.env'
|
1
tests/integration/env_file_tests/__init__.py
Normal file
1
tests/integration/env_file_tests/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -1,2 +1,3 @@
|
|||||||
ZZVAR1='This value is loaded but should be overwritten'
|
ZZVAR1='This value is loaded but should be overwritten'
|
||||||
ZZVAR2='This value is loaded from .env in project/ directory'
|
ZZVAR2='This value is loaded from .env in project/ directory'
|
||||||
|
ZZVAR3=TEST
|
@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["/bin/busybox", "sh", "-c", "env | grep ZZVAR3"]
|
||||||
|
# 'env_file:' section is not used, so .env file is searched in the same directory as compose.yml
|
||||||
|
# file
|
||||||
|
environment:
|
||||||
|
# this is short syntax: podman-compose takes only this variable value from '.env' file and
|
||||||
|
# sends it to container environment
|
||||||
|
- ZZVAR3
|
@ -3,17 +3,17 @@
|
|||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_base_path():
|
def compose_base_path() -> str:
|
||||||
return os.path.join(test_path(), "env-file-tests")
|
return os.path.join(test_path(), "env_file_tests")
|
||||||
|
|
||||||
|
|
||||||
class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
||||||
def test_path_env_file_inline(self):
|
def test_path_env_file_inline(self) -> None:
|
||||||
# Test taking env variable value directly from env-file when its path is inline path
|
# Test taking env variable value directly from env-file when its path is inline path
|
||||||
base_path = compose_base_path()
|
base_path = compose_base_path()
|
||||||
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
|
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
|
||||||
@ -42,7 +42,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_path_env_file_flat_in_compose_file(self):
|
def test_path_env_file_flat_in_compose_file(self) -> None:
|
||||||
# Test taking env variable value from env-file/project-1.env which was declared in
|
# Test taking env variable value from env-file/project-1.env which was declared in
|
||||||
# compose file's env_file
|
# compose file's env_file
|
||||||
base_path = compose_base_path()
|
base_path = compose_base_path()
|
||||||
@ -74,7 +74,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_path_env_file_obj_in_compose_file(self):
|
def test_path_env_file_obj_in_compose_file(self) -> None:
|
||||||
# take variable value from env-file project-1.env which was declared in compose
|
# take variable value from env-file project-1.env which was declared in compose
|
||||||
# file's env_file by -path: ...
|
# file's env_file by -path: ...
|
||||||
base_path = compose_base_path()
|
base_path = compose_base_path()
|
||||||
@ -106,7 +106,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_exists_optional_env_file_path_in_compose_file(self):
|
def test_exists_optional_env_file_path_in_compose_file(self) -> None:
|
||||||
# test taking env variable values from several env-files when one of them is optional
|
# test taking env variable values from several env-files when one of them is optional
|
||||||
# and exists
|
# and exists
|
||||||
base_path = compose_base_path()
|
base_path = compose_base_path()
|
||||||
@ -139,7 +139,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_missing_optional_env_file_path_in_compose_file(self):
|
def test_missing_optional_env_file_path_in_compose_file(self) -> None:
|
||||||
# test taking env variable values from several env-files when one of them is optional and
|
# test taking env variable values from several env-files when one of them is optional and
|
||||||
# is missing (silently skip it)
|
# is missing (silently skip it)
|
||||||
base_path = compose_base_path()
|
base_path = compose_base_path()
|
||||||
@ -173,7 +173,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_var_value_inline_overrides_env_file_path_inline(self):
|
def test_var_value_inline_overrides_env_file_path_inline(self) -> None:
|
||||||
# Test overriding env value when value is declared in inline command
|
# Test overriding env value when value is declared in inline command
|
||||||
base_path = compose_base_path()
|
base_path = compose_base_path()
|
||||||
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
|
path_compose_file = os.path.join(base_path, "project/container-compose.yaml")
|
||||||
@ -204,7 +204,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_taking_env_variables_from_env_files_from_different_directories(self):
|
def test_taking_env_variables_from_env_files_from_different_directories(self) -> None:
|
||||||
# FIXME: It is not clear what this test actually tests, but from README.md it looks like:
|
# FIXME: It is not clear what this test actually tests, but from README.md it looks like:
|
||||||
# Test overriding env values by directory env-files-tests/.env file values
|
# Test overriding env values by directory env-files-tests/.env file values
|
||||||
# and only take value from project/.env, when it does not exist in env-files-tests/.env
|
# and only take value from project/.env, when it does not exist in env-files-tests/.env
|
||||||
@ -233,7 +233,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
[
|
[
|
||||||
'ZZVAR1=This value is loaded but should be overwritten\r',
|
'ZZVAR1=This value is loaded but should be overwritten\r',
|
||||||
'ZZVAR2=This value is loaded from .env in project/ directory\r',
|
'ZZVAR2=This value is loaded from .env in project/ directory\r',
|
||||||
'ZZVAR3=$ZZVAR3\r',
|
'ZZVAR3=TEST\r',
|
||||||
'',
|
'',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -244,3 +244,36 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin):
|
|||||||
path_compose_file,
|
path_compose_file,
|
||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_env_var_value_accessed_in_compose_file_short_syntax(self) -> None:
|
||||||
|
# Test that compose file can access the environment variable set in .env file using
|
||||||
|
# short syntax, that is: only the name of environment variable is used in "environment:" in
|
||||||
|
# compose.yml file and its value is picked up directly from .env file
|
||||||
|
# long syntax of environment variables interpolation is tested in
|
||||||
|
# tests/integration/interpolation
|
||||||
|
|
||||||
|
base_path = compose_base_path()
|
||||||
|
compose_file_path = os.path.join(base_path, "project/container-compose.short_syntax.yaml")
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_file_path,
|
||||||
|
"up",
|
||||||
|
"-d",
|
||||||
|
])
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_file_path,
|
||||||
|
"logs",
|
||||||
|
])
|
||||||
|
# ZZVAR3 was set in .env file
|
||||||
|
self.assertEqual(output, b"ZZVAR3=TEST\n")
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_file_path,
|
||||||
|
"down",
|
||||||
|
])
|
1
tests/integration/env_tests/__init__.py
Normal file
1
tests/integration/env_tests/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -1,5 +1,7 @@
|
|||||||
version: "3"
|
version: "3"
|
||||||
|
|
||||||
|
name: my-project-name
|
||||||
|
|
||||||
services:
|
services:
|
||||||
env-test:
|
env-test:
|
||||||
image: busybox
|
image: busybox
|
||||||
@ -8,3 +10,9 @@ services:
|
|||||||
ZZVAR1: myval1
|
ZZVAR1: myval1
|
||||||
ZZVAR2: 2-$ZZVAR1
|
ZZVAR2: 2-$ZZVAR1
|
||||||
ZZVAR3: 3-$ZZVAR2
|
ZZVAR3: 3-$ZZVAR2
|
||||||
|
|
||||||
|
project-name-test:
|
||||||
|
image: busybox
|
||||||
|
command: sh -c "echo $$PNAME"
|
||||||
|
environment:
|
||||||
|
PNAME: ${COMPOSE_PROJECT_NAME}
|
89
tests/integration/env_tests/test_podman_compose_env.py
Normal file
89
tests/integration/env_tests/test_podman_compose_env.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
|
def compose_yaml_path() -> str:
|
||||||
|
return os.path.join(os.path.join(test_path(), "env_tests"), "container-compose.yml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeEnv(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
"""Test that inline environment variable overrides environment variable from compose file."""
|
||||||
|
|
||||||
|
def test_env(self) -> None:
|
||||||
|
try:
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"run",
|
||||||
|
"-l",
|
||||||
|
"monkey",
|
||||||
|
"-e",
|
||||||
|
"ZZVAR1=myval2",
|
||||||
|
"env-test",
|
||||||
|
])
|
||||||
|
self.assertIn("ZZVAR1='myval2'", str(output))
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
"""
|
||||||
|
Tests interpolation of COMPOSE_PROJECT_NAME in the podman-compose config,
|
||||||
|
which is different from external environment variables because COMPOSE_PROJECT_NAME
|
||||||
|
is a predefined environment variable generated from the `name` value in the top-level
|
||||||
|
of the compose.yaml.
|
||||||
|
|
||||||
|
See also
|
||||||
|
- https://docs.docker.com/reference/compose-file/interpolation/
|
||||||
|
- https://docs.docker.com/reference/compose-file/version-and-name/#name-top-level-element
|
||||||
|
- https://docs.docker.com/compose/how-tos/environment-variables/envvars/
|
||||||
|
- https://github.com/compose-spec/compose-spec/blob/main/04-version-and-name.md
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_project_name(self) -> None:
|
||||||
|
try:
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"run",
|
||||||
|
"project-name-test",
|
||||||
|
])
|
||||||
|
self.assertIn("my-project-name", str(output))
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_project_name_override(self) -> None:
|
||||||
|
try:
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"run",
|
||||||
|
"-e",
|
||||||
|
"COMPOSE_PROJECT_NAME=project-name-override",
|
||||||
|
"project-name-test",
|
||||||
|
])
|
||||||
|
self.assertIn("project-name-override", str(output))
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
1
tests/integration/exit_from/__init__.py
Normal file
1
tests/integration/exit_from/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -3,17 +3,17 @@
|
|||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_yaml_path():
|
def compose_yaml_path() -> str:
|
||||||
return os.path.join(os.path.join(test_path(), "exit-from"), "docker-compose.yaml")
|
return os.path.join(os.path.join(test_path(), "exit_from"), "docker-compose.yaml")
|
||||||
|
|
||||||
|
|
||||||
class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
|
class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
|
||||||
def test_exit_code_sh1(self):
|
def test_exit_code_sh1(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(
|
self.run_subprocess_assert_returncode(
|
||||||
[
|
[
|
||||||
@ -33,7 +33,7 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_exit_code_sh2(self):
|
def test_exit_code_sh2(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(
|
self.run_subprocess_assert_returncode(
|
||||||
[
|
[
|
||||||
@ -52,3 +52,16 @@ class TestComposeExitFrom(unittest.TestCase, RunSubprocessMixin):
|
|||||||
compose_yaml_path(),
|
compose_yaml_path(),
|
||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_podman_compose_exit_from(self) -> None:
|
||||||
|
up_cmd = [
|
||||||
|
"coverage",
|
||||||
|
"run",
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"up",
|
||||||
|
]
|
||||||
|
|
||||||
|
self.run_subprocess_assert_returncode(up_cmd + ["--exit-code-from", "sh1"], 1)
|
||||||
|
self.run_subprocess_assert_returncode(up_cmd + ["--exit-code-from", "sh2"], 2)
|
1
tests/integration/extends/__init__.py
Normal file
1
tests/integration/extends/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -3,17 +3,17 @@
|
|||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_yaml_path():
|
def compose_yaml_path() -> str:
|
||||||
return os.path.join(os.path.join(test_path(), "extends"), "docker-compose.yaml")
|
return os.path.join(os.path.join(test_path(), "extends"), "docker-compose.yaml")
|
||||||
|
|
||||||
|
|
||||||
class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
|
class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
|
||||||
def test_extends_service_launch_echo(self):
|
def test_extends_service_launch_echo(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode([
|
self.run_subprocess_assert_returncode([
|
||||||
podman_compose_path(),
|
podman_compose_path(),
|
||||||
@ -38,7 +38,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_extends_service_launch_echo1(self):
|
def test_extends_service_launch_echo1(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode([
|
self.run_subprocess_assert_returncode([
|
||||||
podman_compose_path(),
|
podman_compose_path(),
|
||||||
@ -63,7 +63,7 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_extends_service_launch_env1(self):
|
def test_extends_service_launch_env1(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode([
|
self.run_subprocess_assert_returncode([
|
||||||
podman_compose_path(),
|
podman_compose_path(),
|
||||||
@ -80,18 +80,25 @@ class TestComposeExteds(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"env1",
|
"env1",
|
||||||
])
|
])
|
||||||
lines = output.decode('utf-8').split('\n')
|
lines = output.decode('utf-8').split('\n')
|
||||||
# HOSTNAME name is random string so is ignored in asserting
|
# Test selected env variables to improve robustness
|
||||||
lines = sorted([line for line in lines if not line.startswith("HOSTNAME")])
|
lines = sorted([
|
||||||
|
line
|
||||||
|
for line in lines
|
||||||
|
if line.startswith("BAR")
|
||||||
|
or line.startswith("BAZ")
|
||||||
|
or line.startswith("FOO")
|
||||||
|
or line.startswith("HOME")
|
||||||
|
or line.startswith("PATH")
|
||||||
|
or line.startswith("container")
|
||||||
|
])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
lines,
|
lines,
|
||||||
[
|
[
|
||||||
'',
|
|
||||||
'BAR=local',
|
'BAR=local',
|
||||||
'BAZ=local',
|
'BAZ=local',
|
||||||
'FOO=original',
|
'FOO=original',
|
||||||
'HOME=/root',
|
'HOME=/root',
|
||||||
'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
|
'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
|
||||||
'TERM=xterm',
|
|
||||||
'container=podman',
|
'container=podman',
|
||||||
],
|
],
|
||||||
)
|
)
|
1
tests/integration/extends_w_empty_service/__init__.py
Normal file
1
tests/integration/extends_w_empty_service/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -2,18 +2,19 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_yaml_path():
|
def compose_yaml_path() -> str:
|
||||||
return os.path.join(os.path.join(test_path(), "extends_w_empty_service"), "docker-compose.yml")
|
return os.path.join(os.path.join(test_path(), "extends_w_empty_service"), "docker-compose.yml")
|
||||||
|
|
||||||
|
|
||||||
class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
|
class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
|
||||||
def test_extends_w_empty_service(self):
|
def test_extends_w_empty_service(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(
|
self.run_subprocess_assert_returncode(
|
||||||
[
|
[
|
||||||
@ -37,3 +38,26 @@ class TestComposeExtendsWithEmptyService(unittest.TestCase, RunSubprocessMixin):
|
|||||||
compose_yaml_path(),
|
compose_yaml_path(),
|
||||||
"down",
|
"down",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_podman_compose_extends_w_empty_service(self) -> None:
|
||||||
|
"""
|
||||||
|
Test that podman-compose can execute podman-compose -f <file> up with extended File which
|
||||||
|
includes an empty service. (e.g. if the file is used as placeholder for more complex
|
||||||
|
configurations.)
|
||||||
|
"""
|
||||||
|
main_path = Path(__file__).parent.parent.parent.parent
|
||||||
|
|
||||||
|
command_up = [
|
||||||
|
"python3",
|
||||||
|
str(main_path.joinpath("podman_compose.py")),
|
||||||
|
"-f",
|
||||||
|
str(
|
||||||
|
main_path.joinpath(
|
||||||
|
"tests", "integration", "extends_w_empty_service", "docker-compose.yml"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"up",
|
||||||
|
"-d",
|
||||||
|
]
|
||||||
|
|
||||||
|
self.run_subprocess_assert_returncode(command_up)
|
1
tests/integration/extends_w_file/__init__.py
Normal file
1
tests/integration/extends_w_file/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -3,17 +3,17 @@
|
|||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def compose_yaml_path():
|
def compose_yaml_path() -> str:
|
||||||
return os.path.join(os.path.join(test_path(), "extends_w_file"), "docker-compose.yml")
|
return os.path.join(os.path.join(test_path(), "extends_w_file"), "docker-compose.yml")
|
||||||
|
|
||||||
|
|
||||||
class TestComposeExtendsWithFile(unittest.TestCase, RunSubprocessMixin):
|
class TestComposeExtendsWithFile(unittest.TestCase, RunSubprocessMixin):
|
||||||
def test_extends_w_file(self): # when file is Dockerfile for building the image
|
def test_extends_w_file(self) -> None: # when file is Dockerfile for building the image
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(
|
self.run_subprocess_assert_returncode(
|
||||||
[
|
[
|
1
tests/integration/extends_w_file_subdir/__init__.py
Normal file
1
tests/integration/extends_w_file_subdir/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -5,31 +5,47 @@ import unittest
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
def base_path():
|
def compose_yaml_path() -> str:
|
||||||
"""Returns the base path for the project"""
|
return os.path.join(os.path.join(test_path(), "extends_w_file_subdir"), "docker-compose.yml")
|
||||||
return Path(__file__).parent.parent.parent
|
|
||||||
|
|
||||||
|
|
||||||
def test_path():
|
class TestComposeExtendsWithFileSubdir(unittest.TestCase, RunSubprocessMixin):
|
||||||
"""Returns the path to the tests directory"""
|
def test_extends_w_file_subdir(self) -> None: # when file is Dockerfile for building the image
|
||||||
return os.path.join(base_path(), "tests/integration")
|
try:
|
||||||
|
self.run_subprocess_assert_returncode(
|
||||||
|
[
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"up",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
output, _ = self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"ps",
|
||||||
|
])
|
||||||
|
self.assertIn("extends_w_file_subdir_web_1", str(output))
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_podman_compose_extends_w_file_subdir(self) -> None:
|
||||||
def podman_compose_path():
|
|
||||||
"""Returns the path to the podman compose script"""
|
|
||||||
return os.path.join(base_path(), "podman_compose.py")
|
|
||||||
|
|
||||||
|
|
||||||
class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin):
|
|
||||||
def test_extends_w_file_subdir(self):
|
|
||||||
"""
|
"""
|
||||||
Test that podman-compose can execute podman-compose -f <file> up with extended File which
|
Test that podman-compose can execute podman-compose -f <file> up with extended File which
|
||||||
includes a build context
|
includes a build context
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
main_path = Path(__file__).parent.parent.parent
|
main_path = Path(__file__).parent.parent.parent.parent
|
||||||
|
|
||||||
command_up = [
|
command_up = [
|
||||||
"coverage",
|
"coverage",
|
||||||
@ -86,26 +102,3 @@ class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# check container did not exists anymore
|
# check container did not exists anymore
|
||||||
out, _ = self.run_subprocess_assert_returncode(command_check_container)
|
out, _ = self.run_subprocess_assert_returncode(command_check_container)
|
||||||
self.assertEqual(out, b'')
|
self.assertEqual(out, b'')
|
||||||
|
|
||||||
def test_extends_w_empty_service(self):
|
|
||||||
"""
|
|
||||||
Test that podman-compose can execute podman-compose -f <file> up with extended File which
|
|
||||||
includes an empty service. (e.g. if the file is used as placeholder for more complex
|
|
||||||
configurations.)
|
|
||||||
"""
|
|
||||||
main_path = Path(__file__).parent.parent.parent
|
|
||||||
|
|
||||||
command_up = [
|
|
||||||
"python3",
|
|
||||||
str(main_path.joinpath("podman_compose.py")),
|
|
||||||
"-f",
|
|
||||||
str(
|
|
||||||
main_path.joinpath(
|
|
||||||
"tests", "integration", "extends_w_empty_service", "docker-compose.yml"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
"up",
|
|
||||||
"-d",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.run_subprocess_assert_returncode(command_up)
|
|
1
tests/integration/filesystem/__init__.py
Normal file
1
tests/integration/filesystem/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -4,13 +4,13 @@
|
|||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.integration.test_podman_compose import podman_compose_path
|
|
||||||
from tests.integration.test_podman_compose import test_path
|
|
||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
class TestFilesystem(unittest.TestCase, RunSubprocessMixin):
|
class TestFilesystem(unittest.TestCase, RunSubprocessMixin):
|
||||||
def test_compose_symlink(self):
|
def test_compose_symlink(self) -> None:
|
||||||
"""The context of podman-compose.yml should come from the same directory as the file even
|
"""The context of podman-compose.yml should come from the same directory as the file even
|
||||||
if it is a symlink
|
if it is a symlink
|
||||||
"""
|
"""
|
||||||
@ -35,8 +35,7 @@ class TestFilesystem(unittest.TestCase, RunSubprocessMixin):
|
|||||||
"container1",
|
"container1",
|
||||||
])
|
])
|
||||||
|
|
||||||
# BUG: figure out why cat is called twice
|
self.assertEqual(out, b'data_compose_symlink\n')
|
||||||
self.assertEqual(out, b'data_compose_symlink\ndata_compose_symlink\n')
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
out, _ = self.run_subprocess_assert_returncode([
|
out, _ = self.run_subprocess_assert_returncode([
|
1
tests/integration/in_pod/__init__.py
Normal file
1
tests/integration/in_pod/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
cont:
|
||||||
|
image: nopush/podman-compose-test
|
||||||
|
command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"]
|
||||||
|
|
||||||
|
x-podman:
|
||||||
|
in_pod: custom_test_pod_name
|
@ -6,28 +6,38 @@ import unittest
|
|||||||
from tests.integration.test_utils import RunSubprocessMixin
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
|
||||||
|
|
||||||
def base_path():
|
def base_path() -> str:
|
||||||
"""Returns the base path for the project"""
|
"""Returns the base path for the project"""
|
||||||
return os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
return os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||||
|
|
||||||
|
|
||||||
def test_path():
|
def test_path() -> str:
|
||||||
"""Returns the path to the tests directory"""
|
"""Returns the path to the tests directory"""
|
||||||
return os.path.join(base_path(), "tests/integration")
|
return os.path.join(base_path(), "tests/integration")
|
||||||
|
|
||||||
|
|
||||||
def podman_compose_path():
|
def podman_compose_path() -> str:
|
||||||
"""Returns the path to the podman compose script"""
|
"""Returns the path to the podman compose script"""
|
||||||
return os.path.join(base_path(), "podman_compose.py")
|
return os.path.join(base_path(), "podman_compose.py")
|
||||||
|
|
||||||
|
|
||||||
|
def is_root() -> bool:
|
||||||
|
return os.geteuid() == 0
|
||||||
|
|
||||||
|
|
||||||
|
def failure_exitcode_when_rootful() -> int:
|
||||||
|
if is_root():
|
||||||
|
return 125
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# If a compose file has userns_mode set, setting in_pod to True, results in error.
|
# If a compose file has userns_mode set, setting in_pod to True, results in error.
|
||||||
# Default in_pod setting is True, unless compose file provides otherwise.
|
# Default in_pod setting is True, unless compose file provides otherwise.
|
||||||
# Compose file provides custom in_pod option, which can be overridden by command line in_pod option.
|
# Compose file provides custom in_pod option, which can be overridden by command line in_pod option.
|
||||||
# Test all combinations of command line argument in_pod and compose file argument in_pod.
|
# Test all combinations of command line argument in_pod and compose file argument in_pod.
|
||||||
class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
||||||
# compose file provides x-podman in_pod=false
|
# compose file provides x-podman in_pod=false
|
||||||
def test_x_podman_in_pod_false_command_line_in_pod_not_exists(self):
|
def test_x_podman_in_pod_false_command_line_in_pod_not_exists(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
|
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
|
||||||
does not provide this option
|
does not provide this option
|
||||||
@ -64,7 +74,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(command_up)
|
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.run_subprocess_assert_returncode(down_cmd)
|
self.run_subprocess_assert_returncode(down_cmd)
|
||||||
@ -72,7 +82,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# throws an error, can not actually find this pod because it was not created
|
# throws an error, can not actually find this pod because it was not created
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod, expected_returncode=1)
|
self.run_subprocess_assert_returncode(command_rm_pod, expected_returncode=1)
|
||||||
|
|
||||||
def test_x_podman_in_pod_false_command_line_in_pod_true(self):
|
def test_x_podman_in_pod_false_command_line_in_pod_true(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose does not allow pod creating even with command line in_pod=True
|
Test that podman-compose does not allow pod creating even with command line in_pod=True
|
||||||
when --userns and --pod are set together: throws an error
|
when --userns and --pod are set together: throws an error
|
||||||
@ -96,7 +106,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err = self.run_subprocess_assert_returncode(command_up)
|
out, err = self.run_subprocess_assert_returncode(command_up, 125)
|
||||||
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -105,7 +115,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# been created) and have expected_returncode=1 (see FIXME above)
|
# been created) and have expected_returncode=1 (see FIXME above)
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod)
|
self.run_subprocess_assert_returncode(command_rm_pod)
|
||||||
|
|
||||||
def test_x_podman_in_pod_false_command_line_in_pod_false(self):
|
def test_x_podman_in_pod_false_command_line_in_pod_false(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose will not create a pod as command line sets in_pod=False
|
Test that podman-compose will not create a pod as command line sets in_pod=False
|
||||||
"""
|
"""
|
||||||
@ -142,7 +152,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(command_up)
|
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.run_subprocess_assert_returncode(down_cmd)
|
self.run_subprocess_assert_returncode(down_cmd)
|
||||||
@ -150,7 +160,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# can not actually find this pod because it was not created
|
# can not actually find this pod because it was not created
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||||
|
|
||||||
def test_x_podman_in_pod_false_command_line_in_pod_empty_string(self):
|
def test_x_podman_in_pod_false_command_line_in_pod_empty_string(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
|
Test that podman-compose will not create a pod, when x-podman in_pod=false and command line
|
||||||
command line in_pod=""
|
command line in_pod=""
|
||||||
@ -188,7 +198,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(command_up)
|
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.run_subprocess_assert_returncode(down_cmd)
|
self.run_subprocess_assert_returncode(down_cmd)
|
||||||
@ -197,7 +207,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||||
|
|
||||||
# compose file provides x-podman in_pod=true
|
# compose file provides x-podman in_pod=true
|
||||||
def test_x_podman_in_pod_true_command_line_in_pod_not_exists(self):
|
def test_x_podman_in_pod_true_command_line_in_pod_not_exists(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
||||||
together even when x-podman in_pod=true: throws an error
|
together even when x-podman in_pod=true: throws an error
|
||||||
@ -221,7 +231,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err = self.run_subprocess_assert_returncode(command_up)
|
out, err = self.run_subprocess_assert_returncode(command_up, 125)
|
||||||
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -230,7 +240,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# created) and have expected_returncode=1 (see FIXME above)
|
# created) and have expected_returncode=1 (see FIXME above)
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod)
|
self.run_subprocess_assert_returncode(command_rm_pod)
|
||||||
|
|
||||||
def test_x_podman_in_pod_true_command_line_in_pod_true(self):
|
def test_x_podman_in_pod_true_command_line_in_pod_true(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
||||||
together even when x-podman in_pod=true and and command line in_pod=True: throws an error
|
together even when x-podman in_pod=true and and command line in_pod=True: throws an error
|
||||||
@ -255,7 +265,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err = self.run_subprocess_assert_returncode(command_up)
|
out, err = self.run_subprocess_assert_returncode(command_up, 125)
|
||||||
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -264,7 +274,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# been created) and have expected_returncode=1 (see FIXME above)
|
# been created) and have expected_returncode=1 (see FIXME above)
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod)
|
self.run_subprocess_assert_returncode(command_rm_pod)
|
||||||
|
|
||||||
def test_x_podman_in_pod_true_command_line_in_pod_false(self):
|
def test_x_podman_in_pod_true_command_line_in_pod_false(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose will not create a pod as command line sets in_pod=False
|
Test that podman-compose will not create a pod as command line sets in_pod=False
|
||||||
"""
|
"""
|
||||||
@ -301,7 +311,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(command_up)
|
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.run_subprocess_assert_returncode(down_cmd)
|
self.run_subprocess_assert_returncode(down_cmd)
|
||||||
@ -309,7 +319,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# can not actually find this pod because it was not created
|
# can not actually find this pod because it was not created
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||||
|
|
||||||
def test_x_podman_in_pod_true_command_line_in_pod_empty_string(self):
|
def test_x_podman_in_pod_true_command_line_in_pod_empty_string(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
||||||
together even when x-podman in_pod=true and command line in_pod="": throws an error
|
together even when x-podman in_pod=true and command line in_pod="": throws an error
|
||||||
@ -334,7 +344,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err = self.run_subprocess_assert_returncode(command_up)
|
out, err = self.run_subprocess_assert_returncode(command_up, 125)
|
||||||
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -344,7 +354,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
self.run_subprocess_assert_returncode(command_rm_pod)
|
self.run_subprocess_assert_returncode(command_rm_pod)
|
||||||
|
|
||||||
# compose file does not provide x-podman in_pod
|
# compose file does not provide x-podman in_pod
|
||||||
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists(self):
|
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
||||||
together: throws an error
|
together: throws an error
|
||||||
@ -368,7 +378,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err = self.run_subprocess_assert_returncode(command_up)
|
out, err = self.run_subprocess_assert_returncode(command_up, 125)
|
||||||
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -377,7 +387,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# created) and have expected_returncode=1 (see FIXME above)
|
# created) and have expected_returncode=1 (see FIXME above)
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod)
|
self.run_subprocess_assert_returncode(command_rm_pod)
|
||||||
|
|
||||||
def test_x_podman_in_pod_not_exists_command_line_in_pod_true(self):
|
def test_x_podman_in_pod_not_exists_command_line_in_pod_true(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
||||||
together even when x-podman in_pod=true: throws an error
|
together even when x-podman in_pod=true: throws an error
|
||||||
@ -402,7 +412,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err = self.run_subprocess_assert_returncode(command_up)
|
out, err = self.run_subprocess_assert_returncode(command_up, 125)
|
||||||
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@ -411,7 +421,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# been created) and have expected_returncode=1 (see FIXME above)
|
# been created) and have expected_returncode=1 (see FIXME above)
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod)
|
self.run_subprocess_assert_returncode(command_rm_pod)
|
||||||
|
|
||||||
def test_x_podman_in_pod_not_exists_command_line_in_pod_false(self):
|
def test_x_podman_in_pod_not_exists_command_line_in_pod_false(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose will not create a pod as command line sets in_pod=False
|
Test that podman-compose will not create a pod as command line sets in_pod=False
|
||||||
"""
|
"""
|
||||||
@ -448,7 +458,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.run_subprocess_assert_returncode(command_up)
|
self.run_subprocess_assert_returncode(command_up, failure_exitcode_when_rootful())
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.run_subprocess_assert_returncode(down_cmd)
|
self.run_subprocess_assert_returncode(down_cmd)
|
||||||
@ -457,7 +467,136 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
# can not actually find this pod because it was not created
|
# can not actually find this pod because it was not created
|
||||||
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||||
|
|
||||||
def test_x_podman_in_pod_not_exists_command_line_in_pod_empty_string(self):
|
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists_docker_compat(self) -> None:
|
||||||
|
"""
|
||||||
|
Test that podman-compose will not create a pod when docker compat is requested.
|
||||||
|
"""
|
||||||
|
command_up = [
|
||||||
|
"python3",
|
||||||
|
os.path.join(base_path(), "podman_compose.py"),
|
||||||
|
"-f",
|
||||||
|
os.path.join(
|
||||||
|
base_path(),
|
||||||
|
"tests",
|
||||||
|
"integration",
|
||||||
|
"in_pod",
|
||||||
|
"custom_x-podman_not_exists",
|
||||||
|
"docker-compose.yml",
|
||||||
|
),
|
||||||
|
"up",
|
||||||
|
"-d",
|
||||||
|
]
|
||||||
|
|
||||||
|
down_cmd = [
|
||||||
|
"python3",
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
os.path.join(
|
||||||
|
base_path(),
|
||||||
|
"tests",
|
||||||
|
"integration",
|
||||||
|
"in_pod",
|
||||||
|
"custom_x-podman_not_exists",
|
||||||
|
"docker-compose.yml",
|
||||||
|
),
|
||||||
|
"down",
|
||||||
|
]
|
||||||
|
|
||||||
|
env = {
|
||||||
|
"PODMAN_COMPOSE_DOCKER_COMPOSE_COMPAT": "1",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode(
|
||||||
|
command_up, failure_exitcode_when_rootful(), env=env
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode(down_cmd, env=env)
|
||||||
|
|
||||||
|
command_rm_pod = ["podman", "pod", "rm", "pod_custom_x-podman_not_exists"]
|
||||||
|
# can not actually find this pod because it was not created
|
||||||
|
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||||
|
|
||||||
|
def test_x_podman_in_pod_not_exists_command_line_in_pod_not_exists_env_var(self) -> None:
|
||||||
|
"""
|
||||||
|
Test that podman-compose will not create a pod when env var is set.
|
||||||
|
"""
|
||||||
|
command_up = [
|
||||||
|
"python3",
|
||||||
|
os.path.join(base_path(), "podman_compose.py"),
|
||||||
|
"-f",
|
||||||
|
os.path.join(
|
||||||
|
base_path(),
|
||||||
|
"tests",
|
||||||
|
"integration",
|
||||||
|
"in_pod",
|
||||||
|
"custom_x-podman_not_exists",
|
||||||
|
"docker-compose.yml",
|
||||||
|
),
|
||||||
|
"up",
|
||||||
|
"-d",
|
||||||
|
]
|
||||||
|
|
||||||
|
down_cmd = [
|
||||||
|
"python3",
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
os.path.join(
|
||||||
|
base_path(),
|
||||||
|
"tests",
|
||||||
|
"integration",
|
||||||
|
"in_pod",
|
||||||
|
"custom_x-podman_not_exists",
|
||||||
|
"docker-compose.yml",
|
||||||
|
),
|
||||||
|
"down",
|
||||||
|
]
|
||||||
|
|
||||||
|
env = {
|
||||||
|
"PODMAN_COMPOSE_IN_POD": "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode(
|
||||||
|
command_up, failure_exitcode_when_rootful(), env=env
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.run_subprocess_assert_returncode(down_cmd, env=env)
|
||||||
|
|
||||||
|
command_rm_pod = ["podman", "pod", "rm", "pod_custom_x-podman_not_exists"]
|
||||||
|
# can not actually find this pod because it was not created
|
||||||
|
self.run_subprocess_assert_returncode(command_rm_pod, 1)
|
||||||
|
|
||||||
|
def test_x_podman_in_pod_custom_name(self) -> None:
|
||||||
|
"""
|
||||||
|
Test that podman-compose will create a pod with a custom name
|
||||||
|
"""
|
||||||
|
command_up = [
|
||||||
|
"python3",
|
||||||
|
os.path.join(base_path(), "podman_compose.py"),
|
||||||
|
"-f",
|
||||||
|
os.path.join(
|
||||||
|
base_path(),
|
||||||
|
"tests",
|
||||||
|
"integration",
|
||||||
|
"in_pod",
|
||||||
|
"custom_x-podman_custom_name",
|
||||||
|
"docker-compose.yml",
|
||||||
|
),
|
||||||
|
"up",
|
||||||
|
"--no-start",
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.run_subprocess_assert_returncode(command_up)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
command_rm_pod = ["podman", "pod", "rm", "custom_test_pod_name"]
|
||||||
|
self.run_subprocess_assert_returncode(command_rm_pod)
|
||||||
|
|
||||||
|
def test_x_podman_in_pod_not_exists_command_line_in_pod_empty_string(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
Test that podman-compose does not allow pod creating when --userns and --pod are set
|
||||||
together: throws an error
|
together: throws an error
|
||||||
@ -482,7 +621,7 @@ class TestPodmanComposeInPod(unittest.TestCase, RunSubprocessMixin):
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err = self.run_subprocess_assert_returncode(command_up)
|
out, err = self.run_subprocess_assert_returncode(command_up, 125)
|
||||||
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
self.assertEqual(b"Error: --userns and --pod cannot be set together" in err, True)
|
||||||
|
|
||||||
finally:
|
finally:
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user