mirror of
https://github.com/MAKS-IT-COM/podman-client-dotnet.git
synced 2026-08-15 06:38:10 +02:00
(feature): add powershell client and e2e
This commit is contained in:
parent
755f7b2341
commit
9f6284ba6f
@ -4,6 +4,7 @@
|
||||
"skills": [
|
||||
"common/csharp",
|
||||
"common/maksit-repo-maintenance",
|
||||
"local-ollama"
|
||||
"local-ollama",
|
||||
"gh-cli"
|
||||
]
|
||||
}
|
||||
|
||||
@ -9,5 +9,6 @@ alwaysApply: true
|
||||
1. `E:\Users\maksym\source\repos\private\homelab\ai\skills\common\csharp\SKILL.md`
|
||||
2. `E:\Users\maksym\source\repos\private\homelab\ai\skills\common\maksit-repo-maintenance\SKILL.md`
|
||||
3. `E:\Users\maksym\source\repos\private\homelab\ai\skills\local-ollama\SKILL.md` — local Ollama offload (`@local-ollama`)
|
||||
4. `E:\Users\maksym\source\repos\private\homelab\ai\skills\gh-cli\SKILL.md` — git/gh commits & PRs (`/gh-cli`, `@gh-cli`)
|
||||
|
||||
Manifest: `.cursor/maksit-skills.json`.
|
||||
|
||||
118
.editorconfig
Normal file
118
.editorconfig
Normal file
@ -0,0 +1,118 @@
|
||||
# EditorConfig: https://editorconfig.org
|
||||
# Shared code style for VS Code, Cursor, Visual Studio, Rider
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
|
||||
# =========================
|
||||
# C#
|
||||
# =========================
|
||||
[*.cs]
|
||||
indent_size = 2
|
||||
|
||||
# K&R braces (opening brace on same line)
|
||||
csharp_new_line_before_open_brace = none
|
||||
|
||||
# keep else/catch/finally on new line
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
|
||||
# indentation
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
|
||||
# spacing
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
|
||||
# Fluent / chained method calls (ReSharper compatibility)
|
||||
resharper_csharp_continuous_indent_multiplier = 1
|
||||
resharper_continuous_indent_multiplier = 1
|
||||
resharper_csharp_align_multiline_calls_chain = false
|
||||
resharper_align_multiline_calls_chain = false
|
||||
resharper_csharp_outdent_dots = false
|
||||
resharper_outdent_dots = false
|
||||
|
||||
# Two blank lines between last using and namespace
|
||||
resharper_csharp_blank_lines_between_using_and_namespace = 2
|
||||
resharper_blank_lines_between_using_and_namespace = 2
|
||||
|
||||
# Usings: System first; blank line between System and other groups (Roslyn)
|
||||
dotnet_sort_system_directives_first = true
|
||||
dotnet_separate_import_directive_groups = false
|
||||
resharper_sort_usings_system_first = true
|
||||
|
||||
# Remove unnecessary using directives (dotnet format style --diagnostics IDE0005)
|
||||
dotnet_diagnostic.IDE0005.severity = warning
|
||||
|
||||
# File-scoped namespace declarations (IDE0160)
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
dotnet_diagnostic.IDE0160.severity = warning
|
||||
|
||||
# Omit braces on single-line if/else/for/foreach/while/using (IDE0011)
|
||||
csharp_prefer_braces = when_multiline:none
|
||||
dotnet_diagnostic.IDE0011.severity = none
|
||||
|
||||
# Prefer 'var' over explicit type (IDE0008)
|
||||
csharp_style_var_for_built_in_types = true:none
|
||||
csharp_style_var_when_type_is_apparent = true:none
|
||||
csharp_style_var_elsewhere = true:none
|
||||
dotnet_diagnostic.IDE0008.severity = none
|
||||
|
||||
# Prefer if-return over ternary for conditional returns (IDE0046) — multi-line guards stay readable
|
||||
dotnet_style_prefer_conditional_expression_over_return = false:none
|
||||
dotnet_diagnostic.IDE0046.severity = none
|
||||
|
||||
# Expression-bodied members: prefer => over { return ...; } (IDE0022–IDE0027)
|
||||
csharp_style_expression_bodied_methods = true:warning
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
||||
csharp_style_expression_bodied_indexers = true:warning
|
||||
csharp_style_expression_bodied_operators = true:warning
|
||||
csharp_style_expression_bodied_lambdas = true:none
|
||||
csharp_style_expression_bodied_local_functions = false:none
|
||||
csharp_style_expression_bodied_constructors = false:none
|
||||
dotnet_diagnostic.IDE0022.severity = warning
|
||||
dotnet_diagnostic.IDE0023.severity = warning
|
||||
dotnet_diagnostic.IDE0024.severity = warning
|
||||
dotnet_diagnostic.IDE0025.severity = warning
|
||||
dotnet_diagnostic.IDE0026.severity = warning
|
||||
dotnet_diagnostic.IDE0027.severity = warning
|
||||
|
||||
# => on signature line; expression indented on next line (no blank line after =>)
|
||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:warning
|
||||
dotnet_diagnostic.IDE2006.severity = warning
|
||||
resharper_csharp_wrap_before_arrow_with_expressions = false
|
||||
resharper_wrap_before_arrow_with_expressions = false
|
||||
|
||||
|
||||
# =========================
|
||||
# TypeScript / JavaScript
|
||||
# =========================
|
||||
[*.{ts,tsx,js,jsx}]
|
||||
indent_size = 2
|
||||
|
||||
|
||||
# =========================
|
||||
# JSON / YAML
|
||||
# =========================
|
||||
[*.{json,yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
|
||||
# =========================
|
||||
# Markdown
|
||||
# =========================
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -29,6 +29,7 @@ bld/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
test-results/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
|
||||
@ -5,5 +5,6 @@
|
||||
| csharp | [SKILL.md](E:\Users\maksym\source\repos\private\homelab\ai\skills\common\csharp\SKILL.md) |
|
||||
| maksit-repo-maintenance | [SKILL.md](E:\Users\maksym\source\repos\private\homelab\ai\skills\common\maksit-repo-maintenance\SKILL.md) |
|
||||
| local-ollama | [SKILL.md](E:\Users\maksym\source\repos\private\homelab\ai\skills\local-ollama\SKILL.md) |
|
||||
| gh-cli | [SKILL.md](E:\Users\maksym\source\repos\private\homelab\ai\skills\gh-cli\SKILL.md) |
|
||||
|
||||
Manifest: `.cursor/maksit-skills.json`.
|
||||
|
||||
37
CHANGELOG.md
37
CHANGELOG.md
@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.3.0] - 2026-07-27
|
||||
|
||||
### Added
|
||||
|
||||
- **PowerShell module** `MaksIT.PodmanClientDotNet.PowerShell` wrapping the full `IPodmanClient` surface (`Connect-Podman` and domain cmdlets).
|
||||
- **PowerShell E2E** harness under `src/e2e-tests/` (requires `PODMAN_TEST_URL`) covering system, images, containers, exec, volumes, networks, pods, build, manifests, and generate. Validated against **Podman 5.4.0**.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Default `ApiVersion`**: `v5.4.0` (libpod path). Docker-compat `v1.41` is not used — network endpoints reject it.
|
||||
- **Manifests (libpod v4+)**: create via `POST /libpod/manifests/{name}`; add via `PUT` modify body; push via `POST .../registry/{destination}` (replaces deprecated v3 `/create`, `/add`, `/push`).
|
||||
- **Pod stats**: `GetPodsStatsAsync` returns `List<PodStatsDto>` (libpod array), not a dictionary wrapper.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Ping** (`/_ping`): treat Podman's plain-text `OK` body as success instead of JSON-deserializing it (which threw `JsonException`).
|
||||
- **Mount container**: treat plain filesystem path body as `ContainerMountDto.Path`.
|
||||
- **Wait container**: accept bare exit-code integer responses from libpod.
|
||||
- **System DTOs** (`LibpodVersionDto`, `InfoDto`, `SystemDfDto`): align with live libpod JSON shapes (e.g. version `Platform` object, host `distribution` object, numeric memory fields).
|
||||
- **Image DTOs**: `RepoTags`/`RepoDigests` as string arrays; image tree `{Tree}`; image changes as path/kind entries; delete/remove returns a single `ImageDeleteDto` object (not an array).
|
||||
- **Prune APIs**: image/container/volume/pod prune return a list of `PruneReportEntryDto`; system prune returns `SystemPruneReportDto`.
|
||||
- **Container list/inspect/stats/changes/mounted DTOs**: align with live libpod JSON (including multi-container stats wrapper).
|
||||
- **Container inspect**: `Config.StopSignal` is a string (e.g. `SIGTERM`), not `Int64`.
|
||||
- **Pod DTOs**: inspect/list `Containers` as object summaries.
|
||||
|
||||
### Removed
|
||||
|
||||
- C# xUnit live Integration tests (`Category=Integration`); replaced by PowerShell E2E scenarios.
|
||||
|
||||
## [1.2.1] - 2026-07-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Inspect exec** deserialization: `ProcessConfig` is now typed as an object (`InspectExecProcessDto`) matching the Podman libpod API, instead of `string` (which threw `JsonException` when reading exit codes after exec).
|
||||
|
||||
## [1.2.0] - 2026-07-02
|
||||
|
||||
### Added
|
||||
|
||||
@ -8,7 +8,8 @@ Thank you for contributing. This repo follows MaksIT conventions (see `AGENTS.md
|
||||
|
||||
- .NET 10 SDK
|
||||
- Git
|
||||
- Optional: reachable Podman API for integration tests (`PODMAN_TEST_URL` or `PODMAN_INTEGRATION_URL`)
|
||||
- PowerShell 7 hosted on **.NET 10** (for the PowerShell module and E2E)
|
||||
- Optional: reachable Podman REST API for live E2E (`PODMAN_TEST_URL`)
|
||||
|
||||
### Build
|
||||
|
||||
@ -16,7 +17,7 @@ Thank you for contributing. This repo follows MaksIT conventions (see `AGENTS.md
|
||||
dotnet build src/PodmanClientDotNet.slnx
|
||||
```
|
||||
|
||||
### Tests
|
||||
### Unit tests
|
||||
|
||||
**RepoUtils test engine** (coverage + badges):
|
||||
|
||||
@ -30,7 +31,80 @@ utils/Invoke-TestEngine.bat
|
||||
dotnet test src/PodmanClientDotNet.Tests/PodmanClientDotNet.Tests.csproj
|
||||
```
|
||||
|
||||
When coverage changes and the test engine runs **CoverageBadges**, commit updated SVGs under `assets/badges/` (cited in `README.md`).
|
||||
Coverage badges in `README.md` are rewritten by the test engine (`CoverageBadges` with `badgeFormat: shields` and `readmePath` in `utils/engines/test/scriptSettings.json`) using `img.shields.io` URLs. Commit the updated README when coverage changes.
|
||||
|
||||
### Integration / E2E tests (Podman API VM)
|
||||
|
||||
Live API coverage is **PowerShell E2E** under `src/e2e-tests/` (not part of `Invoke-TestEngine`). It builds and imports `MaksIT.PodmanClientDotNet.PowerShell`, then runs domain scenarios against a real Podman API.
|
||||
|
||||
**Validated target:** [Podman](https://podman.io/) **5.4.0** (libpod path default `ApiVersion` = `v5.4.0`). Older engines that expose at least API `4.0.0` may work; Docker-compat path `v1.41` is not used (network endpoints reject it).
|
||||
|
||||
#### 1. Expose Podman on a Linux VM (e.g. Alma)
|
||||
|
||||
```bash
|
||||
podman version # expect 5.4.x for this repo's E2E baseline
|
||||
|
||||
# Bind all interfaces (not only 127.0.0.1)
|
||||
podman system service --time=0 tcp://0.0.0.0:8080
|
||||
```
|
||||
|
||||
On the VM:
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8080/v5.4.0/_ping # expect OK
|
||||
ss -tlnp | grep 8080 # expect 0.0.0.0:8080 (or LAN IP)
|
||||
sudo firewall-cmd --add-port=8080/tcp --permanent && sudo firewall-cmd --reload
|
||||
podman pull alpine:latest # scenarios need registry access
|
||||
```
|
||||
|
||||
Optional systemd unit (lab):
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Podman API service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman system service --time=0 tcp://0.0.0.0:8080
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Unauthenticated TCP API is lab-only — restrict firewall to your developer machine when possible.
|
||||
|
||||
#### 2. Run E2E from Windows
|
||||
|
||||
```powershell
|
||||
Invoke-WebRequest http://<vm-ip>:8080/v5.4.0/_ping # expect 200 / OK
|
||||
$env:PODMAN_TEST_URL = "http://<vm-ip>:8080" # must include http:// or https://
|
||||
.\src\e2e-tests\Test-PodmanE2E.bat
|
||||
# or:
|
||||
pwsh -File .\src\e2e-tests\Test-PodmanE2E.ps1 -Scenario 'System','Images'
|
||||
```
|
||||
|
||||
`PODMAN_TEST_URL` must be an absolute URI. Bare `host:port` causes `UriFormatException` in the .NET client.
|
||||
|
||||
Scenarios cover system, images, containers, exec, volumes, networks, pods, build, manifests, and generate (full PowerShell cmdlet surface). Filter with `-Scenario`.
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
1. **Pull fails** — VM cannot reach a registry; pre-pull `alpine:latest` on the VM.
|
||||
2. **Container create/start fails** — confirm `podman run --rm alpine:latest echo ok` as the same user running `system service`.
|
||||
3. **Attach/exec session failures** — hijack opens a second TCP connection to the same host:port; allow it in the firewall; do not put the API behind a proxy that strips `Upgrade: tcp`.
|
||||
4. **pwsh / .NET 10** — binary module requires PowerShell hosted on .NET 10.
|
||||
5. **`version is not supported` on networks** — use libpod path `v4.0.0+` (default `v5.4.0`), not Docker-compat `v1.41`.
|
||||
|
||||
### PowerShell module
|
||||
|
||||
```powershell
|
||||
dotnet build src/PodmanClient.PowerShell/PodmanClient.PowerShell.csproj
|
||||
Import-Module .\src\PodmanClient.PowerShell\bin\Debug\net10.0\MaksIT.PodmanClientDotNet.PowerShell.psd1 -Force
|
||||
Connect-Podman -BaseAddress $env:PODMAN_TEST_URL
|
||||
```
|
||||
|
||||
See [src/PodmanClient.PowerShell/README.md](src/PodmanClient.PowerShell/README.md).
|
||||
|
||||
## Commit message format
|
||||
|
||||
@ -49,15 +123,14 @@ Types: `(feature):`, `(bugfix):`, `(refactor):`, `(perf):`, `(test):`, `(docs):`
|
||||
- **MaksIT.Results** for API outcomes; **System.Text.Json** source generation via `PodmanJsonContext` for JSON serialization (AOT/trim-safe).
|
||||
- File-scoped namespaces and same-line braces; **Models/** use nullable reference types (`string?`, `List<T>?`, …) for optional JSON fields.
|
||||
- XML documentation on public types (DTOs, interfaces, entry types). Method-level docs on large interfaces are optional (`CS1591` suppressed).
|
||||
- Model layout helpers: `utils/tools/Polish-PodmanClientSources.ps1`, `utils/tools/Enable-ModelsNullable.ps1`.
|
||||
|
||||
## Pull requests
|
||||
|
||||
1. Build and tests pass.
|
||||
1. Build and unit tests pass; run E2E when changing the client or PowerShell surface if a Podman API is available.
|
||||
2. Update **README.md** / **CHANGELOG.md** when behavior or public API changes.
|
||||
3. Refresh **`assets/badges/*.svg`** when coverage badges change.
|
||||
3. If coverage changed: ensure **README.md** shields.io badge lines were updated by the test engine.
|
||||
4. Keep diffs scoped.
|
||||
|
||||
## Versioning
|
||||
|
||||
[Semantic Versioning](https://semver.org): bump `Version` in `src/PodmanClient/PodmanClientDotNet.csproj` with **CHANGELOG.md** for releases. Use `utils/Invoke-ReleasePackage.bat` when releasing.
|
||||
[Semantic Versioning](https://semver.org): bump `Version` in `src/PodmanClient/PodmanClientDotNet.csproj` with **CHANGELOG.md** for releases. Use `utils\Invoke-ReleasePackage-Single.bat` when releasing.
|
||||
|
||||
32
README.md
32
README.md
@ -1,6 +1,8 @@
|
||||
# PodmanClient.DotNet
|
||||
|
||||
  
|
||||

|
||||

|
||||

|
||||
|
||||
## Description
|
||||
|
||||
@ -37,7 +39,7 @@ dotnet add package PodmanClient.DotNet
|
||||
{
|
||||
"PodmanClient": {
|
||||
"ServerUrl": "http://localhost:8080",
|
||||
"ApiVersion": "v1.41",
|
||||
"ApiVersion": "v5.4.0",
|
||||
"TimeoutMinutes": 5
|
||||
}
|
||||
}
|
||||
@ -50,7 +52,7 @@ using MaksIT.PodmanClientDotNet.Extensions;
|
||||
// Host-owned options type (not shipped in this package)
|
||||
public sealed class PodmanClientOptions : IPodmanClientConfiguration {
|
||||
public string ServerUrl { get; set; } = string.Empty;
|
||||
public string ApiVersion { get; set; } = "v1.41";
|
||||
public string ApiVersion { get; set; } = "v5.4.0";
|
||||
public int TimeoutMinutes { get; set; } = 60;
|
||||
}
|
||||
|
||||
@ -162,16 +164,28 @@ Register with `AddPodmanClient` or construct `PodmanClient` manually. Methods re
|
||||
|
||||
API responses are typed under `Dtos/` (for example `ContainerInspectDto`, `ImageInspectDto`, `InfoDto`). Request/spec payloads remain in `Models/`.
|
||||
|
||||
## Tests
|
||||
## PowerShell module
|
||||
|
||||
Unit tests cover multiplex framing, attach sessions, NDJSON progress, and a local hijack mock server. Integration tests require a reachable Podman API:
|
||||
Binary module wrapping the full `IPodmanClient` surface — see [src/PodmanClient.PowerShell/README.md](src/PodmanClient.PowerShell/README.md).
|
||||
|
||||
```shell
|
||||
$env:PODMAN_TEST_URL = "http://localhost:8080"
|
||||
dotnet test src/PodmanClientDotNet.Tests/PodmanClientDotNet.Tests.csproj
|
||||
```powershell
|
||||
dotnet build src/PodmanClient.PowerShell/PodmanClient.PowerShell.csproj
|
||||
Import-Module .\src\PodmanClient.PowerShell\bin\Debug\net10.0\MaksIT.PodmanClientDotNet.PowerShell.psd1 -Force
|
||||
Connect-Podman -BaseAddress 'http://192.168.x.x:8080'
|
||||
```
|
||||
|
||||
Without `PODMAN_TEST_URL` (or `PODMAN_INTEGRATION_URL`), integration tests are skipped automatically. Filter them in CI with `--filter "Category!=Integration"`.
|
||||
## Tests
|
||||
|
||||
Unit tests cover multiplex framing, attach sessions, NDJSON progress, and a local hijack mock server (`dotnet test` / `utils/Invoke-TestEngine.bat`).
|
||||
|
||||
Live API E2E uses the PowerShell module against a reachable **Podman 5.4.0** API (baseline):
|
||||
|
||||
```powershell
|
||||
$env:PODMAN_TEST_URL = "http://192.168.x.x:8080"
|
||||
.\src\e2e-tests\Test-PodmanE2E.bat
|
||||
```
|
||||
|
||||
Default client `ApiVersion` is `v5.4.0`. VM setup, firewall, and troubleshooting: [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
**Note:** Full-duplex attach/exec sessions use a raw TCP hijack connection and do not flow through `HttpClient` delegating handlers (proxy, client certificates, etc.). Configure network access accordingly.
|
||||
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="20" role="img" aria-label="Branch Coverage: 14.2%">
|
||||
<title>Branch Coverage: 14.2%</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r">
|
||||
<rect width="150" height="20" rx="3" fill="#fff"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="107.5" height="20" fill="#555"/>
|
||||
<rect x="107.5" width="42.5" height="20" fill="#fe7d37"/>
|
||||
<rect width="150" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text aria-hidden="true" x="53.75" y="15" fill="#010101" fill-opacity=".3">Branch Coverage</text>
|
||||
<text x="53.75" y="14" fill="#fff">Branch Coverage</text>
|
||||
<text aria-hidden="true" x="128.75" y="15" fill="#010101" fill-opacity=".3">14.2%</text>
|
||||
<text x="128.75" y="14" fill="#fff">14.2%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,21 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="134.5" height="20" role="img" aria-label="Line Coverage: 5%">
|
||||
<title>Line Coverage: 5%</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r">
|
||||
<rect width="134.5" height="20" rx="3" fill="#fff"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="94.5" height="20" fill="#555"/>
|
||||
<rect x="94.5" width="40" height="20" fill="#e05d44"/>
|
||||
<rect width="134.5" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text aria-hidden="true" x="47.25" y="15" fill="#010101" fill-opacity=".3">Line Coverage</text>
|
||||
<text x="47.25" y="14" fill="#fff">Line Coverage</text>
|
||||
<text aria-hidden="true" x="114.5" y="15" fill="#010101" fill-opacity=".3">5%</text>
|
||||
<text x="114.5" y="14" fill="#fff">5%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,21 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="147.5" height="20" role="img" aria-label="Method Coverage: 3.4%">
|
||||
<title>Method Coverage: 3.4%</title>
|
||||
<linearGradient id="s" x2="0" y2="100%">
|
||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||
<stop offset="1" stop-opacity=".1"/>
|
||||
</linearGradient>
|
||||
<clipPath id="r">
|
||||
<rect width="147.5" height="20" rx="3" fill="#fff"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#r)">
|
||||
<rect width="107.5" height="20" fill="#555"/>
|
||||
<rect x="107.5" width="40" height="20" fill="#e05d44"/>
|
||||
<rect width="147.5" height="20" fill="url(#s)"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
||||
<text aria-hidden="true" x="53.75" y="15" fill="#010101" fill-opacity=".3">Method Coverage</text>
|
||||
<text x="53.75" y="14" fill="#fff">Method Coverage</text>
|
||||
<text aria-hidden="true" x="127.5" y="15" fill="#010101" fill-opacity=".3">3.4%</text>
|
||||
<text x="127.5" y="14" fill="#fff">3.4%</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
186
src/PodmanClient.PowerShell/Build/BuildCmdlets.cs
Normal file
186
src/PodmanClient.PowerShell/Build/BuildCmdlets.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Build;
|
||||
using MaksIT.PodmanClientDotNet.Streaming;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanBuildImage")]
|
||||
[OutputType(typeof(BuildReportDto))]
|
||||
public sealed class InvokePodmanBuildImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Dockerfile { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? ContextPath { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Stream? ContextStream { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Pull { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Rm { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter ForceRm { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter NoCache { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Remote { get; set; }
|
||||
|
||||
[Parameter]
|
||||
[Alias("t")]
|
||||
public string? Tag { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Platform { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? BuildArgs { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Labels { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
Stream? owned = null;
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var context = ResolveContext(ref owned);
|
||||
var result = client.BuildImageAsync(
|
||||
Dockerfile,
|
||||
context,
|
||||
Pull.IsPresent,
|
||||
Rm.IsPresent,
|
||||
ForceRm.IsPresent,
|
||||
NoCache.IsPresent,
|
||||
Remote,
|
||||
Tag,
|
||||
Platform,
|
||||
BuildArgs,
|
||||
Labels
|
||||
).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
finally {
|
||||
owned?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Stream? ResolveContext(ref Stream? owned) {
|
||||
if (ContextStream is not null)
|
||||
return ContextStream;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ContextPath))
|
||||
return null;
|
||||
|
||||
owned = File.OpenRead(ContextPath);
|
||||
return owned;
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanBuildImageProgress")]
|
||||
[OutputType(typeof(BuildProgressLineDto))]
|
||||
[OutputType(typeof(IPodmanProgressSession<BuildProgressLineDto>))]
|
||||
public sealed class InvokePodmanBuildImageProgressCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Dockerfile { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? ContextPath { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Stream? ContextStream { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Pull { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Rm { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter ForceRm { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter NoCache { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Remote { get; set; }
|
||||
|
||||
[Parameter]
|
||||
[Alias("t")]
|
||||
public string? Tag { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Platform { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? BuildArgs { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Labels { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Wait { get; set; } = true;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
Stream? owned = null;
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var context = ResolveContext(ref owned);
|
||||
var result = client.BuildImageWithProgressAsync(
|
||||
Dockerfile,
|
||||
context,
|
||||
Pull.IsPresent,
|
||||
Rm.IsPresent,
|
||||
ForceRm.IsPresent,
|
||||
NoCache.IsPresent,
|
||||
Remote,
|
||||
Tag,
|
||||
Platform,
|
||||
BuildArgs,
|
||||
Labels
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
if (!Wait.IsPresent) {
|
||||
WritePodmanResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.IsSuccess) {
|
||||
WritePodmanResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Value is null)
|
||||
return;
|
||||
|
||||
var items = CollectProgress(result.Value);
|
||||
WriteObject(items, true);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
finally {
|
||||
owned?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private Stream? ResolveContext(ref Stream? owned) {
|
||||
if (ContextStream is not null)
|
||||
return ContextStream;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ContextPath))
|
||||
return null;
|
||||
|
||||
owned = File.OpenRead(ContextPath);
|
||||
return owned;
|
||||
}
|
||||
}
|
||||
30
src/PodmanClient.PowerShell/ConnectDisconnectCmdlets.cs
Normal file
30
src/PodmanClient.PowerShell/ConnectDisconnectCmdlets.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsCommunications.Connect, "Podman")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class ConnectPodmanCmdlet : PSCmdlet {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string BaseAddress { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public int TimeoutMinutes { get; set; } = 60;
|
||||
|
||||
[Parameter]
|
||||
public string? ApiVersion { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
PodmanConnectionState.SetConnection(BaseAddress, TimeoutMinutes, ApiVersion);
|
||||
WriteVerbose($"Connected to Podman at {BaseAddress}");
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommunications.Disconnect, "Podman")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class DisconnectPodmanCmdlet : PSCmdlet {
|
||||
protected override void ProcessRecord() {
|
||||
PodmanConnectionState.ClearConnection();
|
||||
WriteVerbose("Disconnected from Podman");
|
||||
}
|
||||
}
|
||||
1026
src/PodmanClient.PowerShell/Containers/ContainersCmdlets.cs
Normal file
1026
src/PodmanClient.PowerShell/Containers/ContainersCmdlets.cs
Normal file
File diff suppressed because it is too large
Load Diff
192
src/PodmanClient.PowerShell/Exec/ExecCmdlets.cs
Normal file
192
src/PodmanClient.PowerShell/Exec/ExecCmdlets.cs
Normal file
@ -0,0 +1,192 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Exec;
|
||||
using MaksIT.PodmanClientDotNet.Streaming;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsCommon.New, "PodmanExec")]
|
||||
[OutputType(typeof(CreateExecResponseDto))]
|
||||
public sealed class NewPodmanExecCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string ContainerName { get; set; } = null!;
|
||||
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
public string[] Cmd { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public bool AttachStderr { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter AttachStdin { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool AttachStdout { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public string? DetachKeys { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string[]? Env { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Privileged { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Tty { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? User { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? WorkingDir { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.CreateExecAsync(
|
||||
ContainerName,
|
||||
Cmd,
|
||||
AttachStderr,
|
||||
AttachStdin.IsPresent,
|
||||
AttachStdout,
|
||||
DetachKeys,
|
||||
Env,
|
||||
Privileged.IsPresent,
|
||||
Tty.IsPresent,
|
||||
User,
|
||||
WorkingDir).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Start, "PodmanExec")]
|
||||
public sealed class StartPodmanExecCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string ExecId { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Detach { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Tty { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int? Height { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int? Width { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.StartExecAsync(ExecId, Detach.IsPresent, Tty.IsPresent, Height, Width)
|
||||
.GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanExec")]
|
||||
[OutputType(typeof(InspectExecResponseDto))]
|
||||
public sealed class GetPodmanExecCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string ExecId { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.InspectExecAsync(ExecId).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Resize, "PodmanExec")]
|
||||
public sealed class ResizePodmanExecCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string ExecId { get; set; } = null!;
|
||||
|
||||
[Parameter(Mandatory = true)]
|
||||
public int Height { get; set; }
|
||||
|
||||
[Parameter(Mandatory = true)]
|
||||
public int Width { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.ResizeExecAsync(ExecId, Height, Width).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanExecSession")]
|
||||
[OutputType(typeof(string))]
|
||||
[OutputType(typeof(IPodmanAttachSession))]
|
||||
public sealed class InvokePodmanExecSessionCmdlet : PodmanCmdletBase {
|
||||
public InvokePodmanExecSessionCmdlet() {
|
||||
CollectOutput = true;
|
||||
}
|
||||
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string ExecId { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Tty { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int? Height { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int? Width { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter CollectOutput { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.StartExecSessionAsync(ExecId, Tty.IsPresent, Height, Width)
|
||||
.GetAwaiter().GetResult();
|
||||
|
||||
if (!CollectOutput) {
|
||||
WritePodmanResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.IsSuccess) {
|
||||
WritePodmanResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Value is null)
|
||||
return;
|
||||
|
||||
try {
|
||||
WriteObject(CollectAttachOutput(result.Value));
|
||||
}
|
||||
finally {
|
||||
result.Value.DisposeAsync().AsTask().GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
122
src/PodmanClient.PowerShell/Generate/GenerateCmdlets.cs
Normal file
122
src/PodmanClient.PowerShell/Generate/GenerateCmdlets.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Generate;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanGenerateSystemd")]
|
||||
[OutputType(typeof(GenerateSystemdDto))]
|
||||
public sealed class InvokePodmanGenerateSystemdCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter UseName { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter CreateNew { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int? RestartSec { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? RestartPolicy { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? ContainerPrefix { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? PodPrefix { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Separator { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GenerateSystemdAsync(
|
||||
Name,
|
||||
UseName.IsPresent,
|
||||
CreateNew.IsPresent,
|
||||
RestartSec,
|
||||
RestartPolicy,
|
||||
ContainerPrefix,
|
||||
PodPrefix,
|
||||
Separator
|
||||
).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanGenerateKube")]
|
||||
[OutputType(typeof(string))]
|
||||
public sealed class InvokePodmanGenerateKubeCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)]
|
||||
public string[] Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Service { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GenerateKubeAsync(Name, Service.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPlayKube", DefaultParameterSetName = "Path")]
|
||||
[OutputType(typeof(PlayKubeReportDto))]
|
||||
public sealed class InvokePodmanPlayKubeCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, ParameterSetName = "Path", Position = 0)]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[Parameter(Mandatory = true, ParameterSetName = "InputStream")]
|
||||
public Stream? InputStream { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Network { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter TlsVerify { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Start { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public string? LogDriver { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
Stream? owned = null;
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var yaml = OpenInputStream(Path, InputStream);
|
||||
if (!ReferenceEquals(yaml, InputStream))
|
||||
owned = yaml;
|
||||
|
||||
var result = client.PlayKubeAsync(
|
||||
yaml,
|
||||
Network,
|
||||
TlsVerify.IsPresent,
|
||||
Start.IsPresent,
|
||||
LogDriver
|
||||
).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
finally {
|
||||
owned?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
537
src/PodmanClient.PowerShell/Images/ImagesCmdlets.cs
Normal file
537
src/PodmanClient.PowerShell/Images/ImagesCmdlets.cs
Normal file
@ -0,0 +1,537 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Common;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Image;
|
||||
using MaksIT.PodmanClientDotNet.Streaming;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPullImage")]
|
||||
public sealed class InvokePodmanPullImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Reference { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public bool TlsVerify { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Quiet { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Policy { get; set; } = "always";
|
||||
|
||||
[Parameter]
|
||||
public string? Arch { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Os { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Variant { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter AllTags { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? AuthHeader { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PullImageAsync(
|
||||
Reference,
|
||||
TlsVerify,
|
||||
Quiet.IsPresent,
|
||||
Policy,
|
||||
Arch,
|
||||
Os,
|
||||
Variant,
|
||||
AllTags.IsPresent,
|
||||
AuthHeader).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanTagImage")]
|
||||
public sealed class InvokePodmanTagImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Image { get; set; } = null!;
|
||||
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
public string Repo { get; set; } = null!;
|
||||
|
||||
[Parameter(Mandatory = true, Position = 2)]
|
||||
public string Tag { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.TagImageAsync(Image, Repo, Tag).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanImageList")]
|
||||
[OutputType(typeof(ImageListEntryDto))]
|
||||
public sealed class GetPodmanImageListCmdlet : PodmanCmdletBase {
|
||||
[Parameter]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Filters { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.ListImagesAsync(All.IsPresent, Filters).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanImage")]
|
||||
[OutputType(typeof(ImageInspectDto))]
|
||||
public sealed class GetPodmanImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.InspectImageAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsDiagnostic.Test, "PodmanImage")]
|
||||
[OutputType(typeof(bool))]
|
||||
public sealed class TestPodmanImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.ImageExistsAsync(Name).GetAwaiter().GetResult();
|
||||
WriteObject(result.IsSuccess);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Remove, "PodmanImage")]
|
||||
[OutputType(typeof(ImageDeleteDto))]
|
||||
public sealed class RemovePodmanImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.DeleteImageAsync(Name, Force.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Remove, "PodmanImageBatch")]
|
||||
[OutputType(typeof(ImageDeleteDto))]
|
||||
public sealed class RemovePodmanImageBatchCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true)]
|
||||
public string[] Image { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.RemoveImagesAsync(Image, All.IsPresent, Force.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPruneImage")]
|
||||
[OutputType(typeof(PruneReportEntryDto))]
|
||||
public sealed class InvokePodmanPruneImageCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PruneImagesAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Search, "PodmanImage")]
|
||||
[OutputType(typeof(ImageSearchResultDto))]
|
||||
public sealed class SearchPodmanImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Term { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public int? Limit { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.SearchImagesAsync(Term, Limit).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPushImage")]
|
||||
public sealed class InvokePodmanPushImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? Destination { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool TlsVerify { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Compress { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? AuthHeader { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PushImageAsync(Name, Destination, TlsVerify, Compress.IsPresent, AuthHeader)
|
||||
.GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanUntagImage")]
|
||||
public sealed class InvokePodmanUntagImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? Repo { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Tag { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.UntagImageAsync(Name, Repo, Tag).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanImageHistory")]
|
||||
[OutputType(typeof(ImageHistoryEntryDto))]
|
||||
public sealed class GetPodmanImageHistoryCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetImageHistoryAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanImageTree")]
|
||||
[OutputType(typeof(ImageTreeDto))]
|
||||
public sealed class GetPodmanImageTreeCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetImageTreeAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanImageChange")]
|
||||
[OutputType(typeof(ImageChangesDto))]
|
||||
public sealed class GetPodmanImageChangeCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetImageChangesAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsData.Import, "PodmanImage")]
|
||||
[OutputType(typeof(ImageImportDto))]
|
||||
public sealed class ImportPodmanImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Stream? InputStream { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Changes { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Message { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Reference { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Url { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
Stream? stream = null;
|
||||
var ownsStream = false;
|
||||
if (InputStream is not null || !string.IsNullOrWhiteSpace(Path)) {
|
||||
stream = OpenInputStream(Path, InputStream);
|
||||
ownsStream = InputStream is null;
|
||||
}
|
||||
|
||||
try {
|
||||
var result = client.ImportImageAsync(stream, Changes, Message, Reference, Url)
|
||||
.GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
finally {
|
||||
if (ownsStream)
|
||||
stream?.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsData.Import, "PodmanImageArchive")]
|
||||
[OutputType(typeof(ImageLoadDto))]
|
||||
public sealed class ImportPodmanImageArchiveCmdlet : PodmanCmdletBase {
|
||||
[Parameter]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Stream? InputStream { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var stream = OpenInputStream(Path, InputStream);
|
||||
var ownsStream = InputStream is null;
|
||||
try {
|
||||
var result = client.LoadImageAsync(stream).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
finally {
|
||||
if (ownsStream)
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsData.Export, "PodmanImage")]
|
||||
[OutputType(typeof(Stream))]
|
||||
[OutputType(typeof(string))]
|
||||
public sealed class ExportPodmanImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true)]
|
||||
public string[] Reference { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? Format { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Compress { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? OutFile { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.ExportImagesAsync(Reference, Format, Compress.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanStream(result, OutFile);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsData.Save, "PodmanImage")]
|
||||
[OutputType(typeof(Stream))]
|
||||
[OutputType(typeof(string))]
|
||||
public sealed class SavePodmanImageCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? Format { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Compress { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? OutFile { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetImageAsync(Name, Format, Compress.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanStream(result, OutFile);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPullImageProgress")]
|
||||
[OutputType(typeof(PullImageResponseDto))]
|
||||
[OutputType(typeof(IPodmanProgressSession<PullImageResponseDto>))]
|
||||
public sealed class InvokePodmanPullImageProgressCmdlet : PodmanCmdletBase {
|
||||
public InvokePodmanPullImageProgressCmdlet() {
|
||||
Wait = true;
|
||||
}
|
||||
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Reference { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public bool TlsVerify { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Quiet { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Policy { get; set; } = "always";
|
||||
|
||||
[Parameter]
|
||||
public string? Arch { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Os { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Variant { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter AllTags { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? AuthHeader { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Wait { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PullImageWithProgressAsync(
|
||||
Reference,
|
||||
TlsVerify,
|
||||
Quiet.IsPresent,
|
||||
Policy,
|
||||
Arch,
|
||||
Os,
|
||||
Variant,
|
||||
AllTags.IsPresent,
|
||||
AuthHeader).GetAwaiter().GetResult();
|
||||
|
||||
if (!Wait) {
|
||||
WritePodmanResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.IsSuccess) {
|
||||
WritePodmanResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Value is null)
|
||||
return;
|
||||
|
||||
try {
|
||||
foreach (var item in CollectProgress(result.Value))
|
||||
WriteObject(item);
|
||||
}
|
||||
finally {
|
||||
result.Value.DisposeAsync().AsTask().GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
@{
|
||||
RootModule = 'MaksIT.PodmanClientDotNet.PowerShell.dll'
|
||||
ModuleVersion = '1.3.0'
|
||||
GUID = 'b7e4c2a1-9f3d-4e8b-a6c5-1d2e3f4a5b6c'
|
||||
Author = 'Maksym Sadovnychyy'
|
||||
CompanyName = 'MAKS-IT'
|
||||
Description = 'PowerShell cmdlets for PodmanClient.DotNet. Use Connect-Podman -BaseAddress, then domain cmdlets mirroring IPodmanClient.'
|
||||
PowerShellVersion = '7.0'
|
||||
RequiredModules = @()
|
||||
RequiredAssemblies = @('MaksIT.PodmanClientDotNet.PowerShell.dll')
|
||||
FunctionsToExport = @()
|
||||
CmdletsToExport = @(
|
||||
'Add-PodmanManifest',
|
||||
'Checkpoint-PodmanContainer',
|
||||
'Connect-Podman',
|
||||
'Connect-PodmanNetwork',
|
||||
'Disconnect-Podman',
|
||||
'Disconnect-PodmanNetwork',
|
||||
'Dismount-PodmanContainer',
|
||||
'Export-PodmanContainer',
|
||||
'Export-PodmanImage',
|
||||
'Get-PodmanContainer',
|
||||
'Get-PodmanContainerArchive',
|
||||
'Get-PodmanContainerChange',
|
||||
'Get-PodmanContainerList',
|
||||
'Get-PodmanContainerLog',
|
||||
'Get-PodmanContainerProcess',
|
||||
'Get-PodmanContainerStat',
|
||||
'Get-PodmanContainerStatBatch',
|
||||
'Get-PodmanContainerTop',
|
||||
'Get-PodmanEvent',
|
||||
'Get-PodmanExec',
|
||||
'Get-PodmanImage',
|
||||
'Get-PodmanImageChange',
|
||||
'Get-PodmanImageHistory',
|
||||
'Get-PodmanImageList',
|
||||
'Get-PodmanImageTree',
|
||||
'Get-PodmanInfo',
|
||||
'Get-PodmanManifest',
|
||||
'Get-PodmanMountedContainer',
|
||||
'Get-PodmanNetwork',
|
||||
'Get-PodmanNetworkList',
|
||||
'Get-PodmanPod',
|
||||
'Get-PodmanPodList',
|
||||
'Get-PodmanPodStat',
|
||||
'Get-PodmanPodTop',
|
||||
'Get-PodmanSystemDiskUsage',
|
||||
'Get-PodmanVersion',
|
||||
'Get-PodmanVolume',
|
||||
'Get-PodmanVolumeList',
|
||||
'Import-PodmanImage',
|
||||
'Import-PodmanImageArchive',
|
||||
'Initialize-PodmanContainer',
|
||||
'Invoke-PodmanBuildImage',
|
||||
'Invoke-PodmanBuildImageProgress',
|
||||
'Invoke-PodmanCommitContainer',
|
||||
'Invoke-PodmanContainerAttach',
|
||||
'Invoke-PodmanContainerHealthCheck',
|
||||
'Invoke-PodmanContainerSession',
|
||||
'Invoke-PodmanExecSession',
|
||||
'Invoke-PodmanExtractArchive',
|
||||
'Invoke-PodmanGenerateKube',
|
||||
'Invoke-PodmanGenerateSystemd',
|
||||
'Invoke-PodmanPlayKube',
|
||||
'Invoke-PodmanPruneContainer',
|
||||
'Invoke-PodmanPruneImage',
|
||||
'Invoke-PodmanPrunePod',
|
||||
'Invoke-PodmanPruneSystem',
|
||||
'Invoke-PodmanPruneVolume',
|
||||
'Invoke-PodmanPullImage',
|
||||
'Invoke-PodmanPullImageProgress',
|
||||
'Invoke-PodmanPushImage',
|
||||
'Invoke-PodmanPushManifest',
|
||||
'Invoke-PodmanPutContainerArchive',
|
||||
'Invoke-PodmanTagImage',
|
||||
'Invoke-PodmanUntagImage',
|
||||
'Kill-PodmanContainer',
|
||||
'Kill-PodmanPod',
|
||||
'Mount-PodmanContainer',
|
||||
'New-PodmanContainer',
|
||||
'New-PodmanExec',
|
||||
'New-PodmanManifest',
|
||||
'New-PodmanNetwork',
|
||||
'New-PodmanPod',
|
||||
'New-PodmanVolume',
|
||||
'Publish-PodmanManifest',
|
||||
'Remove-PodmanContainer',
|
||||
'Remove-PodmanImage',
|
||||
'Remove-PodmanImageBatch',
|
||||
'Remove-PodmanManifest',
|
||||
'Remove-PodmanNetwork',
|
||||
'Remove-PodmanPod',
|
||||
'Remove-PodmanVolume',
|
||||
'Rename-PodmanContainer',
|
||||
'Resize-PodmanExec',
|
||||
'Restart-PodmanContainer',
|
||||
'Restart-PodmanPod',
|
||||
'Restore-PodmanContainer',
|
||||
'Resume-PodmanContainer',
|
||||
'Resume-PodmanPod',
|
||||
'Save-PodmanImage',
|
||||
'Search-PodmanImage',
|
||||
'Set-PodmanContainerArchive',
|
||||
'Start-PodmanContainer',
|
||||
'Start-PodmanExec',
|
||||
'Start-PodmanPod',
|
||||
'Stop-PodmanContainer',
|
||||
'Stop-PodmanPod',
|
||||
'Suspend-PodmanContainer',
|
||||
'Suspend-PodmanPod',
|
||||
'Test-PodmanConnection',
|
||||
'Test-PodmanContainer',
|
||||
'Test-PodmanImage',
|
||||
'Test-PodmanPod',
|
||||
'Wait-PodmanContainer'
|
||||
)
|
||||
VariablesToExport = @()
|
||||
AliasesToExport = @()
|
||||
PrivateData = @{
|
||||
PSData = @{
|
||||
Tags = @('Podman', 'Container', 'MaksIT', 'API')
|
||||
ProjectUri = 'https://github.com/MAKS-IT-COM/podman-client-dotnet'
|
||||
}
|
||||
}
|
||||
}
|
||||
164
src/PodmanClient.PowerShell/Manifests/ManifestsCmdlets.cs
Normal file
164
src/PodmanClient.PowerShell/Manifests/ManifestsCmdlets.cs
Normal file
@ -0,0 +1,164 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Manifest;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsCommon.New, "PodmanManifest")]
|
||||
[OutputType(typeof(ManifestCreateDto))]
|
||||
public sealed class NewPodmanManifestCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? Image { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.CreateManifestAsync(Name, Image, All.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Remove, "PodmanManifest", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class RemovePodmanManifestCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? Digest { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
if (!ShouldProcess(Name, "Remove Podman manifest"))
|
||||
return;
|
||||
|
||||
var client = RequireClient();
|
||||
var result = client.DeleteManifestAsync(Name, Digest).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanManifest")]
|
||||
[OutputType(typeof(ManifestInspectDto))]
|
||||
public sealed class GetPodmanManifestCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.InspectManifestAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Add, "PodmanManifest")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class AddPodmanManifestCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter(Position = 1)]
|
||||
public string? Image { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Operation { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public ManifestAddRequestDto? Request { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var request = Request ?? new ManifestAddRequestDto {
|
||||
Images = string.IsNullOrWhiteSpace(Image) ? null : [Image],
|
||||
Image = Image,
|
||||
All = All.IsPresent,
|
||||
Operation = Operation ?? "update",
|
||||
};
|
||||
if (Request is null && (request.Images is null || request.Images.Count == 0) && string.IsNullOrWhiteSpace(request.Image))
|
||||
throw new ArgumentException("Specify -Image or -Request.");
|
||||
|
||||
if (request.Images is null && !string.IsNullOrWhiteSpace(request.Image))
|
||||
request.Images = [request.Image];
|
||||
if (string.IsNullOrWhiteSpace(request.Operation))
|
||||
request.Operation = "update";
|
||||
|
||||
var result = client.AddToManifestAsync(Name, request).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsData.Publish, "PodmanManifest")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class PublishPodmanManifestCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
public string Destination { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PushManifestAsync(Name, Destination, All.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPushManifest")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class InvokePodmanPushManifestCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
public string Destination { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PushManifestAsync(Name, Destination, All.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
147
src/PodmanClient.PowerShell/Networks/NetworksCmdlets.cs
Normal file
147
src/PodmanClient.PowerShell/Networks/NetworksCmdlets.cs
Normal file
@ -0,0 +1,147 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Network;
|
||||
using MaksIT.PodmanClientDotNet.Models.Network;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsCommon.New, "PodmanNetwork")]
|
||||
[OutputType(typeof(NetworkListEntryDto))]
|
||||
public sealed class NewPodmanNetworkCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Position = 0)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public NetworkCreateRequest? Request { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var request = Request ?? new NetworkCreateRequest();
|
||||
if (!string.IsNullOrWhiteSpace(Name))
|
||||
request.Name = Name;
|
||||
|
||||
var result = client.CreateNetworkAsync(request).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanNetworkList")]
|
||||
[OutputType(typeof(NetworkListEntryDto))]
|
||||
public sealed class GetPodmanNetworkListCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.ListNetworksAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanNetwork")]
|
||||
[OutputType(typeof(NetworkInspectDto))]
|
||||
public sealed class GetPodmanNetworkCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.InspectNetworkAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Remove, "PodmanNetwork", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class RemovePodmanNetworkCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
if (!ShouldProcess(Name, "Remove Podman network"))
|
||||
return;
|
||||
|
||||
var client = RequireClient();
|
||||
var result = client.DeleteNetworkAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommunications.Connect, "PodmanNetwork")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class ConnectPodmanNetworkCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter(Position = 1)]
|
||||
public string? Container { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public NetworkConnectRequest? Request { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var request = Request ?? new NetworkConnectRequest();
|
||||
if (!string.IsNullOrWhiteSpace(Container))
|
||||
request.Container = Container;
|
||||
|
||||
var result = client.ConnectNetworkAsync(Name, request).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommunications.Disconnect, "PodmanNetwork")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class DisconnectPodmanNetworkCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter(Position = 1)]
|
||||
public string? Container { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public NetworkDisconnectRequest? Request { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var request = Request ?? new NetworkDisconnectRequest();
|
||||
if (!string.IsNullOrWhiteSpace(Container))
|
||||
request.Container = Container;
|
||||
if (Force.IsPresent)
|
||||
request.Force = true;
|
||||
|
||||
var result = client.DisconnectNetworkAsync(Name, request).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/PodmanClient.PowerShell/PodmanClient.PowerShell.csproj
Normal file
33
src/PodmanClient.PowerShell/PodmanClient.PowerShell.csproj
Normal file
@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MaksIT.PodmanClientDotNet.PowerShell</RootNamespace>
|
||||
<AssemblyName>MaksIT.PodmanClientDotNet.PowerShell</AssemblyName>
|
||||
<Description>PowerShell module with cmdlets for PodmanClient.DotNet.</Description>
|
||||
<Version>1.3.0</Version>
|
||||
<Authors>Maksym Sadovnychyy</Authors>
|
||||
<Company>MAKS-IT</Company>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Management.Automation" Version="7.6.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PodmanClient\PodmanClientDotNet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="MaksIT.PodmanClientDotNet.PowerShell.psd1">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
111
src/PodmanClient.PowerShell/PodmanCmdletBase.cs
Normal file
111
src/PodmanClient.PowerShell/PodmanCmdletBase.cs
Normal file
@ -0,0 +1,111 @@
|
||||
using System.Management.Automation;
|
||||
using System.Text;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Streaming;
|
||||
using MaksIT.Results;
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
public abstract class PodmanCmdletBase : PSCmdlet {
|
||||
protected IPodmanClient RequireClient() {
|
||||
var client = PodmanConnectionState.Client;
|
||||
if (client is null) {
|
||||
ThrowTerminatingError(new ErrorRecord(
|
||||
new InvalidOperationException("Not connected. Run Connect-Podman -BaseAddress <url> first."),
|
||||
"NotConnected",
|
||||
ErrorCategory.InvalidOperation,
|
||||
null));
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
protected void WritePodmanResult(Result result) {
|
||||
if (result.IsSuccess)
|
||||
return;
|
||||
|
||||
WriteError(new ErrorRecord(
|
||||
new InvalidOperationException(string.Join("; ", result.Messages)),
|
||||
"PodmanApiError",
|
||||
ErrorCategory.InvalidOperation,
|
||||
null));
|
||||
}
|
||||
|
||||
protected void WritePodmanResult<T>(Result<T?> result) {
|
||||
if (!result.IsSuccess) {
|
||||
WriteError(new ErrorRecord(
|
||||
new InvalidOperationException(string.Join("; ", result.Messages)),
|
||||
"PodmanApiError",
|
||||
ErrorCategory.InvalidOperation,
|
||||
null));
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Value is null)
|
||||
return;
|
||||
|
||||
// Avoid PowerShell enumerating list results onto the host unexpectedly.
|
||||
if (result.Value is System.Collections.IEnumerable and not string and not System.Collections.IDictionary)
|
||||
WriteObject(result.Value, enumerateCollection: false);
|
||||
else
|
||||
WriteObject(result.Value);
|
||||
}
|
||||
|
||||
protected void WritePodmanStream(Result<Stream?> result, string? outFile) {
|
||||
if (!result.IsSuccess) {
|
||||
WriteError(new ErrorRecord(
|
||||
new InvalidOperationException(string.Join("; ", result.Messages)),
|
||||
"PodmanApiError",
|
||||
ErrorCategory.InvalidOperation,
|
||||
null));
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Value is null)
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(outFile)) {
|
||||
using (result.Value)
|
||||
using (var fs = File.Create(outFile))
|
||||
result.Value.CopyTo(fs);
|
||||
WriteObject(outFile);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteObject(result.Value);
|
||||
}
|
||||
|
||||
protected static Stream OpenInputStream(string? path, Stream? inputStream) {
|
||||
if (inputStream is not null)
|
||||
return inputStream;
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
throw new ArgumentException("Specify -Path or -InputStream.");
|
||||
return File.OpenRead(path);
|
||||
}
|
||||
|
||||
protected static string CollectAttachOutput(IPodmanAttachSession session) {
|
||||
var output = new StringBuilder();
|
||||
while (true) {
|
||||
var frame = session.ReadFrameAsync().GetAwaiter().GetResult();
|
||||
if (frame is null)
|
||||
break;
|
||||
output.Append(Encoding.UTF8.GetString(frame.Data));
|
||||
}
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
protected static List<T> CollectProgress<T>(IPodmanProgressSession<T> session) {
|
||||
var items = new List<T>();
|
||||
var enumerator = session.ReadProgressAsync().GetAsyncEnumerator();
|
||||
try {
|
||||
while (enumerator.MoveNextAsync().AsTask().GetAwaiter().GetResult())
|
||||
items.Add(enumerator.Current);
|
||||
}
|
||||
finally {
|
||||
enumerator.DisposeAsync().AsTask().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
38
src/PodmanClient.PowerShell/PodmanConnectionState.cs
Normal file
38
src/PodmanClient.PowerShell/PodmanConnectionState.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
/// <summary>Holds the current Podman client for the PowerShell session.</summary>
|
||||
internal static class PodmanConnectionState {
|
||||
private static readonly Lock Lock = new();
|
||||
private static HttpClient? _httpClient;
|
||||
|
||||
public static IPodmanClient? Client { get; private set; }
|
||||
|
||||
public static void SetConnection(string baseAddress, int timeoutMinutes = 60, string? apiVersion = null) {
|
||||
lock (Lock) {
|
||||
_httpClient?.Dispose();
|
||||
_httpClient = new HttpClient { Timeout = TimeSpan.FromMinutes(Math.Max(1, timeoutMinutes)) };
|
||||
var configuration = new PodmanClientSessionConfiguration {
|
||||
ServerUrl = baseAddress,
|
||||
ApiVersion = string.IsNullOrWhiteSpace(apiVersion) ? "v5.4.0" : apiVersion,
|
||||
TimeoutMinutes = timeoutMinutes
|
||||
};
|
||||
Client = new PodmanClient(_httpClient, NullLogger<PodmanClient>.Instance, configuration);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearConnection() {
|
||||
lock (Lock) {
|
||||
Client = null;
|
||||
_httpClient?.Dispose();
|
||||
_httpClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class PodmanClientSessionConfiguration : IPodmanClientConfiguration {
|
||||
public string ServerUrl { get; set; } = "";
|
||||
public string ApiVersion { get; set; } = "v5.4.0";
|
||||
public int TimeoutMinutes { get; set; } = 60;
|
||||
}
|
||||
}
|
||||
276
src/PodmanClient.PowerShell/Pods/PodsCmdlets.cs
generated
Normal file
276
src/PodmanClient.PowerShell/Pods/PodsCmdlets.cs
generated
Normal file
@ -0,0 +1,276 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Common;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Pod;
|
||||
using MaksIT.PodmanClientDotNet.Models.Pod;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsCommon.New, "PodmanPod")]
|
||||
[OutputType(typeof(PodListEntryDto))]
|
||||
public sealed class NewPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Position = 0)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public PodCreateRequest? Request { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var request = Request ?? new PodCreateRequest();
|
||||
if (!string.IsNullOrWhiteSpace(Name))
|
||||
request.Name = Name;
|
||||
|
||||
var result = client.CreatePodAsync(request).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanPodList")]
|
||||
[OutputType(typeof(PodListEntryDto))]
|
||||
public sealed class GetPodmanPodListCmdlet : PodmanCmdletBase {
|
||||
[Parameter]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.ListPodsAsync(All.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanPod")]
|
||||
[OutputType(typeof(PodInspectDto))]
|
||||
public sealed class GetPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.InspectPodAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsDiagnostic.Test, "PodmanPod")]
|
||||
[OutputType(typeof(bool))]
|
||||
public sealed class TestPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PodExistsAsync(Name).GetAwaiter().GetResult();
|
||||
WriteObject(result.IsSuccess);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Remove, "PodmanPod", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class RemovePodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
if (!ShouldProcess(Name, "Remove Podman pod"))
|
||||
return;
|
||||
|
||||
var client = RequireClient();
|
||||
var result = client.DeletePodAsync(Name, Force.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Start, "PodmanPod")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class StartPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.StartPodAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Stop, "PodmanPod")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class StopPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public int Timeout { get; set; } = 10;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.StopPodAsync(Name, Timeout).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Restart, "PodmanPod")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class RestartPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public int Timeout { get; set; } = 10;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.RestartPodAsync(Name, Timeout).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet("Kill", "PodmanPod")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class KillPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string? Signal { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.KillPodAsync(Name, Signal).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Suspend, "PodmanPod")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class SuspendPodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PausePodAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Resume, "PodmanPod")]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class ResumePodmanPodCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.UnpausePodAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPrunePod")]
|
||||
[OutputType(typeof(PruneReportEntryDto))]
|
||||
public sealed class InvokePodmanPrunePodCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PrunePodsAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanPodTop")]
|
||||
[OutputType(typeof(PodTopDto))]
|
||||
public sealed class GetPodmanPodTopCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.TopPodAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanPodStat")]
|
||||
[OutputType(typeof(PodStatsDto))]
|
||||
public sealed class GetPodmanPodStatCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetPodsStatsAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/PodmanClient.PowerShell/README.md
Normal file
21
src/PodmanClient.PowerShell/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# MaksIT.PodmanClientDotNet.PowerShell
|
||||
|
||||
Binary PowerShell module wrapping **PodmanClient.DotNet** (`IPodmanClient`).
|
||||
|
||||
## Requirements
|
||||
|
||||
- PowerShell 7 hosted on **.NET 10**
|
||||
- Reachable Podman REST API (`podman system service`) — E2E baseline **Podman 5.4.0** (`Connect-Podman` default `ApiVersion` = `v5.4.0`)
|
||||
|
||||
## Quick start
|
||||
|
||||
```powershell
|
||||
dotnet build src/PodmanClient.PowerShell/PodmanClient.PowerShell.csproj
|
||||
Import-Module .\src\PodmanClient.PowerShell\bin\Debug\net10.0\MaksIT.PodmanClientDotNet.PowerShell.psd1 -Force
|
||||
Connect-Podman -BaseAddress 'http://192.168.2.128:8080' -ApiVersion 'v5.4.0'
|
||||
Test-PodmanConnection
|
||||
Get-PodmanVersion
|
||||
Disconnect-Podman
|
||||
```
|
||||
|
||||
Cmdlets mirror the .NET client domains (system, images, containers, exec, volumes, networks, pods, build, manifests, generate). See `CmdletsToExport` in the `.psd1` and live E2E under `src/e2e-tests/`.
|
||||
135
src/PodmanClient.PowerShell/System/SystemCmdlets.cs
Normal file
135
src/PodmanClient.PowerShell/System/SystemCmdlets.cs
Normal file
@ -0,0 +1,135 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Common;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.System;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsDiagnostic.Test, "PodmanConnection")]
|
||||
[OutputType(typeof(LibpodPingDto))]
|
||||
public sealed class TestPodmanConnectionCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PingAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanVersion")]
|
||||
[OutputType(typeof(LibpodVersionDto))]
|
||||
public sealed class GetPodmanVersionCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetVersionAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanInfo")]
|
||||
[OutputType(typeof(InfoDto))]
|
||||
public sealed class GetPodmanInfoCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetInfoAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanSystemDiskUsage")]
|
||||
[OutputType(typeof(SystemDfDto))]
|
||||
public sealed class GetPodmanSystemDiskUsageCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetSystemDiskUsageAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPruneSystem")]
|
||||
[OutputType(typeof(SystemPruneReportDto))]
|
||||
public sealed class InvokePodmanPruneSystemCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PruneSystemAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanEvent")]
|
||||
[OutputType(typeof(Stream))]
|
||||
[OutputType(typeof(string))]
|
||||
public sealed class GetPodmanEventCmdlet : PodmanCmdletBase {
|
||||
[Parameter]
|
||||
public string? OutFile { get; set; }
|
||||
|
||||
/// <summary>Max time to read from the events stream when <see cref="OutFile"/> is set (stream is otherwise open-ended).</summary>
|
||||
[Parameter]
|
||||
public int ReadTimeoutSeconds { get; set; } = 2;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.GetEventsAsync().GetAwaiter().GetResult();
|
||||
if (!result.IsSuccess) {
|
||||
WritePodmanResult(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Value is null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(OutFile)) {
|
||||
WriteObject(result.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
using (result.Value)
|
||||
using (var fs = File.Create(OutFile)) {
|
||||
var buffer = new byte[8192];
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(1, ReadTimeoutSeconds)));
|
||||
try {
|
||||
while (true) {
|
||||
var read = result.Value.ReadAsync(buffer.AsMemory(0, buffer.Length), cts.Token).AsTask().GetAwaiter().GetResult();
|
||||
if (read <= 0)
|
||||
break;
|
||||
fs.Write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) {
|
||||
// Timed sample of the open-ended events stream.
|
||||
}
|
||||
}
|
||||
|
||||
WriteObject(OutFile);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
108
src/PodmanClient.PowerShell/Volumes/VolumesCmdlets.cs
Normal file
108
src/PodmanClient.PowerShell/Volumes/VolumesCmdlets.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using System.Management.Automation;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Common;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Volume;
|
||||
using MaksIT.PodmanClientDotNet.Models.Volume;
|
||||
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.PowerShell;
|
||||
|
||||
[Cmdlet(VerbsCommon.New, "PodmanVolume")]
|
||||
[OutputType(typeof(VolumeInspectResponseDto))]
|
||||
public sealed class NewPodmanVolumeCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Position = 0)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Driver { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public CreateVolumeRequest? Request { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var request = Request ?? new CreateVolumeRequest {
|
||||
Name = Name,
|
||||
Driver = Driver,
|
||||
};
|
||||
var result = client.CreateVolumeAsync(request).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanVolumeList")]
|
||||
[OutputType(typeof(VolumeListEntryDto))]
|
||||
public sealed class GetPodmanVolumeListCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.ListVolumesAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PodmanVolume")]
|
||||
[OutputType(typeof(VolumeInspectResponseDto))]
|
||||
public sealed class GetPodmanVolumeCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.InspectVolumeAsync(Name).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsCommon.Remove, "PodmanVolume", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(void))]
|
||||
public sealed class RemovePodmanVolumeCmdlet : PodmanCmdletBase {
|
||||
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
if (!ShouldProcess(Name, "Remove Podman volume"))
|
||||
return;
|
||||
|
||||
var client = RequireClient();
|
||||
var result = client.DeleteVolumeAsync(Name, Force.IsPresent).GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PodmanPruneVolume")]
|
||||
[OutputType(typeof(PruneReportEntryDto))]
|
||||
public sealed class InvokePodmanPruneVolumeCmdlet : PodmanCmdletBase {
|
||||
protected override void ProcessRecord() {
|
||||
try {
|
||||
var client = RequireClient();
|
||||
var result = client.PruneVolumesAsync().GetAwaiter().GetResult();
|
||||
WritePodmanResult(result);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteError(new ErrorRecord(ex, "PodmanApiError", ErrorCategory.NotSpecified, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Common;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
using MaksIT.PodmanClientDotNet.Models;
|
||||
using MaksIT.PodmanClientDotNet.Models.Container;
|
||||
using MaksIT.PodmanClientDotNet.Streaming;
|
||||
using MaksIT.Results;
|
||||
|
||||
@ -163,13 +162,13 @@ public interface IPodmanContainersClient {
|
||||
);
|
||||
|
||||
Task<Result<ContainerStatsDto?>> GetContainerStatsAsync(string name, bool stream = false, CancellationToken cancellationToken = default);
|
||||
Task<Result<Dictionary<string, ContainerStatsDto>?>> GetContainersStatsAsync(
|
||||
Task<Result<ContainersStatsResponseDto?>> GetContainersStatsAsync(
|
||||
IEnumerable<string>? containers = null,
|
||||
bool stream = false,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
Task<Result<PruneReportDto?>> PruneContainersAsync(string? filters = null, CancellationToken cancellationToken = default);
|
||||
Task<Result<List<PruneReportEntryDto>?>> PruneContainersAsync(string? filters = null, CancellationToken cancellationToken = default);
|
||||
Task<Result> RenameContainerAsync(string name, string newName, CancellationToken cancellationToken = default);
|
||||
Task<Result> InitContainerAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result<Stream?>> CheckpointContainerAsync(
|
||||
@ -239,6 +238,6 @@ public interface IPodmanContainersClient {
|
||||
);
|
||||
|
||||
Task<Result<ContainerHealthCheckDto?>> HealthCheckContainerAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result<MountedContainersResponseDto?>> GetMountedContainersAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<List<Dictionary<string, string>>?>> GetMountedContainersAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<ContainerTopDto?>> TopContainerAsync(string name, string psArgs = "-ef", bool stream = true, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -29,15 +29,15 @@ public interface IPodmanImagesClient {
|
||||
|
||||
Task<Result<ImageInspectDto?>> InspectImageAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result> ImageExistsAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result<ImageDeleteDto[]?>> DeleteImageAsync(string name, bool force = false, CancellationToken cancellationToken = default);
|
||||
Task<Result<ImageDeleteDto[]?>> RemoveImagesAsync(
|
||||
Task<Result<ImageDeleteDto?>> DeleteImageAsync(string name, bool force = false, CancellationToken cancellationToken = default);
|
||||
Task<Result<ImageDeleteDto?>> RemoveImagesAsync(
|
||||
IEnumerable<string> images,
|
||||
bool all = false,
|
||||
bool force = false,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
Task<Result<PruneReportDto?>> PruneImagesAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<List<PruneReportEntryDto>?>> PruneImagesAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<List<ImageSearchResultDto>?>> SearchImagesAsync(string term, int? limit = null, CancellationToken cancellationToken = default);
|
||||
Task<Result> PushImageAsync(
|
||||
string name,
|
||||
|
||||
@ -18,7 +18,7 @@ public interface IPodmanPodsClient {
|
||||
Task<Result> KillPodAsync(string name, string? signal = null, CancellationToken cancellationToken = default);
|
||||
Task<Result> PausePodAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result> UnpausePodAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result<PruneReportDto?>> PrunePodsAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<List<PruneReportEntryDto>?>> PrunePodsAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<PodTopDto?>> TopPodAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result<PodStatsResponseDto?>> GetPodsStatsAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<List<PodStatsDto>?>> GetPodsStatsAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -10,6 +10,6 @@ public interface IPodmanSystemClient {
|
||||
Task<Result<LibpodVersionDto?>> GetVersionAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<InfoDto?>> GetInfoAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<SystemDfDto?>> GetSystemDiskUsageAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<PruneReportDto?>> PruneSystemAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<SystemPruneReportDto?>> PruneSystemAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<Stream?>> GetEventsAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -11,5 +11,5 @@ public interface IPodmanVolumesClient {
|
||||
Task<Result<List<VolumeListEntryDto>?>> ListVolumesAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<VolumeInspectResponseDto?>> InspectVolumeAsync(string name, CancellationToken cancellationToken = default);
|
||||
Task<Result> DeleteVolumeAsync(string name, bool force = false, CancellationToken cancellationToken = default);
|
||||
Task<Result<PruneReportDto?>> PruneVolumesAsync(CancellationToken cancellationToken = default);
|
||||
Task<Result<List<PruneReportEntryDto>?>> PruneVolumesAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Common;
|
||||
|
||||
/// <summary>Prune operation report (containers, images, volumes, pods, networks).</summary>
|
||||
/// <summary>Single entry from libpod prune endpoints that return a JSON array.</summary>
|
||||
public sealed class PruneReportEntryDto {
|
||||
public string? Id { get; set; }
|
||||
public long Size { get; set; }
|
||||
public string? Err { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Legacy aggregate prune fields (kept for compatibility where applicable).</summary>
|
||||
public sealed class PruneReportDto {
|
||||
public string[]? Id { get; set; }
|
||||
public string[]? IdDeleted { get; set; }
|
||||
@ -12,3 +19,13 @@ public sealed class PruneReportDto {
|
||||
public string[]? ImagesDeleted { get; set; }
|
||||
public string[]? ContainersDeleted { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Response from <c>POST /libpod/system/prune</c>.</summary>
|
||||
public sealed class SystemPruneReportDto {
|
||||
public List<PruneReportEntryDto>? PodPruneReport { get; set; }
|
||||
public List<PruneReportEntryDto>? ContainerPruneReports { get; set; }
|
||||
public List<PruneReportEntryDto>? ImagePruneReports { get; set; }
|
||||
public List<PruneReportEntryDto>? NetworkPruneReports { get; set; }
|
||||
public List<PruneReportEntryDto>? VolumePruneReports { get; set; }
|
||||
public long ReclaimedSpace { get; set; }
|
||||
}
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
|
||||
/// <summary>Podman returns a JSON array of filesystem change paths.</summary>
|
||||
public sealed class ContainerChangesDto : List<string> {
|
||||
/// <summary>
|
||||
/// Single filesystem change entry from container changes.
|
||||
/// </summary>
|
||||
public sealed class ContainerChangeEntryDto {
|
||||
public string? Path { get; set; }
|
||||
public int Kind { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Podman returns a JSON array of path/kind change objects.
|
||||
/// </summary>
|
||||
public sealed class ContainerChangesDto : List<ContainerChangeEntryDto> {
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container Inspect).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ContainerInspectDto {
|
||||
public string? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
@ -21,12 +21,12 @@ public sealed class ContainerInspectDto {
|
||||
public string? Driver { get; set; }
|
||||
public string? OCIConfigPath { get; set; }
|
||||
public string? OCIRuntime { get; set; }
|
||||
public long Created { get; set; }
|
||||
public string? Created { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container State).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ContainerStateDto {
|
||||
public string? Status { get; set; }
|
||||
public bool Running { get; set; }
|
||||
@ -39,12 +39,11 @@ public sealed class ContainerStateDto {
|
||||
public string? Error { get; set; }
|
||||
public string? StartedAt { get; set; }
|
||||
public string? FinishedAt { get; set; }
|
||||
public string? Health { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container Config).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ContainerConfigDto {
|
||||
public string? Hostname { get; set; }
|
||||
public string? Domainname { get; set; }
|
||||
@ -52,7 +51,7 @@ public sealed class ContainerConfigDto {
|
||||
public bool AttachStdin { get; set; }
|
||||
public bool AttachStdout { get; set; }
|
||||
public bool AttachStderr { get; set; }
|
||||
public string? Tty { get; set; }
|
||||
public bool Tty { get; set; }
|
||||
public bool OpenStdin { get; set; }
|
||||
public bool StdinOnce { get; set; }
|
||||
public string[]? Env { get; set; }
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container List Entry).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ContainerListEntryDto {
|
||||
public string? Id { get; set; }
|
||||
public string[]? Names { get; set; }
|
||||
public string? Image { get; set; }
|
||||
public string? ImageID { get; set; }
|
||||
public string? Command { get; set; }
|
||||
public long Created { get; set; }
|
||||
public string[]? Command { get; set; }
|
||||
public string? Created { get; set; }
|
||||
public string? State { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public string? Pod { get; set; }
|
||||
public string? PodName { get; set; }
|
||||
public bool AutoRemove { get; set; }
|
||||
public long Pid { get; set; }
|
||||
public string[]? Networks { get; set; }
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container Mount).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Result of mounting a container's root filesystem (libpod returns a plain path string).
|
||||
/// </summary>
|
||||
public sealed class ContainerMountDto {
|
||||
public string? Id { get; set; }
|
||||
public string? Path { get; set; }
|
||||
}
|
||||
|
||||
@ -1,41 +1,96 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container Stats).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ContainerStatsDto {
|
||||
public string? Name { get; set; }
|
||||
public string? Id { get; set; }
|
||||
public ContainerStatsCpuDto? CpuStats { get; set; }
|
||||
public ContainerStatsMemoryDto? MemoryStats { get; set; }
|
||||
public ContainerStatsNetworkDto[]? Networks { get; set; }
|
||||
public string? Read { get; set; }
|
||||
public string? Preread { get; set; }
|
||||
public ContainerStatsCpuBlockDto? CpuStats { get; set; }
|
||||
public ContainerStatsCpuBlockDto? PrecpuStats { get; set; }
|
||||
public ContainerStatsMemoryDto? MemoryStats { get; set; }
|
||||
public Dictionary<string, ContainerStatsNetworkDto>? Networks { get; set; }
|
||||
public ContainerStatsPidsDto? PidsStats { get; set; }
|
||||
public int NumProcs { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container Stats Cpu).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ContainerStatsCpuDto {
|
||||
/// <summary>
|
||||
/// CPU stats block from container stats.
|
||||
/// </summary>
|
||||
public sealed class ContainerStatsCpuBlockDto {
|
||||
public ContainerStatsCpuUsageDto? CpuUsage { get; set; }
|
||||
public ulong SystemCpuUsage { get; set; }
|
||||
public int OnlineCpus { get; set; }
|
||||
public double Cpu { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Nested CPU usage counters.
|
||||
/// </summary>
|
||||
public sealed class ContainerStatsCpuUsageDto {
|
||||
public ulong TotalUsage { get; set; }
|
||||
public ulong SystemUsage { get; set; }
|
||||
public ulong KernelMode { get; set; }
|
||||
public ulong UserMode { get; set; }
|
||||
public ulong UsageInKernelmode { get; set; }
|
||||
public ulong UsageInUsermode { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container Stats Memory).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Memory stats from container stats.
|
||||
/// </summary>
|
||||
public sealed class ContainerStatsMemoryDto {
|
||||
public ulong Usage { get; set; }
|
||||
public ulong MaxUsage { get; set; }
|
||||
public ulong Limit { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Container Stats Network).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Per-interface network counters.
|
||||
/// </summary>
|
||||
public sealed class ContainerStatsNetworkDto {
|
||||
public ulong RxBytes { get; set; }
|
||||
public ulong RxPackets { get; set; }
|
||||
public ulong RxErrors { get; set; }
|
||||
public ulong RxDropped { get; set; }
|
||||
public ulong TxBytes { get; set; }
|
||||
public ulong TxPackets { get; set; }
|
||||
public ulong TxErrors { get; set; }
|
||||
public ulong TxDropped { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PID stats from container stats.
|
||||
/// </summary>
|
||||
public sealed class ContainerStatsPidsDto {
|
||||
public long Current { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response from <c>GET /libpod/containers/stats</c> (multi-container).
|
||||
/// </summary>
|
||||
public sealed class ContainersStatsResponseDto {
|
||||
public string? Error { get; set; }
|
||||
public List<ContainerLibpodStatsDto>? Stats { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Libpod multi-container stats entry.
|
||||
/// </summary>
|
||||
public sealed class ContainerLibpodStatsDto {
|
||||
public double AvgCPU { get; set; }
|
||||
public string? ContainerID { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public double CPU { get; set; }
|
||||
public long CPUNano { get; set; }
|
||||
public long CPUSystemNano { get; set; }
|
||||
public long SystemNano { get; set; }
|
||||
public long MemUsage { get; set; }
|
||||
public long MemLimit { get; set; }
|
||||
public double MemPerc { get; set; }
|
||||
public Dictionary<string, ContainerStatsNetworkDto>? Network { get; set; }
|
||||
public long BlockInput { get; set; }
|
||||
public long BlockOutput { get; set; }
|
||||
public long PIDs { get; set; }
|
||||
public long UpTime { get; set; }
|
||||
public long Duration { get; set; }
|
||||
}
|
||||
|
||||
@ -1,17 +1,7 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Mounted Container).
|
||||
/// </summary>
|
||||
|
||||
public sealed class MountedContainerDto {
|
||||
public string? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Mountpoint { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Mounted Containers response).
|
||||
/// Libpod <c>showmounted</c> returns a JSON array of single-entry maps (container id → mount path).
|
||||
/// </summary>
|
||||
|
||||
public sealed class MountedContainersResponseDto {
|
||||
public List<MountedContainerDto>? Containers { get; set; }
|
||||
public sealed class MountedContainersResponseDto : List<Dictionary<string, string>> {
|
||||
}
|
||||
|
||||
@ -7,11 +7,30 @@ public sealed class CreateExecResponseDto {
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Inspect Exec process config).
|
||||
/// </summary>
|
||||
|
||||
public sealed class InspectExecProcessDto {
|
||||
public string[]? Arguments { get; set; }
|
||||
public string? Entrypoint { get; set; }
|
||||
public bool Privileged { get; set; }
|
||||
public bool Tty { get; set; }
|
||||
public string? User { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Inspect Exec response).
|
||||
/// </summary>
|
||||
|
||||
public sealed class InspectExecResponseDto {
|
||||
public bool Running { get; set; }
|
||||
public bool CanRemove { get; set; }
|
||||
public string? ContainerID { get; set; }
|
||||
public string? DetachKeys { get; set; }
|
||||
public int ExitCode { get; set; }
|
||||
public string? ProcessConfig { get; set; }
|
||||
public string? ID { get; set; }
|
||||
public bool OpenStderr { get; set; }
|
||||
public bool OpenStdin { get; set; }
|
||||
public bool OpenStdout { get; set; }
|
||||
public bool Running { get; set; }
|
||||
public int Pid { get; set; }
|
||||
public InspectExecProcessDto? ProcessConfig { get; set; }
|
||||
}
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Image;
|
||||
|
||||
/// <summary>Podman returns a JSON array of filesystem change paths.</summary>
|
||||
public sealed class ImageChangesDto : List<string> {
|
||||
/// <summary>
|
||||
/// Single filesystem change entry from image/container changes.
|
||||
/// </summary>
|
||||
public sealed class ImageChangeEntryDto {
|
||||
public string? Path { get; set; }
|
||||
public int Kind { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Podman returns a JSON array of path/kind change objects.
|
||||
/// </summary>
|
||||
public sealed class ImageChangesDto : List<ImageChangeEntryDto> {
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Image;
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Image Delete).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Image Delete / Remove).
|
||||
/// </summary>
|
||||
public sealed class ImageDeleteDto {
|
||||
public string? Deleted { get; set; }
|
||||
public string[]? Deleted { get; set; }
|
||||
public string[]? Untagged { get; set; }
|
||||
public int ExitCode { get; set; }
|
||||
public string[]? Errors { get; set; }
|
||||
}
|
||||
|
||||
@ -1,23 +1,30 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Image;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Image List Entry).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ImageListEntryDto {
|
||||
public string? Id { get; set; }
|
||||
public string? ParentId { get; set; }
|
||||
public string[]? RepoTags { get; set; }
|
||||
public string[]? RepoDigests { get; set; }
|
||||
public string[]? Names { get; set; }
|
||||
public string[]? History { get; set; }
|
||||
public string? Digest { get; set; }
|
||||
public long Created { get; set; }
|
||||
public long Size { get; set; }
|
||||
public long SharedSize { get; set; }
|
||||
public string? ParentId { get; set; }
|
||||
public string? RepoTags { get; set; }
|
||||
public string? RepoDigests { get; set; }
|
||||
public long VirtualSize { get; set; }
|
||||
public long Containers { get; set; }
|
||||
public string? Arch { get; set; }
|
||||
public string? Os { get; set; }
|
||||
public bool IsManifestList { get; set; }
|
||||
public Dictionary<string, string>? Labels { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Image Search Result).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ImageSearchResultDto {
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
@ -1,18 +1,8 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Image;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Image Tree).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ImageTreeDto {
|
||||
public string? Id { get; set; }
|
||||
public ImageTreeLayerDto[]? Layers { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Image Tree Layer).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ImageTreeLayerDto {
|
||||
public string? Id { get; set; }
|
||||
public string? Parent { get; set; }
|
||||
public string[]? Tags { get; set; }
|
||||
public string? Tree { get; set; }
|
||||
}
|
||||
|
||||
@ -1,36 +1,50 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Manifest;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Manifest Create).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ManifestCreateDto {
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Manifest Inspect).
|
||||
/// </summary>
|
||||
|
||||
public sealed class ManifestInspectDto {
|
||||
public int? SchemaVersion { get; set; }
|
||||
public string? MediaType { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public ManifestListSpecDto[]? Manifests { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Manifest List Spec).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Manifest List Spec entry).
|
||||
/// </summary>
|
||||
public sealed class ManifestListSpecDto {
|
||||
public string? Digest { get; set; }
|
||||
public string? MediaType { get; set; }
|
||||
public long? Size { get; set; }
|
||||
public string? Image { get; set; }
|
||||
public string? Platform { get; set; }
|
||||
public ManifestPlatformDto? Platform { get; set; }
|
||||
public string? Os { get; set; }
|
||||
public string? Arch { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Manifest Add request).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Platform object nested in a manifest list entry.
|
||||
/// </summary>
|
||||
public sealed class ManifestPlatformDto {
|
||||
public string? Architecture { get; set; }
|
||||
public string? Os { get; set; }
|
||||
public string? Variant { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Libpod ManifestModifyOptions body (v4+ PUT /libpod/manifests/{name}).
|
||||
/// </summary>
|
||||
public sealed class ManifestAddRequestDto {
|
||||
public string Image { get; set; } = "";
|
||||
public List<string>? Images { get; set; }
|
||||
public string? Image { get; set; }
|
||||
public bool All { get; set; }
|
||||
public string? Operation { get; set; }
|
||||
}
|
||||
|
||||
@ -1,70 +1,94 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.Pod;
|
||||
|
||||
/// <summary>
|
||||
/// Container summary nested in pod list/inspect responses.
|
||||
/// </summary>
|
||||
public sealed class PodContainerSummaryDto {
|
||||
public string? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Names { get; set; }
|
||||
public string? State { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public int? RestartCount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod List Entry).
|
||||
/// </summary>
|
||||
|
||||
public sealed class PodListEntryDto {
|
||||
public string? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public string? Cgroup { get; set; }
|
||||
public string? CgroupParent { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public string? Created { get; set; }
|
||||
public Dictionary<string, string>? Labels { get; set; }
|
||||
public string? Namespace { get; set; }
|
||||
public string? RestartPolicy { get; set; }
|
||||
public ulong? StopTimeout { get; set; }
|
||||
public string? InfraId { get; set; }
|
||||
public string[]? Networks { get; set; }
|
||||
public List<PodContainerSummaryDto>? Containers { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod Kill Report).
|
||||
/// </summary>
|
||||
|
||||
public sealed class PodKillReportDto {
|
||||
public string[]? Ids { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod Inspect).
|
||||
/// </summary>
|
||||
|
||||
public sealed class PodInspectDto {
|
||||
public string? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? State { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public string? CgroupParent { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public string? Created { get; set; }
|
||||
public Dictionary<string, string>? Labels { get; set; }
|
||||
public string? Namespace { get; set; }
|
||||
public string? RestartPolicy { get; set; }
|
||||
public ulong? StopTimeout { get; set; }
|
||||
public string[]? Containers { get; set; }
|
||||
public string? InfraContainerId { get; set; }
|
||||
public List<PodContainerSummaryDto>? Containers { get; set; }
|
||||
public string? InfraContainerID { get; set; }
|
||||
public int? NumContainers { get; set; }
|
||||
public string[]? SharedNamespaces { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod Top).
|
||||
/// </summary>
|
||||
|
||||
public sealed class PodTopDto {
|
||||
public string[]? Titles { get; set; }
|
||||
public List<string[]>? Processes { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod Stats).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod Stats entry).
|
||||
/// </summary>
|
||||
public sealed class PodStatsDto {
|
||||
public string? Id { get; set; }
|
||||
public string? CID { get; set; }
|
||||
public string? Pod { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? CPU { get; set; }
|
||||
public string? MemUsage { get; set; }
|
||||
public string? MemUsageBytes { get; set; }
|
||||
public string? MemLimit { get; set; }
|
||||
public string? Mem { get; set; }
|
||||
public string? MemPercent { get; set; }
|
||||
public string? NetIO { get; set; }
|
||||
public string? BlockIO { get; set; }
|
||||
public string? PIDs { get; set; }
|
||||
public string? PIDS { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod Stats response).
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Pod Stats response wrapper).
|
||||
/// Prefer <see cref="List{PodStatsDto}"/> from the API; this type remains for callers that expect a named bag.
|
||||
/// </summary>
|
||||
public sealed class PodStatsResponseDto {
|
||||
public Dictionary<string, PodStatsDto>? Stats { get; set; }
|
||||
public List<PodStatsDto>? Stats { get; set; }
|
||||
}
|
||||
|
||||
@ -1,49 +1,121 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.System;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Info).
|
||||
/// </summary>
|
||||
|
||||
public sealed class InfoDto {
|
||||
public InfoHostDto? Host { get; set; }
|
||||
public InfoStoreDto? Store { get; set; }
|
||||
public Dictionary<string, object>? Version { get; set; }
|
||||
public InfoVersionDto? Version { get; set; }
|
||||
public InfoPluginsDto? Plugins { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Version block under info.
|
||||
/// </summary>
|
||||
public sealed class InfoVersionDto {
|
||||
public string? APIVersion { get; set; }
|
||||
public string? Version { get; set; }
|
||||
public string? GoVersion { get; set; }
|
||||
public string? GitCommit { get; set; }
|
||||
public string? BuiltTime { get; set; }
|
||||
public long Built { get; set; }
|
||||
public string? BuildOrigin { get; set; }
|
||||
public string? OsArch { get; set; }
|
||||
public string? Os { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Info Host).
|
||||
/// </summary>
|
||||
|
||||
public sealed class InfoHostDto {
|
||||
public string? Arch { get; set; }
|
||||
public string? BuildahVersion { get; set; }
|
||||
public long Containers { get; set; }
|
||||
public string? Distribution { get; set; }
|
||||
public string? Kernel { get; set; }
|
||||
public string? MemTotal { get; set; }
|
||||
public int MemFree { get; set; }
|
||||
public string? OSType { get; set; }
|
||||
public string? OS { get; set; }
|
||||
public int CPUs { get; set; }
|
||||
public string? PodmanVersion { get; set; }
|
||||
public string? Machine { get; set; }
|
||||
public string? CgroupManager { get; set; }
|
||||
public string? CgroupVersion { get; set; }
|
||||
public List<string>? CgroupControllers { get; set; }
|
||||
public InfoConmonDto? Conmon { get; set; }
|
||||
public int Cpus { get; set; }
|
||||
public InfoCpuUtilizationDto? CpuUtilization { get; set; }
|
||||
public string? DatabaseBackend { get; set; }
|
||||
public InfoDistributionDto? Distribution { get; set; }
|
||||
public string? EventLogger { get; set; }
|
||||
public long FreeLocks { get; set; }
|
||||
public string? Hostname { get; set; }
|
||||
public string? Kernel { get; set; }
|
||||
public string? LogDriver { get; set; }
|
||||
public long MemFree { get; set; }
|
||||
public long MemTotal { get; set; }
|
||||
public string? NetworkBackend { get; set; }
|
||||
public string? Os { get; set; }
|
||||
public string? OSType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Conmon info under host.
|
||||
/// </summary>
|
||||
public sealed class InfoConmonDto {
|
||||
public string? Package { get; set; }
|
||||
public string? Path { get; set; }
|
||||
public string? Version { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CPU utilization percentages under host.
|
||||
/// </summary>
|
||||
public sealed class InfoCpuUtilizationDto {
|
||||
public double UserPercent { get; set; }
|
||||
public double SystemPercent { get; set; }
|
||||
public double IdlePercent { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distribution object under host.
|
||||
/// </summary>
|
||||
public sealed class InfoDistributionDto {
|
||||
public string? Distribution { get; set; }
|
||||
public string? Version { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Info Store).
|
||||
/// </summary>
|
||||
|
||||
public sealed class InfoStoreDto {
|
||||
public string? ConfigFile { get; set; }
|
||||
public InfoContainerStoreDto? ContainerStore { get; set; }
|
||||
public string? GraphRoot { get; set; }
|
||||
public string? GraphDriverName { get; set; }
|
||||
public Dictionary<string, string>? GraphOptions { get; set; }
|
||||
public long ImageStoreNumber { get; set; }
|
||||
public long RunRoot { get; set; }
|
||||
public long VolumePath { get; set; }
|
||||
public long GraphRootAllocated { get; set; }
|
||||
public long GraphRootUsed { get; set; }
|
||||
public Dictionary<string, string>? GraphStatus { get; set; }
|
||||
public string? ImageCopyTmpDir { get; set; }
|
||||
public InfoImageStoreDto? ImageStore { get; set; }
|
||||
public string? RunRoot { get; set; }
|
||||
public bool TransientStore { get; set; }
|
||||
public string? VolumePath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container store counters under store.
|
||||
/// </summary>
|
||||
public sealed class InfoContainerStoreDto {
|
||||
public long Number { get; set; }
|
||||
public long Paused { get; set; }
|
||||
public long Running { get; set; }
|
||||
public long Stopped { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Image store counters under store.
|
||||
/// </summary>
|
||||
public sealed class InfoImageStoreDto {
|
||||
public long Number { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Info Plugins).
|
||||
/// </summary>
|
||||
|
||||
public sealed class InfoPluginsDto {
|
||||
public string[]? Volume { get; set; }
|
||||
public string[]? Network { get; set; }
|
||||
|
||||
@ -1,18 +1,34 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.System;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Libpod Version).
|
||||
/// </summary>
|
||||
|
||||
public sealed class LibpodVersionDto {
|
||||
public VersionComponentsDto? Version { get; set; }
|
||||
public string? Platform { get; set; }
|
||||
public LibpodVersionPlatformDto? Platform { get; set; }
|
||||
public List<LibpodVersionComponentDto>? Components { get; set; }
|
||||
public string? Version { get; set; }
|
||||
public string? ApiVersion { get; set; }
|
||||
public string? MinAPIVersion { get; set; }
|
||||
public string? GitCommit { get; set; }
|
||||
public string? GoVersion { get; set; }
|
||||
public string? Os { get; set; }
|
||||
public string? Arch { get; set; }
|
||||
public string? KernelVersion { get; set; }
|
||||
public string? BuildTime { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (Version Components).
|
||||
/// </summary>
|
||||
|
||||
public sealed class VersionComponentsDto {
|
||||
public int Major { get; set; }
|
||||
public int Minor { get; set; }
|
||||
public int Micro { get; set; }
|
||||
/// <summary>
|
||||
/// Platform object from libpod version.
|
||||
/// </summary>
|
||||
public sealed class LibpodVersionPlatformDto {
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Component entry from libpod version.
|
||||
/// </summary>
|
||||
public sealed class LibpodVersionComponentDto {
|
||||
public string? Name { get; set; }
|
||||
public string? Version { get; set; }
|
||||
public Dictionary<string, string>? Details { get; set; }
|
||||
}
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
namespace MaksIT.PodmanClientDotNet.Dtos.System;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (System Df).
|
||||
/// </summary>
|
||||
|
||||
public sealed class SystemDfDto {
|
||||
public long ImagesSize { get; set; }
|
||||
public SystemDfEntryDto[]? Images { get; set; }
|
||||
public SystemDfEntryDto[]? Containers { get; set; }
|
||||
public SystemDfEntryDto[]? Volumes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialized Podman libpod API payload (System Df Entry).
|
||||
/// </summary>
|
||||
|
||||
public sealed class SystemDfEntryDto {
|
||||
public long Size { get; set; }
|
||||
public long Reclaimable { get; set; }
|
||||
|
||||
@ -14,7 +14,8 @@ public interface IPodmanClientConfiguration {
|
||||
string ServerUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Podman API version segment used in request paths. Defaults to <c>v1.41</c>.
|
||||
/// Podman libpod API version segment used in request paths. Defaults to <c>v5.4.0</c>
|
||||
/// (validated E2E target; use at least <c>v4.0.0</c> — Docker-compat <c>v1.41</c> is rejected by network endpoints).
|
||||
/// </summary>
|
||||
string ApiVersion { get; set; }
|
||||
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Common;
|
||||
using MaksIT.Results;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.Internal;
|
||||
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Build;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Image;
|
||||
using MaksIT.Results;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.Internal;
|
||||
|
||||
|
||||
@ -12,4 +12,4 @@ public class AutoUserNsOptions {
|
||||
public int InitialSize { get; set; }
|
||||
public string? PasswdFile { get; set; }
|
||||
public int Size { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,4 +11,4 @@ public class BindOptions {
|
||||
public string? Propagation { get; set; }
|
||||
public bool ReadOnlyForceRecursive { get; set; }
|
||||
public bool ReadOnlyNonRecursive { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,4 +13,4 @@ public class BlockIO {
|
||||
public List<ThrottleDevice>? ThrottleWriteIopsDevice { get; set; }
|
||||
public int Weight { get; set; }
|
||||
public List<WeightDevice>? WeightDevice { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,4 +15,4 @@ public class CPU {
|
||||
public int RealtimePeriod { get; set; }
|
||||
public int RealtimeRuntime { get; set; }
|
||||
public int Shares { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,4 +124,4 @@ public class CreateContainerRequest {
|
||||
public List<string>? VolumesFrom { get; set; }
|
||||
public Dictionary<string, ulong>? WeightDevice { get; set; }
|
||||
public string? WorkDir { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models.Container;
|
||||
public class CreateContainerResponse {
|
||||
public string? Id { get; set; }
|
||||
public string[]? Warnings { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models.Container;
|
||||
public class DeleteContainerResponse {
|
||||
public string? Err { get; set; }
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class DriverConfig {
|
||||
public string? Name { get; set; }
|
||||
public Dictionary<string, string>? Options { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,4 @@ public class ErrorResponse {
|
||||
public string? Cause { get; set; }
|
||||
public string? Message { get; set; }
|
||||
public int Response { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,4 +16,4 @@ public class CreateExecRequest {
|
||||
public bool Tty { get; set; }
|
||||
public string? User { get; set; }
|
||||
public string? WorkingDir { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,4 +7,4 @@ namespace MaksIT.PodmanClientDotNet.Models.Exec;
|
||||
|
||||
public class CreateExecResponse {
|
||||
public string? Id { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,32 @@
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.Models.Exec;
|
||||
|
||||
/// <summary>
|
||||
/// Libpod API response body for Inspect Exec process config.
|
||||
/// </summary>
|
||||
|
||||
public class InspectExecProcess {
|
||||
public string[]? Arguments { get; set; }
|
||||
public string? Entrypoint { get; set; }
|
||||
public bool Privileged { get; set; }
|
||||
public bool Tty { get; set; }
|
||||
public string? User { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Libpod API response body for Inspect Exec response.
|
||||
/// </summary>
|
||||
|
||||
public class InspectExecResponse {
|
||||
public bool Running { get; set; }
|
||||
public bool CanRemove { get; set; }
|
||||
public string? ContainerID { get; set; }
|
||||
public string? DetachKeys { get; set; }
|
||||
public int ExitCode { get; set; }
|
||||
public string? ProcessConfig { get; set; }
|
||||
}
|
||||
public string? ID { get; set; }
|
||||
public bool OpenStderr { get; set; }
|
||||
public bool OpenStdin { get; set; }
|
||||
public bool OpenStdout { get; set; }
|
||||
public bool Running { get; set; }
|
||||
public int Pid { get; set; }
|
||||
public InspectExecProcess? ProcessConfig { get; set; }
|
||||
}
|
||||
|
||||
@ -10,4 +10,4 @@ public class StartExecRequest {
|
||||
public bool Tty { get; set; }
|
||||
public int? Height { get; set; } // Optional, nullable if not provided
|
||||
public int? Width { get; set; } // Optional, nullable if not provided
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class HugepageLimit {
|
||||
public long Limit { get; set; }
|
||||
public string? PageSize { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,4 @@ public class IDMapping {
|
||||
public int ContainerId { get; set; }
|
||||
public int HostId { get; set; }
|
||||
public int Size { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,4 +12,4 @@ public class IDMappingOptions {
|
||||
public bool HostGIDMapping { get; set; }
|
||||
public bool HostUIDMapping { get; set; }
|
||||
public List<IDMapping>? UIDMap { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,26 +1,25 @@
|
||||
|
||||
namespace MaksIT.PodmanClientDotNet.Models.Image;
|
||||
|
||||
public class PullImageResponse
|
||||
{
|
||||
public class PullImageResponse {
|
||||
|
||||
/// <summary>
|
||||
/// Error contains text of errors from c/image.
|
||||
/// </summary>
|
||||
public string? Error { get; set; }
|
||||
/// <summary>
|
||||
/// Error contains text of errors from c/image.
|
||||
/// </summary>
|
||||
public string? Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ID contains image ID (retained for backwards compatibility).
|
||||
/// </summary>
|
||||
public string? Id { get; set; }
|
||||
/// <summary>
|
||||
/// ID contains image ID (retained for backwards compatibility).
|
||||
/// </summary>
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Images contains the IDs of the images pulled.
|
||||
/// </summary>
|
||||
public List<string>? Images { get; set; }
|
||||
/// <summary>
|
||||
/// Images contains the IDs of the images pulled.
|
||||
/// </summary>
|
||||
public List<string>? Images { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stream used to provide output from c/image.
|
||||
/// </summary>
|
||||
public string? Stream { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Stream used to provide output from c/image.
|
||||
/// </summary>
|
||||
public string? Stream { get; set; }
|
||||
}
|
||||
|
||||
@ -10,4 +10,4 @@ public class ImageVolume {
|
||||
public bool ReadWrite { get; set; }
|
||||
public string? Source { get; set; }
|
||||
public string? SubPath { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,4 +11,4 @@ public class IntelRdt {
|
||||
public bool EnableMBM { get; set; }
|
||||
public string? L3CacheSchema { get; set; }
|
||||
public string? MemBwSchema { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,4 +13,4 @@ public class LinuxDevice {
|
||||
public string? Path { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public int Uid { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,4 +11,4 @@ public class LinuxDeviceCgroup {
|
||||
public int Major { get; set; }
|
||||
public int Minor { get; set; }
|
||||
public string? Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,4 +11,4 @@ public class LinuxIntelRdt {
|
||||
public bool EnableMBM { get; set; }
|
||||
public string? L3CacheSchema { get; set; }
|
||||
public string? MemBwSchema { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class LinuxPersonality {
|
||||
public string? Domain { get; set; }
|
||||
public List<string>? Flags { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,4 +15,4 @@ public class LinuxResources {
|
||||
public Pids? Pids { get; set; }
|
||||
public Dictionary<string, RdmaResource>? Rdma { get; set; }
|
||||
public Dictionary<string, string>? Unified { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,4 +10,4 @@ public class LogConfigLibpod {
|
||||
public Dictionary<string, string>? Options { get; set; }
|
||||
public string? Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,4 +15,4 @@ public class Memory {
|
||||
public long Swap { get; set; }
|
||||
public int Swappiness { get; set; }
|
||||
public bool UseHierarchy { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,4 +14,4 @@ public class Mount {
|
||||
public TmpfsOptions? TmpfsOptions { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public VolumeOptions? VolumeOptions { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,4 +11,4 @@ public class NamedVolume {
|
||||
public string? Name { get; set; }
|
||||
public List<string>? Options { get; set; }
|
||||
public string? SubPath { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class Namespace {
|
||||
public string? Nsmode { get; set; }
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class NetworkPriority {
|
||||
public string? Name { get; set; }
|
||||
public int Priority { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,4 +10,4 @@ public class NetworkSettings {
|
||||
public string? InterfaceName { get; set; }
|
||||
public List<string>? StaticIps { get; set; }
|
||||
public string? StaticMac { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,4 @@ public class OverlayVolume {
|
||||
public string? Destination { get; set; }
|
||||
public List<string>? Options { get; set; }
|
||||
public string? Source { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,4 @@ public class POSIXRlimit {
|
||||
public long Hard { get; set; }
|
||||
public long Soft { get; set; }
|
||||
public string? Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,4 +7,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
|
||||
public class Pids {
|
||||
public int Limit { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,4 +11,4 @@ public class PortMapping {
|
||||
public int HostPort { get; set; }
|
||||
public string? Protocol { get; set; }
|
||||
public int Range { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class ProgressDetail {
|
||||
public long? Current { get; set; }
|
||||
public long? Total { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class RdmaResource {
|
||||
public int HcaHandles { get; set; }
|
||||
public int HcaObjects { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,4 +12,4 @@ public class Schema2HealthConfig {
|
||||
public long StartPeriod { get; set; }
|
||||
public List<string>? Test { get; set; }
|
||||
public long Timeout { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,4 @@ namespace MaksIT.PodmanClientDotNet.Models;
|
||||
public class SecretProp {
|
||||
public string? Key { get; set; }
|
||||
public string? Secret { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,4 +13,4 @@ public class StartupHealthConfig {
|
||||
public int Successes { get; set; }
|
||||
public List<string>? Test { get; set; }
|
||||
public long Timeout { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,4 @@ public class ThrottleDevice {
|
||||
public int Major { get; set; }
|
||||
public int Minor { get; set; }
|
||||
public long Rate { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,4 +9,4 @@ public class TmpfsOptions {
|
||||
public int Mode { get; set; }
|
||||
public List<string>? Options { get; set; }
|
||||
public long SizeBytes { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,4 +10,4 @@ public class VolumeOptions {
|
||||
public Dictionary<string, string>? Labels { get; set; }
|
||||
public bool NoCopy { get; set; }
|
||||
public string? Subpath { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,4 +10,4 @@ public class WeightDevice {
|
||||
public int Major { get; set; }
|
||||
public int Minor { get; set; }
|
||||
public int Weight { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
using MaksIT.PodmanClientDotNet;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MaksIT.PodmanClientDotNet;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
using MaksIT.PodmanClientDotNet.Internal;
|
||||
using MaksIT.PodmanClientDotNet.Models;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Container;
|
||||
using MaksIT.PodmanClientDotNet.Models.Container;
|
||||
using MaksIT.PodmanClientDotNet.Models.Exec;
|
||||
using MaksIT.Results;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public partial class PodmanClient {
|
||||
public async Task<Result<CreateContainerResponseDto?>> CreateContainerAsync(
|
||||
|
||||
@ -57,12 +57,21 @@ public partial class PodmanClient {
|
||||
PostWithoutBodyAsync($"{ContainerPath(name)}/unpause", "Unpause container", cancellationToken: cancellationToken);
|
||||
|
||||
public Task<Result<ContainerWaitDto?>> WaitContainerAsync(string name, string? condition = null, CancellationToken cancellationToken = default) =>
|
||||
PostLibpodAsync<ContainerWaitDto>(
|
||||
$"{ContainerPath(name)}/wait",
|
||||
SendAsync(
|
||||
() => _httpClient.PostAsync(
|
||||
LibpodPath($"{ContainerPath(name)}/wait") + BuildQuery(condition is null ? [] : [("condition", condition)]),
|
||||
content: null,
|
||||
cancellationToken),
|
||||
"Wait container",
|
||||
PodmanJsonContext.Default.ContainerWaitDto,
|
||||
query: condition is null ? null : [("condition", condition)],
|
||||
cancellationToken: cancellationToken
|
||||
// Libpod may return a bare exit-code integer or a JSON object.
|
||||
body => {
|
||||
var trimmed = body.Trim();
|
||||
if (long.TryParse(trimmed, out var code))
|
||||
return new ContainerWaitDto { StatusCode = code };
|
||||
|
||||
return System.Text.Json.JsonSerializer.Deserialize(trimmed, PodmanJsonContext.Default.ContainerWaitDto);
|
||||
},
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
public Task<Result<Stream?>> GetContainerLogsAsync(
|
||||
@ -100,7 +109,7 @@ public partial class PodmanClient {
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
public Task<Result<Dictionary<string, ContainerStatsDto>?>> GetContainersStatsAsync(
|
||||
public Task<Result<ContainersStatsResponseDto?>> GetContainersStatsAsync(
|
||||
IEnumerable<string>? containers = null,
|
||||
bool stream = false,
|
||||
CancellationToken cancellationToken = default
|
||||
@ -111,14 +120,14 @@ public partial class PodmanClient {
|
||||
query.Add(("containers", c));
|
||||
}
|
||||
|
||||
return GetJsonAsync<Dictionary<string, ContainerStatsDto>>("/libpod/containers/stats", "Get containers stats", PodmanJsonContext.Default.DictionaryStringContainerStatsDto, query, cancellationToken);
|
||||
return GetJsonAsync<ContainersStatsResponseDto>("/libpod/containers/stats", "Get containers stats", PodmanJsonContext.Default.ContainersStatsResponseDto, query, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<Result<PruneReportDto?>> PruneContainersAsync(string? filters = null, CancellationToken cancellationToken = default) =>
|
||||
PostLibpodAsync<PruneReportDto>(
|
||||
public Task<Result<List<PruneReportEntryDto>?>> PruneContainersAsync(string? filters = null, CancellationToken cancellationToken = default) =>
|
||||
PostLibpodAsync<List<PruneReportEntryDto>>(
|
||||
"/libpod/containers/prune",
|
||||
"Prune containers",
|
||||
PodmanJsonContext.Default.PruneReportDto,
|
||||
PodmanJsonContext.Default.ListPruneReportEntryDto,
|
||||
query: filters is null ? null : [("filters", filters)],
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
@ -183,7 +192,13 @@ public partial class PodmanClient {
|
||||
);
|
||||
|
||||
public Task<Result<ContainerMountDto?>> MountContainerAsync(string name, CancellationToken cancellationToken = default) =>
|
||||
PostLibpodAsync<ContainerMountDto>($"{ContainerPath(name)}/mount", "Mount container", PodmanJsonContext.Default.ContainerMountDto, cancellationToken: cancellationToken);
|
||||
SendAsync(
|
||||
() => _httpClient.PostAsync(LibpodPath($"{ContainerPath(name)}/mount"), content: null, cancellationToken),
|
||||
"Mount container",
|
||||
// Podman returns a plain filesystem path, not JSON.
|
||||
body => new ContainerMountDto { Path = body.Trim().Trim('"') },
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
public Task<Result> UnmountContainerAsync(string name, CancellationToken cancellationToken = default) =>
|
||||
PostWithoutBodyAsync($"{ContainerPath(name)}/unmount", "Unmount container", cancellationToken: cancellationToken);
|
||||
@ -266,8 +281,32 @@ public partial class PodmanClient {
|
||||
public Task<Result<ContainerHealthCheckDto?>> HealthCheckContainerAsync(string name, CancellationToken cancellationToken = default) =>
|
||||
GetJsonAsync<ContainerHealthCheckDto>($"{ContainerPath(name)}/healthcheck", "Health check container", PodmanJsonContext.Default.ContainerHealthCheckDto, cancellationToken: cancellationToken);
|
||||
|
||||
public Task<Result<MountedContainersResponseDto?>> GetMountedContainersAsync(CancellationToken cancellationToken = default) =>
|
||||
GetJsonAsync<MountedContainersResponseDto>("/libpod/containers/showmounted", "Get mounted containers", PodmanJsonContext.Default.MountedContainersResponseDto, cancellationToken: cancellationToken);
|
||||
public Task<Result<List<Dictionary<string, string>>?>> GetMountedContainersAsync(CancellationToken cancellationToken = default) =>
|
||||
SendAsync(
|
||||
() => _httpClient.GetAsync(LibpodPath("/libpod/containers/showmounted"), cancellationToken),
|
||||
"Get mounted containers",
|
||||
body => {
|
||||
// Libpod returns [{"<id>":"<path>"}, ...] (and [{}}] when empty).
|
||||
using var doc = System.Text.Json.JsonDocument.Parse(string.IsNullOrWhiteSpace(body) ? "[]" : body);
|
||||
var list = new List<Dictionary<string, string>>();
|
||||
if (doc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array)
|
||||
return list;
|
||||
|
||||
foreach (var el in doc.RootElement.EnumerateArray()) {
|
||||
var dict = new Dictionary<string, string>();
|
||||
if (el.ValueKind == System.Text.Json.JsonValueKind.Object) {
|
||||
foreach (var prop in el.EnumerateObject())
|
||||
dict[prop.Name] = prop.Value.ValueKind == System.Text.Json.JsonValueKind.String
|
||||
? (prop.Value.GetString() ?? string.Empty)
|
||||
: prop.Value.ToString();
|
||||
}
|
||||
list.Add(dict);
|
||||
}
|
||||
|
||||
return list;
|
||||
},
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
public Task<Result<ContainerTopDto?>> TopContainerAsync(
|
||||
string name,
|
||||
|
||||
@ -1,13 +1,8 @@
|
||||
using MaksIT.PodmanClientDotNet;
|
||||
using System.Text.Json;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MaksIT.PodmanClientDotNet.Internal;
|
||||
using MaksIT.PodmanClientDotNet.Models;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Exec;
|
||||
using MaksIT.PodmanClientDotNet.Models.Exec;
|
||||
using MaksIT.Results;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public partial class PodmanClient {
|
||||
public async Task<Result<CreateExecResponseDto?>> CreateExecAsync(
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using MaksIT.PodmanClientDotNet;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
using MaksIT.PodmanClientDotNet;
|
||||
using MaksIT.PodmanClientDotNet.Dtos.Generate;
|
||||
using MaksIT.Results;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user