diff --git a/build.gradle.kts b/build.gradle.kts index cb49b643f..40dda1fcb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,9 +4,16 @@ plugins { id("net.ossindex.audit") version "0.4.11" id("io.freefair.maven-central.validate-poms") version "6.1.0" id("io.github.gradle-nexus.publish-plugin") version "1.1.0" + id("org.jetbrains.kotlin.jvm") version "1.5.30" apply false + id("org.jetbrains.kotlin.kapt") version "1.5.30" apply false } val dependencyVersions = listOf( + "com.fasterxml.jackson.core:jackson-databind:2.9.10.8", + "com.squareup.moshi:moshi:1.12.0", + "com.squareup.okio:okio:2.10.0", + "org.apache.commons:commons-lang3:3.12.0", + "org.apiguardian:apiguardian-api:1.1.0", "org.codehaus.groovy:groovy:2.5.14", "org.codehaus.groovy:groovy-json:2.5.14", "org.codehaus.groovy:groovy-macro:2.5.14", @@ -15,11 +22,31 @@ val dependencyVersions = listOf( "org.codehaus.groovy:groovy-templates:2.5.14", "org.codehaus.groovy:groovy-test:2.5.14", "org.codehaus.groovy:groovy-xml:2.5.14", - "org.jetbrains:annotations:22.0.0" + "org.jetbrains:annotations:22.0.0", + "org.jetbrains.kotlin:kotlin-reflect:1.5.30", + "org.jetbrains.kotlin:kotlin-stdlib:1.5.30", + "org.jetbrains.kotlin:kotlin-stdlib-common:1.5.30", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30", + "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1", + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.1", + "org.junit:junit-bom:5.7.2", + "org.junit.jupiter:junit-jupiter-api:5.7.2", + "org.junit.platform:junit-platform-commons:1.7.2", + "org.junit.platform:junit-platform-engine:1.7.2", + "org.junit.platform:junit-platform-launcher:1.7.2", + "org.junit.platform:junit-platform-suite-api:1.7.2", + "org.opentest4j:opentest4j:1.2.0" ) val dependencyVersionsByGroup = mapOf() +subprojects { + repositories { + mavenCentral() + } +} + allprojects { configurations.all { resolutionStrategy { diff --git a/client/build.gradle.kts b/client/build.gradle.kts index a7d1d2966..1bfa49eb9 100644 --- a/client/build.gradle.kts +++ b/client/build.gradle.kts @@ -11,10 +11,6 @@ plugins { id("io.freefair.maven-central.validate-poms") } -repositories { - mavenCentral() -} - dependencies { constraints { implementation("org.slf4j:slf4j-api") { @@ -71,7 +67,7 @@ dependencies { api("de.gesellix:docker-engine:2021-08-27-18-17-00") api("de.gesellix:docker-compose:2021-08-27T18-26-00") - implementation("org.codehaus.groovy:groovy:[2.5,)") + api("org.codehaus.groovy:groovy:[2.5,)") implementation("org.codehaus.groovy:groovy-json:[2.5,)") api("com.squareup.moshi:moshi:[1.9,2)") diff --git a/engine-api/.gitignore b/engine-api/.gitignore new file mode 100644 index 000000000..a530464af --- /dev/null +++ b/engine-api/.gitignore @@ -0,0 +1,21 @@ +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# exclude jar for gradle wrapper +!gradle/wrapper/*.jar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# build files +**/target +target +.gradle +build diff --git a/engine-api/README.md b/engine-api/README.md new file mode 100644 index 000000000..0b16bb5e4 --- /dev/null +++ b/engine-api/README.md @@ -0,0 +1,321 @@ +# org.openapitools.client - Kotlin client library for Docker Engine API + +## Requires + +* Kotlin 1.4.30 +* Gradle 6.8.3 + +## Features/Implementation Notes + +* Supports JSON inputs/outputs, File inputs, and Form inputs. +* Supports collection formats for query parameters: csv, tsv, ssv, pipes. +* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions. +* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets. + + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost/v1.41* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*ConfigApi* | [**configCreate**](docs/ConfigApi.md#configcreate) | **POST** /configs/create | Create a config +*ConfigApi* | [**configDelete**](docs/ConfigApi.md#configdelete) | **DELETE** /configs/{id} | Delete a config +*ConfigApi* | [**configInspect**](docs/ConfigApi.md#configinspect) | **GET** /configs/{id} | Inspect a config +*ConfigApi* | [**configList**](docs/ConfigApi.md#configlist) | **GET** /configs | List configs +*ConfigApi* | [**configUpdate**](docs/ConfigApi.md#configupdate) | **POST** /configs/{id}/update | Update a Config +*ContainerApi* | [**containerArchive**](docs/ContainerApi.md#containerarchive) | **GET** /containers/{id}/archive | Get an archive of a filesystem resource in a container +*ContainerApi* | [**containerArchiveInfo**](docs/ContainerApi.md#containerarchiveinfo) | **HEAD** /containers/{id}/archive | Get information about files in a container +*ContainerApi* | [**containerAttach**](docs/ContainerApi.md#containerattach) | **POST** /containers/{id}/attach | Attach to a container +*ContainerApi* | [**containerAttachWebsocket**](docs/ContainerApi.md#containerattachwebsocket) | **GET** /containers/{id}/attach/ws | Attach to a container via a websocket +*ContainerApi* | [**containerChanges**](docs/ContainerApi.md#containerchanges) | **GET** /containers/{id}/changes | Get changes on a container’s filesystem +*ContainerApi* | [**containerCreate**](docs/ContainerApi.md#containercreate) | **POST** /containers/create | Create a container +*ContainerApi* | [**containerDelete**](docs/ContainerApi.md#containerdelete) | **DELETE** /containers/{id} | Remove a container +*ContainerApi* | [**containerExport**](docs/ContainerApi.md#containerexport) | **GET** /containers/{id}/export | Export a container +*ContainerApi* | [**containerInspect**](docs/ContainerApi.md#containerinspect) | **GET** /containers/{id}/json | Inspect a container +*ContainerApi* | [**containerKill**](docs/ContainerApi.md#containerkill) | **POST** /containers/{id}/kill | Kill a container +*ContainerApi* | [**containerList**](docs/ContainerApi.md#containerlist) | **GET** /containers/json | List containers +*ContainerApi* | [**containerLogs**](docs/ContainerApi.md#containerlogs) | **GET** /containers/{id}/logs | Get container logs +*ContainerApi* | [**containerPause**](docs/ContainerApi.md#containerpause) | **POST** /containers/{id}/pause | Pause a container +*ContainerApi* | [**containerPrune**](docs/ContainerApi.md#containerprune) | **POST** /containers/prune | Delete stopped containers +*ContainerApi* | [**containerRename**](docs/ContainerApi.md#containerrename) | **POST** /containers/{id}/rename | Rename a container +*ContainerApi* | [**containerResize**](docs/ContainerApi.md#containerresize) | **POST** /containers/{id}/resize | Resize a container TTY +*ContainerApi* | [**containerRestart**](docs/ContainerApi.md#containerrestart) | **POST** /containers/{id}/restart | Restart a container +*ContainerApi* | [**containerStart**](docs/ContainerApi.md#containerstart) | **POST** /containers/{id}/start | Start a container +*ContainerApi* | [**containerStats**](docs/ContainerApi.md#containerstats) | **GET** /containers/{id}/stats | Get container stats based on resource usage +*ContainerApi* | [**containerStop**](docs/ContainerApi.md#containerstop) | **POST** /containers/{id}/stop | Stop a container +*ContainerApi* | [**containerTop**](docs/ContainerApi.md#containertop) | **GET** /containers/{id}/top | List processes running inside a container +*ContainerApi* | [**containerUnpause**](docs/ContainerApi.md#containerunpause) | **POST** /containers/{id}/unpause | Unpause a container +*ContainerApi* | [**containerUpdate**](docs/ContainerApi.md#containerupdate) | **POST** /containers/{id}/update | Update a container +*ContainerApi* | [**containerWait**](docs/ContainerApi.md#containerwait) | **POST** /containers/{id}/wait | Wait for a container +*ContainerApi* | [**putContainerArchive**](docs/ContainerApi.md#putcontainerarchive) | **PUT** /containers/{id}/archive | Extract an archive of files or folders to a directory in a container +*DistributionApi* | [**distributionInspect**](docs/DistributionApi.md#distributioninspect) | **GET** /distribution/{name}/json | Get image information from the registry +*ExecApi* | [**containerExec**](docs/ExecApi.md#containerexec) | **POST** /containers/{id}/exec | Create an exec instance +*ExecApi* | [**execInspect**](docs/ExecApi.md#execinspect) | **GET** /exec/{id}/json | Inspect an exec instance +*ExecApi* | [**execResize**](docs/ExecApi.md#execresize) | **POST** /exec/{id}/resize | Resize an exec instance +*ExecApi* | [**execStart**](docs/ExecApi.md#execstart) | **POST** /exec/{id}/start | Start an exec instance +*ImageApi* | [**buildPrune**](docs/ImageApi.md#buildprune) | **POST** /build/prune | Delete builder cache +*ImageApi* | [**imageBuild**](docs/ImageApi.md#imagebuild) | **POST** /build | Build an image +*ImageApi* | [**imageCommit**](docs/ImageApi.md#imagecommit) | **POST** /commit | Create a new image from a container +*ImageApi* | [**imageCreate**](docs/ImageApi.md#imagecreate) | **POST** /images/create | Create an image +*ImageApi* | [**imageDelete**](docs/ImageApi.md#imagedelete) | **DELETE** /images/{name} | Remove an image +*ImageApi* | [**imageGet**](docs/ImageApi.md#imageget) | **GET** /images/{name}/get | Export an image +*ImageApi* | [**imageGetAll**](docs/ImageApi.md#imagegetall) | **GET** /images/get | Export several images +*ImageApi* | [**imageHistory**](docs/ImageApi.md#imagehistory) | **GET** /images/{name}/history | Get the history of an image +*ImageApi* | [**imageInspect**](docs/ImageApi.md#imageinspect) | **GET** /images/{name}/json | Inspect an image +*ImageApi* | [**imageList**](docs/ImageApi.md#imagelist) | **GET** /images/json | List Images +*ImageApi* | [**imageLoad**](docs/ImageApi.md#imageload) | **POST** /images/load | Import images +*ImageApi* | [**imagePrune**](docs/ImageApi.md#imageprune) | **POST** /images/prune | Delete unused images +*ImageApi* | [**imagePush**](docs/ImageApi.md#imagepush) | **POST** /images/{name}/push | Push an image +*ImageApi* | [**imageSearch**](docs/ImageApi.md#imagesearch) | **GET** /images/search | Search images +*ImageApi* | [**imageTag**](docs/ImageApi.md#imagetag) | **POST** /images/{name}/tag | Tag an image +*NetworkApi* | [**networkConnect**](docs/NetworkApi.md#networkconnect) | **POST** /networks/{id}/connect | Connect a container to a network +*NetworkApi* | [**networkCreate**](docs/NetworkApi.md#networkcreate) | **POST** /networks/create | Create a network +*NetworkApi* | [**networkDelete**](docs/NetworkApi.md#networkdelete) | **DELETE** /networks/{id} | Remove a network +*NetworkApi* | [**networkDisconnect**](docs/NetworkApi.md#networkdisconnect) | **POST** /networks/{id}/disconnect | Disconnect a container from a network +*NetworkApi* | [**networkInspect**](docs/NetworkApi.md#networkinspect) | **GET** /networks/{id} | Inspect a network +*NetworkApi* | [**networkList**](docs/NetworkApi.md#networklist) | **GET** /networks | List networks +*NetworkApi* | [**networkPrune**](docs/NetworkApi.md#networkprune) | **POST** /networks/prune | Delete unused networks +*NodeApi* | [**nodeDelete**](docs/NodeApi.md#nodedelete) | **DELETE** /nodes/{id} | Delete a node +*NodeApi* | [**nodeInspect**](docs/NodeApi.md#nodeinspect) | **GET** /nodes/{id} | Inspect a node +*NodeApi* | [**nodeList**](docs/NodeApi.md#nodelist) | **GET** /nodes | List nodes +*NodeApi* | [**nodeUpdate**](docs/NodeApi.md#nodeupdate) | **POST** /nodes/{id}/update | Update a node +*PluginApi* | [**getPluginPrivileges**](docs/PluginApi.md#getpluginprivileges) | **GET** /plugins/privileges | Get plugin privileges +*PluginApi* | [**pluginCreate**](docs/PluginApi.md#plugincreate) | **POST** /plugins/create | Create a plugin +*PluginApi* | [**pluginDelete**](docs/PluginApi.md#plugindelete) | **DELETE** /plugins/{name} | Remove a plugin +*PluginApi* | [**pluginDisable**](docs/PluginApi.md#plugindisable) | **POST** /plugins/{name}/disable | Disable a plugin +*PluginApi* | [**pluginEnable**](docs/PluginApi.md#pluginenable) | **POST** /plugins/{name}/enable | Enable a plugin +*PluginApi* | [**pluginInspect**](docs/PluginApi.md#plugininspect) | **GET** /plugins/{name}/json | Inspect a plugin +*PluginApi* | [**pluginList**](docs/PluginApi.md#pluginlist) | **GET** /plugins | List plugins +*PluginApi* | [**pluginPull**](docs/PluginApi.md#pluginpull) | **POST** /plugins/pull | Install a plugin +*PluginApi* | [**pluginPush**](docs/PluginApi.md#pluginpush) | **POST** /plugins/{name}/push | Push a plugin +*PluginApi* | [**pluginSet**](docs/PluginApi.md#pluginset) | **POST** /plugins/{name}/set | Configure a plugin +*PluginApi* | [**pluginUpgrade**](docs/PluginApi.md#pluginupgrade) | **POST** /plugins/{name}/upgrade | Upgrade a plugin +*SecretApi* | [**secretCreate**](docs/SecretApi.md#secretcreate) | **POST** /secrets/create | Create a secret +*SecretApi* | [**secretDelete**](docs/SecretApi.md#secretdelete) | **DELETE** /secrets/{id} | Delete a secret +*SecretApi* | [**secretInspect**](docs/SecretApi.md#secretinspect) | **GET** /secrets/{id} | Inspect a secret +*SecretApi* | [**secretList**](docs/SecretApi.md#secretlist) | **GET** /secrets | List secrets +*SecretApi* | [**secretUpdate**](docs/SecretApi.md#secretupdate) | **POST** /secrets/{id}/update | Update a Secret +*ServiceApi* | [**serviceCreate**](docs/ServiceApi.md#servicecreate) | **POST** /services/create | Create a service +*ServiceApi* | [**serviceDelete**](docs/ServiceApi.md#servicedelete) | **DELETE** /services/{id} | Delete a service +*ServiceApi* | [**serviceInspect**](docs/ServiceApi.md#serviceinspect) | **GET** /services/{id} | Inspect a service +*ServiceApi* | [**serviceList**](docs/ServiceApi.md#servicelist) | **GET** /services | List services +*ServiceApi* | [**serviceLogs**](docs/ServiceApi.md#servicelogs) | **GET** /services/{id}/logs | Get service logs +*ServiceApi* | [**serviceUpdate**](docs/ServiceApi.md#serviceupdate) | **POST** /services/{id}/update | Update a service +*SessionApi* | [**session**](docs/SessionApi.md#session) | **POST** /session | Initialize interactive session +*SwarmApi* | [**swarmInit**](docs/SwarmApi.md#swarminit) | **POST** /swarm/init | Initialize a new swarm +*SwarmApi* | [**swarmInspect**](docs/SwarmApi.md#swarminspect) | **GET** /swarm | Inspect swarm +*SwarmApi* | [**swarmJoin**](docs/SwarmApi.md#swarmjoin) | **POST** /swarm/join | Join an existing swarm +*SwarmApi* | [**swarmLeave**](docs/SwarmApi.md#swarmleave) | **POST** /swarm/leave | Leave a swarm +*SwarmApi* | [**swarmUnlock**](docs/SwarmApi.md#swarmunlock) | **POST** /swarm/unlock | Unlock a locked manager +*SwarmApi* | [**swarmUnlockkey**](docs/SwarmApi.md#swarmunlockkey) | **GET** /swarm/unlockkey | Get the unlock key +*SwarmApi* | [**swarmUpdate**](docs/SwarmApi.md#swarmupdate) | **POST** /swarm/update | Update a swarm +*SystemApi* | [**systemAuth**](docs/SystemApi.md#systemauth) | **POST** /auth | Check auth configuration +*SystemApi* | [**systemDataUsage**](docs/SystemApi.md#systemdatausage) | **GET** /system/df | Get data usage information +*SystemApi* | [**systemEvents**](docs/SystemApi.md#systemevents) | **GET** /events | Monitor events +*SystemApi* | [**systemInfo**](docs/SystemApi.md#systeminfo) | **GET** /info | Get system information +*SystemApi* | [**systemPing**](docs/SystemApi.md#systemping) | **GET** /_ping | Ping +*SystemApi* | [**systemPingHead**](docs/SystemApi.md#systempinghead) | **HEAD** /_ping | Ping +*SystemApi* | [**systemVersion**](docs/SystemApi.md#systemversion) | **GET** /version | Get version +*TaskApi* | [**taskInspect**](docs/TaskApi.md#taskinspect) | **GET** /tasks/{id} | Inspect a task +*TaskApi* | [**taskList**](docs/TaskApi.md#tasklist) | **GET** /tasks | List tasks +*TaskApi* | [**taskLogs**](docs/TaskApi.md#tasklogs) | **GET** /tasks/{id}/logs | Get task logs +*VolumeApi* | [**volumeCreate**](docs/VolumeApi.md#volumecreate) | **POST** /volumes/create | Create a volume +*VolumeApi* | [**volumeDelete**](docs/VolumeApi.md#volumedelete) | **DELETE** /volumes/{name} | Remove a volume +*VolumeApi* | [**volumeInspect**](docs/VolumeApi.md#volumeinspect) | **GET** /volumes/{name} | Inspect a volume +*VolumeApi* | [**volumeList**](docs/VolumeApi.md#volumelist) | **GET** /volumes | List volumes +*VolumeApi* | [**volumePrune**](docs/VolumeApi.md#volumeprune) | **POST** /volumes/prune | Delete unused volumes + + + +## Documentation for Models + + - [de.gesellix.docker.engine.model.Address](docs/Address.md) + - [de.gesellix.docker.engine.model.AuthConfig](docs/AuthConfig.md) + - [de.gesellix.docker.engine.model.BuildCache](docs/BuildCache.md) + - [de.gesellix.docker.engine.model.BuildInfo](docs/BuildInfo.md) + - [de.gesellix.docker.engine.model.BuildPruneResponse](docs/BuildPruneResponse.md) + - [de.gesellix.docker.engine.model.ClusterInfo](docs/ClusterInfo.md) + - [de.gesellix.docker.engine.model.Commit](docs/Commit.md) + - [de.gesellix.docker.engine.model.Config](docs/Config.md) + - [de.gesellix.docker.engine.model.ConfigSpec](docs/ConfigSpec.md) + - [de.gesellix.docker.engine.model.ContainerChangeResponseItem](docs/ContainerChangeResponseItem.md) + - [de.gesellix.docker.engine.model.ContainerConfig](docs/ContainerConfig.md) + - [de.gesellix.docker.engine.model.ContainerCreateResponse](docs/ContainerCreateResponse.md) + - [de.gesellix.docker.engine.model.ContainerInspectResponse](docs/ContainerInspectResponse.md) + - [de.gesellix.docker.engine.model.ContainerPruneResponse](docs/ContainerPruneResponse.md) + - [de.gesellix.docker.engine.model.ContainerState](docs/ContainerState.md) + - [de.gesellix.docker.engine.model.ContainerTopResponse](docs/ContainerTopResponse.md) + - [de.gesellix.docker.engine.model.ContainerUpdateResponse](docs/ContainerUpdateResponse.md) + - [de.gesellix.docker.engine.model.ContainerWaitResponse](docs/ContainerWaitResponse.md) + - [de.gesellix.docker.engine.model.ContainerWaitResponseError](docs/ContainerWaitResponseError.md) + - [de.gesellix.docker.engine.model.CreateImageInfo](docs/CreateImageInfo.md) + - [de.gesellix.docker.engine.model.DeviceMapping](docs/DeviceMapping.md) + - [de.gesellix.docker.engine.model.DeviceRequest](docs/DeviceRequest.md) + - [de.gesellix.docker.engine.model.DistributionInspectResponse](docs/DistributionInspectResponse.md) + - [de.gesellix.docker.engine.model.DistributionInspectResponseDescriptor](docs/DistributionInspectResponseDescriptor.md) + - [de.gesellix.docker.engine.model.DistributionInspectResponsePlatforms](docs/DistributionInspectResponsePlatforms.md) + - [de.gesellix.docker.engine.model.Driver](docs/Driver.md) + - [de.gesellix.docker.engine.model.EndpointIPAMConfig](docs/EndpointIPAMConfig.md) + - [de.gesellix.docker.engine.model.EndpointPortConfig](docs/EndpointPortConfig.md) + - [de.gesellix.docker.engine.model.EndpointSettings](docs/EndpointSettings.md) + - [de.gesellix.docker.engine.model.EndpointSpec](docs/EndpointSpec.md) + - [de.gesellix.docker.engine.model.EngineDescription](docs/EngineDescription.md) + - [de.gesellix.docker.engine.model.EngineDescriptionPlugins](docs/EngineDescriptionPlugins.md) + - [de.gesellix.docker.engine.model.ErrorDetail](docs/ErrorDetail.md) + - [de.gesellix.docker.engine.model.ErrorResponse](docs/ErrorResponse.md) + - [de.gesellix.docker.engine.model.ExecInspectResponse](docs/ExecInspectResponse.md) + - [de.gesellix.docker.engine.model.GraphDriverData](docs/GraphDriverData.md) + - [de.gesellix.docker.engine.model.Health](docs/Health.md) + - [de.gesellix.docker.engine.model.HealthConfig](docs/HealthConfig.md) + - [de.gesellix.docker.engine.model.HealthcheckResult](docs/HealthcheckResult.md) + - [de.gesellix.docker.engine.model.HistoryResponseItem](docs/HistoryResponseItem.md) + - [de.gesellix.docker.engine.model.HostConfig](docs/HostConfig.md) + - [de.gesellix.docker.engine.model.HostConfigAllOf](docs/HostConfigAllOf.md) + - [de.gesellix.docker.engine.model.HostConfigAllOfLogConfig](docs/HostConfigAllOfLogConfig.md) + - [de.gesellix.docker.engine.model.IPAM](docs/IPAM.md) + - [de.gesellix.docker.engine.model.IdResponse](docs/IdResponse.md) + - [de.gesellix.docker.engine.model.Image](docs/Image.md) + - [de.gesellix.docker.engine.model.ImageDeleteResponseItem](docs/ImageDeleteResponseItem.md) + - [de.gesellix.docker.engine.model.ImageID](docs/ImageID.md) + - [de.gesellix.docker.engine.model.ImageMetadata](docs/ImageMetadata.md) + - [de.gesellix.docker.engine.model.ImagePruneResponse](docs/ImagePruneResponse.md) + - [de.gesellix.docker.engine.model.ImageRootFS](docs/ImageRootFS.md) + - [de.gesellix.docker.engine.model.ImageSearchResponseItem](docs/ImageSearchResponseItem.md) + - [de.gesellix.docker.engine.model.ImageSummary](docs/ImageSummary.md) + - [de.gesellix.docker.engine.model.IndexInfo](docs/IndexInfo.md) + - [de.gesellix.docker.engine.model.InlineObject](docs/InlineObject.md) + - [de.gesellix.docker.engine.model.InlineObject1](docs/InlineObject1.md) + - [de.gesellix.docker.engine.model.InlineObject2](docs/InlineObject2.md) + - [de.gesellix.docker.engine.model.InlineObject3](docs/InlineObject3.md) + - [de.gesellix.docker.engine.model.InlineObject4](docs/InlineObject4.md) + - [de.gesellix.docker.engine.model.InlineObject5](docs/InlineObject5.md) + - [de.gesellix.docker.engine.model.InlineObject6](docs/InlineObject6.md) + - [de.gesellix.docker.engine.model.InlineObject7](docs/InlineObject7.md) + - [de.gesellix.docker.engine.model.InlineResponse400](docs/InlineResponse400.md) + - [de.gesellix.docker.engine.model.JoinTokens](docs/JoinTokens.md) + - [de.gesellix.docker.engine.model.Limit](docs/Limit.md) + - [de.gesellix.docker.engine.model.LocalNodeState](docs/LocalNodeState.md) + - [de.gesellix.docker.engine.model.ManagerStatus](docs/ManagerStatus.md) + - [de.gesellix.docker.engine.model.Mount](docs/Mount.md) + - [de.gesellix.docker.engine.model.MountBindOptions](docs/MountBindOptions.md) + - [de.gesellix.docker.engine.model.MountPoint](docs/MountPoint.md) + - [de.gesellix.docker.engine.model.MountTmpfsOptions](docs/MountTmpfsOptions.md) + - [de.gesellix.docker.engine.model.MountVolumeOptions](docs/MountVolumeOptions.md) + - [de.gesellix.docker.engine.model.MountVolumeOptionsDriverConfig](docs/MountVolumeOptionsDriverConfig.md) + - [de.gesellix.docker.engine.model.Network](docs/Network.md) + - [de.gesellix.docker.engine.model.NetworkAttachmentConfig](docs/NetworkAttachmentConfig.md) + - [de.gesellix.docker.engine.model.NetworkContainer](docs/NetworkContainer.md) + - [de.gesellix.docker.engine.model.NetworkCreateResponse](docs/NetworkCreateResponse.md) + - [de.gesellix.docker.engine.model.NetworkPruneResponse](docs/NetworkPruneResponse.md) + - [de.gesellix.docker.engine.model.NetworkSettings](docs/NetworkSettings.md) + - [de.gesellix.docker.engine.model.NetworkingConfig](docs/NetworkingConfig.md) + - [de.gesellix.docker.engine.model.Node](docs/Node.md) + - [de.gesellix.docker.engine.model.NodeDescription](docs/NodeDescription.md) + - [de.gesellix.docker.engine.model.NodeSpec](docs/NodeSpec.md) + - [de.gesellix.docker.engine.model.NodeState](docs/NodeState.md) + - [de.gesellix.docker.engine.model.NodeStatus](docs/NodeStatus.md) + - [de.gesellix.docker.engine.model.ObjectVersion](docs/ObjectVersion.md) + - [de.gesellix.docker.engine.model.PeerNode](docs/PeerNode.md) + - [de.gesellix.docker.engine.model.Platform](docs/Platform.md) + - [de.gesellix.docker.engine.model.Plugin](docs/Plugin.md) + - [de.gesellix.docker.engine.model.PluginConfig](docs/PluginConfig.md) + - [de.gesellix.docker.engine.model.PluginConfigArgs](docs/PluginConfigArgs.md) + - [de.gesellix.docker.engine.model.PluginConfigInterface](docs/PluginConfigInterface.md) + - [de.gesellix.docker.engine.model.PluginConfigLinux](docs/PluginConfigLinux.md) + - [de.gesellix.docker.engine.model.PluginConfigNetwork](docs/PluginConfigNetwork.md) + - [de.gesellix.docker.engine.model.PluginConfigRootfs](docs/PluginConfigRootfs.md) + - [de.gesellix.docker.engine.model.PluginConfigUser](docs/PluginConfigUser.md) + - [de.gesellix.docker.engine.model.PluginDevice](docs/PluginDevice.md) + - [de.gesellix.docker.engine.model.PluginEnv](docs/PluginEnv.md) + - [de.gesellix.docker.engine.model.PluginInterfaceType](docs/PluginInterfaceType.md) + - [de.gesellix.docker.engine.model.PluginMount](docs/PluginMount.md) + - [de.gesellix.docker.engine.model.PluginPrivilegeItem](docs/PluginPrivilegeItem.md) + - [de.gesellix.docker.engine.model.PluginSettings](docs/PluginSettings.md) + - [de.gesellix.docker.engine.model.PluginsInfo](docs/PluginsInfo.md) + - [de.gesellix.docker.engine.model.Port](docs/Port.md) + - [de.gesellix.docker.engine.model.PortBinding](docs/PortBinding.md) + - [de.gesellix.docker.engine.model.ProcessConfig](docs/ProcessConfig.md) + - [de.gesellix.docker.engine.model.ProgressDetail](docs/ProgressDetail.md) + - [de.gesellix.docker.engine.model.PushImageInfo](docs/PushImageInfo.md) + - [de.gesellix.docker.engine.model.Reachability](docs/Reachability.md) + - [de.gesellix.docker.engine.model.RegistryServiceConfig](docs/RegistryServiceConfig.md) + - [de.gesellix.docker.engine.model.ResourceObject](docs/ResourceObject.md) + - [de.gesellix.docker.engine.model.Resources](docs/Resources.md) + - [de.gesellix.docker.engine.model.ResourcesBlkioWeightDevice](docs/ResourcesBlkioWeightDevice.md) + - [de.gesellix.docker.engine.model.ResourcesUlimits](docs/ResourcesUlimits.md) + - [de.gesellix.docker.engine.model.RestartPolicy](docs/RestartPolicy.md) + - [de.gesellix.docker.engine.model.Runtime](docs/Runtime.md) + - [de.gesellix.docker.engine.model.Secret](docs/Secret.md) + - [de.gesellix.docker.engine.model.SecretSpec](docs/SecretSpec.md) + - [de.gesellix.docker.engine.model.Service](docs/Service.md) + - [de.gesellix.docker.engine.model.ServiceCreateResponse](docs/ServiceCreateResponse.md) + - [de.gesellix.docker.engine.model.ServiceEndpoint](docs/ServiceEndpoint.md) + - [de.gesellix.docker.engine.model.ServiceEndpointVirtualIPs](docs/ServiceEndpointVirtualIPs.md) + - [de.gesellix.docker.engine.model.ServiceJobStatus](docs/ServiceJobStatus.md) + - [de.gesellix.docker.engine.model.ServiceServiceStatus](docs/ServiceServiceStatus.md) + - [de.gesellix.docker.engine.model.ServiceSpec](docs/ServiceSpec.md) + - [de.gesellix.docker.engine.model.ServiceSpecMode](docs/ServiceSpecMode.md) + - [de.gesellix.docker.engine.model.ServiceSpecModeReplicated](docs/ServiceSpecModeReplicated.md) + - [de.gesellix.docker.engine.model.ServiceSpecModeReplicatedJob](docs/ServiceSpecModeReplicatedJob.md) + - [de.gesellix.docker.engine.model.ServiceSpecRollbackConfig](docs/ServiceSpecRollbackConfig.md) + - [de.gesellix.docker.engine.model.ServiceSpecUpdateConfig](docs/ServiceSpecUpdateConfig.md) + - [de.gesellix.docker.engine.model.ServiceUpdateResponse](docs/ServiceUpdateResponse.md) + - [de.gesellix.docker.engine.model.ServiceUpdateStatus](docs/ServiceUpdateStatus.md) + - [de.gesellix.docker.engine.model.Swarm](docs/Swarm.md) + - [de.gesellix.docker.engine.model.SwarmAllOf](docs/SwarmAllOf.md) + - [de.gesellix.docker.engine.model.SwarmInfo](docs/SwarmInfo.md) + - [de.gesellix.docker.engine.model.SwarmSpec](docs/SwarmSpec.md) + - [de.gesellix.docker.engine.model.SwarmSpecCAConfig](docs/SwarmSpecCAConfig.md) + - [de.gesellix.docker.engine.model.SwarmSpecCAConfigExternalCAs](docs/SwarmSpecCAConfigExternalCAs.md) + - [de.gesellix.docker.engine.model.SwarmSpecDispatcher](docs/SwarmSpecDispatcher.md) + - [de.gesellix.docker.engine.model.SwarmSpecEncryptionConfig](docs/SwarmSpecEncryptionConfig.md) + - [de.gesellix.docker.engine.model.SwarmSpecOrchestration](docs/SwarmSpecOrchestration.md) + - [de.gesellix.docker.engine.model.SwarmSpecRaft](docs/SwarmSpecRaft.md) + - [de.gesellix.docker.engine.model.SwarmSpecTaskDefaults](docs/SwarmSpecTaskDefaults.md) + - [de.gesellix.docker.engine.model.SwarmSpecTaskDefaultsLogDriver](docs/SwarmSpecTaskDefaultsLogDriver.md) + - [de.gesellix.docker.engine.model.SystemAuthResponse](docs/SystemAuthResponse.md) + - [de.gesellix.docker.engine.model.SystemDataUsageResponse](docs/SystemDataUsageResponse.md) + - [de.gesellix.docker.engine.model.SystemEventsResponse](docs/SystemEventsResponse.md) + - [de.gesellix.docker.engine.model.SystemEventsResponseActor](docs/SystemEventsResponseActor.md) + - [de.gesellix.docker.engine.model.SystemInfo](docs/SystemInfo.md) + - [de.gesellix.docker.engine.model.SystemInfoDefaultAddressPools](docs/SystemInfoDefaultAddressPools.md) + - [de.gesellix.docker.engine.model.SystemVersion](docs/SystemVersion.md) + - [de.gesellix.docker.engine.model.SystemVersionComponents](docs/SystemVersionComponents.md) + - [de.gesellix.docker.engine.model.SystemVersionPlatform](docs/SystemVersionPlatform.md) + - [de.gesellix.docker.engine.model.TLSInfo](docs/TLSInfo.md) + - [de.gesellix.docker.engine.model.Task](docs/Task.md) + - [de.gesellix.docker.engine.model.TaskSpec](docs/TaskSpec.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpec](docs/TaskSpecContainerSpec.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecConfigs](docs/TaskSpecContainerSpecConfigs.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecDNSConfig](docs/TaskSpecContainerSpecDNSConfig.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecFile](docs/TaskSpecContainerSpecFile.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecFile1](docs/TaskSpecContainerSpecFile1.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecPrivileges](docs/TaskSpecContainerSpecPrivileges.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecPrivilegesCredentialSpec](docs/TaskSpecContainerSpecPrivilegesCredentialSpec.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecPrivilegesSELinuxContext](docs/TaskSpecContainerSpecPrivilegesSELinuxContext.md) + - [de.gesellix.docker.engine.model.TaskSpecContainerSpecSecrets](docs/TaskSpecContainerSpecSecrets.md) + - [de.gesellix.docker.engine.model.TaskSpecLogDriver](docs/TaskSpecLogDriver.md) + - [de.gesellix.docker.engine.model.TaskSpecNetworkAttachmentSpec](docs/TaskSpecNetworkAttachmentSpec.md) + - [de.gesellix.docker.engine.model.TaskSpecPlacement](docs/TaskSpecPlacement.md) + - [de.gesellix.docker.engine.model.TaskSpecPlacementPreferences](docs/TaskSpecPlacementPreferences.md) + - [de.gesellix.docker.engine.model.TaskSpecPlacementSpread](docs/TaskSpecPlacementSpread.md) + - [de.gesellix.docker.engine.model.TaskSpecPluginSpec](docs/TaskSpecPluginSpec.md) + - [de.gesellix.docker.engine.model.TaskSpecResources](docs/TaskSpecResources.md) + - [de.gesellix.docker.engine.model.TaskSpecRestartPolicy](docs/TaskSpecRestartPolicy.md) + - [de.gesellix.docker.engine.model.TaskState](docs/TaskState.md) + - [de.gesellix.docker.engine.model.TaskStatus](docs/TaskStatus.md) + - [de.gesellix.docker.engine.model.TaskStatusContainerStatus](docs/TaskStatusContainerStatus.md) + - [de.gesellix.docker.engine.model.ThrottleDevice](docs/ThrottleDevice.md) + - [de.gesellix.docker.engine.model.UnlockKeyResponse](docs/UnlockKeyResponse.md) + - [de.gesellix.docker.engine.model.Volume](docs/Volume.md) + - [de.gesellix.docker.engine.model.VolumeConfig](docs/VolumeConfig.md) + - [de.gesellix.docker.engine.model.VolumeListResponse](docs/VolumeListResponse.md) + - [de.gesellix.docker.engine.model.VolumePruneResponse](docs/VolumePruneResponse.md) + - [de.gesellix.docker.engine.model.VolumeUsageData](docs/VolumeUsageData.md) + + + +## Documentation for Authorization + +All endpoints do not require authorization. diff --git a/engine-api/build.gradle.kts b/engine-api/build.gradle.kts new file mode 100644 index 000000000..37564e1ea --- /dev/null +++ b/engine-api/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + id("java") + id("org.jetbrains.kotlin.jvm") + id("org.jetbrains.kotlin.kapt") + id("com.github.ben-manes.versions") +} + +version = "1.41" + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1") + implementation("com.squareup.moshi:moshi:1.12.0") +// implementation("com.squareup.moshi:moshi-kotlin:1.12.0") + kapt("com.squareup.moshi:moshi-kotlin-codegen:1.12.0") + implementation("com.squareup.okhttp3:okhttp:4.9.1") + testImplementation("io.kotlintest:kotlintest-runner-junit5:3.4.2") + implementation("de.gesellix:docker-api-model:2021-08-27-18-17-00") + implementation("de.gesellix:docker-engine:2021-08-27-18-17-00") + implementation("de.gesellix:docker-filesocket:2021-08-05T21-58-10") + + implementation("org.slf4j:slf4j-api:[1.7,)!!1.7.32") + testImplementation("ch.qos.logback:logback-classic:1.2.5") + +// implementation("com.squareup.okhttp3:logging-interceptor:4.9.1") +// implementation("org.apache.commons:commons-lang3:3.10") +// implementation("javax.annotation:javax.annotation-api:1.3.2") +// testImplementation("junit:junit:4.13.1") +} + +tasks.withType(Test::class.java) { + useJUnitPlatform() +} + +//tasks.javadoc { +// options.tags = ["http.response.details:a:Http Response Details"] +//} diff --git a/engine-api/docs/ConfigApi.md b/engine-api/docs/ConfigApi.md new file mode 100644 index 000000000..9fef776c8 --- /dev/null +++ b/engine-api/docs/ConfigApi.md @@ -0,0 +1,240 @@ +# ConfigApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**configCreate**](ConfigApi.md#configCreate) | **POST** /configs/create | Create a config | ✅ +[**configDelete**](ConfigApi.md#configDelete) | **DELETE** /configs/{id} | Delete a config | ✅ +[**configInspect**](ConfigApi.md#configInspect) | **GET** /configs/{id} | Inspect a config | ✅ +[**configList**](ConfigApi.md#configList) | **GET** /configs | List configs | ✅ +[**configUpdate**](ConfigApi.md#configUpdate) | **POST** /configs/{id}/update | Update a Config | ✅ + + + +# **configCreate** +> IdResponse configCreate(body) + +Create a config + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ConfigApi() +val body : UNKNOWN_BASE_TYPE = // UNKNOWN_BASE_TYPE | +try { + val result : IdResponse = apiInstance.configCreate(body) + println(result) +} catch (e: ClientException) { + println("4xx response calling ConfigApi#configCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ConfigApi#configCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**UNKNOWN_BASE_TYPE**](UNKNOWN_BASE_TYPE.md)| | [optional] + +### Return type + +[**IdResponse**](IdResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **configDelete** +> configDelete(id) + +Delete a config + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ConfigApi() +val id : kotlin.String = id_example // kotlin.String | ID of the config +try { + apiInstance.configDelete(id) +} catch (e: ClientException) { + println("4xx response calling ConfigApi#configDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ConfigApi#configDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID of the config | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **configInspect** +> Config configInspect(id) + +Inspect a config + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ConfigApi() +val id : kotlin.String = id_example // kotlin.String | ID of the config +try { + val result : Config = apiInstance.configInspect(id) + println(result) +} catch (e: ClientException) { + println("4xx response calling ConfigApi#configInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ConfigApi#configInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID of the config | + +### Return type + +[**Config**](Config.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **configList** +> kotlin.collections.List<Config> configList(filters) + +List configs + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ConfigApi() +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the configs list. Available filters: - `id=` - `label= or label==value` - `name=` - `names=` +try { + val result : kotlin.collections.List = apiInstance.configList(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling ConfigApi#configList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ConfigApi#configList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the configs list. Available filters: - `id=<config id>` - `label=<key> or label=<key>=value` - `name=<config name>` - `names=<config name>` | [optional] + +### Return type + +[**kotlin.collections.List<Config>**](Config.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **configUpdate** +> configUpdate(id, version, body) + +Update a Config + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ConfigApi() +val id : kotlin.String = id_example // kotlin.String | The ID or name of the config +val version : kotlin.Long = 789 // kotlin.Long | The version number of the config object being updated. This is required to avoid conflicting writes. +val body : ConfigSpec = // ConfigSpec | The spec of the config to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [ConfigInspect endpoint](#operation/ConfigInspect) response values. +try { + apiInstance.configUpdate(id, version, body) +} catch (e: ClientException) { + println("4xx response calling ConfigApi#configUpdate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ConfigApi#configUpdate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| The ID or name of the config | + **version** | **kotlin.Long**| The version number of the config object being updated. This is required to avoid conflicting writes. | + **body** | [**ConfigSpec**](ConfigSpec.md)| The spec of the config to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [ConfigInspect endpoint](#operation/ConfigInspect) response values. | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/ContainerApi.md b/engine-api/docs/ContainerApi.md new file mode 100644 index 000000000..4625d32fe --- /dev/null +++ b/engine-api/docs/ContainerApi.md @@ -0,0 +1,1268 @@ +# ContainerApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**containerArchive**](ContainerApi.md#containerArchive) | **GET** /containers/{id}/archive | Get an archive of a filesystem resource in a container | ❌ +[**containerArchiveInfo**](ContainerApi.md#containerArchiveInfo) | **HEAD** /containers/{id}/archive | Get information about files in a container | ❌ +[**containerAttach**](ContainerApi.md#containerAttach) | **POST** /containers/{id}/attach | Attach to a container (non-interactive) | ✅ +[**containerAttach**](ContainerApi.md#containerAttach) | **POST** /containers/{id}/attach | Attach to a container (interactive) | ❌ +[**containerAttachWebsocket**](ContainerApi.md#containerAttachWebsocket) | **GET** /containers/{id}/attach/ws | Attach to a container via a websocket | ❌ +[**containerChanges**](ContainerApi.md#containerChanges) | **GET** /containers/{id}/changes | Get changes on a container’s filesystem | ❌ +[**containerCreate**](ContainerApi.md#containerCreate) | **POST** /containers/create | Create a container | ✅ +[**containerDelete**](ContainerApi.md#containerDelete) | **DELETE** /containers/{id} | Remove a container | ✅ +[**containerExport**](ContainerApi.md#containerExport) | **GET** /containers/{id}/export | Export a container | ❌ +[**containerInspect**](ContainerApi.md#containerInspect) | **GET** /containers/{id}/json | Inspect a container | ✅ +[**containerKill**](ContainerApi.md#containerKill) | **POST** /containers/{id}/kill | Kill a container | ✅ +[**containerList**](ContainerApi.md#containerList) | **GET** /containers/json | List containers | ✅ +[**containerLogs**](ContainerApi.md#containerLogs) | **GET** /containers/{id}/logs | Get container logs | ✅ +[**containerPause**](ContainerApi.md#containerPause) | **POST** /containers/{id}/pause | Pause a container | ✅ +[**containerPrune**](ContainerApi.md#containerPrune) | **POST** /containers/prune | Delete stopped containers | ✅ +[**containerRename**](ContainerApi.md#containerRename) | **POST** /containers/{id}/rename | Rename a container | ✅ +[**containerResize**](ContainerApi.md#containerResize) | **POST** /containers/{id}/resize | Resize a container TTY | ❌ +[**containerRestart**](ContainerApi.md#containerRestart) | **POST** /containers/{id}/restart | Restart a container | ✅ +[**containerStart**](ContainerApi.md#containerStart) | **POST** /containers/{id}/start | Start a container | ✅ +[**containerStats**](ContainerApi.md#containerStats) | **GET** /containers/{id}/stats | Get container stats based on resource usage | ✅ +[**containerStop**](ContainerApi.md#containerStop) | **POST** /containers/{id}/stop | Stop a container | ✅ +[**containerTop**](ContainerApi.md#containerTop) | **GET** /containers/{id}/top | List processes running inside a container | ✅ +[**containerUnpause**](ContainerApi.md#containerUnpause) | **POST** /containers/{id}/unpause | Unpause a container | ✅ +[**containerUpdate**](ContainerApi.md#containerUpdate) | **POST** /containers/{id}/update | Update a container | ✅ +[**containerWait**](ContainerApi.md#containerWait) | **POST** /containers/{id}/wait | Wait for a container | ✅ +[**putContainerArchive**](ContainerApi.md#putContainerArchive) | **PUT** /containers/{id}/archive | Extract an archive of files or folders to a directory in a container | ❌ + + + +# **containerArchive** +> containerArchive(id, path) + +Get an archive of a filesystem resource in a container + +Get a tar archive of a resource in the filesystem of container id. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val path : kotlin.String = path_example // kotlin.String | Resource in the container’s filesystem to archive. +try { + apiInstance.containerArchive(id, path) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerArchive") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerArchive") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **path** | **kotlin.String**| Resource in the container’s filesystem to archive. | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/x-tar, application/json + + +# **containerArchiveInfo** +> containerArchiveInfo(id, path) + +Get information about files in a container + +A response header `X-Docker-Container-Path-Stat` is returned, containing a base64 - encoded JSON object with some filesystem header information about the path. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val path : kotlin.String = path_example // kotlin.String | Resource in the container’s filesystem to archive. +try { + apiInstance.containerArchiveInfo(id, path) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerArchiveInfo") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerArchiveInfo") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **path** | **kotlin.String**| Resource in the container’s filesystem to archive. | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerAttach** +> containerAttach(id, detachKeys, logs, stream, stdin, stdout, stderr) + +Attach to a container + +Attach to a container to read its output or send it input. You can attach to the same container multiple times and you can reattach to containers that have been detached. Either the `stream` or `logs` parameter must be `true` for this endpoint to do anything. See the [documentation for the `docker attach` command](https://docs.docker.com/engine/reference/commandline/attach/) for more details. ### Hijacking This endpoint hijacks the HTTP connection to transport `stdin`, `stdout`, and `stderr` on the same socket. This is the response from the daemon for an attach request: ``` HTTP/1.1 200 OK Content-Type: application/vnd.docker.raw-stream [STREAM] ``` After the headers and two new lines, the TCP connection can now be used for raw, bidirectional communication between the client and server. To hint potential proxies about connection hijacking, the Docker client can also optionally send connection upgrade headers. For example, the client sends this request to upgrade the connection: ``` POST /containers/16253994b7c4/attach?stream=1&stdout=1 HTTP/1.1 Upgrade: tcp Connection: Upgrade ``` The Docker daemon will respond with a `101 UPGRADED` response, and will similarly follow with the raw stream: ``` HTTP/1.1 101 UPGRADED Content-Type: application/vnd.docker.raw-stream Connection: Upgrade Upgrade: tcp [STREAM] ``` ### Stream format When the TTY setting is disabled in [`POST /containers/create`](#operation/ContainerCreate), the stream over the hijacked connected is multiplexed to separate out `stdout` and `stderr`. The stream consists of a series of frames, each containing a header and a payload. The header contains the information which the stream writes (`stdout` or `stderr`). It also contains the size of the associated frame encoded in the last four bytes (`uint32`). It is encoded on the first eight bytes like this: ```go header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4} ``` `STREAM_TYPE` can be: - 0: `stdin` (is written on `stdout`) - 1: `stdout` - 2: `stderr` `SIZE1, SIZE2, SIZE3, SIZE4` are the four bytes of the `uint32` size encoded as big endian. Following the header is the payload, which is the specified number of bytes of `STREAM_TYPE`. The simplest way to implement this protocol is the following: 1. Read 8 bytes. 2. Choose `stdout` or `stderr` depending on the first byte. 3. Extract the frame size from the last four bytes. 4. Read the extracted size and output it on the correct output. 5. Goto 1. ### Stream format when using a TTY When the TTY setting is enabled in [`POST /containers/create`](#operation/ContainerCreate), the stream is not multiplexed. The data exchanged over the hijacked connection is simply the raw data from the process PTY and client's `stdin`. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val detachKeys : kotlin.String = detachKeys_example // kotlin.String | Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-` where `` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. +val logs : kotlin.Boolean = true // kotlin.Boolean | Replay previous logs from the container. This is useful for attaching to a container that has started and you want to output everything since the container started. If `stream` is also enabled, once all the previous output has been returned, it will seamlessly transition into streaming current output. +val stream : kotlin.Boolean = true // kotlin.Boolean | Stream attached streams from the time the request was made onwards. +val stdin : kotlin.Boolean = true // kotlin.Boolean | Attach to `stdin` +val stdout : kotlin.Boolean = true // kotlin.Boolean | Attach to `stdout` +val stderr : kotlin.Boolean = true // kotlin.Boolean | Attach to `stderr` +try { + apiInstance.containerAttach(id, detachKeys, logs, stream, stdin, stdout, stderr) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerAttach") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerAttach") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **detachKeys** | **kotlin.String**| Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. | [optional] + **logs** | **kotlin.Boolean**| Replay previous logs from the container. This is useful for attaching to a container that has started and you want to output everything since the container started. If `stream` is also enabled, once all the previous output has been returned, it will seamlessly transition into streaming current output. | [optional] [default to false] + **stream** | **kotlin.Boolean**| Stream attached streams from the time the request was made onwards. | [optional] [default to false] + **stdin** | **kotlin.Boolean**| Attach to `stdin` | [optional] [default to false] + **stdout** | **kotlin.Boolean**| Attach to `stdout` | [optional] [default to false] + **stderr** | **kotlin.Boolean**| Attach to `stderr` | [optional] [default to false] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/vnd.docker.raw-stream, application/json + + +# **containerAttachWebsocket** +> containerAttachWebsocket(id, detachKeys, logs, stream, stdin, stdout, stderr) + +Attach to a container via a websocket + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val detachKeys : kotlin.String = detachKeys_example // kotlin.String | Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-` where `` is one of: `a-z`, `@`, `^`, `[`, `,`, or `_`. +val logs : kotlin.Boolean = true // kotlin.Boolean | Return logs +val stream : kotlin.Boolean = true // kotlin.Boolean | Return stream +val stdin : kotlin.Boolean = true // kotlin.Boolean | Attach to `stdin` +val stdout : kotlin.Boolean = true // kotlin.Boolean | Attach to `stdout` +val stderr : kotlin.Boolean = true // kotlin.Boolean | Attach to `stderr` +try { + apiInstance.containerAttachWebsocket(id, detachKeys, logs, stream, stdin, stdout, stderr) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerAttachWebsocket") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerAttachWebsocket") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **detachKeys** | **kotlin.String**| Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,`, or `_`. | [optional] + **logs** | **kotlin.Boolean**| Return logs | [optional] [default to false] + **stream** | **kotlin.Boolean**| Return stream | [optional] [default to false] + **stdin** | **kotlin.Boolean**| Attach to `stdin` | [optional] [default to false] + **stdout** | **kotlin.Boolean**| Attach to `stdout` | [optional] [default to false] + **stderr** | **kotlin.Boolean**| Attach to `stderr` | [optional] [default to false] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerChanges** +> kotlin.collections.List<ContainerChangeResponseItem> containerChanges(id) + +Get changes on a container’s filesystem + +Returns which files in a container's filesystem have been added, deleted, or modified. The `Kind` of modification can be one of: - `0`: Modified - `1`: Added - `2`: Deleted + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +try { + val result : kotlin.collections.List = apiInstance.containerChanges(id) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerChanges") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerChanges") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + +### Return type + +[**kotlin.collections.List<ContainerChangeResponseItem>**](ContainerChangeResponseItem.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **containerCreate** +> ContainerCreateResponse containerCreate(body, name) + +Create a container + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val body : UNKNOWN_BASE_TYPE = // UNKNOWN_BASE_TYPE | Container to create +val name : kotlin.String = name_example // kotlin.String | Assign the specified name to the container. Must match `/?[a-zA-Z0-9][a-zA-Z0-9_.-]+`. +try { + val result : ContainerCreateResponse = apiInstance.containerCreate(body, name) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**UNKNOWN_BASE_TYPE**](UNKNOWN_BASE_TYPE.md)| Container to create | + **name** | **kotlin.String**| Assign the specified name to the container. Must match `/?[a-zA-Z0-9][a-zA-Z0-9_.-]+`. | [optional] + +### Return type + +[**ContainerCreateResponse**](ContainerCreateResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, application/octet-stream + - **Accept**: application/json + + +# **containerDelete** +> containerDelete(id, v, force, link) + +Remove a container + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val v : kotlin.Boolean = true // kotlin.Boolean | Remove anonymous volumes associated with the container. +val force : kotlin.Boolean = true // kotlin.Boolean | If the container is running, kill it before removing it. +val link : kotlin.Boolean = true // kotlin.Boolean | Remove the specified link associated with the container. +try { + apiInstance.containerDelete(id, v, force, link) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **v** | **kotlin.Boolean**| Remove anonymous volumes associated with the container. | [optional] [default to false] + **force** | **kotlin.Boolean**| If the container is running, kill it before removing it. | [optional] [default to false] + **link** | **kotlin.Boolean**| Remove the specified link associated with the container. | [optional] [default to false] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerExport** +> containerExport(id) + +Export a container + +Export the contents of a container as a tarball. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +try { + apiInstance.containerExport(id) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerExport") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerExport") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/octet-stream, application/json + + +# **containerInspect** +> ContainerInspectResponse containerInspect(id, size) + +Inspect a container + +Return low-level information about a container. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val size : kotlin.Boolean = true // kotlin.Boolean | Return the size of container as fields `SizeRw` and `SizeRootFs` +try { + val result : ContainerInspectResponse = apiInstance.containerInspect(id, size) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **size** | **kotlin.Boolean**| Return the size of container as fields `SizeRw` and `SizeRootFs` | [optional] [default to false] + +### Return type + +[**ContainerInspectResponse**](ContainerInspectResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **containerKill** +> containerKill(id, signal) + +Kill a container + +Send a POSIX signal to a container, defaulting to killing to the container. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val signal : kotlin.String = signal_example // kotlin.String | Signal to send to the container as an integer or string (e.g. `SIGINT`) +try { + apiInstance.containerKill(id, signal) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerKill") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerKill") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **signal** | **kotlin.String**| Signal to send to the container as an integer or string (e.g. `SIGINT`) | [optional] [default to "SIGKILL"] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerList** +> kotlin.collections.List<ContainerSummary> containerList(all, limit, size, filters) + +List containers + +Returns a list of containers. For details on the format, see the [inspect endpoint](#operation/ContainerInspect). Note that it uses a different, smaller representation of a container than inspecting a single container. For example, the list of linked containers is not propagated . + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val all : kotlin.Boolean = true // kotlin.Boolean | Return all containers. By default, only running containers are shown. +val limit : kotlin.Int = 56 // kotlin.Int | Return this number of most recently created containers, including non-running ones. +val size : kotlin.Boolean = true // kotlin.Boolean | Return the size of container as fields `SizeRw` and `SizeRootFs`. +val filters : kotlin.String = filters_example // kotlin.String | Filters to process on the container list, encoded as JSON (a `map[string][]string`). For example, `{\"status\": [\"paused\"]}` will only return paused containers. Available filters: - `ancestor`=(`[:]`, ``, or ``) - `before`=(`` or ``) - `expose`=(`[/]`|`/[]`) - `exited=` containers with exit code of `` - `health`=(`starting`|`healthy`|`unhealthy`|`none`) - `id=` a container's ID - `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only) - `is-task=`(`true`|`false`) - `label=key` or `label=\"key=value\"` of a container label - `name=` a container's name - `network`=(`` or ``) - `publish`=(`[/]`|`/[]`) - `since`=(`` or ``) - `status=`(`created`|`restarting`|`running`|`removing`|`paused`|`exited`|`dead`) - `volume`=(`` or ``) +try { + val result : kotlin.collections.List = apiInstance.containerList(all, limit, size, filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **all** | **kotlin.Boolean**| Return all containers. By default, only running containers are shown. | [optional] [default to false] + **limit** | **kotlin.Int**| Return this number of most recently created containers, including non-running ones. | [optional] + **size** | **kotlin.Boolean**| Return the size of container as fields `SizeRw` and `SizeRootFs`. | [optional] [default to false] + **filters** | **kotlin.String**| Filters to process on the container list, encoded as JSON (a `map[string][]string`). For example, `{\"status\": [\"paused\"]}` will only return paused containers. Available filters: - `ancestor`=(`<image-name>[:<tag>]`, `<image id>`, or `<image@digest>`) - `before`=(`<container id>` or `<container name>`) - `expose`=(`<port>[/<proto>]`|`<startport-endport>/[<proto>]`) - `exited=<int>` containers with exit code of `<int>` - `health`=(`starting`|`healthy`|`unhealthy`|`none`) - `id=<ID>` a container's ID - `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only) - `is-task=`(`true`|`false`) - `label=key` or `label=\"key=value\"` of a container label - `name=<name>` a container's name - `network`=(`<network id>` or `<network name>`) - `publish`=(`<port>[/<proto>]`|`<startport-endport>/[<proto>]`) - `since`=(`<container id>` or `<container name>`) - `status=`(`created`|`restarting`|`running`|`removing`|`paused`|`exited`|`dead`) - `volume`=(`<volume name>` or `<mount point destination>`) | [optional] + +### Return type + +[**kotlin.collections.List<ContainerSummary>**](ContainerSummary.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **containerLogs** +> java.io.File containerLogs(id, follow, stdout, stderr, since, until, timestamps, tail) + +Get container logs + +Get `stdout` and `stderr` logs from a container. Note: This endpoint works only for containers with the `json-file` or `journald` logging driver. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val follow : kotlin.Boolean = true // kotlin.Boolean | Keep connection after returning logs. +val stdout : kotlin.Boolean = true // kotlin.Boolean | Return logs from `stdout` +val stderr : kotlin.Boolean = true // kotlin.Boolean | Return logs from `stderr` +val since : kotlin.Int = 56 // kotlin.Int | Only return logs since this time, as a UNIX timestamp +val until : kotlin.Int = 56 // kotlin.Int | Only return logs before this time, as a UNIX timestamp +val timestamps : kotlin.Boolean = true // kotlin.Boolean | Add timestamps to every log line +val tail : kotlin.String = tail_example // kotlin.String | Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. +try { + val result : java.io.File = apiInstance.containerLogs(id, follow, stdout, stderr, since, until, timestamps, tail) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerLogs") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerLogs") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **follow** | **kotlin.Boolean**| Keep connection after returning logs. | [optional] [default to false] + **stdout** | **kotlin.Boolean**| Return logs from `stdout` | [optional] [default to false] + **stderr** | **kotlin.Boolean**| Return logs from `stderr` | [optional] [default to false] + **since** | **kotlin.Int**| Only return logs since this time, as a UNIX timestamp | [optional] [default to 0] + **until** | **kotlin.Int**| Only return logs before this time, as a UNIX timestamp | [optional] [default to 0] + **timestamps** | **kotlin.Boolean**| Add timestamps to every log line | [optional] [default to false] + **tail** | **kotlin.String**| Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. | [optional] [default to "all"] + +### Return type + +[**java.io.File**](java.io.File.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerPause** +> containerPause(id) + +Pause a container + +Use the freezer cgroup to suspend all processes in a container. Traditionally, when suspending a process the `SIGSTOP` signal is used, which is observable by the process being suspended. With the freezer cgroup the process is unaware, and unable to capture, that it is being suspended, and subsequently resumed. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +try { + apiInstance.containerPause(id) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerPause") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerPause") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerPrune** +> ContainerPruneResponse containerPrune(filters) + +Delete stopped containers + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val filters : kotlin.String = filters_example // kotlin.String | Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=` Prune containers created before this timestamp. The `` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune containers with (or without, in case `label!=...` is used) the specified labels. +try { + val result : ContainerPruneResponse = apiInstance.containerPrune(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerPrune") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerPrune") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=<timestamp>` Prune containers created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune containers with (or without, in case `label!=...` is used) the specified labels. | [optional] + +### Return type + +[**ContainerPruneResponse**](ContainerPruneResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **containerRename** +> containerRename(id, name) + +Rename a container + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val name : kotlin.String = name_example // kotlin.String | New name for the container +try { + apiInstance.containerRename(id, name) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerRename") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerRename") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **name** | **kotlin.String**| New name for the container | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerResize** +> containerResize(id, h, w) + +Resize a container TTY + +Resize the TTY for a container. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val h : kotlin.Int = 56 // kotlin.Int | Height of the TTY session in characters +val w : kotlin.Int = 56 // kotlin.Int | Width of the TTY session in characters +try { + apiInstance.containerResize(id, h, w) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerResize") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerResize") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **h** | **kotlin.Int**| Height of the TTY session in characters | [optional] + **w** | **kotlin.Int**| Width of the TTY session in characters | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: text/plain, application/json + + +# **containerRestart** +> containerRestart(id, t) + +Restart a container + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val t : kotlin.Int = 56 // kotlin.Int | Number of seconds to wait before killing the container +try { + apiInstance.containerRestart(id, t) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerRestart") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerRestart") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **t** | **kotlin.Int**| Number of seconds to wait before killing the container | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerStart** +> containerStart(id, detachKeys) + +Start a container + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val detachKeys : kotlin.String = detachKeys_example // kotlin.String | Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-` where `` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. +try { + apiInstance.containerStart(id, detachKeys) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerStart") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerStart") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **detachKeys** | **kotlin.String**| Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerStats** +> kotlin.Any containerStats(id, stream, oneShot) + +Get container stats based on resource usage + +This endpoint returns a live stream of a container’s resource usage statistics. The `precpu_stats` is the CPU statistic of the *previous* read, and is used to calculate the CPU usage percentage. It is not an exact copy of the `cpu_stats` field. If either `precpu_stats.online_cpus` or `cpu_stats.online_cpus` is nil then for compatibility with older daemons the length of the corresponding `cpu_usage.percpu_usage` array should be used. On a cgroup v2 host, the following fields are not set * `blkio_stats`: all fields other than `io_service_bytes_recursive` * `cpu_stats`: `cpu_usage.percpu_usage` * `memory_stats`: `max_usage` and `failcnt` Also, `memory_stats.stats` fields are incompatible with cgroup v1. To calculate the values shown by the `stats` command of the docker cli tool the following formulas can be used: * used_memory = `memory_stats.usage - memory_stats.stats.cache` * available_memory = `memory_stats.limit` * Memory usage % = `(used_memory / available_memory) * 100.0` * cpu_delta = `cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage` * system_cpu_delta = `cpu_stats.system_cpu_usage - precpu_stats.system_cpu_usage` * number_cpus = `lenght(cpu_stats.cpu_usage.percpu_usage)` or `cpu_stats.online_cpus` * CPU usage % = `(cpu_delta / system_cpu_delta) * number_cpus * 100.0` + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val stream : kotlin.Boolean = true // kotlin.Boolean | Stream the output. If false, the stats will be output once and then it will disconnect. +val oneShot : kotlin.Boolean = true // kotlin.Boolean | Only get a single stat instead of waiting for 2 cycles. Must be used with `stream=false`. +try { + val result : kotlin.Any = apiInstance.containerStats(id, stream, oneShot) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerStats") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerStats") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **stream** | **kotlin.Boolean**| Stream the output. If false, the stats will be output once and then it will disconnect. | [optional] [default to true] + **oneShot** | **kotlin.Boolean**| Only get a single stat instead of waiting for 2 cycles. Must be used with `stream=false`. | [optional] [default to false] + +### Return type + +[**kotlin.Any**](kotlin.Any.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **containerStop** +> containerStop(id, t) + +Stop a container + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val t : kotlin.Int = 56 // kotlin.Int | Number of seconds to wait before killing the container +try { + apiInstance.containerStop(id, t) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerStop") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerStop") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **t** | **kotlin.Int**| Number of seconds to wait before killing the container | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerTop** +> ContainerTopResponse containerTop(id, psArgs) + +List processes running inside a container + +On Unix systems, this is done by running the `ps` command. This endpoint is not supported on Windows. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val psArgs : kotlin.String = psArgs_example // kotlin.String | The arguments to pass to `ps`. For example, `aux` +try { + val result : ContainerTopResponse = apiInstance.containerTop(id, psArgs) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerTop") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerTop") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **psArgs** | **kotlin.String**| The arguments to pass to `ps`. For example, `aux` | [optional] [default to "-ef"] + +### Return type + +[**ContainerTopResponse**](ContainerTopResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerUnpause** +> containerUnpause(id) + +Unpause a container + +Resume a container which has been paused. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +try { + apiInstance.containerUnpause(id) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerUnpause") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerUnpause") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **containerUpdate** +> ContainerUpdateResponse containerUpdate(id, update) + +Update a container + +Change various configuration options of a container without having to recreate it. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val update : UNKNOWN_BASE_TYPE = // UNKNOWN_BASE_TYPE | +try { + val result : ContainerUpdateResponse = apiInstance.containerUpdate(id, update) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerUpdate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerUpdate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **update** | [**UNKNOWN_BASE_TYPE**](UNKNOWN_BASE_TYPE.md)| | + +### Return type + +[**ContainerUpdateResponse**](ContainerUpdateResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **containerWait** +> ContainerWaitResponse containerWait(id, condition) + +Wait for a container + +Block until a container stops, then returns the exit code. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val condition : kotlin.String = condition_example // kotlin.String | Wait until a container state reaches the given condition, either 'not-running' (default), 'next-exit', or 'removed'. +try { + val result : ContainerWaitResponse = apiInstance.containerWait(id, condition) + println(result) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#containerWait") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#containerWait") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **condition** | **kotlin.String**| Wait until a container state reaches the given condition, either 'not-running' (default), 'next-exit', or 'removed'. | [optional] [default to "not-running"] + +### Return type + +[**ContainerWaitResponse**](ContainerWaitResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **putContainerArchive** +> putContainerArchive(id, path, inputStream, noOverwriteDirNonDir, copyUIDGID) + +Extract an archive of files or folders to a directory in a container + +Upload a tar archive to be extracted to a path in the filesystem of container id. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ContainerApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the container +val path : kotlin.String = path_example // kotlin.String | Path to a directory in the container to extract the archive’s contents into. +val inputStream : java.io.File = BINARY_DATA_HERE // java.io.File | The input stream must be a tar archive compressed with one of the following algorithms: `identity` (no compression), `gzip`, `bzip2`, or `xz`. +val noOverwriteDirNonDir : kotlin.String = noOverwriteDirNonDir_example // kotlin.String | If `1`, `true`, or `True` then it will be an error if unpacking the given content would cause an existing directory to be replaced with a non-directory and vice versa. +val copyUIDGID : kotlin.String = copyUIDGID_example // kotlin.String | If `1`, `true`, then it will copy UID/GID maps to the dest file or dir +try { + apiInstance.putContainerArchive(id, path, inputStream, noOverwriteDirNonDir, copyUIDGID) +} catch (e: ClientException) { + println("4xx response calling ContainerApi#putContainerArchive") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ContainerApi#putContainerArchive") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the container | + **path** | **kotlin.String**| Path to a directory in the container to extract the archive’s contents into. | + **inputStream** | **java.io.File**| The input stream must be a tar archive compressed with one of the following algorithms: `identity` (no compression), `gzip`, `bzip2`, or `xz`. | + **noOverwriteDirNonDir** | **kotlin.String**| If `1`, `true`, or `True` then it will be an error if unpacking the given content would cause an existing directory to be replaced with a non-directory and vice versa. | [optional] + **copyUIDGID** | **kotlin.String**| If `1`, `true`, then it will copy UID/GID maps to the dest file or dir | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/x-tar, application/octet-stream + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/DistributionApi.md b/engine-api/docs/DistributionApi.md new file mode 100644 index 000000000..a756dc5c9 --- /dev/null +++ b/engine-api/docs/DistributionApi.md @@ -0,0 +1,56 @@ +# DistributionApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**distributionInspect**](DistributionApi.md#distributionInspect) | **GET** /distribution/{name}/json | Get image information from the registry | ✅ + + + +# **distributionInspect** +> DistributionInspectResponse distributionInspect(name) + +Get image information from the registry + +Return image digest and platform information by contacting the registry. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = DistributionApi() +val name : kotlin.String = name_example // kotlin.String | Image name or id +try { + val result : DistributionInspectResponse = apiInstance.distributionInspect(name) + println(result) +} catch (e: ClientException) { + println("4xx response calling DistributionApi#distributionInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling DistributionApi#distributionInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Image name or id | + +### Return type + +[**DistributionInspectResponse**](DistributionInspectResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + diff --git a/engine-api/docs/ExecApi.md b/engine-api/docs/ExecApi.md new file mode 100644 index 000000000..4c768e536 --- /dev/null +++ b/engine-api/docs/ExecApi.md @@ -0,0 +1,206 @@ +# ExecApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**containerExec**](ExecApi.md#containerExec) | **POST** /containers/{id}/exec | Create an exec instance | ✅ +[**execInspect**](ExecApi.md#execInspect) | **GET** /exec/{id}/json | Inspect an exec instance | ✅ +[**execResize**](ExecApi.md#execResize) | **POST** /exec/{id}/resize | Resize an exec instance | ❌ +[**execStart**](ExecApi.md#execStart) | **POST** /exec/{id}/start | Start an exec instance | ✅ + + + +# **containerExec** +> IdResponse containerExec(id, execConfig) + +Create an exec instance + +Run a command inside a running container. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ExecApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of container +val execConfig : ExecConfig = // ExecConfig | +try { + val result : IdResponse = apiInstance.containerExec(id, execConfig) + println(result) +} catch (e: ClientException) { + println("4xx response calling ExecApi#containerExec") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ExecApi#containerExec") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of container | + **execConfig** | [**ExecConfig**](ExecConfig.md)| | + +### Return type + +[**IdResponse**](IdResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **execInspect** +> ExecInspectResponse execInspect(id) + +Inspect an exec instance + +Return low-level information about an exec instance. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ExecApi() +val id : kotlin.String = id_example // kotlin.String | Exec instance ID +try { + val result : ExecInspectResponse = apiInstance.execInspect(id) + println(result) +} catch (e: ClientException) { + println("4xx response calling ExecApi#execInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ExecApi#execInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| Exec instance ID | + +### Return type + +[**ExecInspectResponse**](ExecInspectResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **execResize** +> execResize(id, h, w) + +Resize an exec instance + +Resize the TTY session used by an exec instance. This endpoint only works if `tty` was specified as part of creating and starting the exec instance. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ExecApi() +val id : kotlin.String = id_example // kotlin.String | Exec instance ID +val h : kotlin.Int = 56 // kotlin.Int | Height of the TTY session in characters +val w : kotlin.Int = 56 // kotlin.Int | Width of the TTY session in characters +try { + apiInstance.execResize(id, h, w) +} catch (e: ClientException) { + println("4xx response calling ExecApi#execResize") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ExecApi#execResize") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| Exec instance ID | + **h** | **kotlin.Int**| Height of the TTY session in characters | [optional] + **w** | **kotlin.Int**| Width of the TTY session in characters | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **execStart** +> execStart(id, execStartConfig) + +Start an exec instance + +Starts a previously set up exec instance. If detach is true, this endpoint returns immediately after starting the command. Otherwise, it sets up an interactive session with the command. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ExecApi() +val id : kotlin.String = id_example // kotlin.String | Exec instance ID +val execStartConfig : ExecStartConfig = // ExecStartConfig | +try { + apiInstance.execStart(id, execStartConfig) +} catch (e: ClientException) { + println("4xx response calling ExecApi#execStart") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ExecApi#execStart") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| Exec instance ID | + **execStartConfig** | [**ExecStartConfig**](ExecStartConfig.md)| | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/vnd.docker.raw-stream + diff --git a/engine-api/docs/ImageApi.md b/engine-api/docs/ImageApi.md new file mode 100644 index 000000000..322b4530c --- /dev/null +++ b/engine-api/docs/ImageApi.md @@ -0,0 +1,825 @@ +# ImageApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**buildPrune**](ImageApi.md#buildPrune) | **POST** /build/prune | Delete builder cache | ✅ +[**imageBuild**](ImageApi.md#imageBuild) | **POST** /build | Build an image | ✅ +[**imageCommit**](ImageApi.md#imageCommit) | **POST** /commit | Create a new image from a container | ✅ +[**imageCreate**](ImageApi.md#imageCreate) | **POST** /images/create | Create an image | ✅ +[**imageDelete**](ImageApi.md#imageDelete) | **DELETE** /images/{name} | Remove an image | ✅ +[**imageGet**](ImageApi.md#imageGet) | **GET** /images/{name}/get | Export an image | ✅ +[**imageGetAll**](ImageApi.md#imageGetAll) | **GET** /images/get | Export several images | ✅ +[**imageHistory**](ImageApi.md#imageHistory) | **GET** /images/{name}/history | Get the history of an image | ✅ +[**imageInspect**](ImageApi.md#imageInspect) | **GET** /images/{name}/json | Inspect an image | ✅ +[**imageList**](ImageApi.md#imageList) | **GET** /images/json | List Images | ✅ +[**imageLoad**](ImageApi.md#imageLoad) | **POST** /images/load | Import images | ✅ +[**imagePrune**](ImageApi.md#imagePrune) | **POST** /images/prune | Delete unused images | ✅ +[**imagePush**](ImageApi.md#imagePush) | **POST** /images/{name}/push | Push an image | ✅ +[**imageSearch**](ImageApi.md#imageSearch) | **GET** /images/search | Search images | ✅ +[**imageTag**](ImageApi.md#imageTag) | **POST** /images/{name}/tag | Tag an image | ✅ + + + +# **buildPrune** +> BuildPruneResponse buildPrune(keepStorage, all, filters) + +Delete builder cache + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val keepStorage : kotlin.Long = 789 // kotlin.Long | Amount of disk space in bytes to keep for cache +val all : kotlin.Boolean = true // kotlin.Boolean | Remove all types of build cache +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the list of build cache objects. Available filters: - `until=`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h') - `id=` - `parent=` - `type=` - `description=` - `inuse` - `shared` - `private` +try { + val result : BuildPruneResponse = apiInstance.buildPrune(keepStorage, all, filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#buildPrune") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#buildPrune") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **keepStorage** | **kotlin.Long**| Amount of disk space in bytes to keep for cache | [optional] + **all** | **kotlin.Boolean**| Remove all types of build cache | [optional] + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the list of build cache objects. Available filters: - `until=<duration>`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h') - `id=<id>` - `parent=<id>` - `type=<string>` - `description=<string>` - `inuse` - `shared` - `private` | [optional] + +### Return type + +[**BuildPruneResponse**](BuildPruneResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **imageBuild** +> imageBuild(dockerfile, t, extrahosts, remote, q, nocache, cachefrom, pull, rm, forcerm, memory, memswap, cpushares, cpusetcpus, cpuperiod, cpuquota, buildargs, shmsize, squash, labels, networkmode, contentType, xRegistryConfig, platform, target, outputs, inputStream) + +Build an image + +Build an image from a tar archive with a `Dockerfile` in it. The `Dockerfile` specifies how the image is built from the tar archive. It is typically in the archive's root, but can be at a different path or have a different name by specifying the `dockerfile` parameter. [See the `Dockerfile` reference for more information](https://docs.docker.com/engine/reference/builder/). The Docker daemon performs a preliminary validation of the `Dockerfile` before starting the build, and returns an error if the syntax is incorrect. After that, each instruction is run one-by-one until the ID of the new image is output. The build is canceled if the client drops the connection by quitting or being killed. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val dockerfile : kotlin.String = dockerfile_example // kotlin.String | Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and points to an external `Dockerfile`. +val t : kotlin.String = t_example // kotlin.String | A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag the default `latest` value is assumed. You can provide several `t` parameters. +val extrahosts : kotlin.String = extrahosts_example // kotlin.String | Extra hosts to add to /etc/hosts +val remote : kotlin.String = remote_example // kotlin.String | A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file, the file’s contents are placed into a file called `Dockerfile` and the image is built from that file. If the URI points to a tarball, the file is downloaded by the daemon and the contents therein used as the context for the build. If the URI points to a tarball and the `dockerfile` parameter is also specified, there must be a file with the corresponding path inside the tarball. +val q : kotlin.Boolean = true // kotlin.Boolean | Suppress verbose build output. +val nocache : kotlin.Boolean = true // kotlin.Boolean | Do not use the cache when building the image. +val cachefrom : kotlin.String = cachefrom_example // kotlin.String | JSON array of images used for build cache resolution. +val pull : kotlin.String = pull_example // kotlin.String | Attempt to pull the image even if an older image exists locally. +val rm : kotlin.Boolean = true // kotlin.Boolean | Remove intermediate containers after a successful build. +val forcerm : kotlin.Boolean = true // kotlin.Boolean | Always remove intermediate containers, even upon failure. +val memory : kotlin.Int = 56 // kotlin.Int | Set memory limit for build. +val memswap : kotlin.Int = 56 // kotlin.Int | Total memory (memory + swap). Set as `-1` to disable swap. +val cpushares : kotlin.Int = 56 // kotlin.Int | CPU shares (relative weight). +val cpusetcpus : kotlin.String = cpusetcpus_example // kotlin.String | CPUs in which to allow execution (e.g., `0-3`, `0,1`). +val cpuperiod : kotlin.Int = 56 // kotlin.Int | The length of a CPU period in microseconds. +val cpuquota : kotlin.Int = 56 // kotlin.Int | Microseconds of CPU time that the container can get in a CPU period. +val buildargs : kotlin.String = buildargs_example // kotlin.String | JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. For example, the build arg `FOO=bar` would become `{\"FOO\":\"bar\"}` in JSON. This would result in the query parameter `buildargs={\"FOO\":\"bar\"}`. Note that `{\"FOO\":\"bar\"}` should be URI component encoded. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg) +val shmsize : kotlin.Int = 56 // kotlin.Int | Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB. +val squash : kotlin.Boolean = true // kotlin.Boolean | Squash the resulting images layers into a single layer. *(Experimental release only.)* +val labels : kotlin.String = labels_example // kotlin.String | Arbitrary key/value labels to set on the image, as a JSON map of string pairs. +val networkmode : kotlin.String = networkmode_example // kotlin.String | Sets the networking mode for the run commands during build. Supported standard values are: `bridge`, `host`, `none`, and `container:`. Any other value is taken as a custom network's name or ID to which this container should connect to. +val contentType : kotlin.String = contentType_example // kotlin.String | +val xRegistryConfig : kotlin.String = xRegistryConfig_example // kotlin.String | This is a base64-encoded JSON object with auth configurations for multiple registries that a build may refer to. The key is a registry URL, and the value is an auth configuration object, [as described in the authentication section](#section/Authentication). For example: ``` { \"docker.example.com\": { \"username\": \"janedoe\", \"password\": \"hunter2\" }, \"https://index.docker.io/v1/\": { \"username\": \"mobydock\", \"password\": \"conta1n3rize14\" } } ``` Only the registry domain name (and port if not the default 443) are required. However, for legacy reasons, the Docker Hub registry must be specified with both a `https://` prefix and a `/v1/` suffix even though Docker will prefer to use the v2 registry API. +val platform : kotlin.String = platform_example // kotlin.String | Platform in the format os[/arch[/variant]] +val target : kotlin.String = target_example // kotlin.String | Target build stage +val outputs : kotlin.String = outputs_example // kotlin.String | BuildKit output configuration +val inputStream : java.io.File = BINARY_DATA_HERE // java.io.File | A tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. +try { + apiInstance.imageBuild(dockerfile, t, extrahosts, remote, q, nocache, cachefrom, pull, rm, forcerm, memory, memswap, cpushares, cpusetcpus, cpuperiod, cpuquota, buildargs, shmsize, squash, labels, networkmode, contentType, xRegistryConfig, platform, target, outputs, inputStream) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageBuild") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageBuild") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **dockerfile** | **kotlin.String**| Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and points to an external `Dockerfile`. | [optional] [default to "Dockerfile"] + **t** | **kotlin.String**| A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag the default `latest` value is assumed. You can provide several `t` parameters. | [optional] + **extrahosts** | **kotlin.String**| Extra hosts to add to /etc/hosts | [optional] + **remote** | **kotlin.String**| A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file, the file’s contents are placed into a file called `Dockerfile` and the image is built from that file. If the URI points to a tarball, the file is downloaded by the daemon and the contents therein used as the context for the build. If the URI points to a tarball and the `dockerfile` parameter is also specified, there must be a file with the corresponding path inside the tarball. | [optional] + **q** | **kotlin.Boolean**| Suppress verbose build output. | [optional] [default to false] + **nocache** | **kotlin.Boolean**| Do not use the cache when building the image. | [optional] [default to false] + **cachefrom** | **kotlin.String**| JSON array of images used for build cache resolution. | [optional] + **pull** | **kotlin.String**| Attempt to pull the image even if an older image exists locally. | [optional] + **rm** | **kotlin.Boolean**| Remove intermediate containers after a successful build. | [optional] [default to true] + **forcerm** | **kotlin.Boolean**| Always remove intermediate containers, even upon failure. | [optional] [default to false] + **memory** | **kotlin.Int**| Set memory limit for build. | [optional] + **memswap** | **kotlin.Int**| Total memory (memory + swap). Set as `-1` to disable swap. | [optional] + **cpushares** | **kotlin.Int**| CPU shares (relative weight). | [optional] + **cpusetcpus** | **kotlin.String**| CPUs in which to allow execution (e.g., `0-3`, `0,1`). | [optional] + **cpuperiod** | **kotlin.Int**| The length of a CPU period in microseconds. | [optional] + **cpuquota** | **kotlin.Int**| Microseconds of CPU time that the container can get in a CPU period. | [optional] + **buildargs** | **kotlin.String**| JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. For example, the build arg `FOO=bar` would become `{\"FOO\":\"bar\"}` in JSON. This would result in the query parameter `buildargs={\"FOO\":\"bar\"}`. Note that `{\"FOO\":\"bar\"}` should be URI component encoded. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg) | [optional] + **shmsize** | **kotlin.Int**| Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB. | [optional] + **squash** | **kotlin.Boolean**| Squash the resulting images layers into a single layer. *(Experimental release only.)* | [optional] + **labels** | **kotlin.String**| Arbitrary key/value labels to set on the image, as a JSON map of string pairs. | [optional] + **networkmode** | **kotlin.String**| Sets the networking mode for the run commands during build. Supported standard values are: `bridge`, `host`, `none`, and `container:<name|id>`. Any other value is taken as a custom network's name or ID to which this container should connect to. | [optional] + **contentType** | **kotlin.String**| | [optional] [default to application/x-tar] [enum: application/x-tar] + **xRegistryConfig** | **kotlin.String**| This is a base64-encoded JSON object with auth configurations for multiple registries that a build may refer to. The key is a registry URL, and the value is an auth configuration object, [as described in the authentication section](#section/Authentication). For example: ``` { \"docker.example.com\": { \"username\": \"janedoe\", \"password\": \"hunter2\" }, \"https://index.docker.io/v1/\": { \"username\": \"mobydock\", \"password\": \"conta1n3rize14\" } } ``` Only the registry domain name (and port if not the default 443) are required. However, for legacy reasons, the Docker Hub registry must be specified with both a `https://` prefix and a `/v1/` suffix even though Docker will prefer to use the v2 registry API. | [optional] + **platform** | **kotlin.String**| Platform in the format os[/arch[/variant]] | [optional] + **target** | **kotlin.String**| Target build stage | [optional] + **outputs** | **kotlin.String**| BuildKit output configuration | [optional] + **inputStream** | **java.io.File**| A tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/octet-stream + - **Accept**: application/json + + +# **imageCommit** +> IdResponse imageCommit(container, repo, tag, comment, author, pause, changes, containerConfig) + +Create a new image from a container + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val container : kotlin.String = container_example // kotlin.String | The ID or name of the container to commit +val repo : kotlin.String = repo_example // kotlin.String | Repository name for the created image +val tag : kotlin.String = tag_example // kotlin.String | Tag name for the create image +val comment : kotlin.String = comment_example // kotlin.String | Commit message +val author : kotlin.String = author_example // kotlin.String | Author of the image (e.g., `John Hannibal Smith `) +val pause : kotlin.Boolean = true // kotlin.Boolean | Whether to pause the container before committing +val changes : kotlin.String = changes_example // kotlin.String | `Dockerfile` instructions to apply while committing +val containerConfig : ContainerConfig = // ContainerConfig | The container configuration +try { + val result : IdResponse = apiInstance.imageCommit(container, repo, tag, comment, author, pause, changes, containerConfig) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageCommit") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageCommit") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **container** | **kotlin.String**| The ID or name of the container to commit | [optional] + **repo** | **kotlin.String**| Repository name for the created image | [optional] + **tag** | **kotlin.String**| Tag name for the create image | [optional] + **comment** | **kotlin.String**| Commit message | [optional] + **author** | **kotlin.String**| Author of the image (e.g., `John Hannibal Smith <hannibal@a-team.com>`) | [optional] + **pause** | **kotlin.Boolean**| Whether to pause the container before committing | [optional] [default to true] + **changes** | **kotlin.String**| `Dockerfile` instructions to apply while committing | [optional] + **containerConfig** | [**ContainerConfig**](ContainerConfig.md)| The container configuration | [optional] + +### Return type + +[**IdResponse**](IdResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **imageCreate** +> imageCreate(fromImage, fromSrc, repo, tag, message, xRegistryAuth, changes, platform, inputImage) + +Create an image + +Create an image by either pulling it from a registry or importing it. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val fromImage : kotlin.String = fromImage_example // kotlin.String | Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed. +val fromSrc : kotlin.String = fromSrc_example // kotlin.String | Source to import. The value may be a URL from which the image can be retrieved or `-` to read the image from the request body. This parameter may only be used when importing an image. +val repo : kotlin.String = repo_example // kotlin.String | Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image. +val tag : kotlin.String = tag_example // kotlin.String | Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled. +val message : kotlin.String = message_example // kotlin.String | Set commit message for imported image. +val xRegistryAuth : kotlin.String = xRegistryAuth_example // kotlin.String | A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. +val changes : kotlin.collections.List = // kotlin.collections.List | Apply Dockerfile instruction to the created image. +val platform : kotlin.String = platform_example // kotlin.String | Platform in the format os[/arch[/variant]] +val inputImage : kotlin.String = inputImage_example // kotlin.String | Image content if the value `-` has been specified in fromSrc query parameter +try { + apiInstance.imageCreate(fromImage, fromSrc, repo, tag, message, xRegistryAuth, changes, platform, inputImage) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **fromImage** | **kotlin.String**| Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed. | [optional] + **fromSrc** | **kotlin.String**| Source to import. The value may be a URL from which the image can be retrieved or `-` to read the image from the request body. This parameter may only be used when importing an image. | [optional] + **repo** | **kotlin.String**| Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image. | [optional] + **tag** | **kotlin.String**| Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled. | [optional] + **message** | **kotlin.String**| Set commit message for imported image. | [optional] + **xRegistryAuth** | **kotlin.String**| A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. | [optional] + **changes** | [**kotlin.collections.List<kotlin.String>**](kotlin.String.md)| Apply Dockerfile instruction to the created image. | [optional] + **platform** | **kotlin.String**| Platform in the format os[/arch[/variant]] | [optional] + **inputImage** | **kotlin.String**| Image content if the value `-` has been specified in fromSrc query parameter | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: text/plain, application/octet-stream + - **Accept**: application/json + + +# **imageDelete** +> kotlin.collections.List<ImageDeleteResponseItem> imageDelete(name, force, noprune) + +Remove an image + +Remove an image, along with any untagged parent images that were referenced by that image. Images can't be removed if they have descendant images, are being used by a running container or are being used by a build. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val name : kotlin.String = name_example // kotlin.String | Image name or ID +val force : kotlin.Boolean = true // kotlin.Boolean | Remove the image even if it is being used by stopped containers or has other tags +val noprune : kotlin.Boolean = true // kotlin.Boolean | Do not delete untagged parent images +try { + val result : kotlin.collections.List = apiInstance.imageDelete(name, force, noprune) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Image name or ID | + **force** | **kotlin.Boolean**| Remove the image even if it is being used by stopped containers or has other tags | [optional] [default to false] + **noprune** | **kotlin.Boolean**| Do not delete untagged parent images | [optional] [default to false] + +### Return type + +[**kotlin.collections.List<ImageDeleteResponseItem>**](ImageDeleteResponseItem.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **imageGet** +> java.io.File imageGet(name) + +Export an image + +Get a tarball containing all images and metadata for a repository. If `name` is a specific name and tag (e.g. `ubuntu:latest`), then only that image (and its parents) are returned. If `name` is an image ID, similarly only that image (and its parents) are returned, but with the exclusion of the `repositories` file in the tarball, as there were no image names referenced. ### Image tarball format An image tarball contains one directory per image layer (named using its long ID), each containing these files: - `VERSION`: currently `1.0` - the file format version - `json`: detailed layer information, similar to `docker inspect layer_id` - `layer.tar`: A tarfile containing the filesystem changes in this layer The `layer.tar` file contains `aufs` style `.wh..wh.aufs` files and directories for storing attribute changes and deletions. If the tarball defines a repository, the tarball should also include a `repositories` file at the root that contains a list of repository and tag names mapped to layer IDs. ```json { \"hello-world\": { \"latest\": \"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1\" } } ``` + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val name : kotlin.String = name_example // kotlin.String | Image name or ID +try { + val result : java.io.File = apiInstance.imageGet(name) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageGet") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageGet") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Image name or ID | + +### Return type + +[**java.io.File**](java.io.File.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/x-tar + + +# **imageGetAll** +> java.io.File imageGetAll(names) + +Export several images + +Get a tarball containing all images and metadata for several image repositories. For each value of the `names` parameter: if it is a specific name and tag (e.g. `ubuntu:latest`), then only that image (and its parents) are returned; if it is an image ID, similarly only that image (and its parents) are returned and there would be no names referenced in the 'repositories' file for this image ID. For details on the format, see the [export image endpoint](#operation/ImageGet). + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val names : kotlin.collections.List = // kotlin.collections.List | Image names to filter by +try { + val result : java.io.File = apiInstance.imageGetAll(names) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageGetAll") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageGetAll") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **names** | [**kotlin.collections.List<kotlin.String>**](kotlin.String.md)| Image names to filter by | [optional] + +### Return type + +[**java.io.File**](java.io.File.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/x-tar + + +# **imageHistory** +> kotlin.collections.List<HistoryResponseItem> imageHistory(name) + +Get the history of an image + +Return parent layers of an image. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val name : kotlin.String = name_example // kotlin.String | Image name or ID +try { + val result : kotlin.collections.List = apiInstance.imageHistory(name) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageHistory") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageHistory") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Image name or ID | + +### Return type + +[**kotlin.collections.List<HistoryResponseItem>**](HistoryResponseItem.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **imageInspect** +> Image imageInspect(name) + +Inspect an image + +Return low-level information about an image. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val name : kotlin.String = name_example // kotlin.String | Image name or id +try { + val result : Image = apiInstance.imageInspect(name) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Image name or id | + +### Return type + +[**Image**](Image.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **imageList** +> kotlin.collections.List<ImageSummary> imageList(all, filters, digests) + +List Images + +Returns a list of images on the server. Note that it uses a different, smaller representation of an image than inspecting a single image. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val all : kotlin.Boolean = true // kotlin.Boolean | Show all images. Only images from a final layer (no children) are shown by default. +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `before`=(`[:]`, `` or ``) - `dangling=true` - `label=key` or `label=\"key=value\"` of an image label - `reference`=(`[:]`) - `since`=(`[:]`, `` or ``) +val digests : kotlin.Boolean = true // kotlin.Boolean | Show digest information as a `RepoDigests` field on each image. +try { + val result : kotlin.collections.List = apiInstance.imageList(all, filters, digests) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **all** | **kotlin.Boolean**| Show all images. Only images from a final layer (no children) are shown by default. | [optional] [default to false] + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - `dangling=true` - `label=key` or `label=\"key=value\"` of an image label - `reference`=(`<image-name>[:<tag>]`) - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) | [optional] + **digests** | **kotlin.Boolean**| Show digest information as a `RepoDigests` field on each image. | [optional] [default to false] + +### Return type + +[**kotlin.collections.List<ImageSummary>**](ImageSummary.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **imageLoad** +> imageLoad(quiet, imagesTarball) + +Import images + +Load a set of images and tags into a repository. For details on the format, see the [export image endpoint](#operation/ImageGet). + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val quiet : kotlin.Boolean = true // kotlin.Boolean | Suppress progress details during load. +val imagesTarball : java.io.File = BINARY_DATA_HERE // java.io.File | Tar archive containing images +try { + apiInstance.imageLoad(quiet, imagesTarball) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageLoad") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageLoad") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **quiet** | **kotlin.Boolean**| Suppress progress details during load. | [optional] [default to false] + **imagesTarball** | **java.io.File**| Tar archive containing images | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/x-tar + - **Accept**: application/json + + +# **imagePrune** +> ImagePruneResponse imagePrune(filters) + +Delete unused images + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val filters : kotlin.String = filters_example // kotlin.String | Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `dangling=` When set to `true` (or `1`), prune only unused *and* untagged images. When set to `false` (or `0`), all unused images are pruned. - `until=` Prune images created before this timestamp. The `` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune images with (or without, in case `label!=...` is used) the specified labels. +try { + val result : ImagePruneResponse = apiInstance.imagePrune(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imagePrune") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imagePrune") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `dangling=<boolean>` When set to `true` (or `1`), prune only unused *and* untagged images. When set to `false` (or `0`), all unused images are pruned. - `until=<string>` Prune images created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune images with (or without, in case `label!=...` is used) the specified labels. | [optional] + +### Return type + +[**ImagePruneResponse**](ImagePruneResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **imagePush** +> imagePush(name, xRegistryAuth, tag) + +Push an image + +Push an image to a registry. If you wish to push an image on to a private registry, that image must already have a tag which references the registry. For example, `registry.example.com/myimage:latest`. The push is cancelled if the HTTP connection is closed. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val name : kotlin.String = name_example // kotlin.String | Image name or ID. +val xRegistryAuth : kotlin.String = xRegistryAuth_example // kotlin.String | A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. +val tag : kotlin.String = tag_example // kotlin.String | The tag to associate with the image on the registry. +try { + apiInstance.imagePush(name, xRegistryAuth, tag) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imagePush") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imagePush") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Image name or ID. | + **xRegistryAuth** | **kotlin.String**| A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. | + **tag** | **kotlin.String**| The tag to associate with the image on the registry. | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **imageSearch** +> kotlin.collections.List<ImageSearchResponseItem> imageSearch(term, limit, filters) + +Search images + +Search for an image on Docker Hub. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val term : kotlin.String = term_example // kotlin.String | Term to search +val limit : kotlin.Int = 56 // kotlin.Int | Maximum number of results to return +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `is-automated=(true|false)` - `is-official=(true|false)` - `stars=` Matches images that has at least 'number' stars. +try { + val result : kotlin.collections.List = apiInstance.imageSearch(term, limit, filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageSearch") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageSearch") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **term** | **kotlin.String**| Term to search | + **limit** | **kotlin.Int**| Maximum number of results to return | [optional] + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `is-automated=(true|false)` - `is-official=(true|false)` - `stars=<number>` Matches images that has at least 'number' stars. | [optional] + +### Return type + +[**kotlin.collections.List<ImageSearchResponseItem>**](ImageSearchResponseItem.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **imageTag** +> imageTag(name, repo, tag) + +Tag an image + +Tag an image so that it becomes part of a repository. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ImageApi() +val name : kotlin.String = name_example // kotlin.String | Image name or ID to tag. +val repo : kotlin.String = repo_example // kotlin.String | The repository to tag in. For example, `someuser/someimage`. +val tag : kotlin.String = tag_example // kotlin.String | The name of the new tag. +try { + apiInstance.imageTag(name, repo, tag) +} catch (e: ClientException) { + println("4xx response calling ImageApi#imageTag") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ImageApi#imageTag") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Image name or ID to tag. | + **repo** | **kotlin.String**| The repository to tag in. For example, `someuser/someimage`. | [optional] + **tag** | **kotlin.String**| The name of the new tag. | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/NetworkApi.md b/engine-api/docs/NetworkApi.md new file mode 100644 index 000000000..04a20eff9 --- /dev/null +++ b/engine-api/docs/NetworkApi.md @@ -0,0 +1,337 @@ +# NetworkApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**networkConnect**](NetworkApi.md#networkConnect) | **POST** /networks/{id}/connect | Connect a container to a network | ✅ +[**networkCreate**](NetworkApi.md#networkCreate) | **POST** /networks/create | Create a network | ✅ +[**networkDelete**](NetworkApi.md#networkDelete) | **DELETE** /networks/{id} | Remove a network | ✅ +[**networkDisconnect**](NetworkApi.md#networkDisconnect) | **POST** /networks/{id}/disconnect | Disconnect a container from a network | ✅ +[**networkInspect**](NetworkApi.md#networkInspect) | **GET** /networks/{id} | Inspect a network | ✅ +[**networkList**](NetworkApi.md#networkList) | **GET** /networks | List networks | ✅ +[**networkPrune**](NetworkApi.md#networkPrune) | **POST** /networks/prune | Delete unused networks | ✅ + + + +# **networkConnect** +> networkConnect(id, container) + +Connect a container to a network + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NetworkApi() +val id : kotlin.String = id_example // kotlin.String | Network ID or name +val container : NetworkConnectRequest = // NetworkConnectRequest | +try { + apiInstance.networkConnect(id, container) +} catch (e: ClientException) { + println("4xx response calling NetworkApi#networkConnect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NetworkApi#networkConnect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| Network ID or name | + **container** | [**NetworkConnectRequest**](NetworkConnectRequest.md)| | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json, text/plain + + +# **networkCreate** +> NetworkCreateResponse networkCreate(networkConfig) + +Create a network + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NetworkApi() +val networkConfig : NetworkCreateRequest = // NetworkCreateRequest | +try { + val result : NetworkCreateResponse = apiInstance.networkCreate(networkConfig) + println(result) +} catch (e: ClientException) { + println("4xx response calling NetworkApi#networkCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NetworkApi#networkCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **networkConfig** | [**NetworkCreateRequest**](NetworkCreateRequest.md)| | + +### Return type + +[**NetworkCreateResponse**](NetworkCreateResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **networkDelete** +> networkDelete(id) + +Remove a network + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NetworkApi() +val id : kotlin.String = id_example // kotlin.String | Network ID or name +try { + apiInstance.networkDelete(id) +} catch (e: ClientException) { + println("4xx response calling NetworkApi#networkDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NetworkApi#networkDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| Network ID or name | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **networkDisconnect** +> networkDisconnect(id, container) + +Disconnect a container from a network + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NetworkApi() +val id : kotlin.String = id_example // kotlin.String | Network ID or name +val container : NetworkDisconnectRequest = // NetworkDisconnectRequest | +try { + apiInstance.networkDisconnect(id, container) +} catch (e: ClientException) { + println("4xx response calling NetworkApi#networkDisconnect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NetworkApi#networkDisconnect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| Network ID or name | + **container** | [**NetworkDisconnectRequest**](NetworkDisconnectRequest.md)| | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json, text/plain + + +# **networkInspect** +> Network networkInspect(id, verbose, scope) + +Inspect a network + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NetworkApi() +val id : kotlin.String = id_example // kotlin.String | Network ID or name +val verbose : kotlin.Boolean = true // kotlin.Boolean | Detailed inspect output for troubleshooting +val scope : kotlin.String = scope_example // kotlin.String | Filter the network by scope (swarm, global, or local) +try { + val result : Network = apiInstance.networkInspect(id, verbose, scope) + println(result) +} catch (e: ClientException) { + println("4xx response calling NetworkApi#networkInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NetworkApi#networkInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| Network ID or name | + **verbose** | **kotlin.Boolean**| Detailed inspect output for troubleshooting | [optional] [default to false] + **scope** | **kotlin.String**| Filter the network by scope (swarm, global, or local) | [optional] + +### Return type + +[**Network**](Network.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **networkList** +> kotlin.collections.List<Network> networkList(filters) + +List networks + +Returns a list of networks. For details on the format, see the [network inspect endpoint](#operation/NetworkInspect). Note that it uses a different, smaller representation of a network than inspecting a single network. For example, the list of containers attached to the network is not propagated in API versions 1.28 and up. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NetworkApi() +val filters : kotlin.String = filters_example // kotlin.String | JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters: - `dangling=` When set to `true` (or `1`), returns all networks that are not in use by a container. When set to `false` (or `0`), only networks that are in use by one or more containers are returned. - `driver=` Matches a network's driver. - `id=` Matches all or part of a network ID. - `label=` or `label==` of a network label. - `name=` Matches all or part of a network name. - `scope=[\"swarm\"|\"global\"|\"local\"]` Filters networks by scope (`swarm`, `global`, or `local`). - `type=[\"custom\"|\"builtin\"]` Filters networks by type. The `custom` keyword returns all user-defined networks. +try { + val result : kotlin.collections.List = apiInstance.networkList(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling NetworkApi#networkList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NetworkApi#networkList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters: - `dangling=<boolean>` When set to `true` (or `1`), returns all networks that are not in use by a container. When set to `false` (or `0`), only networks that are in use by one or more containers are returned. - `driver=<driver-name>` Matches a network's driver. - `id=<network-id>` Matches all or part of a network ID. - `label=<key>` or `label=<key>=<value>` of a network label. - `name=<network-name>` Matches all or part of a network name. - `scope=[\"swarm\"|\"global\"|\"local\"]` Filters networks by scope (`swarm`, `global`, or `local`). - `type=[\"custom\"|\"builtin\"]` Filters networks by type. The `custom` keyword returns all user-defined networks. | [optional] + +### Return type + +[**kotlin.collections.List<Network>**](Network.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **networkPrune** +> NetworkPruneResponse networkPrune(filters) + +Delete unused networks + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NetworkApi() +val filters : kotlin.String = filters_example // kotlin.String | Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=` Prune networks created before this timestamp. The `` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune networks with (or without, in case `label!=...` is used) the specified labels. +try { + val result : NetworkPruneResponse = apiInstance.networkPrune(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling NetworkApi#networkPrune") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NetworkApi#networkPrune") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=<timestamp>` Prune networks created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune networks with (or without, in case `label!=...` is used) the specified labels. | [optional] + +### Return type + +[**NetworkPruneResponse**](NetworkPruneResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + diff --git a/engine-api/docs/NodeApi.md b/engine-api/docs/NodeApi.md new file mode 100644 index 000000000..76c636233 --- /dev/null +++ b/engine-api/docs/NodeApi.md @@ -0,0 +1,196 @@ +# NodeApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**nodeDelete**](NodeApi.md#nodeDelete) | **DELETE** /nodes/{id} | Delete a node | ✅ +[**nodeInspect**](NodeApi.md#nodeInspect) | **GET** /nodes/{id} | Inspect a node | ✅ +[**nodeList**](NodeApi.md#nodeList) | **GET** /nodes | List nodes | ✅ +[**nodeUpdate**](NodeApi.md#nodeUpdate) | **POST** /nodes/{id}/update | Update a node | ✅ + + + +# **nodeDelete** +> nodeDelete(id, force) + +Delete a node + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NodeApi() +val id : kotlin.String = id_example // kotlin.String | The ID or name of the node +val force : kotlin.Boolean = true // kotlin.Boolean | Force remove a node from the swarm +try { + apiInstance.nodeDelete(id, force) +} catch (e: ClientException) { + println("4xx response calling NodeApi#nodeDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NodeApi#nodeDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| The ID or name of the node | + **force** | **kotlin.Boolean**| Force remove a node from the swarm | [optional] [default to false] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **nodeInspect** +> Node nodeInspect(id) + +Inspect a node + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NodeApi() +val id : kotlin.String = id_example // kotlin.String | The ID or name of the node +try { + val result : Node = apiInstance.nodeInspect(id) + println(result) +} catch (e: ClientException) { + println("4xx response calling NodeApi#nodeInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NodeApi#nodeInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| The ID or name of the node | + +### Return type + +[**Node**](Node.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **nodeList** +> kotlin.collections.List<Node> nodeList(filters) + +List nodes + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NodeApi() +val filters : kotlin.String = filters_example // kotlin.String | Filters to process on the nodes list, encoded as JSON (a `map[string][]string`). Available filters: - `id=` - `label=` - `membership=`(`accepted`|`pending`)` - `name=` - `node.label=` - `role=`(`manager`|`worker`)` +try { + val result : kotlin.collections.List = apiInstance.nodeList(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling NodeApi#nodeList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NodeApi#nodeList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| Filters to process on the nodes list, encoded as JSON (a `map[string][]string`). Available filters: - `id=<node id>` - `label=<engine label>` - `membership=`(`accepted`|`pending`)` - `name=<node name>` - `node.label=<node label>` - `role=`(`manager`|`worker`)` | [optional] + +### Return type + +[**kotlin.collections.List<Node>**](Node.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **nodeUpdate** +> nodeUpdate(id, version, body) + +Update a node + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = NodeApi() +val id : kotlin.String = id_example // kotlin.String | The ID of the node +val version : kotlin.Long = 789 // kotlin.Long | The version number of the node object being updated. This is required to avoid conflicting writes. +val body : NodeSpec = // NodeSpec | +try { + apiInstance.nodeUpdate(id, version, body) +} catch (e: ClientException) { + println("4xx response calling NodeApi#nodeUpdate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling NodeApi#nodeUpdate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| The ID of the node | + **version** | **kotlin.Long**| The version number of the node object being updated. This is required to avoid conflicting writes. | + **body** | [**NodeSpec**](NodeSpec.md)| | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/PluginApi.md b/engine-api/docs/PluginApi.md new file mode 100644 index 000000000..b74b6c3de --- /dev/null +++ b/engine-api/docs/PluginApi.md @@ -0,0 +1,533 @@ +# PluginApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**getPluginPrivileges**](PluginApi.md#getPluginPrivileges) | **GET** /plugins/privileges | Get plugin privileges | ✅ +[**pluginCreate**](PluginApi.md#pluginCreate) | **POST** /plugins/create | Create a plugin | ❌ +[**pluginDelete**](PluginApi.md#pluginDelete) | **DELETE** /plugins/{name} | Remove a plugin | ❌ +[**pluginDisable**](PluginApi.md#pluginDisable) | **POST** /plugins/{name}/disable | Disable a plugin | ❌ +[**pluginEnable**](PluginApi.md#pluginEnable) | **POST** /plugins/{name}/enable | Enable a plugin | ❌ +[**pluginInspect**](PluginApi.md#pluginInspect) | **GET** /plugins/{name}/json | Inspect a plugin | ❌ +[**pluginList**](PluginApi.md#pluginList) | **GET** /plugins | List plugins | ✅ +[**pluginPull**](PluginApi.md#pluginPull) | **POST** /plugins/pull | Install a plugin | ❌ +[**pluginPush**](PluginApi.md#pluginPush) | **POST** /plugins/{name}/push | Push a plugin | ❌ +[**pluginSet**](PluginApi.md#pluginSet) | **POST** /plugins/{name}/set | Configure a plugin | ❌ +[**pluginUpgrade**](PluginApi.md#pluginUpgrade) | **POST** /plugins/{name}/upgrade | Upgrade a plugin | ❌ + + + +# **getPluginPrivileges** +> kotlin.collections.List<PluginPrivilegeItem> getPluginPrivileges(remote) + +Get plugin privileges + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val remote : kotlin.String = remote_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +try { + val result : kotlin.collections.List = apiInstance.getPluginPrivileges(remote) + println(result) +} catch (e: ClientException) { + println("4xx response calling PluginApi#getPluginPrivileges") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#getPluginPrivileges") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **remote** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + +### Return type + +[**kotlin.collections.List<PluginPrivilegeItem>**](PluginPrivilegeItem.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **pluginCreate** +> pluginCreate(name, tarContext) + +Create a plugin + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +val tarContext : java.io.File = BINARY_DATA_HERE // java.io.File | Path to tar containing plugin rootfs and manifest +try { + apiInstance.pluginCreate(name, tarContext) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + **tarContext** | **java.io.File**| Path to tar containing plugin rootfs and manifest | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/x-tar + - **Accept**: application/json, text/plain + + +# **pluginDelete** +> Plugin pluginDelete(name, force) + +Remove a plugin + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +val force : kotlin.Boolean = true // kotlin.Boolean | Disable the plugin before removing. This may result in issues if the plugin is in use by a container. +try { + val result : Plugin = apiInstance.pluginDelete(name, force) + println(result) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + **force** | **kotlin.Boolean**| Disable the plugin before removing. This may result in issues if the plugin is in use by a container. | [optional] [default to false] + +### Return type + +[**Plugin**](Plugin.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **pluginDisable** +> pluginDisable(name) + +Disable a plugin + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +try { + apiInstance.pluginDisable(name) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginDisable") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginDisable") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **pluginEnable** +> pluginEnable(name, timeout) + +Enable a plugin + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +val timeout : kotlin.Int = 56 // kotlin.Int | Set the HTTP client timeout (in seconds) +try { + apiInstance.pluginEnable(name, timeout) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginEnable") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginEnable") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + **timeout** | **kotlin.Int**| Set the HTTP client timeout (in seconds) | [optional] [default to 0] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **pluginInspect** +> Plugin pluginInspect(name) + +Inspect a plugin + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +try { + val result : Plugin = apiInstance.pluginInspect(name) + println(result) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + +### Return type + +[**Plugin**](Plugin.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **pluginList** +> kotlin.collections.List<Plugin> pluginList(filters) + +List plugins + +Returns information about installed plugins. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the plugin list. Available filters: - `capability=` - `enable=|` +try { + val result : kotlin.collections.List = apiInstance.pluginList(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the plugin list. Available filters: - `capability=<capability name>` - `enable=<true>|<false>` | [optional] + +### Return type + +[**kotlin.collections.List<Plugin>**](Plugin.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **pluginPull** +> pluginPull(remote, name, xRegistryAuth, body) + +Install a plugin + +Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PostPluginsEnable). + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val remote : kotlin.String = remote_example // kotlin.String | Remote reference for plugin to install. The `:latest` tag is optional, and is used as the default if omitted. +val name : kotlin.String = name_example // kotlin.String | Local name for the pulled plugin. The `:latest` tag is optional, and is used as the default if omitted. +val xRegistryAuth : kotlin.String = xRegistryAuth_example // kotlin.String | A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. +val body : kotlin.collections.List = // kotlin.collections.List | +try { + apiInstance.pluginPull(remote, name, xRegistryAuth, body) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginPull") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginPull") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **remote** | **kotlin.String**| Remote reference for plugin to install. The `:latest` tag is optional, and is used as the default if omitted. | + **name** | **kotlin.String**| Local name for the pulled plugin. The `:latest` tag is optional, and is used as the default if omitted. | [optional] + **xRegistryAuth** | **kotlin.String**| A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. | [optional] + **body** | [**kotlin.collections.List<PluginPrivilegeItem>**](PluginPrivilegeItem.md)| | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json + + +# **pluginPush** +> pluginPush(name) + +Push a plugin + +Push a plugin to the registry. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +try { + apiInstance.pluginPush(name) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginPush") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginPush") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **pluginSet** +> pluginSet(name, body) + +Configure a plugin + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +val body : kotlin.collections.List = // kotlin.collections.List | +try { + apiInstance.pluginSet(name, body) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginSet") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginSet") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + **body** | [**kotlin.collections.List<kotlin.String>**](kotlin.String.md)| | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json, text/plain + + +# **pluginUpgrade** +> pluginUpgrade(name, remote, xRegistryAuth, body) + +Upgrade a plugin + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = PluginApi() +val name : kotlin.String = name_example // kotlin.String | The name of the plugin. The `:latest` tag is optional, and is the default if omitted. +val remote : kotlin.String = remote_example // kotlin.String | Remote reference to upgrade to. The `:latest` tag is optional, and is used as the default if omitted. +val xRegistryAuth : kotlin.String = xRegistryAuth_example // kotlin.String | A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. +val body : kotlin.collections.List = // kotlin.collections.List | +try { + apiInstance.pluginUpgrade(name, remote, xRegistryAuth, body) +} catch (e: ClientException) { + println("4xx response calling PluginApi#pluginUpgrade") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling PluginApi#pluginUpgrade") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| The name of the plugin. The `:latest` tag is optional, and is the default if omitted. | + **remote** | **kotlin.String**| Remote reference to upgrade to. The `:latest` tag is optional, and is used as the default if omitted. | + **xRegistryAuth** | **kotlin.String**| A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. | [optional] + **body** | [**kotlin.collections.List<PluginPrivilegeItem>**](PluginPrivilegeItem.md)| | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/SecretApi.md b/engine-api/docs/SecretApi.md new file mode 100644 index 000000000..89c27ec51 --- /dev/null +++ b/engine-api/docs/SecretApi.md @@ -0,0 +1,240 @@ +# SecretApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**secretCreate**](SecretApi.md#secretCreate) | **POST** /secrets/create | Create a secret | ✅ +[**secretDelete**](SecretApi.md#secretDelete) | **DELETE** /secrets/{id} | Delete a secret | ✅ +[**secretInspect**](SecretApi.md#secretInspect) | **GET** /secrets/{id} | Inspect a secret | ✅ +[**secretList**](SecretApi.md#secretList) | **GET** /secrets | List secrets | ✅ +[**secretUpdate**](SecretApi.md#secretUpdate) | **POST** /secrets/{id}/update | Update a Secret | ✅ + + + +# **secretCreate** +> IdResponse secretCreate(body) + +Create a secret + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SecretApi() +val body : UNKNOWN_BASE_TYPE = // UNKNOWN_BASE_TYPE | +try { + val result : IdResponse = apiInstance.secretCreate(body) + println(result) +} catch (e: ClientException) { + println("4xx response calling SecretApi#secretCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SecretApi#secretCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**UNKNOWN_BASE_TYPE**](UNKNOWN_BASE_TYPE.md)| | [optional] + +### Return type + +[**IdResponse**](IdResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **secretDelete** +> secretDelete(id) + +Delete a secret + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SecretApi() +val id : kotlin.String = id_example // kotlin.String | ID of the secret +try { + apiInstance.secretDelete(id) +} catch (e: ClientException) { + println("4xx response calling SecretApi#secretDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SecretApi#secretDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID of the secret | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **secretInspect** +> Secret secretInspect(id) + +Inspect a secret + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SecretApi() +val id : kotlin.String = id_example // kotlin.String | ID of the secret +try { + val result : Secret = apiInstance.secretInspect(id) + println(result) +} catch (e: ClientException) { + println("4xx response calling SecretApi#secretInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SecretApi#secretInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID of the secret | + +### Return type + +[**Secret**](Secret.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **secretList** +> kotlin.collections.List<Secret> secretList(filters) + +List secrets + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SecretApi() +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Available filters: - `id=` - `label= or label==value` - `name=` - `names=` +try { + val result : kotlin.collections.List = apiInstance.secretList(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling SecretApi#secretList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SecretApi#secretList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Available filters: - `id=<secret id>` - `label=<key> or label=<key>=value` - `name=<secret name>` - `names=<secret name>` | [optional] + +### Return type + +[**kotlin.collections.List<Secret>**](Secret.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **secretUpdate** +> secretUpdate(id, version, body) + +Update a Secret + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SecretApi() +val id : kotlin.String = id_example // kotlin.String | The ID or name of the secret +val version : kotlin.Long = 789 // kotlin.Long | The version number of the secret object being updated. This is required to avoid conflicting writes. +val body : SecretSpec = // SecretSpec | The spec of the secret to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [SecretInspect endpoint](#operation/SecretInspect) response values. +try { + apiInstance.secretUpdate(id, version, body) +} catch (e: ClientException) { + println("4xx response calling SecretApi#secretUpdate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SecretApi#secretUpdate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| The ID or name of the secret | + **version** | **kotlin.Long**| The version number of the secret object being updated. This is required to avoid conflicting writes. | + **body** | [**SecretSpec**](SecretSpec.md)| The spec of the secret to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [SecretInspect endpoint](#operation/SecretInspect) response values. | [optional] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/ServiceApi.md b/engine-api/docs/ServiceApi.md new file mode 100644 index 000000000..d41faa334 --- /dev/null +++ b/engine-api/docs/ServiceApi.md @@ -0,0 +1,315 @@ +# ServiceApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**serviceCreate**](ServiceApi.md#serviceCreate) | **POST** /services/create | Create a service | ✅ +[**serviceDelete**](ServiceApi.md#serviceDelete) | **DELETE** /services/{id} | Delete a service | ✅ +[**serviceInspect**](ServiceApi.md#serviceInspect) | **GET** /services/{id} | Inspect a service | ✅ +[**serviceList**](ServiceApi.md#serviceList) | **GET** /services | List services | ✅ +[**serviceLogs**](ServiceApi.md#serviceLogs) | **GET** /services/{id}/logs | Get service logs | ✅ +[**serviceUpdate**](ServiceApi.md#serviceUpdate) | **POST** /services/{id}/update | Update a service | ✅ + + + +# **serviceCreate** +> ServiceCreateResponse serviceCreate(body, xRegistryAuth) + +Create a service + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ServiceApi() +val body : UNKNOWN_BASE_TYPE = // UNKNOWN_BASE_TYPE | +val xRegistryAuth : kotlin.String = xRegistryAuth_example // kotlin.String | A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. +try { + val result : ServiceCreateResponse = apiInstance.serviceCreate(body, xRegistryAuth) + println(result) +} catch (e: ClientException) { + println("4xx response calling ServiceApi#serviceCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ServiceApi#serviceCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**UNKNOWN_BASE_TYPE**](UNKNOWN_BASE_TYPE.md)| | + **xRegistryAuth** | **kotlin.String**| A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. | [optional] + +### Return type + +[**ServiceCreateResponse**](ServiceCreateResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **serviceDelete** +> serviceDelete(id) + +Delete a service + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ServiceApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of service. +try { + apiInstance.serviceDelete(id) +} catch (e: ClientException) { + println("4xx response calling ServiceApi#serviceDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ServiceApi#serviceDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of service. | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **serviceInspect** +> Service serviceInspect(id, insertDefaults) + +Inspect a service + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ServiceApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of service. +val insertDefaults : kotlin.Boolean = true // kotlin.Boolean | Fill empty fields with default values. +try { + val result : Service = apiInstance.serviceInspect(id, insertDefaults) + println(result) +} catch (e: ClientException) { + println("4xx response calling ServiceApi#serviceInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ServiceApi#serviceInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of service. | + **insertDefaults** | **kotlin.Boolean**| Fill empty fields with default values. | [optional] [default to false] + +### Return type + +[**Service**](Service.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **serviceList** +> kotlin.collections.List<Service> serviceList(filters, status) + +List services + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ServiceApi() +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the services list. Available filters: - `id=` - `label=` - `mode=[\"replicated\"|\"global\"]` - `name=` +val status : kotlin.Boolean = true // kotlin.Boolean | Include service status, with count of running and desired tasks. +try { + val result : kotlin.collections.List = apiInstance.serviceList(filters, status) + println(result) +} catch (e: ClientException) { + println("4xx response calling ServiceApi#serviceList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ServiceApi#serviceList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the services list. Available filters: - `id=<service id>` - `label=<service label>` - `mode=[\"replicated\"|\"global\"]` - `name=<service name>` | [optional] + **status** | **kotlin.Boolean**| Include service status, with count of running and desired tasks. | [optional] + +### Return type + +[**kotlin.collections.List<Service>**](Service.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **serviceLogs** +> java.io.File serviceLogs(id, details, follow, stdout, stderr, since, timestamps, tail) + +Get service logs + +Get `stdout` and `stderr` logs from a service. See also [`/containers/{id}/logs`](#operation/ContainerLogs). **Note**: This endpoint works only for services with the `local`, `json-file` or `journald` logging drivers. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ServiceApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of the service +val details : kotlin.Boolean = true // kotlin.Boolean | Show service context and extra details provided to logs. +val follow : kotlin.Boolean = true // kotlin.Boolean | Keep connection after returning logs. +val stdout : kotlin.Boolean = true // kotlin.Boolean | Return logs from `stdout` +val stderr : kotlin.Boolean = true // kotlin.Boolean | Return logs from `stderr` +val since : kotlin.Int = 56 // kotlin.Int | Only return logs since this time, as a UNIX timestamp +val timestamps : kotlin.Boolean = true // kotlin.Boolean | Add timestamps to every log line +val tail : kotlin.String = tail_example // kotlin.String | Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. +try { + val result : java.io.File = apiInstance.serviceLogs(id, details, follow, stdout, stderr, since, timestamps, tail) + println(result) +} catch (e: ClientException) { + println("4xx response calling ServiceApi#serviceLogs") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ServiceApi#serviceLogs") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of the service | + **details** | **kotlin.Boolean**| Show service context and extra details provided to logs. | [optional] [default to false] + **follow** | **kotlin.Boolean**| Keep connection after returning logs. | [optional] [default to false] + **stdout** | **kotlin.Boolean**| Return logs from `stdout` | [optional] [default to false] + **stderr** | **kotlin.Boolean**| Return logs from `stderr` | [optional] [default to false] + **since** | **kotlin.Int**| Only return logs since this time, as a UNIX timestamp | [optional] [default to 0] + **timestamps** | **kotlin.Boolean**| Add timestamps to every log line | [optional] [default to false] + **tail** | **kotlin.String**| Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. | [optional] [default to "all"] + +### Return type + +[**java.io.File**](java.io.File.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **serviceUpdate** +> ServiceUpdateResponse serviceUpdate(id, version, body, registryAuthFrom, rollback, xRegistryAuth) + +Update a service + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = ServiceApi() +val id : kotlin.String = id_example // kotlin.String | ID or name of service. +val version : kotlin.Int = 56 // kotlin.Int | The version number of the service object being updated. This is required to avoid conflicting writes. This version number should be the value as currently set on the service *before* the update. You can find the current version by calling `GET /services/{id}` +val body : UNKNOWN_BASE_TYPE = // UNKNOWN_BASE_TYPE | +val registryAuthFrom : kotlin.String = registryAuthFrom_example // kotlin.String | If the `X-Registry-Auth` header is not specified, this parameter indicates where to find registry authorization credentials. +val rollback : kotlin.String = rollback_example // kotlin.String | Set to this parameter to `previous` to cause a server-side rollback to the previous service spec. The supplied spec will be ignored in this case. +val xRegistryAuth : kotlin.String = xRegistryAuth_example // kotlin.String | A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. +try { + val result : ServiceUpdateResponse = apiInstance.serviceUpdate(id, version, body, registryAuthFrom, rollback, xRegistryAuth) + println(result) +} catch (e: ClientException) { + println("4xx response calling ServiceApi#serviceUpdate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling ServiceApi#serviceUpdate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID or name of service. | + **version** | **kotlin.Int**| The version number of the service object being updated. This is required to avoid conflicting writes. This version number should be the value as currently set on the service *before* the update. You can find the current version by calling `GET /services/{id}` | + **body** | [**UNKNOWN_BASE_TYPE**](UNKNOWN_BASE_TYPE.md)| | + **registryAuthFrom** | **kotlin.String**| If the `X-Registry-Auth` header is not specified, this parameter indicates where to find registry authorization credentials. | [optional] [default to spec] [enum: spec, previous-spec] + **rollback** | **kotlin.String**| Set to this parameter to `previous` to cause a server-side rollback to the previous service spec. The supplied spec will be ignored in this case. | [optional] + **xRegistryAuth** | **kotlin.String**| A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. | [optional] + +### Return type + +[**ServiceUpdateResponse**](ServiceUpdateResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + diff --git a/engine-api/docs/SessionApi.md b/engine-api/docs/SessionApi.md new file mode 100644 index 000000000..cedf11567 --- /dev/null +++ b/engine-api/docs/SessionApi.md @@ -0,0 +1,51 @@ +# SessionApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**session**](SessionApi.md#session) | **POST** /session | Initialize interactive session | ❌ + + + +# **session** +> session() + +Initialize interactive session + +Start a new interactive session with a server. Session allows server to call back to the client for advanced capabilities. ### Hijacking This endpoint hijacks the HTTP connection to HTTP2 transport that allows the client to expose gPRC services on that connection. For example, the client sends this request to upgrade the connection: ``` POST /session HTTP/1.1 Upgrade: h2c Connection: Upgrade ``` The Docker daemon responds with a `101 UPGRADED` response follow with the raw stream: ``` HTTP/1.1 101 UPGRADED Connection: Upgrade Upgrade: h2c ``` + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SessionApi() +try { + apiInstance.session() +} catch (e: ClientException) { + println("4xx response calling SessionApi#session") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SessionApi#session") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/vnd.docker.raw-stream + diff --git a/engine-api/docs/SwarmApi.md b/engine-api/docs/SwarmApi.md new file mode 100644 index 000000000..dcb2f7012 --- /dev/null +++ b/engine-api/docs/SwarmApi.md @@ -0,0 +1,326 @@ +# SwarmApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**swarmInit**](SwarmApi.md#swarmInit) | **POST** /swarm/init | Initialize a new swarm | ✅ +[**swarmInspect**](SwarmApi.md#swarmInspect) | **GET** /swarm | Inspect swarm | ✅ +[**swarmJoin**](SwarmApi.md#swarmJoin) | **POST** /swarm/join | Join an existing swarm | ❌ +[**swarmLeave**](SwarmApi.md#swarmLeave) | **POST** /swarm/leave | Leave a swarm | ✅ +[**swarmUnlock**](SwarmApi.md#swarmUnlock) | **POST** /swarm/unlock | Unlock a locked manager | ❌ +[**swarmUnlockkey**](SwarmApi.md#swarmUnlockkey) | **GET** /swarm/unlockkey | Get the unlock key | ✅ +[**swarmUpdate**](SwarmApi.md#swarmUpdate) | **POST** /swarm/update | Update a swarm | ❌ + + + +# **swarmInit** +> kotlin.String swarmInit(body) + +Initialize a new swarm + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SwarmApi() +val body : SwarmInitRequest = // SwarmInitRequest | +try { + val result : kotlin.String = apiInstance.swarmInit(body) + println(result) +} catch (e: ClientException) { + println("4xx response calling SwarmApi#swarmInit") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SwarmApi#swarmInit") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**SwarmInitRequest**](SwarmInitRequest.md)| | + +### Return type + +**kotlin.String** + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json, text/plain + + +# **swarmInspect** +> Swarm swarmInspect() + +Inspect swarm + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SwarmApi() +try { + val result : Swarm = apiInstance.swarmInspect() + println(result) +} catch (e: ClientException) { + println("4xx response calling SwarmApi#swarmInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SwarmApi#swarmInspect") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**Swarm**](Swarm.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **swarmJoin** +> swarmJoin(body) + +Join an existing swarm + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SwarmApi() +val body : SwarmJoinRequest = // SwarmJoinRequest | +try { + apiInstance.swarmJoin(body) +} catch (e: ClientException) { + println("4xx response calling SwarmApi#swarmJoin") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SwarmApi#swarmJoin") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**SwarmJoinRequest**](SwarmJoinRequest.md)| | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json, text/plain + + +# **swarmLeave** +> swarmLeave(force) + +Leave a swarm + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SwarmApi() +val force : kotlin.Boolean = true // kotlin.Boolean | Force leave swarm, even if this is the last manager or that it will break the cluster. +try { + apiInstance.swarmLeave(force) +} catch (e: ClientException) { + println("4xx response calling SwarmApi#swarmLeave") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SwarmApi#swarmLeave") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **force** | **kotlin.Boolean**| Force leave swarm, even if this is the last manager or that it will break the cluster. | [optional] [default to false] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **swarmUnlock** +> swarmUnlock(body) + +Unlock a locked manager + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SwarmApi() +val body : SwarmUnlockRequest = // SwarmUnlockRequest | +try { + apiInstance.swarmUnlock(body) +} catch (e: ClientException) { + println("4xx response calling SwarmApi#swarmUnlock") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SwarmApi#swarmUnlock") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**SwarmUnlockRequest**](SwarmUnlockRequest.md)| | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **swarmUnlockkey** +> UnlockKeyResponse swarmUnlockkey() + +Get the unlock key + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SwarmApi() +try { + val result : UnlockKeyResponse = apiInstance.swarmUnlockkey() + println(result) +} catch (e: ClientException) { + println("4xx response calling SwarmApi#swarmUnlockkey") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SwarmApi#swarmUnlockkey") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**UnlockKeyResponse**](UnlockKeyResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **swarmUpdate** +> swarmUpdate(version, body, rotateWorkerToken, rotateManagerToken, rotateManagerUnlockKey) + +Update a swarm + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SwarmApi() +val version : kotlin.Long = 789 // kotlin.Long | The version number of the swarm object being updated. This is required to avoid conflicting writes. +val body : SwarmSpec = // SwarmSpec | +val rotateWorkerToken : kotlin.Boolean = true // kotlin.Boolean | Rotate the worker join token. +val rotateManagerToken : kotlin.Boolean = true // kotlin.Boolean | Rotate the manager join token. +val rotateManagerUnlockKey : kotlin.Boolean = true // kotlin.Boolean | Rotate the manager unlock key. +try { + apiInstance.swarmUpdate(version, body, rotateWorkerToken, rotateManagerToken, rotateManagerUnlockKey) +} catch (e: ClientException) { + println("4xx response calling SwarmApi#swarmUpdate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SwarmApi#swarmUpdate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **version** | **kotlin.Long**| The version number of the swarm object being updated. This is required to avoid conflicting writes. | + **body** | [**SwarmSpec**](SwarmSpec.md)| | + **rotateWorkerToken** | **kotlin.Boolean**| Rotate the worker join token. | [optional] [default to false] + **rotateManagerToken** | **kotlin.Boolean**| Rotate the manager join token. | [optional] [default to false] + **rotateManagerUnlockKey** | **kotlin.Boolean**| Rotate the manager unlock key. | [optional] [default to false] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json, text/plain + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/SystemApi.md b/engine-api/docs/SystemApi.md new file mode 100644 index 000000000..34fa996df --- /dev/null +++ b/engine-api/docs/SystemApi.md @@ -0,0 +1,324 @@ +# SystemApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**systemAuth**](SystemApi.md#systemAuth) | **POST** /auth | Check auth configuration | ✅ +[**systemDataUsage**](SystemApi.md#systemDataUsage) | **GET** /system/df | Get data usage information | ✅ +[**systemEvents**](SystemApi.md#systemEvents) | **GET** /events | Monitor events | ✅ +[**systemInfo**](SystemApi.md#systemInfo) | **GET** /info | Get system information | ✅ +[**systemPing**](SystemApi.md#systemPing) | **GET** /_ping | Ping | ✅ +[**systemPingHead**](SystemApi.md#systemPingHead) | **HEAD** /_ping | Ping | ✅ +[**systemVersion**](SystemApi.md#systemVersion) | **GET** /version | Get version | ✅ + + + +# **systemAuth** +> SystemAuthResponse systemAuth(authConfig) + +Check auth configuration + +Validate credentials for a registry and, if available, get an identity token for accessing the registry without password. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SystemApi() +val authConfig : AuthConfig = // AuthConfig | Authentication to check +try { + val result : SystemAuthResponse = apiInstance.systemAuth(authConfig) + println(result) +} catch (e: ClientException) { + println("4xx response calling SystemApi#systemAuth") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SystemApi#systemAuth") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **authConfig** | [**AuthConfig**](AuthConfig.md)| Authentication to check | [optional] + +### Return type + +[**SystemAuthResponse**](SystemAuthResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **systemDataUsage** +> SystemDataUsageResponse systemDataUsage() + +Get data usage information + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SystemApi() +try { + val result : SystemDataUsageResponse = apiInstance.systemDataUsage() + println(result) +} catch (e: ClientException) { + println("4xx response calling SystemApi#systemDataUsage") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SystemApi#systemDataUsage") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**SystemDataUsageResponse**](SystemDataUsageResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **systemEvents** +> SystemEventsResponse systemEvents(since, until, filters) + +Monitor events + +Stream real-time events from the server. Various objects within Docker report events when something happens to them. Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, `update`, and `prune` Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune` Volumes report these events: `create`, `mount`, `unmount`, `destroy`, and `prune` Networks report these events: `create`, `connect`, `disconnect`, `destroy`, `update`, `remove`, and `prune` The Docker daemon reports these events: `reload` Services report these events: `create`, `update`, and `remove` Nodes report these events: `create`, `update`, and `remove` Secrets report these events: `create`, `update`, and `remove` Configs report these events: `create`, `update`, and `remove` The Builder reports `prune` events + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SystemApi() +val since : kotlin.String = since_example // kotlin.String | Show events created since this timestamp then stream new events. +val until : kotlin.String = until_example // kotlin.String | Show events created until this timestamp then stop streaming. +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of filters (a `map[string][]string`) to process on the event list. Available filters: - `config=` config name or ID - `container=` container name or ID - `daemon=` daemon name or ID - `event=` event type - `image=` image name or ID - `label=` image or container label - `network=` network name or ID - `node=` node ID - `plugin`= plugin name or ID - `scope`= local or swarm - `secret=` secret name or ID - `service=` service name or ID - `type=` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service`, `secret` or `config` - `volume=` volume name +try { + val result : SystemEventsResponse = apiInstance.systemEvents(since, until, filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling SystemApi#systemEvents") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SystemApi#systemEvents") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **since** | **kotlin.String**| Show events created since this timestamp then stream new events. | [optional] + **until** | **kotlin.String**| Show events created until this timestamp then stop streaming. | [optional] + **filters** | **kotlin.String**| A JSON encoded value of filters (a `map[string][]string`) to process on the event list. Available filters: - `config=<string>` config name or ID - `container=<string>` container name or ID - `daemon=<string>` daemon name or ID - `event=<string>` event type - `image=<string>` image name or ID - `label=<string>` image or container label - `network=<string>` network name or ID - `node=<string>` node ID - `plugin`=<string> plugin name or ID - `scope`=<string> local or swarm - `secret=<string>` secret name or ID - `service=<string>` service name or ID - `type=<string>` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service`, `secret` or `config` - `volume=<string>` volume name | [optional] + +### Return type + +[**SystemEventsResponse**](SystemEventsResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **systemInfo** +> SystemInfo systemInfo() + +Get system information + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SystemApi() +try { + val result : SystemInfo = apiInstance.systemInfo() + println(result) +} catch (e: ClientException) { + println("4xx response calling SystemApi#systemInfo") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SystemApi#systemInfo") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**SystemInfo**](SystemInfo.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **systemPing** +> kotlin.String systemPing() + +Ping + +This is a dummy endpoint you can use to test if the server is accessible. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SystemApi() +try { + val result : kotlin.String = apiInstance.systemPing() + println(result) +} catch (e: ClientException) { + println("4xx response calling SystemApi#systemPing") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SystemApi#systemPing") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +**kotlin.String** + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: text/plain + + +# **systemPingHead** +> kotlin.String systemPingHead() + +Ping + +This is a dummy endpoint you can use to test if the server is accessible. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SystemApi() +try { + val result : kotlin.String = apiInstance.systemPingHead() + println(result) +} catch (e: ClientException) { + println("4xx response calling SystemApi#systemPingHead") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SystemApi#systemPingHead") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +**kotlin.String** + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: text/plain + + +# **systemVersion** +> SystemVersion systemVersion() + +Get version + +Returns the version of Docker that is running and various information about the system that Docker is running on. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = SystemApi() +try { + val result : SystemVersion = apiInstance.systemVersion() + println(result) +} catch (e: ClientException) { + println("4xx response calling SystemApi#systemVersion") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling SystemApi#systemVersion") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**SystemVersion**](SystemVersion.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + diff --git a/engine-api/docs/TaskApi.md b/engine-api/docs/TaskApi.md new file mode 100644 index 000000000..513d7fc16 --- /dev/null +++ b/engine-api/docs/TaskApi.md @@ -0,0 +1,162 @@ +# TaskApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**taskInspect**](TaskApi.md#taskInspect) | **GET** /tasks/{id} | Inspect a task | ✅ +[**taskList**](TaskApi.md#taskList) | **GET** /tasks | List tasks | ✅ +[**taskLogs**](TaskApi.md#taskLogs) | **GET** /tasks/{id}/logs | Get task logs | ✅ + + + +# **taskInspect** +> Task taskInspect(id) + +Inspect a task + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = TaskApi() +val id : kotlin.String = id_example // kotlin.String | ID of the task +try { + val result : Task = apiInstance.taskInspect(id) + println(result) +} catch (e: ClientException) { + println("4xx response calling TaskApi#taskInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling TaskApi#taskInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID of the task | + +### Return type + +[**Task**](Task.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **taskList** +> kotlin.collections.List<Task> taskList(filters) + +List tasks + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = TaskApi() +val filters : kotlin.String = filters_example // kotlin.String | A JSON encoded value of the filters (a `map[string][]string`) to process on the tasks list. Available filters: - `desired-state=(running | shutdown | accepted)` - `id=` - `label=key` or `label=\"key=value\"` - `name=` - `node=` - `service=` +try { + val result : kotlin.collections.List = apiInstance.taskList(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling TaskApi#taskList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling TaskApi#taskList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| A JSON encoded value of the filters (a `map[string][]string`) to process on the tasks list. Available filters: - `desired-state=(running | shutdown | accepted)` - `id=<task id>` - `label=key` or `label=\"key=value\"` - `name=<task name>` - `node=<node id or name>` - `service=<service name>` | [optional] + +### Return type + +[**kotlin.collections.List<Task>**](Task.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **taskLogs** +> java.io.File taskLogs(id, details, follow, stdout, stderr, since, timestamps, tail) + +Get task logs + +Get `stdout` and `stderr` logs from a task. See also [`/containers/{id}/logs`](#operation/ContainerLogs). **Note**: This endpoint works only for services with the `local`, `json-file` or `journald` logging drivers. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = TaskApi() +val id : kotlin.String = id_example // kotlin.String | ID of the task +val details : kotlin.Boolean = true // kotlin.Boolean | Show task context and extra details provided to logs. +val follow : kotlin.Boolean = true // kotlin.Boolean | Keep connection after returning logs. +val stdout : kotlin.Boolean = true // kotlin.Boolean | Return logs from `stdout` +val stderr : kotlin.Boolean = true // kotlin.Boolean | Return logs from `stderr` +val since : kotlin.Int = 56 // kotlin.Int | Only return logs since this time, as a UNIX timestamp +val timestamps : kotlin.Boolean = true // kotlin.Boolean | Add timestamps to every log line +val tail : kotlin.String = tail_example // kotlin.String | Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. +try { + val result : java.io.File = apiInstance.taskLogs(id, details, follow, stdout, stderr, since, timestamps, tail) + println(result) +} catch (e: ClientException) { + println("4xx response calling TaskApi#taskLogs") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling TaskApi#taskLogs") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **kotlin.String**| ID of the task | + **details** | **kotlin.Boolean**| Show task context and extra details provided to logs. | [optional] [default to false] + **follow** | **kotlin.Boolean**| Keep connection after returning logs. | [optional] [default to false] + **stdout** | **kotlin.Boolean**| Return logs from `stdout` | [optional] [default to false] + **stderr** | **kotlin.Boolean**| Return logs from `stderr` | [optional] [default to false] + **since** | **kotlin.Int**| Only return logs since this time, as a UNIX timestamp | [optional] [default to 0] + **timestamps** | **kotlin.Boolean**| Add timestamps to every log line | [optional] [default to false] + **tail** | **kotlin.String**| Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. | [optional] [default to "all"] + +### Return type + +[**java.io.File**](java.io.File.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + diff --git a/engine-api/docs/VolumeApi.md b/engine-api/docs/VolumeApi.md new file mode 100644 index 000000000..109051416 --- /dev/null +++ b/engine-api/docs/VolumeApi.md @@ -0,0 +1,241 @@ +# VolumeApi + +All URIs are relative to *http://localhost/v1.41* + +Method | HTTP request | Description | Integration tests +------------- | ------------- | ------------- | --- +[**volumeCreate**](VolumeApi.md#volumeCreate) | **POST** /volumes/create | Create a volume | ✅ +[**volumeDelete**](VolumeApi.md#volumeDelete) | **DELETE** /volumes/{name} | Remove a volume | ✅ +[**volumeInspect**](VolumeApi.md#volumeInspect) | **GET** /volumes/{name} | Inspect a volume | ✅ +[**volumeList**](VolumeApi.md#volumeList) | **GET** /volumes | List volumes | ✅ +[**volumePrune**](VolumeApi.md#volumePrune) | **POST** /volumes/prune | Delete unused volumes | ✅ + + + +# **volumeCreate** +> Volume volumeCreate(volumeConfig) + +Create a volume + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = VolumeApi() +val volumeConfig : VolumeConfig = // VolumeConfig | +try { + val result : Volume = apiInstance.volumeCreate(volumeConfig) + println(result) +} catch (e: ClientException) { + println("4xx response calling VolumeApi#volumeCreate") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling VolumeApi#volumeCreate") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **volumeConfig** | [**VolumeConfig**](VolumeConfig.md)| | + +### Return type + +[**Volume**](Volume.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +# **volumeDelete** +> volumeDelete(name, force) + +Remove a volume + +Instruct the driver to remove the volume. + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = VolumeApi() +val name : kotlin.String = name_example // kotlin.String | Volume name or ID +val force : kotlin.Boolean = true // kotlin.Boolean | Force the removal of the volume +try { + apiInstance.volumeDelete(name, force) +} catch (e: ClientException) { + println("4xx response calling VolumeApi#volumeDelete") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling VolumeApi#volumeDelete") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Volume name or ID | + **force** | **kotlin.Boolean**| Force the removal of the volume | [optional] [default to false] + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json, text/plain + + +# **volumeInspect** +> Volume volumeInspect(name) + +Inspect a volume + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = VolumeApi() +val name : kotlin.String = name_example // kotlin.String | Volume name or ID +try { + val result : Volume = apiInstance.volumeInspect(name) + println(result) +} catch (e: ClientException) { + println("4xx response calling VolumeApi#volumeInspect") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling VolumeApi#volumeInspect") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **name** | **kotlin.String**| Volume name or ID | + +### Return type + +[**Volume**](Volume.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **volumeList** +> VolumeListResponse volumeList(filters) + +List volumes + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = VolumeApi() +val filters : kotlin.String = filters_example // kotlin.String | JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. Available filters: - `dangling=` When set to `true` (or `1`), returns all volumes that are not in use by a container. When set to `false` (or `0`), only volumes that are in use by one or more containers are returned. - `driver=` Matches volumes based on their driver. - `label=` or `label=:` Matches volumes based on the presence of a `label` alone or a `label` and a value. - `name=` Matches all or part of a volume name. +try { + val result : VolumeListResponse = apiInstance.volumeList(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling VolumeApi#volumeList") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling VolumeApi#volumeList") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. Available filters: - `dangling=<boolean>` When set to `true` (or `1`), returns all volumes that are not in use by a container. When set to `false` (or `0`), only volumes that are in use by one or more containers are returned. - `driver=<volume-driver-name>` Matches volumes based on their driver. - `label=<key>` or `label=<key>:<value>` Matches volumes based on the presence of a `label` alone or a `label` and a value. - `name=<volume-name>` Matches all or part of a volume name. | [optional] + +### Return type + +[**VolumeListResponse**](VolumeListResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +# **volumePrune** +> VolumePruneResponse volumePrune(filters) + +Delete unused volumes + +### Example +```kotlin +// Import classes: +//import de.gesellix.docker.engine.client.infrastructure.* +//import de.gesellix.docker.engine.model.* + +val apiInstance = VolumeApi() +val filters : kotlin.String = filters_example // kotlin.String | Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `label` (`label=`, `label==`, `label!=`, or `label!==`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. +try { + val result : VolumePruneResponse = apiInstance.volumePrune(filters) + println(result) +} catch (e: ClientException) { + println("4xx response calling VolumeApi#volumePrune") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling VolumeApi#volumePrune") + e.printStackTrace() +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **filters** | **kotlin.String**| Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. | [optional] + +### Return type + +[**VolumePruneResponse**](VolumePruneResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + diff --git a/engine-api/src/main/java/de/gesellix/docker/engine/api/Cancellable.java b/engine-api/src/main/java/de/gesellix/docker/engine/api/Cancellable.java new file mode 100644 index 000000000..2c1e18866 --- /dev/null +++ b/engine-api/src/main/java/de/gesellix/docker/engine/api/Cancellable.java @@ -0,0 +1,6 @@ +package de.gesellix.docker.engine.api; + +public interface Cancellable { + + void cancel(); +} diff --git a/engine-api/src/main/java/de/gesellix/docker/engine/client/infrastructure/Frame.java b/engine-api/src/main/java/de/gesellix/docker/engine/api/Frame.java similarity index 94% rename from engine-api/src/main/java/de/gesellix/docker/engine/client/infrastructure/Frame.java rename to engine-api/src/main/java/de/gesellix/docker/engine/api/Frame.java index 9a926a824..d796e29f7 100644 --- a/engine-api/src/main/java/de/gesellix/docker/engine/client/infrastructure/Frame.java +++ b/engine-api/src/main/java/de/gesellix/docker/engine/api/Frame.java @@ -1,4 +1,4 @@ -package de.gesellix.docker.engine.client.infrastructure; +package de.gesellix.docker.engine.api; import java.nio.charset.StandardCharsets; @@ -46,6 +46,8 @@ public String toString() { */ public enum StreamType { + // special case for `container.tty == false` + RAW((byte) -1), STDIN((byte) 0), STDOUT((byte) 1), STDERR((byte) 2), diff --git a/engine-api/src/main/java/de/gesellix/docker/engine/api/StreamCallback.java b/engine-api/src/main/java/de/gesellix/docker/engine/api/StreamCallback.java new file mode 100644 index 000000000..6b221bcd0 --- /dev/null +++ b/engine-api/src/main/java/de/gesellix/docker/engine/api/StreamCallback.java @@ -0,0 +1,16 @@ +package de.gesellix.docker.engine.api; + +public interface StreamCallback { + + default void onStarting(Cancellable cancellable) { + } + + void onNext(T element); + + default void onFailed(Exception e) { + throw new RuntimeException(e); + } + + default void onFinished() { + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ConfigApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ConfigApi.kt new file mode 100644 index 000000000..fb7e3584e --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ConfigApi.kt @@ -0,0 +1,314 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.Config +import de.gesellix.docker.engine.model.ConfigSpec +import de.gesellix.docker.engine.model.IdResponse + +class ConfigApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Create a config + * + * @param body (optional) + * @return IdResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun configCreate(body: ConfigSpec?): IdResponse { + val localVariableConfig = configCreateRequestConfig(body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as IdResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation configCreate + * + * @param body (optional) + * @return RequestConfig + */ + fun configCreateRequestConfig(body: ConfigSpec?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/configs/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Delete a config + * + * @param id ID of the config + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun configDelete(id: String) { + val localVariableConfig = configDeleteRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation configDelete + * + * @param id ID of the config + * @return RequestConfig + */ + fun configDeleteRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/configs/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a config + * + * @param id ID of the config + * @return Config + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun configInspect(id: String): Config { + val localVariableConfig = configInspectRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Config + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation configInspect + * + * @param id ID of the config + * @return RequestConfig + */ + fun configInspectRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/configs/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List configs + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the configs list. Available filters: - `id=<config id>` - `label=<key> or label=<key>=value` - `name=<config name>` - `names=<config name>` (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun configList(filters: String?): List { + val localVariableConfig = configListRequestConfig(filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation configList + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the configs list. Available filters: - `id=<config id>` - `label=<key> or label=<key>=value` - `name=<config name>` - `names=<config name>` (optional) + * @return RequestConfig + */ + fun configListRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/configs", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = Config::class.java + ) + } + + /** + * Update a Config + * + * @param id The ID or name of the config + * @param version The version number of the config object being updated. This is required to avoid conflicting writes. + * @param body The spec of the config to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [ConfigInspect endpoint](#operation/ConfigInspect) response values. (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun configUpdate(id: String, version: Long, body: ConfigSpec?) { + val localVariableConfig = configUpdateRequestConfig(id = id, version = version, body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation configUpdate + * + * @param id The ID or name of the config + * @param version The version number of the config object being updated. This is required to avoid conflicting writes. + * @param body The spec of the config to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [ConfigInspect endpoint](#operation/ConfigInspect) response values. (optional) + * @return RequestConfig + */ + fun configUpdateRequestConfig(id: String, version: Long, body: ConfigSpec?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("version", listOf(version.toString())) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/configs/{id}/update".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ContainerApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ContainerApi.kt new file mode 100644 index 000000000..e96be4887 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ContainerApi.kt @@ -0,0 +1,1703 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.* +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.client.infrastructure.SuccessStream +import de.gesellix.docker.engine.model.ContainerChangeResponseItem +import de.gesellix.docker.engine.model.ContainerCreateRequest +import de.gesellix.docker.engine.model.ContainerCreateResponse +import de.gesellix.docker.engine.model.ContainerInspectResponse +import de.gesellix.docker.engine.model.ContainerPruneResponse +import de.gesellix.docker.engine.model.ContainerTopResponse +import de.gesellix.docker.engine.model.ContainerUpdateRequest +import de.gesellix.docker.engine.model.ContainerUpdateResponse +import de.gesellix.docker.engine.model.ContainerWaitResponse +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import java.net.HttpURLConnection.HTTP_NOT_FOUND +import java.net.HttpURLConnection.HTTP_NOT_MODIFIED + +class ContainerApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Get an archive of a filesystem resource in a container + * Get a tar archive of a resource in the filesystem of container id. + * @param id ID or name of the container + * @param path Resource in the container’s filesystem to archive. + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerArchive(id: String, path: String) { + val localVariableConfig = containerArchiveRequestConfig(id = id, path = path) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerArchive + * + * @param id ID or name of the container + * @param path Resource in the container’s filesystem to archive. + * @return RequestConfig + */ + fun containerArchiveRequestConfig(id: String, path: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("path", listOf(path)) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/archive".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get information about files in a container + * A response header `X-Docker-Container-Path-Stat` is returned, containing a base64 - encoded JSON object with some filesystem header information about the path. + * @param id ID or name of the container + * @param path Resource in the container’s filesystem to archive. + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerArchiveInfo(id: String, path: String) { + val localVariableConfig = containerArchiveInfoRequestConfig(id = id, path = path) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerArchiveInfo + * + * @param id ID or name of the container + * @param path Resource in the container’s filesystem to archive. + * @return RequestConfig + */ + fun containerArchiveInfoRequestConfig(id: String, path: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("path", listOf(path)) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = HEAD, + path = "/containers/{id}/archive".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Attach to a container + * Attach to a container to read its output or send it input. You can attach to the same container multiple times and you can reattach to containers that have been detached. Either the `stream` or `logs` parameter must be `true` for this endpoint to do anything. See the [documentation for the `docker attach` command](https://docs.docker.com/engine/reference/commandline/attach/) for more details. ### Hijacking This endpoint hijacks the HTTP connection to transport `stdin`, `stdout`, and `stderr` on the same socket. This is the response from the daemon for an attach request: ``` HTTP/1.1 200 OK Content-Type: application/vnd.docker.raw-stream [STREAM] ``` After the headers and two new lines, the TCP connection can now be used for raw, bidirectional communication between the client and server. To hint potential proxies about connection hijacking, the Docker client can also optionally send connection upgrade headers. For example, the client sends this request to upgrade the connection: ``` POST /containers/16253994b7c4/attach?stream=1&stdout=1 HTTP/1.1 Upgrade: tcp Connection: Upgrade ``` The Docker daemon will respond with a `101 UPGRADED` response, and will similarly follow with the raw stream: ``` HTTP/1.1 101 UPGRADED Content-Type: application/vnd.docker.raw-stream Connection: Upgrade Upgrade: tcp [STREAM] ``` ### Stream format When the TTY setting is disabled in [`POST /containers/create`](#operation/ContainerCreate), the stream over the hijacked connected is multiplexed to separate out `stdout` and `stderr`. The stream consists of a series of frames, each containing a header and a payload. The header contains the information which the stream writes (`stdout` or `stderr`). It also contains the size of the associated frame encoded in the last four bytes (`uint32`). It is encoded on the first eight bytes like this: ```go header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4} ``` `STREAM_TYPE` can be: - 0: `stdin` (is written on `stdout`) - 1: `stdout` - 2: `stderr` `SIZE1, SIZE2, SIZE3, SIZE4` are the four bytes of the `uint32` size encoded as big endian. Following the header is the payload, which is the specified number of bytes of `STREAM_TYPE`. The simplest way to implement this protocol is the following: 1. Read 8 bytes. 2. Choose `stdout` or `stderr` depending on the first byte. 3. Extract the frame size from the last four bytes. 4. Read the extracted size and output it on the correct output. 5. Goto 1. ### Stream format when using a TTY When the TTY setting is enabled in [`POST /containers/create`](#operation/ContainerCreate), the stream is not multiplexed. The data exchanged over the hijacked connection is simply the raw data from the process PTY and client's `stdin`. + * @param id ID or name of the container + * @param detachKeys Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. (optional) + * @param logs Replay previous logs from the container. This is useful for attaching to a container that has started and you want to output everything since the container started. If `stream` is also enabled, once all the previous output has been returned, it will seamlessly transition into streaming current output. (optional, default to false) + * @param stream Stream attached streams from the time the request was made onwards. (optional, default to false) + * @param stdin Attach to `stdin` (optional, default to false) + * @param stdout Attach to `stdout` (optional, default to false) + * @param stderr Attach to `stderr` (optional, default to false) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerAttach( + id: String, detachKeys: String?, logs: Boolean?, stream: Boolean?, stdin: Boolean?, stdout: Boolean?, stderr: Boolean?, + callback: StreamCallback, timeoutMillis: Long /*= 24.hours.toLongMilliseconds()*/ + ) { + val localVariableConfig = containerAttachRequestConfig(id = id, detachKeys = detachKeys, logs = logs, stream = stream, stdin = stdin, stdout = stdout, stderr = stderr) + + val expectMultiplexedResponse = !(containerInspect(id, false).config?.tty ?: false) + val localVarResponse = requestFrames( + localVariableConfig, expectMultiplexedResponse + ) + + when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeoutMillis) { + callback.onStarting(this@launch::cancel) + ((localVarResponse as SuccessStream<*>).data as Flow).collect { callback.onNext(it) } + callback.onFinished() + } + } + } + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerAttach + * + * @param id ID or name of the container + * @param detachKeys Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. (optional) + * @param logs Replay previous logs from the container. This is useful for attaching to a container that has started and you want to output everything since the container started. If `stream` is also enabled, once all the previous output has been returned, it will seamlessly transition into streaming current output. (optional, default to false) + * @param stream Stream attached streams from the time the request was made onwards. (optional, default to false) + * @param stdin Attach to `stdin` (optional, default to false) + * @param stdout Attach to `stdout` (optional, default to false) + * @param stderr Attach to `stderr` (optional, default to false) + * @return RequestConfig + */ + fun containerAttachRequestConfig( + id: String, + detachKeys: String?, + logs: Boolean?, + stream: Boolean?, + stdin: Boolean?, + stdout: Boolean?, + stderr: Boolean? + ): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (detachKeys != null) { + put("detachKeys", listOf(detachKeys.toString())) + } + if (logs != null) { + put("logs", listOf(logs.toString())) + } + if (stream != null) { + put("stream", listOf(stream.toString())) + } + if (stdin != null) { + put("stdin", listOf(stdin.toString())) + } + if (stdout != null) { + put("stdout", listOf(stdout.toString())) + } + if (stderr != null) { + put("stderr", listOf(stderr.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/attach".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Attach to a container via a websocket + * + * @param id ID or name of the container + * @param detachKeys Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,`, or `_`. (optional) + * @param logs Return logs (optional, default to false) + * @param stream Return stream (optional, default to false) + * @param stdin Attach to `stdin` (optional, default to false) + * @param stdout Attach to `stdout` (optional, default to false) + * @param stderr Attach to `stderr` (optional, default to false) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerAttachWebsocket( + id: String, + detachKeys: String?, + logs: Boolean?, + stream: Boolean?, + stdin: Boolean?, + stdout: Boolean?, + stderr: Boolean? + ) { + val localVariableConfig = containerAttachWebsocketRequestConfig(id = id, detachKeys = detachKeys, logs = logs, stream = stream, stdin = stdin, stdout = stdout, stderr = stderr) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerAttachWebsocket + * + * @param id ID or name of the container + * @param detachKeys Override the key sequence for detaching a container.Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,`, or `_`. (optional) + * @param logs Return logs (optional, default to false) + * @param stream Return stream (optional, default to false) + * @param stdin Attach to `stdin` (optional, default to false) + * @param stdout Attach to `stdout` (optional, default to false) + * @param stderr Attach to `stderr` (optional, default to false) + * @return RequestConfig + */ + fun containerAttachWebsocketRequestConfig( + id: String, + detachKeys: String?, + logs: Boolean?, + stream: Boolean?, + stdin: Boolean?, + stdout: Boolean?, + stderr: Boolean? + ): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (detachKeys != null) { + put("detachKeys", listOf(detachKeys.toString())) + } + if (logs != null) { + put("logs", listOf(logs.toString())) + } + if (stream != null) { + put("stream", listOf(stream.toString())) + } + if (stdin != null) { + put("stdin", listOf(stdin.toString())) + } + if (stdout != null) { + put("stdout", listOf(stdout.toString())) + } + if (stderr != null) { + put("stderr", listOf(stderr.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/attach/ws".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get changes on a container’s filesystem + * Returns which files in a container's filesystem have been added, deleted, or modified. The `Kind` of modification can be one of: - `0`: Modified - `1`: Added - `2`: Deleted + * @param id ID or name of the container + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerChanges(id: String): List { + val localVariableConfig = containerChangesRequestConfig(id = id) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerChanges + * + * @param id ID or name of the container + * @return RequestConfig + */ + fun containerChangesRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/changes".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Create a container + * + * @param body Container to create + * @param name Assign the specified name to the container. Must match `/?[a-zA-Z0-9][a-zA-Z0-9_.-]+`. (optional) + * @return ContainerCreateResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerCreate(body: ContainerCreateRequest, name: String?): ContainerCreateResponse { + val localVariableConfig = containerCreateRequestConfig(body = body, name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ContainerCreateResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerCreate + * + * @param body Container to create + * @param name Assign the specified name to the container. Must match `/?[a-zA-Z0-9][a-zA-Z0-9_.-]+`. (optional) + * @return RequestConfig + */ + fun containerCreateRequestConfig(body: ContainerCreateRequest, name: String?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (name != null) { + put("name", listOf(name.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Remove a container + * + * @param id ID or name of the container + * @param v Remove anonymous volumes associated with the container. (optional, default to false) + * @param force If the container is running, kill it before removing it. (optional, default to false) + * @param link Remove the specified link associated with the container. (optional, default to false) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerDelete(id: String, v: Boolean?, force: Boolean?, link: Boolean?) { + val localVariableConfig = containerDeleteRequestConfig(id = id, v = v, force = force, link = link) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + if (localVarError.statusCode == HTTP_NOT_FOUND) { + return + } + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerDelete + * + * @param id ID or name of the container + * @param v Remove anonymous volumes associated with the container. (optional, default to false) + * @param force If the container is running, kill it before removing it. (optional, default to false) + * @param link Remove the specified link associated with the container. (optional, default to false) + * @return RequestConfig + */ + fun containerDeleteRequestConfig(id: String, v: Boolean?, force: Boolean?, link: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (v != null) { + put("v", listOf(v.toString())) + } + if (force != null) { + put("force", listOf(force.toString())) + } + if (link != null) { + put("link", listOf(link.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/containers/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Export a container + * Export the contents of a container as a tarball. + * @param id ID or name of the container + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerExport(id: String) { + val localVariableConfig = containerExportRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerExport + * + * @param id ID or name of the container + * @return RequestConfig + */ + fun containerExportRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/export".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a container + * Return low-level information about a container. + * @param id ID or name of the container + * @param size Return the size of container as fields `SizeRw` and `SizeRootFs` (optional, default to false) + * @return ContainerInspectResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerInspect(id: String, size: Boolean?): ContainerInspectResponse { + val localVariableConfig = containerInspectRequestConfig(id = id, size = size) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ContainerInspectResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerInspect + * + * @param id ID or name of the container + * @param size Return the size of container as fields `SizeRw` and `SizeRootFs` (optional, default to false) + * @return RequestConfig + */ + fun containerInspectRequestConfig(id: String, size: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (size != null) { + put("size", listOf(size.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/json".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Kill a container + * Send a POSIX signal to a container, defaulting to killing to the container. + * @param id ID or name of the container + * @param signal Signal to send to the container as an integer or string (e.g. `SIGINT`) (optional, default to "SIGKILL") + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerKill(id: String, signal: String?) { + val localVariableConfig = containerKillRequestConfig(id = id, signal = signal) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerKill + * + * @param id ID or name of the container + * @param signal Signal to send to the container as an integer or string (e.g. `SIGINT`) (optional, default to "SIGKILL") + * @return RequestConfig + */ + fun containerKillRequestConfig(id: String, signal: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (signal != null) { + put("signal", listOf(signal.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/kill".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List containers + * Returns a list of containers. For details on the format, see the [inspect endpoint](#operation/ContainerInspect). Note that it uses a different, smaller representation of a container than inspecting a single container. For example, the list of linked containers is not propagated . + * @param all Return all containers. By default, only running containers are shown. (optional, default to false) + * @param limit Return this number of most recently created containers, including non-running ones. (optional) + * @param size Return the size of container as fields `SizeRw` and `SizeRootFs`. (optional, default to false) + * @param filters Filters to process on the container list, encoded as JSON (a `map[string][]string`). For example, `{\"status\": [\"paused\"]}` will only return paused containers. Available filters: - `ancestor`=(`<image-name>[:<tag>]`, `<image id>`, or `<image@digest>`) - `before`=(`<container id>` or `<container name>`) - `expose`=(`<port>[/<proto>]`|`<startport-endport>/[<proto>]`) - `exited=<int>` containers with exit code of `<int>` - `health`=(`starting`|`healthy`|`unhealthy`|`none`) - `id=<ID>` a container's ID - `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only) - `is-task=`(`true`|`false`) - `label=key` or `label=\"key=value\"` of a container label - `name=<name>` a container's name - `network`=(`<network id>` or `<network name>`) - `publish`=(`<port>[/<proto>]`|`<startport-endport>/[<proto>]`) - `since`=(`<container id>` or `<container name>`) - `status=`(`created`|`restarting`|`running`|`removing`|`paused`|`exited`|`dead`) - `volume`=(`<volume name>` or `<mount point destination>`) (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerList(all: Boolean?, limit: Int?, size: Boolean?, filters: String?): List> { + val localVariableConfig = containerListRequestConfig(all = all, limit = limit, size = size, filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List> + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerList + * + * @param all Return all containers. By default, only running containers are shown. (optional, default to false) + * @param limit Return this number of most recently created containers, including non-running ones. (optional) + * @param size Return the size of container as fields `SizeRw` and `SizeRootFs`. (optional, default to false) + * @param filters Filters to process on the container list, encoded as JSON (a `map[string][]string`). For example, `{\"status\": [\"paused\"]}` will only return paused containers. Available filters: - `ancestor`=(`<image-name>[:<tag>]`, `<image id>`, or `<image@digest>`) - `before`=(`<container id>` or `<container name>`) - `expose`=(`<port>[/<proto>]`|`<startport-endport>/[<proto>]`) - `exited=<int>` containers with exit code of `<int>` - `health`=(`starting`|`healthy`|`unhealthy`|`none`) - `id=<ID>` a container's ID - `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only) - `is-task=`(`true`|`false`) - `label=key` or `label=\"key=value\"` of a container label - `name=<name>` a container's name - `network`=(`<network id>` or `<network name>`) - `publish`=(`<port>[/<proto>]`|`<startport-endport>/[<proto>]`) - `since`=(`<container id>` or `<container name>`) - `status=`(`created`|`restarting`|`running`|`removing`|`paused`|`exited`|`dead`) - `volume`=(`<volume name>` or `<mount point destination>`) (optional) + * @return RequestConfig + */ + fun containerListRequestConfig(all: Boolean?, limit: Int?, size: Boolean?, filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (all != null) { + put("all", listOf(all.toString())) + } + if (limit != null) { + put("limit", listOf(limit.toString())) + } + if (size != null) { + put("size", listOf(size.toString())) + } + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/json", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get container logs + * Get `stdout` and `stderr` logs from a container. Note: This endpoint works only for containers with the `json-file` or `journald` logging driver. + * @param id ID or name of the container + * @param follow Keep connection after returning logs. (optional, default to false) + * @param stdout Return logs from `stdout` (optional, default to false) + * @param stderr Return logs from `stderr` (optional, default to false) + * @param since Only return logs since this time, as a UNIX timestamp (optional, default to 0) + * @param until Only return logs before this time, as a UNIX timestamp (optional, default to 0) + * @param timestamps Add timestamps to every log line (optional, default to false) + * @param tail Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. (optional, default to "all") + * @return java.io.File + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerLogs( + id: String, + follow: Boolean?, + stdout: Boolean?, + stderr: Boolean?, + since: Int?, + until: Int?, + timestamps: Boolean?, + tail: String?, + callback: StreamCallback, timeoutMillis: Long /*= 24.hours.toLongMilliseconds()*/ + ) { + val localVariableConfig = containerLogsRequestConfig(id = id, follow = follow, stdout = stdout, stderr = stderr, since = since, until = until, timestamps = timestamps, tail = tail) + + val expectMultiplexedResponse = !(containerInspect(id, false).config?.tty ?: false) + val localVarResponse = requestFrames( + localVariableConfig, expectMultiplexedResponse + ) + + when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeoutMillis) { + callback.onStarting(this@launch::cancel) + ((localVarResponse as SuccessStream<*>).data as Flow).collect { callback.onNext(it) } + callback.onFinished() + } + } + } + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerLogs + * + * @param id ID or name of the container + * @param follow Keep connection after returning logs. (optional, default to false) + * @param stdout Return logs from `stdout` (optional, default to false) + * @param stderr Return logs from `stderr` (optional, default to false) + * @param since Only return logs since this time, as a UNIX timestamp (optional, default to 0) + * @param until Only return logs before this time, as a UNIX timestamp (optional, default to 0) + * @param timestamps Add timestamps to every log line (optional, default to false) + * @param tail Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. (optional, default to "all") + * @return RequestConfig + */ + fun containerLogsRequestConfig( + id: String, + follow: Boolean?, + stdout: Boolean?, + stderr: Boolean?, + since: Int?, + until: Int?, + timestamps: Boolean?, + tail: String? + ): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (follow != null) { + put("follow", listOf(follow.toString())) + } + if (stdout != null) { + put("stdout", listOf(stdout.toString())) + } + if (stderr != null) { + put("stderr", listOf(stderr.toString())) + } + if (since != null) { + put("since", listOf(since.toString())) + } + if (until != null) { + put("until", listOf(until.toString())) + } + if (timestamps != null) { + put("timestamps", listOf(timestamps.toString())) + } + if (tail != null) { + put("tail", listOf(tail.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/logs".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Pause a container + * Use the freezer cgroup to suspend all processes in a container. Traditionally, when suspending a process the `SIGSTOP` signal is used, which is observable by the process being suspended. With the freezer cgroup the process is unaware, and unable to capture, that it is being suspended, and subsequently resumed. + * @param id ID or name of the container + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerPause(id: String) { + val localVariableConfig = containerPauseRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerPause + * + * @param id ID or name of the container + * @return RequestConfig + */ + fun containerPauseRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/pause".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Delete stopped containers + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=<timestamp>` Prune containers created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune containers with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return ContainerPruneResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerPrune(filters: String?): ContainerPruneResponse { + val localVariableConfig = containerPruneRequestConfig(filters = filters) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ContainerPruneResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerPrune + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=<timestamp>` Prune containers created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune containers with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return RequestConfig + */ + fun containerPruneRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/prune", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Rename a container + * + * @param id ID or name of the container + * @param name New name for the container + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerRename(id: String, name: String) { + val localVariableConfig = containerRenameRequestConfig(id = id, name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerRename + * + * @param id ID or name of the container + * @param name New name for the container + * @return RequestConfig + */ + fun containerRenameRequestConfig(id: String, name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("name", listOf(name)) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/rename".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Resize a container TTY + * Resize the TTY for a container. + * @param id ID or name of the container + * @param h Height of the TTY session in characters (optional) + * @param w Width of the TTY session in characters (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerResize(id: String, h: Int?, w: Int?) { + val localVariableConfig = containerResizeRequestConfig(id = id, h = h, w = w) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerResize + * + * @param id ID or name of the container + * @param h Height of the TTY session in characters (optional) + * @param w Width of the TTY session in characters (optional) + * @return RequestConfig + */ + fun containerResizeRequestConfig(id: String, h: Int?, w: Int?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (h != null) { + put("h", listOf(h.toString())) + } + if (w != null) { + put("w", listOf(w.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/resize".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Restart a container + * + * @param id ID or name of the container + * @param t Number of seconds to wait before killing the container (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerRestart(id: String, t: Int?) { + val localVariableConfig = containerRestartRequestConfig(id = id, t = t) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerRestart + * + * @param id ID or name of the container + * @param t Number of seconds to wait before killing the container (optional) + * @return RequestConfig + */ + fun containerRestartRequestConfig(id: String, t: Int?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (t != null) { + put("t", listOf(t.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/restart".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Start a container + * + * @param id ID or name of the container + * @param detachKeys Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerStart(id: String, detachKeys: String?) { + val localVariableConfig = containerStartRequestConfig(id = id, detachKeys = detachKeys) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerStart + * + * @param id ID or name of the container + * @param detachKeys Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. (optional) + * @return RequestConfig + */ + fun containerStartRequestConfig(id: String, detachKeys: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (detachKeys != null) { + put("detachKeys", listOf(detachKeys.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/start".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get container stats based on resource usage + * This endpoint returns a live stream of a container’s resource usage statistics. The `precpu_stats` is the CPU statistic of the *previous* read, and is used to calculate the CPU usage percentage. It is not an exact copy of the `cpu_stats` field. If either `precpu_stats.online_cpus` or `cpu_stats.online_cpus` is nil then for compatibility with older daemons the length of the corresponding `cpu_usage.percpu_usage` array should be used. On a cgroup v2 host, the following fields are not set * `blkio_stats`: all fields other than `io_service_bytes_recursive` * `cpu_stats`: `cpu_usage.percpu_usage` * `memory_stats`: `max_usage` and `failcnt` Also, `memory_stats.stats` fields are incompatible with cgroup v1. To calculate the values shown by the `stats` command of the docker cli tool the following formulas can be used: * used_memory = `memory_stats.usage - memory_stats.stats.cache` * available_memory = `memory_stats.limit` * Memory usage % = `(used_memory / available_memory) * 100.0` * cpu_delta = `cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage` * system_cpu_delta = `cpu_stats.system_cpu_usage - precpu_stats.system_cpu_usage` * number_cpus = `lenght(cpu_stats.cpu_usage.percpu_usage)` or `cpu_stats.online_cpus` * CPU usage % = `(cpu_delta / system_cpu_delta) * number_cpus * 100.0` + * @param id ID or name of the container + * @param stream Stream the output. If false, the stats will be output once and then it will disconnect. (optional, default to true) + * @param oneShot Only get a single stat instead of waiting for 2 cycles. Must be used with `stream=false`. (optional, default to false) + * @return kotlin.Any + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerStats(id: String, stream: Boolean?, oneShot: Boolean?, callback: StreamCallback, timeoutMillis: Long /*= 24.hours.toLongMilliseconds()*/): Any { + val localVariableConfig = containerStatsRequestConfig(id = id, stream = stream, oneShot = oneShot) + + val localVarResponse = requestStream( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeoutMillis) { + callback.onStarting(this@launch::cancel) + (localVarResponse as SuccessStream<*>).data.collect { callback.onNext(it) } + callback.onFinished() + } + } + } + Unit + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerStats + * + * @param id ID or name of the container + * @param stream Stream the output. If false, the stats will be output once and then it will disconnect. (optional, default to true) + * @param oneShot Only get a single stat instead of waiting for 2 cycles. Must be used with `stream=false`. (optional, default to false) + * @return RequestConfig + */ + fun containerStatsRequestConfig(id: String, stream: Boolean?, oneShot: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (stream != null) { + put("stream", listOf(stream.toString())) + } + if (oneShot != null) { + put("one-shot", listOf(oneShot.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/stats".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Stop a container + * + * @param id ID or name of the container + * @param t Number of seconds to wait before killing the container (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerStop(id: String, t: Int?) { + val localVariableConfig = containerStopRequestConfig(id = id, t = t) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + if (localVarError.statusCode == HTTP_NOT_MODIFIED) { + return + } + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerStop + * + * @param id ID or name of the container + * @param t Number of seconds to wait before killing the container (optional) + * @return RequestConfig + */ + fun containerStopRequestConfig(id: String, t: Int?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (t != null) { + put("t", listOf(t.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/stop".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List processes running inside a container + * On Unix systems, this is done by running the `ps` command. This endpoint is not supported on Windows. + * @param id ID or name of the container + * @param psArgs The arguments to pass to `ps`. For example, `aux` (optional, default to "-ef") + * @return ContainerTopResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerTop(id: String, psArgs: String?): ContainerTopResponse { + val localVariableConfig = containerTopRequestConfig(id = id, psArgs = psArgs) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ContainerTopResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerTop + * + * @param id ID or name of the container + * @param psArgs The arguments to pass to `ps`. For example, `aux` (optional, default to "-ef") + * @return RequestConfig + */ + fun containerTopRequestConfig(id: String, psArgs: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (psArgs != null) { + put("ps_args", listOf(psArgs.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/containers/{id}/top".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Unpause a container + * Resume a container which has been paused. + * @param id ID or name of the container + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerUnpause(id: String) { + val localVariableConfig = containerUnpauseRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerUnpause + * + * @param id ID or name of the container + * @return RequestConfig + */ + fun containerUnpauseRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/unpause".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Update a container + * Change various configuration options of a container without having to recreate it. + * @param id ID or name of the container + * @param update + * @return ContainerUpdateResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerUpdate(id: String, update: ContainerUpdateRequest): ContainerUpdateResponse { + val localVariableConfig = containerUpdateRequestConfig(id = id, update = update) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ContainerUpdateResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerUpdate + * + * @param id ID or name of the container + * @param update + * @return RequestConfig + */ + fun containerUpdateRequestConfig(id: String, update: ContainerUpdateRequest): RequestConfig { + val localVariableBody: Any? = update + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/update".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Wait for a container + * Block until a container stops, then returns the exit code. + * @param id ID or name of the container + * @param condition Wait until a container state reaches the given condition, either 'not-running' (default), 'next-exit', or 'removed'. (optional, default to "not-running") + * @return ContainerWaitResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerWait(id: String, condition: String?): ContainerWaitResponse { + val localVariableConfig = containerWaitRequestConfig(id = id, condition = condition) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ContainerWaitResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerWait + * + * @param id ID or name of the container + * @param condition Wait until a container state reaches the given condition, either 'not-running' (default), 'next-exit', or 'removed'. (optional, default to "not-running") + * @return RequestConfig + */ + fun containerWaitRequestConfig(id: String, condition: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (condition != null) { + put("condition", listOf(condition.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/wait".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Extract an archive of files or folders to a directory in a container + * Upload a tar archive to be extracted to a path in the filesystem of container id. + * @param id ID or name of the container + * @param path Path to a directory in the container to extract the archive’s contents into. + * @param inputStream The input stream must be a tar archive compressed with one of the following algorithms: `identity` (no compression), `gzip`, `bzip2`, or `xz`. + * @param noOverwriteDirNonDir If `1`, `true`, or `True` then it will be an error if unpacking the given content would cause an existing directory to be replaced with a non-directory and vice versa. (optional) + * @param copyUIDGID If `1`, `true`, then it will copy UID/GID maps to the dest file or dir (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun putContainerArchive(id: String, path: String, inputStream: java.io.File, noOverwriteDirNonDir: String?, copyUIDGID: String?) { + val localVariableConfig = putContainerArchiveRequestConfig(id = id, path = path, inputStream = inputStream, noOverwriteDirNonDir = noOverwriteDirNonDir, copyUIDGID = copyUIDGID) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation putContainerArchive + * + * @param id ID or name of the container + * @param path Path to a directory in the container to extract the archive’s contents into. + * @param inputStream The input stream must be a tar archive compressed with one of the following algorithms: `identity` (no compression), `gzip`, `bzip2`, or `xz`. + * @param noOverwriteDirNonDir If `1`, `true`, or `True` then it will be an error if unpacking the given content would cause an existing directory to be replaced with a non-directory and vice versa. (optional) + * @param copyUIDGID If `1`, `true`, then it will copy UID/GID maps to the dest file or dir (optional) + * @return RequestConfig + */ + fun putContainerArchiveRequestConfig(id: String, path: String, inputStream: java.io.File, noOverwriteDirNonDir: String?, copyUIDGID: String?): RequestConfig { + val localVariableBody: Any? = inputStream + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("path", listOf(path)) + if (noOverwriteDirNonDir != null) { + put("noOverwriteDirNonDir", listOf(noOverwriteDirNonDir.toString())) + } + if (copyUIDGID != null) { + put("copyUIDGID", listOf(copyUIDGID.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = PUT, + path = "/containers/{id}/archive".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/DistributionApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/DistributionApi.kt new file mode 100644 index 000000000..8e104e5ad --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/DistributionApi.kt @@ -0,0 +1,89 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.DistributionInspect + +class DistributionApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Get image information from the registry + * Return image digest and platform information by contacting the registry. + * @param name Image name or id + * @return DistributionInspectResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun distributionInspect(name: String): DistributionInspect { + val localVariableConfig = distributionInspectRequestConfig(name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as DistributionInspect + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation distributionInspect + * + * @param name Image name or id + * @return RequestConfig + */ + fun distributionInspectRequestConfig(name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + val localVariableConfig = RequestConfig( + method = GET, + path = "/distribution/{name}/json".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + + return localVariableConfig + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ExecApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ExecApi.kt new file mode 100644 index 000000000..ddd15b7d7 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ExecApi.kt @@ -0,0 +1,291 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.LoggingCallback +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.client.infrastructure.SuccessStream +import de.gesellix.docker.engine.model.ExecConfig +import de.gesellix.docker.engine.model.ExecInspectResponse +import de.gesellix.docker.engine.model.ExecStartConfig +import de.gesellix.docker.engine.model.IdResponse +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeoutOrNull +import java.time.Duration +import java.time.temporal.ChronoUnit + +class ExecApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Create an exec instance + * Run a command inside a running container. + * @param id ID or name of container + * @param execConfig + * @return IdResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun containerExec(id: String, execConfig: ExecConfig): IdResponse { + val localVariableConfig = containerExecRequestConfig(id = id, execConfig = execConfig) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as IdResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation containerExec + * + * @param id ID or name of container + * @param execConfig + * @return RequestConfig + */ + fun containerExecRequestConfig(id: String, execConfig: ExecConfig): RequestConfig { + val localVariableBody: Any? = execConfig + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/containers/{id}/exec".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect an exec instance + * Return low-level information about an exec instance. + * @param id Exec instance ID + * @return ExecInspectResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun execInspect(id: String): ExecInspectResponse { + val localVariableConfig = execInspectRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ExecInspectResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation execInspect + * + * @param id Exec instance ID + * @return RequestConfig + */ + fun execInspectRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/exec/{id}/json".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Resize an exec instance + * Resize the TTY session used by an exec instance. This endpoint only works if `tty` was specified as part of creating and starting the exec instance. + * @param id Exec instance ID + * @param h Height of the TTY session in characters (optional) + * @param w Width of the TTY session in characters (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun execResize(id: String, h: Int?, w: Int?) { + val localVariableConfig = execResizeRequestConfig(id = id, h = h, w = w) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation execResize + * + * @param id Exec instance ID + * @param h Height of the TTY session in characters (optional) + * @param w Width of the TTY session in characters (optional) + * @return RequestConfig + */ + fun execResizeRequestConfig(id: String, h: Int?, w: Int?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (h != null) { + put("h", listOf(h.toString())) + } + if (w != null) { + put("w", listOf(w.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/exec/{id}/resize".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Start an exec instance + * Starts a previously set up exec instance. If detach is true, this endpoint returns immediately after starting the command. Otherwise, it sets up an interactive session with the command. + * @param id Exec instance ID + * @param execStartConfig (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun execStart(id: String, execStartConfig: ExecStartConfig?) { + val localVariableConfig = execStartRequestConfig(id = id, execStartConfig = execStartConfig) + + // TODO do we need to inspect the exec, because it might have been created with tty==false? +// val expectMultiplexedResponse = !(execInspect(id).processConfig?.tty ?: false) + val expectMultiplexedResponse = !(execStartConfig?.tty ?: false) + val localVarResponse = requestFrames( + localVariableConfig, expectMultiplexedResponse + ) + + // TODO the caller of #execStart() should decide about timeout and callback + val timeout = Duration.of(1, ChronoUnit.HOURS) + val callback = LoggingCallback() + + when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeoutOrNull(timeout.toMillis()) { + callback.onStarting(this@launch::cancel) + ((localVarResponse as SuccessStream<*>).data as Flow).collect { callback.onNext(it) } + callback.onFinished() + } + } + } + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation execStart + * + * @param id Exec instance ID + * @param execStartConfig (optional) + * @return RequestConfig + */ + fun execStartRequestConfig(id: String, execStartConfig: ExecStartConfig?): RequestConfig { + val localVariableBody: Any? = execStartConfig + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/exec/{id}/start".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ImageApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ImageApi.kt new file mode 100644 index 000000000..4115df25b --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ImageApi.kt @@ -0,0 +1,1309 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.LoggingCallback +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.client.infrastructure.SuccessStream +import de.gesellix.docker.engine.client.infrastructure.toMultiValue +import de.gesellix.docker.engine.model.BuildPruneResponse +import de.gesellix.docker.engine.model.ContainerConfig +import de.gesellix.docker.engine.model.HistoryResponseItem +import de.gesellix.docker.engine.model.IdResponse +import de.gesellix.docker.engine.model.Image +import de.gesellix.docker.engine.model.ImageDeleteResponseItem +import de.gesellix.docker.engine.model.ImagePruneResponse +import de.gesellix.docker.engine.model.ImageSearchResponseItem +import de.gesellix.docker.engine.model.ImageSummary +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import okio.source +import java.io.InputStream +import java.time.Duration +import java.time.temporal.ChronoUnit +import java.util.* + +class ImageApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Delete builder cache + * + * @param keepStorage Amount of disk space in bytes to keep for cache (optional) + * @param all Remove all types of build cache (optional) + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the list of build cache objects. Available filters: - `until=<duration>`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h') - `id=<id>` - `parent=<id>` - `type=<string>` - `description=<string>` - `inuse` - `shared` - `private` (optional) + * @return BuildPruneResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun buildPrune(keepStorage: Long?, all: Boolean?, filters: String?): BuildPruneResponse { + val localVariableConfig = buildPruneRequestConfig(keepStorage = keepStorage, all = all, filters = filters) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as BuildPruneResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation buildPrune + * + * @param keepStorage Amount of disk space in bytes to keep for cache (optional) + * @param all Remove all types of build cache (optional) + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the list of build cache objects. Available filters: - `until=<duration>`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h') - `id=<id>` - `parent=<id>` - `type=<string>` - `description=<string>` - `inuse` - `shared` - `private` (optional) + * @return RequestConfig + */ + fun buildPruneRequestConfig(keepStorage: Long?, all: Boolean?, filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (keepStorage != null) { + put("keep-storage", listOf(keepStorage.toString())) + } + if (all != null) { + put("all", listOf(all.toString())) + } + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/build/prune", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Build an image + * Build an image from a tar archive with a `Dockerfile` in it. The `Dockerfile` specifies how the image is built from the tar archive. It is typically in the archive's root, but can be at a different path or have a different name by specifying the `dockerfile` parameter. [See the `Dockerfile` reference for more information](https://docs.docker.com/engine/reference/builder/). The Docker daemon performs a preliminary validation of the `Dockerfile` before starting the build, and returns an error if the syntax is incorrect. After that, each instruction is run one-by-one until the ID of the new image is output. The build is canceled if the client drops the connection by quitting or being killed. + * @param dockerfile Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and points to an external `Dockerfile`. (optional, default to "Dockerfile") + * @param t A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag the default `latest` value is assumed. You can provide several `t` parameters. (optional) + * @param extrahosts Extra hosts to add to /etc/hosts (optional) + * @param remote A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file, the file’s contents are placed into a file called `Dockerfile` and the image is built from that file. If the URI points to a tarball, the file is downloaded by the daemon and the contents therein used as the context for the build. If the URI points to a tarball and the `dockerfile` parameter is also specified, there must be a file with the corresponding path inside the tarball. (optional) + * @param q Suppress verbose build output. (optional, default to false) + * @param nocache Do not use the cache when building the image. (optional, default to false) + * @param cachefrom JSON array of images used for build cache resolution. (optional) + * @param pull Attempt to pull the image even if an older image exists locally. (optional) + * @param rm Remove intermediate containers after a successful build. (optional, default to true) + * @param forcerm Always remove intermediate containers, even upon failure. (optional, default to false) + * @param memory Set memory limit for build. (optional) + * @param memswap Total memory (memory + swap). Set as `-1` to disable swap. (optional) + * @param cpushares CPU shares (relative weight). (optional) + * @param cpusetcpus CPUs in which to allow execution (e.g., `0-3`, `0,1`). (optional) + * @param cpuperiod The length of a CPU period in microseconds. (optional) + * @param cpuquota Microseconds of CPU time that the container can get in a CPU period. (optional) + * @param buildargs JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. For example, the build arg `FOO=bar` would become `{\"FOO\":\"bar\"}` in JSON. This would result in the query parameter `buildargs={\"FOO\":\"bar\"}`. Note that `{\"FOO\":\"bar\"}` should be URI component encoded. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg) (optional) + * @param shmsize Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB. (optional) + * @param squash Squash the resulting images layers into a single layer. *(Experimental release only.)* (optional) + * @param labels Arbitrary key/value labels to set on the image, as a JSON map of string pairs. (optional) + * @param networkmode Sets the networking mode for the run commands during build. Supported standard values are: `bridge`, `host`, `none`, and `container:<name|id>`. Any other value is taken as a custom network's name or ID to which this container should connect to. (optional) + * @param contentType (optional, default to application/x-tar) + * @param xRegistryConfig This is a base64-encoded JSON object with auth configurations for multiple registries that a build may refer to. The key is a registry URL, and the value is an auth configuration object, [as described in the authentication section](#section/Authentication). For example: ``` { \"docker.example.com\": { \"username\": \"janedoe\", \"password\": \"hunter2\" }, \"https://index.docker.io/v1/\": { \"username\": \"mobydock\", \"password\": \"conta1n3rize14\" } } ``` Only the registry domain name (and port if not the default 443) are required. However, for legacy reasons, the Docker Hub registry must be specified with both a `https://` prefix and a `/v1/` suffix even though Docker will prefer to use the v2 registry API. (optional) + * @param platform Platform in the format os[/arch[/variant]] (optional) + * @param target Target build stage (optional) + * @param outputs BuildKit output configuration (optional) + * @param inputStream A tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + // TODO consider NOT supporting `docker build`, because there might arise compatibility issues + // with Dockerfiles relying on `buildx`. Maybe we can simply shell out to a locally installed docker cli, + // but that's something the user might solve themselves. + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageBuild( + dockerfile: String?, + t: String?, + extrahosts: String?, + remote: String?, + q: Boolean?, + nocache: Boolean?, + cachefrom: String?, + pull: String?, + rm: Boolean?, + forcerm: Boolean?, + memory: Int?, + memswap: Int?, + cpushares: Int?, + cpusetcpus: String?, + cpuperiod: Int?, + cpuquota: Int?, + buildargs: String?, + shmsize: Int?, + squash: Boolean?, + labels: String?, + networkmode: String?, + contentType: String?, + xRegistryConfig: String?, + platform: String?, + target: String?, + outputs: String?, + inputStream: InputStream + ) { + val localVariableConfig = imageBuildRequestConfig( + dockerfile = dockerfile, + t = t, + extrahosts = extrahosts, + remote = remote, + q = q, + nocache = nocache, + cachefrom = cachefrom, + pull = pull, + rm = rm, + forcerm = forcerm, + memory = memory, + memswap = memswap, + cpushares = cpushares, + cpusetcpus = cpusetcpus, + cpuperiod = cpuperiod, + cpuquota = cpuquota, + buildargs = buildargs, + shmsize = shmsize, + squash = squash, + labels = labels, + networkmode = networkmode, + contentType = contentType, + xRegistryConfig = xRegistryConfig, + platform = platform, + target = target, + outputs = outputs, + inputStream = inputStream + ) + + val localVarResponse = requestStream( + localVariableConfig + ) + + val timeout = Duration.of(1, ChronoUnit.MINUTES) + // TODO collect events and/or extract the image id + // from either `aux ID=sha:.*`, + // or `stream Successfully built .*`, + // or `stream Successfully tagged .*` messages. + val callback = LoggingCallback() + + return when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeout.toMillis()) { + callback.onStarting(this@launch::cancel) + (localVarResponse as SuccessStream<*>).data.collect { callback.onNext(it) } + callback.onFinished() + } + } + } + Unit + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageBuild + * + * @param dockerfile Path within the build context to the `Dockerfile`. This is ignored if `remote` is specified and points to an external `Dockerfile`. (optional, default to "Dockerfile") + * @param t A name and optional tag to apply to the image in the `name:tag` format. If you omit the tag the default `latest` value is assumed. You can provide several `t` parameters. (optional) + * @param extrahosts Extra hosts to add to /etc/hosts (optional) + * @param remote A Git repository URI or HTTP/HTTPS context URI. If the URI points to a single text file, the file’s contents are placed into a file called `Dockerfile` and the image is built from that file. If the URI points to a tarball, the file is downloaded by the daemon and the contents therein used as the context for the build. If the URI points to a tarball and the `dockerfile` parameter is also specified, there must be a file with the corresponding path inside the tarball. (optional) + * @param q Suppress verbose build output. (optional, default to false) + * @param nocache Do not use the cache when building the image. (optional, default to false) + * @param cachefrom JSON array of images used for build cache resolution. (optional) + * @param pull Attempt to pull the image even if an older image exists locally. (optional) + * @param rm Remove intermediate containers after a successful build. (optional, default to true) + * @param forcerm Always remove intermediate containers, even upon failure. (optional, default to false) + * @param memory Set memory limit for build. (optional) + * @param memswap Total memory (memory + swap). Set as `-1` to disable swap. (optional) + * @param cpushares CPU shares (relative weight). (optional) + * @param cpusetcpus CPUs in which to allow execution (e.g., `0-3`, `0,1`). (optional) + * @param cpuperiod The length of a CPU period in microseconds. (optional) + * @param cpuquota Microseconds of CPU time that the container can get in a CPU period. (optional) + * @param buildargs JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. For example, the build arg `FOO=bar` would become `{\"FOO\":\"bar\"}` in JSON. This would result in the query parameter `buildargs={\"FOO\":\"bar\"}`. Note that `{\"FOO\":\"bar\"}` should be URI component encoded. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg) (optional) + * @param shmsize Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB. (optional) + * @param squash Squash the resulting images layers into a single layer. *(Experimental release only.)* (optional) + * @param labels Arbitrary key/value labels to set on the image, as a JSON map of string pairs. (optional) + * @param networkmode Sets the networking mode for the run commands during build. Supported standard values are: `bridge`, `host`, `none`, and `container:<name|id>`. Any other value is taken as a custom network's name or ID to which this container should connect to. (optional) + * @param contentType (optional, default to application/x-tar) + * @param xRegistryConfig This is a base64-encoded JSON object with auth configurations for multiple registries that a build may refer to. The key is a registry URL, and the value is an auth configuration object, [as described in the authentication section](#section/Authentication). For example: ``` { \"docker.example.com\": { \"username\": \"janedoe\", \"password\": \"hunter2\" }, \"https://index.docker.io/v1/\": { \"username\": \"mobydock\", \"password\": \"conta1n3rize14\" } } ``` Only the registry domain name (and port if not the default 443) are required. However, for legacy reasons, the Docker Hub registry must be specified with both a `https://` prefix and a `/v1/` suffix even though Docker will prefer to use the v2 registry API. (optional) + * @param platform Platform in the format os[/arch[/variant]] (optional) + * @param target Target build stage (optional) + * @param outputs BuildKit output configuration (optional) + * @param inputStream A tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz. (optional) + * @return RequestConfig + */ + fun imageBuildRequestConfig( + dockerfile: String?, + t: String?, + extrahosts: String?, + remote: String?, + q: Boolean?, + nocache: Boolean?, + cachefrom: String?, + pull: String?, + rm: Boolean?, + forcerm: Boolean?, + memory: Int?, + memswap: Int?, + cpushares: Int?, + cpusetcpus: String?, + cpuperiod: Int?, + cpuquota: Int?, + buildargs: String?, + shmsize: Int?, + squash: Boolean?, + labels: String?, + networkmode: String?, + contentType: String?, + xRegistryConfig: String?, + platform: String?, + target: String?, + outputs: String?, + inputStream: InputStream? + ): RequestConfig { + val localVariableBody: Any? = inputStream?.source() + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (dockerfile != null) { + put("dockerfile", listOf(dockerfile.toString())) + } + if (t != null) { + put("t", listOf(t.toString())) + } + if (extrahosts != null) { + put("extrahosts", listOf(extrahosts.toString())) + } + if (remote != null) { + put("remote", listOf(remote.toString())) + } + if (q != null) { + put("q", listOf(q.toString())) + } + if (nocache != null) { + put("nocache", listOf(nocache.toString())) + } + if (cachefrom != null) { + put("cachefrom", listOf(cachefrom.toString())) + } + if (pull != null) { + put("pull", listOf(pull.toString())) + } + if (rm != null) { + put("rm", listOf(rm.toString())) + } + if (forcerm != null) { + put("forcerm", listOf(forcerm.toString())) + } + if (memory != null) { + put("memory", listOf(memory.toString())) + } + if (memswap != null) { + put("memswap", listOf(memswap.toString())) + } + if (cpushares != null) { + put("cpushares", listOf(cpushares.toString())) + } + if (cpusetcpus != null) { + put("cpusetcpus", listOf(cpusetcpus.toString())) + } + if (cpuperiod != null) { + put("cpuperiod", listOf(cpuperiod.toString())) + } + if (cpuquota != null) { + put("cpuquota", listOf(cpuquota.toString())) + } + if (buildargs != null) { + put("buildargs", listOf(buildargs.toString())) + } + if (shmsize != null) { + put("shmsize", listOf(shmsize.toString())) + } + if (squash != null) { + put("squash", listOf(squash.toString())) + } + if (labels != null) { + put("labels", listOf(labels.toString())) + } + if (networkmode != null) { + put("networkmode", listOf(networkmode.toString())) + } + if (platform != null) { + put("platform", listOf(platform.toString())) + } + if (target != null) { + put("target", listOf(target.toString())) + } + if (outputs != null) { + put("outputs", listOf(outputs.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + contentType?.apply { localVariableHeaders["Content-type"] = this } + xRegistryConfig?.apply { localVariableHeaders["X-Registry-Config"] = this } + + return RequestConfig( + method = POST, + path = "/build", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Create a new image from a container + * + * @param container The ID or name of the container to commit (optional) + * @param repo Repository name for the created image (optional) + * @param tag Tag name for the create image (optional) + * @param comment Commit message (optional) + * @param author Author of the image (e.g., `John Hannibal Smith <hannibal@a-team.com>`) (optional) + * @param pause Whether to pause the container before committing (optional, default to true) + * @param changes `Dockerfile` instructions to apply while committing (optional) + * @param containerConfig The container configuration (optional) + * @return IdResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageCommit( + container: String?, + repo: String?, + tag: String?, + comment: String?, + author: String?, + pause: Boolean?, + changes: String?, + containerConfig: ContainerConfig? + ): IdResponse { + val localVariableConfig = + imageCommitRequestConfig(container = container, repo = repo, tag = tag, comment = comment, author = author, pause = pause, changes = changes, containerConfig = containerConfig) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as IdResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageCommit + * + * @param container The ID or name of the container to commit (optional) + * @param repo Repository name for the created image (optional) + * @param tag Tag name for the create image (optional) + * @param comment Commit message (optional) + * @param author Author of the image (e.g., `John Hannibal Smith <hannibal@a-team.com>`) (optional) + * @param pause Whether to pause the container before committing (optional, default to true) + * @param changes `Dockerfile` instructions to apply while committing (optional) + * @param containerConfig The container configuration (optional) + * @return RequestConfig + */ + fun imageCommitRequestConfig( + container: String?, + repo: String?, + tag: String?, + comment: String?, + author: String?, + pause: Boolean?, + changes: String?, + containerConfig: ContainerConfig? + ): RequestConfig { + val localVariableBody: Any? = containerConfig + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (container != null) { + put("container", listOf(container.toString())) + } + if (repo != null) { + put("repo", listOf(repo.toString())) + } + if (tag != null) { + put("tag", listOf(tag.toString())) + } + if (comment != null) { + put("comment", listOf(comment.toString())) + } + if (author != null) { + put("author", listOf(author.toString())) + } + if (pause != null) { + put("pause", listOf(pause.toString())) + } + if (changes != null) { + put("changes", listOf(changes.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/commit", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Create an image + * Create an image by either pulling it from a registry or importing it. + * @param fromImage Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed. (optional) + * @param fromSrc Source to import. The value may be a URL from which the image can be retrieved or `-` to read the image from the request body. This parameter may only be used when importing an image. (optional) + * @param repo Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image. (optional) + * @param tag Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled. (optional) + * @param message Set commit message for imported image. (optional) + * @param xRegistryAuth A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @param changes Apply Dockerfile instruction to the created image. (optional) + * @param platform Platform in the format os[/arch[/variant]] (optional) + * @param inputImage Image content if the value `-` has been specified in fromSrc query parameter (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageCreate( + fromImage: String?, + fromSrc: String?, + repo: String?, + tag: String?, + message: String?, + xRegistryAuth: String?, + changes: List?, + platform: String?, + inputImage: InputStream? + ) { + val localVariableConfig = + imageCreateRequestConfig( + fromImage = fromImage, + fromSrc = fromSrc, + repo = repo, + tag = tag, + message = message, + xRegistryAuth = xRegistryAuth, + changes = changes, + platform = platform, + inputImage = inputImage + ) + + val localVarResponse = requestStream( + localVariableConfig + ) + + val timeout = Duration.of(1, ChronoUnit.MINUTES) + val callback = LoggingCallback() + + return when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeout.toMillis()) { + callback.onStarting(this@launch::cancel) + (localVarResponse as SuccessStream<*>).data.collect { callback.onNext(it) } + callback.onFinished() + } + } + } + Unit + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageCreate + * + * @param fromImage Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed. (optional) + * @param fromSrc Source to import. The value may be a URL from which the image can be retrieved or `-` to read the image from the request body. This parameter may only be used when importing an image. (optional) + * @param repo Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image. (optional) + * @param tag Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled. (optional) + * @param message Set commit message for imported image. (optional) + * @param xRegistryAuth A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @param changes Apply Dockerfile instruction to the created image. (optional) + * @param platform Platform in the format os[/arch[/variant]] (optional) + * @param inputImage Image content if the value `-` has been specified in fromSrc query parameter (optional) + * @return RequestConfig + */ + fun imageCreateRequestConfig( + fromImage: String?, + fromSrc: String?, + repo: String?, + tag: String?, + message: String?, + xRegistryAuth: String?, + changes: List?, + platform: String?, + inputImage: InputStream? + ): RequestConfig { + val localVariableBody: Any? = inputImage?.source() + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (fromImage != null) { + put("fromImage", listOf(fromImage.toString())) + } + if (fromSrc != null) { + put("fromSrc", listOf(fromSrc.toString())) + } + if (repo != null) { + put("repo", listOf(repo.toString())) + } + if (tag != null) { + put("tag", listOf(tag.toString())) + } + if (message != null) { + put("message", listOf(message.toString())) + } + if (changes != null) { + put("changes", toMultiValue(changes.toList(), "multi")) + } + if (platform != null) { + put("platform", listOf(platform.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + xRegistryAuth?.apply { localVariableHeaders["X-Registry-Auth"] = this } + + return RequestConfig( + method = POST, + path = "/images/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Remove an image + * Remove an image, along with any untagged parent images that were referenced by that image. Images can't be removed if they have descendant images, are being used by a running container or are being used by a build. + * @param name Image name or ID + * @param force Remove the image even if it is being used by stopped containers or has other tags (optional, default to false) + * @param noprune Do not delete untagged parent images (optional, default to false) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageDelete(name: String, force: Boolean?, noprune: Boolean?): List { + val localVariableConfig = imageDeleteRequestConfig(name = name, force = force, noprune = noprune) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageDelete + * + * @param name Image name or ID + * @param force Remove the image even if it is being used by stopped containers or has other tags (optional, default to false) + * @param noprune Do not delete untagged parent images (optional, default to false) + * @return RequestConfig + */ + fun imageDeleteRequestConfig(name: String, force: Boolean?, noprune: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (force != null) { + put("force", listOf(force.toString())) + } + if (noprune != null) { + put("noprune", listOf(noprune.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/images/{name}".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = ImageDeleteResponseItem::class.java + ) + } + + /** + * Export an image + * Get a tarball containing all images and metadata for a repository. If `name` is a specific name and tag (e.g. `ubuntu:latest`), then only that image (and its parents) are returned. If `name` is an image ID, similarly only that image (and its parents) are returned, but with the exclusion of the `repositories` file in the tarball, as there were no image names referenced. ### Image tarball format An image tarball contains one directory per image layer (named using its long ID), each containing these files: - `VERSION`: currently `1.0` - the file format version - `json`: detailed layer information, similar to `docker inspect layer_id` - `layer.tar`: A tarfile containing the filesystem changes in this layer The `layer.tar` file contains `aufs` style `.wh..wh.aufs` files and directories for storing attribute changes and deletions. If the tarball defines a repository, the tarball should also include a `repositories` file at the root that contains a list of repository and tag names mapped to layer IDs. ```json { \"hello-world\": { \"latest\": \"565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1\" } } ``` + * @param name Image name or ID + * @return java.io.File + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageGet(name: String): java.io.File { + return this.imageGetAll(Collections.singletonList(name)) + } + + /** + * Export several images + * Get a tarball containing all images and metadata for several image repositories. For each value of the `names` parameter: if it is a specific name and tag (e.g. `ubuntu:latest`), then only that image (and its parents) are returned; if it is an image ID, similarly only that image (and its parents) are returned and there would be no names referenced in the 'repositories' file for this image ID. For details on the format, see the [export image endpoint](#operation/ImageGet). + * @param names Image names to filter by (optional) + * @return java.io.File + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageGetAll(names: List?): java.io.File { + val localVariableConfig = imageGetAllRequestConfig(names = names) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as java.io.File + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageGetAll + * + * @param names Image names to filter by (optional) + * @return RequestConfig + */ + fun imageGetAllRequestConfig(names: List?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (names != null) { + put("names", toMultiValue(names.toList(), "multi")) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/images/get", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get the history of an image + * Return parent layers of an image. + * @param name Image name or ID + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageHistory(name: String): List { + val localVariableConfig = imageHistoryRequestConfig(name = name) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageHistory + * + * @param name Image name or ID + * @return RequestConfig + */ + fun imageHistoryRequestConfig(name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/images/{name}/history".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = HistoryResponseItem::class.java + ) + } + + /** + * Inspect an image + * Return low-level information about an image. + * @param name Image name or id + * @return Image + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageInspect(name: String): Image { + val localVariableConfig = imageInspectRequestConfig(name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Image + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageInspect + * + * @param name Image name or id + * @return RequestConfig + */ + fun imageInspectRequestConfig(name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/images/{name}/json".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List Images + * Returns a list of images on the server. Note that it uses a different, smaller representation of an image than inspecting a single image. + * @param all Show all images. Only images from a final layer (no children) are shown by default. (optional, default to false) + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - `dangling=true` - `label=key` or `label=\"key=value\"` of an image label - `reference`=(`<image-name>[:<tag>]`) - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) (optional) + * @param digests Show digest information as a `RepoDigests` field on each image. (optional, default to false) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageList(all: Boolean?, filters: String?, digests: Boolean?): List { + val localVariableConfig = imageListRequestConfig(all = all, filters = filters, digests = digests) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageList + * + * @param all Show all images. Only images from a final layer (no children) are shown by default. (optional, default to false) + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - `dangling=true` - `label=key` or `label=\"key=value\"` of an image label - `reference`=(`<image-name>[:<tag>]`) - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) (optional) + * @param digests Show digest information as a `RepoDigests` field on each image. (optional, default to false) + * @return RequestConfig + */ + fun imageListRequestConfig(all: Boolean?, filters: String?, digests: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (all != null) { + put("all", listOf(all.toString())) + } + if (filters != null) { + put("filters", listOf(filters.toString())) + } + if (digests != null) { + put("digests", listOf(digests.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/images/json", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = ImageSummary::class.java + ) + } + + /** + * Import images + * Load a set of images and tags into a repository. For details on the format, see the [export image endpoint](#operation/ImageGet). + * @param quiet Suppress progress details during load. (optional, default to false) + * @param imagesTarball Tar archive containing images (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageLoad(quiet: Boolean?, imagesTarball: java.io.File?) { + val localVariableConfig = imageLoadRequestConfig(quiet = quiet, imagesTarball = imagesTarball) + + val localVarResponse = requestStream( + localVariableConfig + ) + + val timeout = Duration.of(1, ChronoUnit.MINUTES) + val callback = LoggingCallback() + + return when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeout.toMillis()) { + callback.onStarting(this@launch::cancel) + (localVarResponse as SuccessStream<*>).data.collect { callback.onNext(it) } + callback.onFinished() + } + } + } + Unit + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageLoad + * + * @param quiet Suppress progress details during load. (optional, default to false) + * @param imagesTarball Tar archive containing images (optional) + * @return RequestConfig + */ + fun imageLoadRequestConfig(quiet: Boolean?, imagesTarball: java.io.File?): RequestConfig { + val localVariableBody: Any? = imagesTarball + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (quiet != null) { + put("quiet", listOf(quiet.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/images/load", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Delete unused images + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `dangling=<boolean>` When set to `true` (or `1`), prune only unused *and* untagged images. When set to `false` (or `0`), all unused images are pruned. - `until=<string>` Prune images created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune images with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return ImagePruneResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imagePrune(filters: String?): ImagePruneResponse { + val localVariableConfig = imagePruneRequestConfig(filters = filters) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ImagePruneResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imagePrune + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `dangling=<boolean>` When set to `true` (or `1`), prune only unused *and* untagged images. When set to `false` (or `0`), all unused images are pruned. - `until=<string>` Prune images created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune images with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return RequestConfig + */ + fun imagePruneRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/images/prune", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Push an image + * Push an image to a registry. If you wish to push an image on to a private registry, that image must already have a tag which references the registry. For example, `registry.example.com/myimage:latest`. The push is cancelled if the HTTP connection is closed. + * @param name Image name or ID. + * @param xRegistryAuth A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. + * @param tag The tag to associate with the image on the registry. (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imagePush(name: String, xRegistryAuth: String, tag: String?) { + val localVariableConfig = imagePushRequestConfig(name = name, xRegistryAuth = xRegistryAuth, tag = tag) + + val localVarResponse = requestStream( + localVariableConfig + ) + + val timeout = Duration.of(10, ChronoUnit.MINUTES) + val callback = LoggingCallback() + + return when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeout.toMillis()) { + callback.onStarting(this@launch::cancel) + (localVarResponse as SuccessStream<*>).data.collect { callback.onNext(it) } + callback.onFinished() + } + } + } + Unit + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imagePush + * + * @param name Image name or ID. + * @param xRegistryAuth A base64url-encoded auth configuration. Refer to the [authentication section](#section/Authentication) for details. + * @param tag The tag to associate with the image on the registry. (optional) + * @return RequestConfig + */ + fun imagePushRequestConfig(name: String, xRegistryAuth: String, tag: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (tag != null) { + put("tag", listOf(tag.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + xRegistryAuth.apply { localVariableHeaders["X-Registry-Auth"] = this } + + return RequestConfig( + method = POST, + path = "/images/{name}/push".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Search images + * Search for an image on Docker Hub. + * @param term Term to search + * @param limit Maximum number of results to return (optional) + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `is-automated=(true|false)` - `is-official=(true|false)` - `stars=<number>` Matches images that has at least 'number' stars. (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageSearch(term: String, limit: Int?, filters: String?): List { + val localVariableConfig = imageSearchRequestConfig(term = term, limit = limit, filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageSearch + * + * @param term Term to search + * @param limit Maximum number of results to return (optional) + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters: - `is-automated=(true|false)` - `is-official=(true|false)` - `stars=<number>` Matches images that has at least 'number' stars. (optional) + * @return RequestConfig + */ + fun imageSearchRequestConfig(term: String, limit: Int?, filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("term", listOf(term)) + if (limit != null) { + put("limit", listOf(limit.toString())) + } + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/images/search", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = ImageSearchResponseItem::class.java + ) + } + + /** + * Tag an image + * Tag an image so that it becomes part of a repository. + * @param name Image name or ID to tag. + * @param repo The repository to tag in. For example, `someuser/someimage`. (optional) + * @param tag The name of the new tag. (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun imageTag(name: String, repo: String?, tag: String?) { + val localVariableConfig = imageTagRequestConfig(name = name, repo = repo, tag = tag) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation imageTag + * + * @param name Image name or ID to tag. + * @param repo The repository to tag in. For example, `someuser/someimage`. (optional) + * @param tag The name of the new tag. (optional) + * @return RequestConfig + */ + fun imageTagRequestConfig(name: String, repo: String?, tag: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (repo != null) { + put("repo", listOf(repo.toString())) + } + if (tag != null) { + put("tag", listOf(tag.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/images/{name}/tag".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/NetworkApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/NetworkApi.kt new file mode 100644 index 000000000..0c214eaf9 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/NetworkApi.kt @@ -0,0 +1,440 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.Network +import de.gesellix.docker.engine.model.NetworkConnectRequest +import de.gesellix.docker.engine.model.NetworkCreateRequest +import de.gesellix.docker.engine.model.NetworkCreateResponse +import de.gesellix.docker.engine.model.NetworkDisconnectRequest +import de.gesellix.docker.engine.model.NetworkPruneResponse +import java.net.HttpURLConnection + +class NetworkApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Connect a container to a network + * + * @param id Network ID or name + * @param container + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun networkConnect(id: String, container: NetworkConnectRequest) { + val localVariableConfig = networkConnectRequestConfig(id = id, container = container) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation networkConnect + * + * @param id Network ID or name + * @param container + * @return RequestConfig + */ + fun networkConnectRequestConfig(id: String, container: NetworkConnectRequest): RequestConfig { + val localVariableBody: Any? = container + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/networks/{id}/connect".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Create a network + * + * @param networkConfig + * @return NetworkCreateResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun networkCreate(networkConfig: NetworkCreateRequest): NetworkCreateResponse { + val localVariableConfig = networkCreateRequestConfig(networkConfig = networkConfig) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as NetworkCreateResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation networkCreate + * + * @param networkConfig + * @return RequestConfig + */ + fun networkCreateRequestConfig(networkConfig: NetworkCreateRequest): RequestConfig { + val localVariableBody: Any? = networkConfig + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/networks/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Remove a network + * + * @param id Network ID or name + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun networkDelete(id: String) { + val localVariableConfig = networkDeleteRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + if (localVarError.statusCode == HttpURLConnection.HTTP_NOT_FOUND) { + return + } + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation networkDelete + * + * @param id Network ID or name + * @return RequestConfig + */ + fun networkDeleteRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/networks/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Disconnect a container from a network + * + * @param id Network ID or name + * @param container + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun networkDisconnect(id: String, container: NetworkDisconnectRequest) { + val localVariableConfig = networkDisconnectRequestConfig(id = id, container = container) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation networkDisconnect + * + * @param id Network ID or name + * @param container + * @return RequestConfig + */ + fun networkDisconnectRequestConfig(id: String, container: NetworkDisconnectRequest): RequestConfig { + val localVariableBody: Any? = container + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/networks/{id}/disconnect".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a network + * + * @param id Network ID or name + * @param verbose Detailed inspect output for troubleshooting (optional, default to false) + * @param scope Filter the network by scope (swarm, global, or local) (optional) + * @return Network + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun networkInspect(id: String, verbose: Boolean?, scope: String?): Network { + val localVariableConfig = networkInspectRequestConfig(id = id, verbose = verbose, scope = scope) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Network + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation networkInspect + * + * @param id Network ID or name + * @param verbose Detailed inspect output for troubleshooting (optional, default to false) + * @param scope Filter the network by scope (swarm, global, or local) (optional) + * @return RequestConfig + */ + fun networkInspectRequestConfig(id: String, verbose: Boolean?, scope: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (verbose != null) { + put("verbose", listOf(verbose.toString())) + } + if (scope != null) { + put("scope", listOf(scope.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/networks/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List networks + * Returns a list of networks. For details on the format, see the [network inspect endpoint](#operation/NetworkInspect). Note that it uses a different, smaller representation of a network than inspecting a single network. For example, the list of containers attached to the network is not propagated in API versions 1.28 and up. + * @param filters JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters: - `dangling=<boolean>` When set to `true` (or `1`), returns all networks that are not in use by a container. When set to `false` (or `0`), only networks that are in use by one or more containers are returned. - `driver=<driver-name>` Matches a network's driver. - `id=<network-id>` Matches all or part of a network ID. - `label=<key>` or `label=<key>=<value>` of a network label. - `name=<network-name>` Matches all or part of a network name. - `scope=[\"swarm\"|\"global\"|\"local\"]` Filters networks by scope (`swarm`, `global`, or `local`). - `type=[\"custom\"|\"builtin\"]` Filters networks by type. The `custom` keyword returns all user-defined networks. (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun networkList(filters: String?): List { + val localVariableConfig = networkListRequestConfig(filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation networkList + * + * @param filters JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters: - `dangling=<boolean>` When set to `true` (or `1`), returns all networks that are not in use by a container. When set to `false` (or `0`), only networks that are in use by one or more containers are returned. - `driver=<driver-name>` Matches a network's driver. - `id=<network-id>` Matches all or part of a network ID. - `label=<key>` or `label=<key>=<value>` of a network label. - `name=<network-name>` Matches all or part of a network name. - `scope=[\"swarm\"|\"global\"|\"local\"]` Filters networks by scope (`swarm`, `global`, or `local`). - `type=[\"custom\"|\"builtin\"]` Filters networks by type. The `custom` keyword returns all user-defined networks. (optional) + * @return RequestConfig + */ + fun networkListRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/networks", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = Network::class.java + ) + } + + /** + * Delete unused networks + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=<timestamp>` Prune networks created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune networks with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return NetworkPruneResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun networkPrune(filters: String?): NetworkPruneResponse { + val localVariableConfig = networkPruneRequestConfig(filters = filters) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as NetworkPruneResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation networkPrune + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `until=<timestamp>` Prune networks created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune networks with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return RequestConfig + */ + fun networkPruneRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/networks/prune", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/NodeApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/NodeApi.kt new file mode 100644 index 000000000..6b0ef40c2 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/NodeApi.kt @@ -0,0 +1,267 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.Node +import de.gesellix.docker.engine.model.NodeSpec + +class NodeApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Delete a node + * + * @param id The ID or name of the node + * @param force Force remove a node from the swarm (optional, default to false) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun nodeDelete(id: String, force: Boolean?) { + val localVariableConfig = nodeDeleteRequestConfig(id = id, force = force) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation nodeDelete + * + * @param id The ID or name of the node + * @param force Force remove a node from the swarm (optional, default to false) + * @return RequestConfig + */ + fun nodeDeleteRequestConfig(id: String, force: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (force != null) { + put("force", listOf(force.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/nodes/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a node + * + * @param id The ID or name of the node + * @return Node + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun nodeInspect(id: String): Node { + val localVariableConfig = nodeInspectRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Node + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation nodeInspect + * + * @param id The ID or name of the node + * @return RequestConfig + */ + fun nodeInspectRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/nodes/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List nodes + * + * @param filters Filters to process on the nodes list, encoded as JSON (a `map[string][]string`). Available filters: - `id=<node id>` - `label=<engine label>` - `membership=`(`accepted`|`pending`)` - `name=<node name>` - `node.label=<node label>` - `role=`(`manager`|`worker`)` (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun nodeList(filters: String?): List { + val localVariableConfig = nodeListRequestConfig(filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation nodeList + * + * @param filters Filters to process on the nodes list, encoded as JSON (a `map[string][]string`). Available filters: - `id=<node id>` - `label=<engine label>` - `membership=`(`accepted`|`pending`)` - `name=<node name>` - `node.label=<node label>` - `role=`(`manager`|`worker`)` (optional) + * @return RequestConfig + */ + fun nodeListRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/nodes", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = Node::class.java + ) + } + + /** + * Update a node + * + * @param id The ID of the node + * @param version The version number of the node object being updated. This is required to avoid conflicting writes. + * @param body (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun nodeUpdate(id: String, version: Long, body: NodeSpec?) { + val localVariableConfig = nodeUpdateRequestConfig(id = id, version = version, body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation nodeUpdate + * + * @param id The ID of the node + * @param version The version number of the node object being updated. This is required to avoid conflicting writes. + * @param body (optional) + * @return RequestConfig + */ + fun nodeUpdateRequestConfig(id: String, version: Long, body: NodeSpec?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("version", listOf(version.toString())) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/nodes/{id}/update".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/PluginApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/PluginApi.kt new file mode 100644 index 000000000..702306370 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/PluginApi.kt @@ -0,0 +1,667 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.Plugin +import de.gesellix.docker.engine.model.PluginPrivilege + +class PluginApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Get plugin privileges + * + * @param remote The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun getPluginPrivileges(remote: String): List { + val localVariableConfig = getPluginPrivilegesRequestConfig(remote = remote) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation getPluginPrivileges + * + * @param remote The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return RequestConfig + */ + fun getPluginPrivilegesRequestConfig(remote: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("remote", listOf(remote)) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/plugins/privileges", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = PluginPrivilege::class.java + ) + } + + /** + * Create a plugin + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param tarContext Path to tar containing plugin rootfs and manifest (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginCreate(name: String, tarContext: java.io.File?) { + val localVariableConfig = pluginCreateRequestConfig(name = name, tarContext = tarContext) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginCreate + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param tarContext Path to tar containing plugin rootfs and manifest (optional) + * @return RequestConfig + */ + fun pluginCreateRequestConfig(name: String, tarContext: java.io.File?): RequestConfig { + val localVariableBody: Any? = tarContext + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("name", listOf(name)) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/plugins/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Remove a plugin + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param force Disable the plugin before removing. This may result in issues if the plugin is in use by a container. (optional, default to false) + * @return Plugin + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginDelete(name: String, force: Boolean?): Plugin { + val localVariableConfig = pluginDeleteRequestConfig(name = name, force = force) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Plugin + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginDelete + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param force Disable the plugin before removing. This may result in issues if the plugin is in use by a container. (optional, default to false) + * @return RequestConfig + */ + fun pluginDeleteRequestConfig(name: String, force: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (force != null) { + put("force", listOf(force.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/plugins/{name}".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Disable a plugin + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginDisable(name: String) { + val localVariableConfig = pluginDisableRequestConfig(name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginDisable + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return RequestConfig + */ + fun pluginDisableRequestConfig(name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/plugins/{name}/disable".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Enable a plugin + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param timeout Set the HTTP client timeout (in seconds) (optional, default to 0) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginEnable(name: String, timeout: Int?) { + val localVariableConfig = pluginEnableRequestConfig(name = name, timeout = timeout) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginEnable + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param timeout Set the HTTP client timeout (in seconds) (optional, default to 0) + * @return RequestConfig + */ + fun pluginEnableRequestConfig(name: String, timeout: Int?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (timeout != null) { + put("timeout", listOf(timeout.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/plugins/{name}/enable".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a plugin + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return Plugin + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginInspect(name: String): Plugin { + val localVariableConfig = pluginInspectRequestConfig(name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Plugin + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginInspect + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return RequestConfig + */ + fun pluginInspectRequestConfig(name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/plugins/{name}/json".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List plugins + * Returns information about installed plugins. + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the plugin list. Available filters: - `capability=<capability name>` - `enable=<true>|<false>` (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginList(filters: String?): List { + val localVariableConfig = pluginListRequestConfig(filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginList + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the plugin list. Available filters: - `capability=<capability name>` - `enable=<true>|<false>` (optional) + * @return RequestConfig + */ + fun pluginListRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/plugins", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = Plugin::class.java + ) + } + + /** + * Install a plugin + * Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PostPluginsEnable). + * @param remote Remote reference for plugin to install. The `:latest` tag is optional, and is used as the default if omitted. + * @param name Local name for the pulled plugin. The `:latest` tag is optional, and is used as the default if omitted. (optional) + * @param xRegistryAuth A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @param body (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginPull(remote: String, name: String?, xRegistryAuth: String?, body: List?) { + val localVariableConfig = pluginPullRequestConfig(remote = remote, name = name, xRegistryAuth = xRegistryAuth, body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginPull + * + * @param remote Remote reference for plugin to install. The `:latest` tag is optional, and is used as the default if omitted. + * @param name Local name for the pulled plugin. The `:latest` tag is optional, and is used as the default if omitted. (optional) + * @param xRegistryAuth A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @param body (optional) + * @return RequestConfig + */ + fun pluginPullRequestConfig(remote: String, name: String?, xRegistryAuth: String?, body: List?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("remote", listOf(remote)) + if (name != null) { + put("name", listOf(name.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + xRegistryAuth?.apply { localVariableHeaders["X-Registry-Auth"] = this } + + return RequestConfig( + method = POST, + path = "/plugins/pull", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Push a plugin + * Push a plugin to the registry. + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginPush(name: String) { + val localVariableConfig = pluginPushRequestConfig(name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginPush + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @return RequestConfig + */ + fun pluginPushRequestConfig(name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/plugins/{name}/push".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Configure a plugin + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param body (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginSet(name: String, body: List?) { + val localVariableConfig = pluginSetRequestConfig(name = name, body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginSet + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param body (optional) + * @return RequestConfig + */ + fun pluginSetRequestConfig(name: String, body: List?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/plugins/{name}/set".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Upgrade a plugin + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param remote Remote reference to upgrade to. The `:latest` tag is optional, and is used as the default if omitted. + * @param xRegistryAuth A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @param body (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun pluginUpgrade(name: String, remote: String, xRegistryAuth: String?, body: List?) { + val localVariableConfig = pluginUpgradeRequestConfig(name = name, remote = remote, xRegistryAuth = xRegistryAuth, body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation pluginUpgrade + * + * @param name The name of the plugin. The `:latest` tag is optional, and is the default if omitted. + * @param remote Remote reference to upgrade to. The `:latest` tag is optional, and is used as the default if omitted. + * @param xRegistryAuth A base64url-encoded auth configuration to use when pulling a plugin from a registry. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @param body (optional) + * @return RequestConfig + */ + fun pluginUpgradeRequestConfig(name: String, remote: String, xRegistryAuth: String?, body: List?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("remote", listOf(remote)) + } + val localVariableHeaders: MutableMap = mutableMapOf() + xRegistryAuth?.apply { localVariableHeaders["X-Registry-Auth"] = this } + + return RequestConfig( + method = POST, + path = "/plugins/{name}/upgrade".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SecretApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SecretApi.kt new file mode 100644 index 000000000..acba4311d --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SecretApi.kt @@ -0,0 +1,314 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.IdResponse +import de.gesellix.docker.engine.model.Secret +import de.gesellix.docker.engine.model.SecretSpec + +class SecretApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Create a secret + * + * @param body (optional) + * @return IdResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun secretCreate(body: SecretSpec?): IdResponse { + val localVariableConfig = secretCreateRequestConfig(body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as IdResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation secretCreate + * + * @param body (optional) + * @return RequestConfig + */ + fun secretCreateRequestConfig(body: SecretSpec?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/secrets/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Delete a secret + * + * @param id ID of the secret + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun secretDelete(id: String) { + val localVariableConfig = secretDeleteRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation secretDelete + * + * @param id ID of the secret + * @return RequestConfig + */ + fun secretDeleteRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/secrets/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a secret + * + * @param id ID of the secret + * @return Secret + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun secretInspect(id: String): Secret { + val localVariableConfig = secretInspectRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Secret + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation secretInspect + * + * @param id ID of the secret + * @return RequestConfig + */ + fun secretInspectRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/secrets/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List secrets + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Available filters: - `id=<secret id>` - `label=<key> or label=<key>=value` - `name=<secret name>` - `names=<secret name>` (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun secretList(filters: String?): List { + val localVariableConfig = secretListRequestConfig(filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation secretList + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Available filters: - `id=<secret id>` - `label=<key> or label=<key>=value` - `name=<secret name>` - `names=<secret name>` (optional) + * @return RequestConfig + */ + fun secretListRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/secrets", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = Secret::class.java + ) + } + + /** + * Update a Secret + * + * @param id The ID or name of the secret + * @param version The version number of the secret object being updated. This is required to avoid conflicting writes. + * @param body The spec of the secret to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [SecretInspect endpoint](#operation/SecretInspect) response values. (optional) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun secretUpdate(id: String, version: Long, body: SecretSpec?) { + val localVariableConfig = secretUpdateRequestConfig(id = id, version = version, body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation secretUpdate + * + * @param id The ID or name of the secret + * @param version The version number of the secret object being updated. This is required to avoid conflicting writes. + * @param body The spec of the secret to update. Currently, only the Labels field can be updated. All other fields must remain unchanged from the [SecretInspect endpoint](#operation/SecretInspect) response values. (optional) + * @return RequestConfig + */ + fun secretUpdateRequestConfig(id: String, version: Long, body: SecretSpec?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("version", listOf(version.toString())) + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/secrets/{id}/update".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ServiceApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ServiceApi.kt new file mode 100644 index 000000000..2749ee0e4 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/ServiceApi.kt @@ -0,0 +1,481 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.client.infrastructure.SuccessStream +import de.gesellix.docker.engine.model.Service +import de.gesellix.docker.engine.model.ServiceCreateResponse +import de.gesellix.docker.engine.model.ServiceSpec +import de.gesellix.docker.engine.model.ServiceUpdateResponse +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import java.net.HttpURLConnection + +class ServiceApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Create a service + * + * @param body + * @param xRegistryAuth A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @return ServiceCreateResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun serviceCreate(body: ServiceSpec, xRegistryAuth: String?): ServiceCreateResponse { + val localVariableConfig = serviceCreateRequestConfig(body = body, xRegistryAuth = xRegistryAuth) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ServiceCreateResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation serviceCreate + * + * @param body + * @param xRegistryAuth A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @return RequestConfig + */ + fun serviceCreateRequestConfig(body: ServiceSpec, xRegistryAuth: String?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + xRegistryAuth?.apply { localVariableHeaders["X-Registry-Auth"] = this } + + return RequestConfig( + method = POST, + path = "/services/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Delete a service + * + * @param id ID or name of service. + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun serviceDelete(id: String) { + val localVariableConfig = serviceDeleteRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + if (localVarError.statusCode == HttpURLConnection.HTTP_NOT_FOUND) { + return + } + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation serviceDelete + * + * @param id ID or name of service. + * @return RequestConfig + */ + fun serviceDeleteRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/services/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a service + * + * @param id ID or name of service. + * @param insertDefaults Fill empty fields with default values. (optional, default to false) + * @return Service + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun serviceInspect(id: String, insertDefaults: Boolean?): Service { + val localVariableConfig = serviceInspectRequestConfig(id = id, insertDefaults = insertDefaults) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Service + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation serviceInspect + * + * @param id ID or name of service. + * @param insertDefaults Fill empty fields with default values. (optional, default to false) + * @return RequestConfig + */ + fun serviceInspectRequestConfig(id: String, insertDefaults: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (insertDefaults != null) { + put("insertDefaults", listOf(insertDefaults.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/services/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List services + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the services list. Available filters: - `id=<service id>` - `label=<service label>` - `mode=[\"replicated\"|\"global\"]` - `name=<service name>` (optional) + * @param status Include service status, with count of running and desired tasks. (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun serviceList(filters: String?, status: Boolean?): List { + val localVariableConfig = serviceListRequestConfig(filters = filters, status = status) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation serviceList + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the services list. Available filters: - `id=<service id>` - `label=<service label>` - `mode=[\"replicated\"|\"global\"]` - `name=<service name>` (optional) + * @param status Include service status, with count of running and desired tasks. (optional) + * @return RequestConfig + */ + fun serviceListRequestConfig(filters: String?, status: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + if (status != null) { + put("status", listOf(status.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/services", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = Service::class.java + ) + } + + /** + * Get service logs + * Get `stdout` and `stderr` logs from a service. See also [`/containers/{id}/logs`](#operation/ContainerLogs). **Note**: This endpoint works only for services with the `local`, `json-file` or `journald` logging drivers. + * @param id ID or name of the service + * @param details Show service context and extra details provided to logs. (optional, default to false) + * @param follow Keep connection after returning logs. (optional, default to false) + * @param stdout Return logs from `stdout` (optional, default to false) + * @param stderr Return logs from `stderr` (optional, default to false) + * @param since Only return logs since this time, as a UNIX timestamp (optional, default to 0) + * @param timestamps Add timestamps to every log line (optional, default to false) + * @param tail Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. (optional, default to "all") + * @return java.io.File + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun serviceLogs( + id: String, + details: Boolean?, + follow: Boolean?, + stdout: Boolean?, + stderr: Boolean?, + since: Int?, + timestamps: Boolean?, + tail: String?, + callback: StreamCallback, timeoutMillis: Long /*= 24.hours.toLongMilliseconds()*/ + ) { + val localVariableConfig = serviceLogsRequestConfig(id = id, details = details, follow = follow, stdout = stdout, stderr = stderr, since = since, timestamps = timestamps, tail = tail) + + val localVarResponse = requestFrames( + localVariableConfig, true /* do services/tasks always have container.tty == false? */ + ) + + when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeoutMillis) { + callback.onStarting(this@launch::cancel) + ((localVarResponse as SuccessStream<*>).data as Flow).collect { callback.onNext(it) } + callback.onFinished() + } + } + } + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation serviceLogs + * + * @param id ID or name of the service + * @param details Show service context and extra details provided to logs. (optional, default to false) + * @param follow Keep connection after returning logs. (optional, default to false) + * @param stdout Return logs from `stdout` (optional, default to false) + * @param stderr Return logs from `stderr` (optional, default to false) + * @param since Only return logs since this time, as a UNIX timestamp (optional, default to 0) + * @param timestamps Add timestamps to every log line (optional, default to false) + * @param tail Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. (optional, default to "all") + * @return RequestConfig + */ + fun serviceLogsRequestConfig( + id: String, + details: Boolean?, + follow: Boolean?, + stdout: Boolean?, + stderr: Boolean?, + since: Int?, + timestamps: Boolean?, + tail: String? + ): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (details != null) { + put("details", listOf(details.toString())) + } + if (follow != null) { + put("follow", listOf(follow.toString())) + } + if (stdout != null) { + put("stdout", listOf(stdout.toString())) + } + if (stderr != null) { + put("stderr", listOf(stderr.toString())) + } + if (since != null) { + put("since", listOf(since.toString())) + } + if (timestamps != null) { + put("timestamps", listOf(timestamps.toString())) + } + if (tail != null) { + put("tail", listOf(tail.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/services/{id}/logs".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Update a service + * + * @param id ID or name of service. + * @param version The version number of the service object being updated. This is required to avoid conflicting writes. This version number should be the value as currently set on the service *before* the update. You can find the current version by calling `GET /services/{id}` + * @param body + * @param registryAuthFrom If the `X-Registry-Auth` header is not specified, this parameter indicates where to find registry authorization credentials. (optional, default to spec) + * @param rollback Set to this parameter to `previous` to cause a server-side rollback to the previous service spec. The supplied spec will be ignored in this case. (optional) + * @param xRegistryAuth A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @return ServiceUpdateResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun serviceUpdate(id: String, version: Int, body: ServiceSpec, registryAuthFrom: String?, rollback: String?, xRegistryAuth: String?): ServiceUpdateResponse { + val localVariableConfig = serviceUpdateRequestConfig(id = id, version = version, body = body, registryAuthFrom = registryAuthFrom, rollback = rollback, xRegistryAuth = xRegistryAuth) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as ServiceUpdateResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation serviceUpdate + * + * @param id ID or name of service. + * @param version The version number of the service object being updated. This is required to avoid conflicting writes. This version number should be the value as currently set on the service *before* the update. You can find the current version by calling `GET /services/{id}` + * @param body + * @param registryAuthFrom If the `X-Registry-Auth` header is not specified, this parameter indicates where to find registry authorization credentials. (optional, default to spec) + * @param rollback Set to this parameter to `previous` to cause a server-side rollback to the previous service spec. The supplied spec will be ignored in this case. (optional) + * @param xRegistryAuth A base64url-encoded auth configuration for pulling from private registries. Refer to the [authentication section](#section/Authentication) for details. (optional) + * @return RequestConfig + */ + fun serviceUpdateRequestConfig( + id: String, + version: Int, + body: ServiceSpec, + registryAuthFrom: String?, + rollback: String?, + xRegistryAuth: String? + ): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("version", listOf(version.toString())) + if (registryAuthFrom != null) { + put("registryAuthFrom", listOf(registryAuthFrom.toString())) + } + if (rollback != null) { + put("rollback", listOf(rollback.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + xRegistryAuth?.apply { localVariableHeaders["X-Registry-Auth"] = this } + + return RequestConfig( + method = POST, + path = "/services/{id}/update".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SessionApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SessionApi.kt new file mode 100644 index 000000000..9433b77fd --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SessionApi.kt @@ -0,0 +1,82 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException + +class SessionApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Initialize interactive session + * Start a new interactive session with a server. Session allows server to call back to the client for advanced capabilities. ### Hijacking This endpoint hijacks the HTTP connection to HTTP2 transport that allows the client to expose gPRC services on that connection. For example, the client sends this request to upgrade the connection: ``` POST /session HTTP/1.1 Upgrade: h2c Connection: Upgrade ``` The Docker daemon responds with a `101 UPGRADED` response follow with the raw stream: ``` HTTP/1.1 101 UPGRADED Connection: Upgrade Upgrade: h2c ``` + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun session() { + val localVariableConfig = sessionRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation session + * + * @return RequestConfig + */ + fun sessionRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/session", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SwarmApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SwarmApi.kt new file mode 100644 index 000000000..41977e93a --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SwarmApi.kt @@ -0,0 +1,429 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.Swarm +import de.gesellix.docker.engine.model.SwarmInitRequest +import de.gesellix.docker.engine.model.SwarmJoinRequest +import de.gesellix.docker.engine.model.SwarmSpec +import de.gesellix.docker.engine.model.SwarmUnlockRequest +import de.gesellix.docker.engine.model.UnlockKeyResponse + +class SwarmApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Initialize a new swarm + * + * @param body + * @return kotlin.String The node ID + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun swarmInit(body: SwarmInitRequest): String { + val localVariableConfig = swarmInitRequestConfig(body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as String + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation swarmInit + * + * @param body + * @return RequestConfig + */ + fun swarmInitRequestConfig(body: SwarmInitRequest): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/swarm/init", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect swarm + * + * @return Swarm + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun swarmInspect(): Swarm { + val localVariableConfig = swarmInspectRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Swarm + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation swarmInspect + * + * @return RequestConfig + */ + fun swarmInspectRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/swarm", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Join an existing swarm + * + * @param body + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun swarmJoin(body: SwarmJoinRequest) { + val localVariableConfig = swarmJoinRequestConfig(body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation swarmJoin + * + * @param body + * @return RequestConfig + */ + fun swarmJoinRequestConfig(body: SwarmJoinRequest): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/swarm/join", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Leave a swarm + * + * @param force Force leave swarm, even if this is the last manager or that it will break the cluster. (optional, default to false) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun swarmLeave(force: Boolean?) { + val localVariableConfig = swarmLeaveRequestConfig(force = force) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation swarmLeave + * + * @param force Force leave swarm, even if this is the last manager or that it will break the cluster. (optional, default to false) + * @return RequestConfig + */ + fun swarmLeaveRequestConfig(force: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (force != null) { + put("force", listOf(force.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/swarm/leave", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Unlock a locked manager + * + * @param body + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun swarmUnlock(body: SwarmUnlockRequest) { + val localVariableConfig = swarmUnlockRequestConfig(body = body) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation swarmUnlock + * + * @param body + * @return RequestConfig + */ + fun swarmUnlockRequestConfig(body: SwarmUnlockRequest): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/swarm/unlock", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get the unlock key + * + * @return UnlockKeyResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun swarmUnlockkey(): UnlockKeyResponse { + val localVariableConfig = swarmUnlockkeyRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as UnlockKeyResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation swarmUnlockkey + * + * @return RequestConfig + */ + fun swarmUnlockkeyRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/swarm/unlockkey", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Update a swarm + * + * @param version The version number of the swarm object being updated. This is required to avoid conflicting writes. + * @param body + * @param rotateWorkerToken Rotate the worker join token. (optional, default to false) + * @param rotateManagerToken Rotate the manager join token. (optional, default to false) + * @param rotateManagerUnlockKey Rotate the manager unlock key. (optional, default to false) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun swarmUpdate(version: Long, body: SwarmSpec, rotateWorkerToken: Boolean?, rotateManagerToken: Boolean?, rotateManagerUnlockKey: Boolean?): Unit { + val localVariableConfig = + swarmUpdateRequestConfig(version = version, body = body, rotateWorkerToken = rotateWorkerToken, rotateManagerToken = rotateManagerToken, rotateManagerUnlockKey = rotateManagerUnlockKey) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation swarmUpdate + * + * @param version The version number of the swarm object being updated. This is required to avoid conflicting writes. + * @param body + * @param rotateWorkerToken Rotate the worker join token. (optional, default to false) + * @param rotateManagerToken Rotate the manager join token. (optional, default to false) + * @param rotateManagerUnlockKey Rotate the manager unlock key. (optional, default to false) + * @return RequestConfig + */ + fun swarmUpdateRequestConfig(version: Long, body: SwarmSpec, rotateWorkerToken: Boolean?, rotateManagerToken: Boolean?, rotateManagerUnlockKey: Boolean?): RequestConfig { + val localVariableBody: Any? = body + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + put("version", listOf(version.toString())) + if (rotateWorkerToken != null) { + put("rotateWorkerToken", listOf(rotateWorkerToken.toString())) + } + if (rotateManagerToken != null) { + put("rotateManagerToken", listOf(rotateManagerToken.toString())) + } + if (rotateManagerUnlockKey != null) { + put("rotateManagerUnlockKey", listOf(rotateManagerUnlockKey.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/swarm/update", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SystemApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SystemApi.kt new file mode 100644 index 000000000..acf22f67f --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/SystemApi.kt @@ -0,0 +1,435 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.HEAD +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.client.infrastructure.SuccessStream +import de.gesellix.docker.engine.model.AuthConfig +import de.gesellix.docker.engine.model.EventMessage +import de.gesellix.docker.engine.model.SystemAuthResponse +import de.gesellix.docker.engine.model.SystemDataUsageResponse +import de.gesellix.docker.engine.model.SystemInfo +import de.gesellix.docker.engine.model.SystemVersion +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout + +class SystemApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Check auth configuration + * Validate credentials for a registry and, if available, get an identity token for accessing the registry without password. + * @param authConfig Authentication to check (optional) + * @return SystemAuthResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun systemAuth(authConfig: AuthConfig?): SystemAuthResponse { + val localVariableConfig = systemAuthRequestConfig(authConfig = authConfig) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as SystemAuthResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation systemAuth + * + * @param authConfig Authentication to check (optional) + * @return RequestConfig + */ + fun systemAuthRequestConfig(authConfig: AuthConfig?): RequestConfig { + val localVariableBody: Any? = authConfig + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/auth", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get data usage information + * + * @return SystemDataUsageResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun systemDataUsage(): SystemDataUsageResponse { + val localVariableConfig = systemDataUsageRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as SystemDataUsageResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation systemDataUsage + * + * @return RequestConfig + */ + fun systemDataUsageRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/system/df", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Monitor events + * Stream real-time events from the server. Various objects within Docker report events when something happens to them. Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, `update`, and `prune` Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune` Volumes report these events: `create`, `mount`, `unmount`, `destroy`, and `prune` Networks report these events: `create`, `connect`, `disconnect`, `destroy`, `update`, `remove`, and `prune` The Docker daemon reports these events: `reload` Services report these events: `create`, `update`, and `remove` Nodes report these events: `create`, `update`, and `remove` Secrets report these events: `create`, `update`, and `remove` Configs report these events: `create`, `update`, and `remove` The Builder reports `prune` events + * @param since Show events created since this timestamp then stream new events. (optional) + * @param until Show events created until this timestamp then stop streaming. (optional) + * @param filters A JSON encoded value of filters (a `map[string][]string`) to process on the event list. Available filters: - `config=<string>` config name or ID - `container=<string>` container name or ID - `daemon=<string>` daemon name or ID - `event=<string>` event type - `image=<string>` image name or ID - `label=<string>` image or container label - `network=<string>` network name or ID - `node=<string>` node ID - `plugin`=<string> plugin name or ID - `scope`=<string> local or swarm - `secret=<string>` secret name or ID - `service=<string>` service name or ID - `type=<string>` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service`, `secret` or `config` - `volume=<string>` volume name (optional) + * @return SystemEventsResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun systemEvents(since: String?, until: String?, filters: String?, callback: StreamCallback, timeoutMillis: Long /*= 24.hours.toLongMilliseconds()*/) { + val localVariableConfig = systemEventsRequestConfig(since = since, until = until, filters = filters) + + val localVarResponse = requestStream( + localVariableConfig + ) + + when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeoutMillis) { + callback.onStarting(this@launch::cancel) + ((localVarResponse as SuccessStream<*>).data as Flow).collect { callback.onNext(it) } + callback.onFinished() + } + } + } + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation systemEvents + * + * @param since Show events created since this timestamp then stream new events. (optional) + * @param until Show events created until this timestamp then stop streaming. (optional) + * @param filters A JSON encoded value of filters (a `map[string][]string`) to process on the event list. Available filters: - `config=<string>` config name or ID - `container=<string>` container name or ID - `daemon=<string>` daemon name or ID - `event=<string>` event type - `image=<string>` image name or ID - `label=<string>` image or container label - `network=<string>` network name or ID - `node=<string>` node ID - `plugin`=<string> plugin name or ID - `scope`=<string> local or swarm - `secret=<string>` secret name or ID - `service=<string>` service name or ID - `type=<string>` object to filter by, one of `container`, `image`, `volume`, `network`, `daemon`, `plugin`, `node`, `service`, `secret` or `config` - `volume=<string>` volume name (optional) + * @return RequestConfig + */ + fun systemEventsRequestConfig(since: String?, until: String?, filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (since != null) { + put("since", listOf(since.toString())) + } + if (until != null) { + put("until", listOf(until.toString())) + } + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/events", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get system information + * + * @return SystemInfo + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun systemInfo(): SystemInfo { + val localVariableConfig = systemInfoRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as SystemInfo + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation systemInfo + * + * @return RequestConfig + */ + fun systemInfoRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/info", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Ping + * This is a dummy endpoint you can use to test if the server is accessible. + * @return kotlin.String + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun systemPing(): String { + val localVariableConfig = systemPingRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as String + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation systemPing + * + * @return RequestConfig + */ + fun systemPingRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/_ping", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Ping + * This is a dummy endpoint you can use to test if the server is accessible. + * @return kotlin.String + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun systemPingHead(): String { + val localVariableConfig = systemPingHeadRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as String + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation systemPingHead + * + * @return RequestConfig + */ + fun systemPingHeadRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = HEAD, + path = "/_ping", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Get version + * Returns the version of Docker that is running and various information about the system that Docker is running on. + * @return SystemVersion + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun systemVersion(): SystemVersion { + val localVariableConfig = systemVersionRequestConfig() + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as SystemVersion + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation systemVersion + * + * @return RequestConfig + */ + fun systemVersionRequestConfig(): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/version", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/TaskApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/TaskApi.kt new file mode 100644 index 000000000..a08f798f9 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/TaskApi.kt @@ -0,0 +1,272 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.client.infrastructure.SuccessStream +import de.gesellix.docker.engine.model.Task +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout + +class TaskApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Inspect a task + * + * @param id ID of the task + * @return Task + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun taskInspect(id: String): Task { + val localVariableConfig = taskInspectRequestConfig(id = id) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Task + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation taskInspect + * + * @param id ID of the task + * @return RequestConfig + */ + fun taskInspectRequestConfig(id: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/tasks/{id}".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List tasks + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the tasks list. Available filters: - `desired-state=(running | shutdown | accepted)` - `id=<task id>` - `label=key` or `label=\"key=value\"` - `name=<task name>` - `node=<node id or name>` - `service=<service name>` (optional) + * @return kotlin.collections.List + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun taskList(filters: String?): List { + val localVariableConfig = taskListRequestConfig(filters = filters) + + val localVarResponse = request>( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as List + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation taskList + * + * @param filters A JSON encoded value of the filters (a `map[string][]string`) to process on the tasks list. Available filters: - `desired-state=(running | shutdown | accepted)` - `id=<task id>` - `label=key` or `label=\"key=value\"` - `name=<task name>` - `node=<node id or name>` - `service=<service name>` (optional) + * @return RequestConfig + */ + fun taskListRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/tasks", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody, + elementType = Task::class.java + ) + } + + /** + * Get task logs + * Get `stdout` and `stderr` logs from a task. See also [`/containers/{id}/logs`](#operation/ContainerLogs). **Note**: This endpoint works only for services with the `local`, `json-file` or `journald` logging drivers. + * @param id ID of the task + * @param details Show task context and extra details provided to logs. (optional, default to false) + * @param follow Keep connection after returning logs. (optional, default to false) + * @param stdout Return logs from `stdout` (optional, default to false) + * @param stderr Return logs from `stderr` (optional, default to false) + * @param since Only return logs since this time, as a UNIX timestamp (optional, default to 0) + * @param timestamps Add timestamps to every log line (optional, default to false) + * @param tail Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. (optional, default to "all") + * @return java.io.File + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun taskLogs( + id: String, + details: Boolean?, + follow: Boolean?, + stdout: Boolean?, + stderr: Boolean?, + since: Int?, + timestamps: Boolean?, + tail: String?, + callback: StreamCallback, timeoutMillis: Long /*= 24.hours.toLongMilliseconds()*/ + ) { + val localVariableConfig = taskLogsRequestConfig(id = id, details = details, follow = follow, stdout = stdout, stderr = stderr, since = since, timestamps = timestamps, tail = tail) + + val localVarResponse = requestFrames( + localVariableConfig, true /* do services/tasks always have container.tty == false? */ + ) + + when (localVarResponse.responseType) { + ResponseType.Success -> { + runBlocking { + launch { + withTimeout(timeoutMillis) { + callback.onStarting(this@launch::cancel) + ((localVarResponse as SuccessStream<*>).data as Flow).collect { callback.onNext(it) } + callback.onFinished() + } + } + } + } + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation taskLogs + * + * @param id ID of the task + * @param details Show task context and extra details provided to logs. (optional, default to false) + * @param follow Keep connection after returning logs. (optional, default to false) + * @param stdout Return logs from `stdout` (optional, default to false) + * @param stderr Return logs from `stderr` (optional, default to false) + * @param since Only return logs since this time, as a UNIX timestamp (optional, default to 0) + * @param timestamps Add timestamps to every log line (optional, default to false) + * @param tail Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines. (optional, default to "all") + * @return RequestConfig + */ + fun taskLogsRequestConfig( + id: String, + details: Boolean?, + follow: Boolean?, + stdout: Boolean?, + stderr: Boolean?, + since: Int?, + timestamps: Boolean?, + tail: String? + ): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (details != null) { + put("details", listOf(details.toString())) + } + if (follow != null) { + put("follow", listOf(follow.toString())) + } + if (stdout != null) { + put("stdout", listOf(stdout.toString())) + } + if (stderr != null) { + put("stderr", listOf(stderr.toString())) + } + if (since != null) { + put("since", listOf(since.toString())) + } + if (timestamps != null) { + put("timestamps", listOf(timestamps.toString())) + } + if (tail != null) { + put("tail", listOf(tail.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/tasks/{id}/logs".replace("{" + "id" + "}", id), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/VolumeApi.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/VolumeApi.kt new file mode 100644 index 000000000..bb89ee3c9 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/api/VolumeApi.kt @@ -0,0 +1,320 @@ +/** + * Docker Engine API + * The Engine API is an HTTP API served by Docker Engine. It is the API the Docker client uses to communicate with the Engine, so everything the Docker client can do can be done with the API. Most of the client's commands map directly to API endpoints (e.g. `docker ps` is `GET /containers/json`). The notable exception is running containers, which consists of several API calls. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { \"message\": \"page not found\" } ``` # Versioning The API is usually changed in each release, so API calls are versioned to ensure that clients don't break. To lock to a specific version of the API, you prefix the URL with its version, for example, call `/v1.30/info` to use the v1.30 version of the `/info` endpoint. If the API version specified in the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. If you omit the version-prefix, the current version of the API (v1.41) is used. For example, calling `/info` is the same as calling `/v1.41/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, so your client will continue to work even if it is talking to a newer Engine. The API uses an open schema model, which means server may add extra properties to responses. Likewise, the server will ignore any extra query parameters and request body properties. When you write clients, you need to ignore additional properties in responses to ensure they do not break when talking to newer daemons. # Authentication Authentication for registries is handled client side. The client has to send authentication details to various endpoints that need to communicate with registries, such as `POST /images/(name)/push`. These are sent as `X-Registry-Auth` header as a [base64url encoded](https://tools.ietf.org/html/rfc4648#section-5) (JSON) string with the following structure: ``` { \"username\": \"string\", \"password\": \"string\", \"email\": \"string\", \"serveraddress\": \"string\" } ``` The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: ``` { \"identitytoken\": \"9cbaf023786cd7...\" } ``` + * + * The version of the OpenAPI document: 1.41 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package de.gesellix.docker.engine.api + +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.client.infrastructure.ApiClient +import de.gesellix.docker.engine.client.infrastructure.ClientError +import de.gesellix.docker.engine.client.infrastructure.ClientException +import de.gesellix.docker.engine.client.infrastructure.MultiValueMap +import de.gesellix.docker.engine.client.infrastructure.RequestConfig +import de.gesellix.docker.engine.client.infrastructure.ResponseType +import de.gesellix.docker.engine.client.infrastructure.ServerError +import de.gesellix.docker.engine.client.infrastructure.ServerException +import de.gesellix.docker.engine.client.infrastructure.Success +import de.gesellix.docker.engine.model.Volume +import de.gesellix.docker.engine.model.VolumeConfig +import de.gesellix.docker.engine.model.VolumeListResponse +import de.gesellix.docker.engine.model.VolumePruneResponse + +class VolumeApi(basePath: String = defaultBasePath) : ApiClient(basePath) { + companion object { + + @JvmStatic + val defaultBasePath: String by lazy { + System.getProperties().getProperty("docker.client.baseUrl", "http://localhost/v1.41") + } + } + + /** + * Create a volume + * + * @param volumeConfig + * @return Volume + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun volumeCreate(volumeConfig: VolumeConfig): Volume { + val localVariableConfig = volumeCreateRequestConfig(volumeConfig = volumeConfig) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Volume + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation volumeCreate + * + * @param volumeConfig + * @return RequestConfig + */ + fun volumeCreateRequestConfig(volumeConfig: VolumeConfig): RequestConfig { + val localVariableBody: Any? = volumeConfig + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/volumes/create", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Remove a volume + * Instruct the driver to remove the volume. + * @param name Volume name or ID + * @param force Force the removal of the volume (optional, default to false) + * @return void + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun volumeDelete(name: String, force: Boolean?) { + val localVariableConfig = volumeDeleteRequestConfig(name = name, force = force) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> Unit + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation volumeDelete + * + * @param name Volume name or ID + * @param force Force the removal of the volume (optional, default to false) + * @return RequestConfig + */ + fun volumeDeleteRequestConfig(name: String, force: Boolean?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (force != null) { + put("force", listOf(force.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = DELETE, + path = "/volumes/{name}".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Inspect a volume + * + * @param name Volume name or ID + * @return Volume + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun volumeInspect(name: String): Volume { + val localVariableConfig = volumeInspectRequestConfig(name = name) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as Volume + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation volumeInspect + * + * @param name Volume name or ID + * @return RequestConfig + */ + fun volumeInspectRequestConfig(name: String): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/volumes/{name}".replace("{" + "name" + "}", name), + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * List volumes + * + * @param filters JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. Available filters: - `dangling=<boolean>` When set to `true` (or `1`), returns all volumes that are not in use by a container. When set to `false` (or `0`), only volumes that are in use by one or more containers are returned. - `driver=<volume-driver-name>` Matches volumes based on their driver. - `label=<key>` or `label=<key>:<value>` Matches volumes based on the presence of a `label` alone or a `label` and a value. - `name=<volume-name>` Matches all or part of a volume name. (optional) + * @return VolumeListResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun volumeList(filters: String?): VolumeListResponse { + val localVariableConfig = volumeListRequestConfig(filters = filters) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as VolumeListResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation volumeList + * + * @param filters JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. Available filters: - `dangling=<boolean>` When set to `true` (or `1`), returns all volumes that are not in use by a container. When set to `false` (or `0`), only volumes that are in use by one or more containers are returned. - `driver=<volume-driver-name>` Matches volumes based on their driver. - `label=<key>` or `label=<key>:<value>` Matches volumes based on the presence of a `label` alone or a `label` and a value. - `name=<volume-name>` Matches all or part of a volume name. (optional) + * @return RequestConfig + */ + fun volumeListRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = GET, + path = "/volumes", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } + + /** + * Delete unused volumes + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return VolumePruneResponse + * @throws UnsupportedOperationException If the API returns an informational or redirection response + * @throws ClientException If the API returns a client error response + * @throws ServerException If the API returns a server error response + */ + @Suppress("UNCHECKED_CAST") + @Throws(UnsupportedOperationException::class, ClientException::class, ServerException::class) + fun volumePrune(filters: String?): VolumePruneResponse { + val localVariableConfig = volumePruneRequestConfig(filters = filters) + + val localVarResponse = request( + localVariableConfig + ) + + return when (localVarResponse.responseType) { + ResponseType.Success -> (localVarResponse as Success<*>).data as VolumePruneResponse + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> { + val localVarError = localVarResponse as ClientError<*> + throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + ResponseType.ServerError -> { + val localVarError = localVarResponse as ServerError<*> + throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse) + } + } + } + + /** + * To obtain the request config of the operation volumePrune + * + * @param filters Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters: - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. (optional) + * @return RequestConfig + */ + fun volumePruneRequestConfig(filters: String?): RequestConfig { + val localVariableBody: Any? = null + val localVariableQuery: MultiValueMap = mutableMapOf>() + .apply { + if (filters != null) { + put("filters", listOf(filters.toString())) + } + } + val localVariableHeaders: MutableMap = mutableMapOf() + + return RequestConfig( + method = POST, + path = "/volumes/prune", + query = localVariableQuery, + headers = localVariableHeaders, + body = localVariableBody + ) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiAbstractions.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiAbstractions.kt new file mode 100644 index 000000000..3357a1f0e --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiAbstractions.kt @@ -0,0 +1,22 @@ +package de.gesellix.docker.engine.client.infrastructure + +typealias MultiValueMap = MutableMap> + +fun collectionDelimiter(collectionFormat: String) = when (collectionFormat) { + "csv" -> "," + "tsv" -> "\t" + "pipe" -> "|" + "space" -> " " + else -> "" +} + +val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" } + +fun toMultiValue(items: Array, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter) = toMultiValue(items.asIterable(), collectionFormat, map) + +fun toMultiValue(items: Iterable, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List { + return when (collectionFormat) { + "multi" -> items.map(map) + else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map)) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiClient.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiClient.kt new file mode 100644 index 000000000..c24950004 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiClient.kt @@ -0,0 +1,364 @@ +package de.gesellix.docker.engine.client.infrastructure + +import de.gesellix.docker.client.filesocket.NamedPipeSocket +import de.gesellix.docker.client.filesocket.NamedPipeSocketFactory +import de.gesellix.docker.client.filesocket.UnixSocket +import de.gesellix.docker.client.filesocket.UnixSocketFactory +import de.gesellix.docker.client.filesocket.UnixSocketFactorySupport +import de.gesellix.docker.engine.DockerClientConfig +import de.gesellix.docker.engine.EngineRequest +import de.gesellix.docker.engine.RequestMethod.DELETE +import de.gesellix.docker.engine.RequestMethod.GET +import de.gesellix.docker.engine.RequestMethod.HEAD +import de.gesellix.docker.engine.RequestMethod.OPTIONS +import de.gesellix.docker.engine.RequestMethod.PATCH +import de.gesellix.docker.engine.RequestMethod.POST +import de.gesellix.docker.engine.RequestMethod.PUT +import de.gesellix.docker.engine.api.Frame +import de.gesellix.docker.ssl.SslSocketConfigFactory +import okhttp3.HttpUrl +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.ResponseBody +import okio.Source +import java.io.File +import java.lang.reflect.Type +import java.util.concurrent.TimeUnit + +open class ApiClient(val baseUrl: String, val dockerClientConfig: DockerClientConfig = DockerClientConfig()) { + companion object { + + protected const val ContentType = "Content-Type" + protected const val Accept = "Accept" + protected const val Authorization = "Authorization" + protected const val TextPlainMediaType = "text/plain" + protected const val JsonMediaType = "application/json" + protected const val OctetStreamMediaType = "application/octet-stream" + protected const val DockerRawStreamMediaType = "application/vnd.docker.raw-stream" + + // val apiKey: MutableMap = mutableMapOf() +// val apiKeyPrefix: MutableMap = mutableMapOf() + var username: String? = null + var password: String? = null +// var accessToken: String? = null + + val socketFactories: MutableMap OkHttpClient.Builder> = mutableMapOf() + +// @JvmStatic +// val engineClient: EngineClient by lazy { +// OkDockerClient() +// } + + @JvmStatic + val client: OkHttpClient by lazy { + builder.build() + } + + @JvmStatic + val builder: OkHttpClient.Builder = OkHttpClient.Builder() + } + + protected inline fun requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = + when { + content is File -> content.asRequestBody( + mediaType.toMediaTypeOrNull() + ) + content is Source -> content.asRequestBody( + mediaType.toMediaTypeOrNull() + ) + mediaType == JsonMediaType -> Serializer.moshi.adapter(T::class.java).toJson(content).toRequestBody( + mediaType.toMediaTypeOrNull() + ) + else -> throw UnsupportedOperationException("requestBody only supports JSON body and File body, not $mediaType.") + } + + protected inline fun responseBody( + body: ResponseBody?, + mediaType: String? = JsonMediaType, + type: Type? = null + ): T? { + if (body == null) { + return null + } +// val bodyContent = body.string() +// if (bodyContent.isEmpty()) { +// return null +// } +// if (mediaType == null && body.contentLength() == 0L) { +// return null +// } + if (T::class.java == File::class.java) { + return body.consumeFile() as T + } + return when (mediaType) { + JsonMediaType -> when (type) { + null -> body.consumeJson() + else -> body.consumeJson(type) + } + TextPlainMediaType -> body.string() as T + null -> null + else -> throw UnsupportedOperationException("responseBody currently does not support media type $mediaType.") + } + } + + protected inline fun request(requestConfig: RequestConfig): ApiInfrastructureResponse { + val engineRequest = EngineRequest(requestConfig.method, requestConfig.path).also { + it.headers = requestConfig.headers + it.query = requestConfig.query + it.body = requestConfig.body + } + val request = prepareRequest(engineRequest) + val client = prepareClient(engineRequest) + return request(request, client, requestConfig.elementType) + } + + protected inline fun requestStream(requestConfig: RequestConfig): ApiInfrastructureResponse { + val engineRequest = EngineRequest(requestConfig.method, requestConfig.path).also { + it.headers = requestConfig.headers + it.query = requestConfig.query + it.body = requestConfig.body + } + val request = prepareRequest(engineRequest, JsonMediaType) + val client = prepareClient(engineRequest) + return requestStream(request, client) + } + + protected inline fun requestFrames(requestConfig: RequestConfig, expectMultiplexedResponse: Boolean = false): ApiInfrastructureResponse { + val engineRequest = EngineRequest(requestConfig.method, requestConfig.path).also { + it.headers = requestConfig.headers + it.query = requestConfig.query + it.body = requestConfig.body + } + val request = prepareRequest(engineRequest, DockerRawStreamMediaType) + val client = prepareClient(engineRequest) + return requestFrames(request, client, expectMultiplexedResponse) + } + + protected fun prepareRequest(requestConfig: EngineRequest, fallbackContentType: String = ""): Request { + val httpUrl = buildHttpUrl().build() + + val pathWithOptionalApiVersion = when { + requestConfig.apiVersion != null -> { + requestConfig.apiVersion + "/" + requestConfig.path + } + else -> { + requestConfig.path + } + } + + val url = httpUrl.newBuilder() + .addPathSegments(pathWithOptionalApiVersion.trimStart('/')) + .apply { + requestConfig.query.forEach { query -> + query.value.forEach { queryValue -> + addQueryParameter(query.key, queryValue) + } + } + }.build() + + // take content-type/accept from spec or set to default (application/json) if not defined + if (requestConfig.headers[ContentType].isNullOrEmpty()) { + requestConfig.headers[ContentType] = JsonMediaType + } + if (requestConfig.headers[Accept].isNullOrEmpty()) { + requestConfig.headers[Accept] = JsonMediaType + } + val headers = requestConfig.headers + + if ((headers[ContentType] ?: "") == "") { + throw IllegalStateException("Missing Content-Type header. This is required.") + } + + if ((headers[Accept] ?: "") == "") { + throw IllegalStateException("Missing Accept header. This is required.") + } + + // TODO: support multiple contentType options here. + val mediaType = (headers[ContentType] as String).substringBefore(";").toLowerCase() + + val request = when (requestConfig.method) { + DELETE -> Request.Builder().url(url).delete(requestBody(requestConfig.body, mediaType)) + GET -> Request.Builder().url(url) + HEAD -> Request.Builder().url(url).head() + PATCH -> Request.Builder().url(url).patch(requestBody(requestConfig.body, mediaType)) + PUT -> Request.Builder().url(url).put(requestBody(requestConfig.body, mediaType)) + POST -> Request.Builder().url(url).post(requestBody(requestConfig.body, mediaType)) + OPTIONS -> Request.Builder().url(url).method("OPTIONS", null) + null -> throw IllegalStateException("Request method is null") + }.apply { + headers.forEach { header -> addHeader(header.key, header.value) } + }.apply { + tag(EnforceResponseContentTypeConfig::class.java, EnforceResponseContentTypeConfig(fallbackContentType)) + }.build() + return request + } + + protected fun prepareClient(requestConfig: EngineRequest): OkHttpClient { +// val engineResponse = engineClient.request(requestConfig) + val actualClient = buildHttpClient(client.newBuilder()) + // .proxy(proxy) // TODO + // do we need to disable the timeout for streaming? + .connectTimeout(requestConfig.timeout.toLong(), TimeUnit.MILLISECONDS) + .readTimeout(requestConfig.timeout.toLong(), TimeUnit.MILLISECONDS) + .addInterceptor(EnforceResponseContentTypeInterceptor()) + return actualClient.build() + } + + protected inline fun request(request: Request, client: OkHttpClient, elementType: Type? = null): ApiInfrastructureResponse { + val response = client.newCall(request).execute() + val mediaType = response.header(ContentType)?.substringBefore(";")?.toLowerCase() + + // TODO: handle specific mapping types. e.g. Map> + when { + response.isRedirect -> return Redirection( + response.code, + response.headers.toMultimap() + ) + response.isInformational -> return Informational( + response.message, + response.code, + response.headers.toMultimap() + ) + response.isSuccessful -> return Success( + responseBody(response.body, mediaType, elementType), + response.code, + response.headers.toMultimap() + ) + response.isClientError -> return ClientError( + response.message, + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + else -> return ServerError( + response.message, + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + } + } + + protected inline fun requestStream(request: Request, client: OkHttpClient): ApiInfrastructureResponse { + val response = client.newCall(request).execute() + val mediaType = response.header(ContentType)?.substringBefore(";")?.toLowerCase() + + // TODO: handle specific mapping types. e.g. Map> + when { + response.isRedirect -> return Redirection( + response.code, + response.headers.toMultimap() + ) + response.isInformational -> return Informational( + response.message, + response.code, + response.headers.toMultimap() + ) + response.isSuccessful -> return SuccessStream( + response.body.consumeStream(mediaType), + response.code, + response.headers.toMultimap() + ) + response.isClientError -> return ClientError( + response.message, + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + else -> return ServerError( + response.message, + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + } + } + + protected inline fun requestFrames(request: Request, client: OkHttpClient, expectMultiplexedResponse: Boolean = false): ApiInfrastructureResponse { + val response = client.newCall(request).execute() + val mediaType = response.header(ContentType)?.substringBefore(";")?.toLowerCase() + + // TODO: handle specific mapping types. e.g. Map> + when { + response.isRedirect -> return Redirection( + response.code, + response.headers.toMultimap() + ) + response.isInformational -> return Informational( + response.message, + response.code, + response.headers.toMultimap() + ) + response.isSuccessful -> return SuccessStream( + response.body.consumeFrames(mediaType, expectMultiplexedResponse), + response.code, + response.headers.toMultimap() + ) + response.isClientError -> return ClientError( + response.message, + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + else -> return ServerError( + response.message, + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + } + } + + open fun buildHttpUrl(): HttpUrl.Builder { +// baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.") + return when (dockerClientConfig.scheme) { + "unix" -> HttpUrl.Builder() + .scheme("http") + .host(UnixSocket().encodeHostname(dockerClientConfig.host)) + // port(/not/allowed/for/unix/socket/) + "npipe" -> HttpUrl.Builder() + .scheme("http") + .host(NamedPipeSocket().encodeHostname(dockerClientConfig.host)) + // port(/not/allowed/for/npipe/socket/) + else -> HttpUrl.Builder() + .scheme(dockerClientConfig.scheme) + .host(dockerClientConfig.host) + .port(dockerClientConfig.port) + } + } + + open fun buildHttpClient(builder: OkHttpClient.Builder): OkHttpClient.Builder { + val protocol = dockerClientConfig.scheme + val socketFactoryConfiguration = socketFactories[protocol] + if (socketFactoryConfiguration != null) { + return socketFactoryConfiguration(builder) + } + throw IllegalStateException("$protocol socket not supported.") + } + + init { + if (UnixSocketFactorySupport().isSupported) { + socketFactories["unix"] = { builder -> + val factory = UnixSocketFactory() + builder + .socketFactory(factory) + .dns(factory) + } + } + socketFactories["npipe"] = { builder -> + val factory = NamedPipeSocketFactory() + builder + .socketFactory(factory) + .dns(factory) + } + socketFactories["https"] = { builder -> + val dockerSslSocket = SslSocketConfigFactory().createDockerSslSocket(dockerClientConfig.certPath) + builder + .sslSocketFactory(dockerSslSocket.sslSocketFactory, dockerSslSocket.trustManager) + } + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiInfrastructureResponse.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiInfrastructureResponse.kt new file mode 100644 index 000000000..16b6f51d9 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApiInfrastructureResponse.kt @@ -0,0 +1,52 @@ +package de.gesellix.docker.engine.client.infrastructure + +import kotlinx.coroutines.flow.Flow + +enum class ResponseType { + Success, Informational, Redirection, ClientError, ServerError +} + +interface Response + +abstract class ApiInfrastructureResponse(val responseType: ResponseType) : Response { + + abstract val statusCode: Int + abstract val headers: Map> +} + +class SuccessStream( + val data: Flow, + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.Success) + +class Success( + val data: T, + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.Success) + +class Informational( + val statusText: String, + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.Informational) + +class Redirection( + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.Redirection) + +class ClientError( + val message: String? = null, + val body: Any? = null, + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.ClientError) + +class ServerError( + val message: String? = null, + val body: Any? = null, + override val statusCode: Int = -1, + override val headers: Map> +) : ApiInfrastructureResponse(ResponseType.ServerError) diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApplicationDelegates.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApplicationDelegates.kt new file mode 100644 index 000000000..434e5b27c --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ApplicationDelegates.kt @@ -0,0 +1,31 @@ +package de.gesellix.docker.engine.client.infrastructure + +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +object ApplicationDelegates { + + /** + * Provides a property delegate, allowing the property to be set once and only once. + * + * If unset (no default value), a get on the property will throw [IllegalStateException]. + */ + fun setOnce(defaultValue: T? = null): ReadWriteProperty = SetOnce(defaultValue) + + private class SetOnce(defaultValue: T? = null) : ReadWriteProperty { + + private var isSet = false + private var value: T? = defaultValue + + override fun getValue(thisRef: Any?, property: KProperty<*>): T { + return value ?: throw IllegalStateException("${property.name} not initialized") + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = synchronized(this) { + if (!isSet) { + this.value = value + isSet = true + } + } + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/BigDecimalAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/BigDecimalAdapter.kt new file mode 100644 index 000000000..7cb8d1a41 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/BigDecimalAdapter.kt @@ -0,0 +1,18 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.math.BigDecimal + +class BigDecimalAdapter { + + @ToJson + fun toJson(value: BigDecimal): String { + return value.toPlainString() + } + + @FromJson + fun fromJson(value: String): BigDecimal { + return BigDecimal(value) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/BigIntegerAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/BigIntegerAdapter.kt new file mode 100644 index 000000000..6a87f27a0 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/BigIntegerAdapter.kt @@ -0,0 +1,18 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.math.BigInteger + +class BigIntegerAdapter { + + @ToJson + fun toJson(value: BigInteger): String { + return value.toString() + } + + @FromJson + fun fromJson(value: String): BigInteger { + return BigInteger(value) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ByteArrayAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ByteArrayAdapter.kt new file mode 100644 index 000000000..720b6bc7c --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ByteArrayAdapter.kt @@ -0,0 +1,13 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson + +class ByteArrayAdapter { + + @ToJson + fun toJson(data: ByteArray): String = String(data) + + @FromJson + fun fromJson(data: String): ByteArray = data.toByteArray() +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/CallAwait.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/CallAwait.kt new file mode 100644 index 000000000..ea05b3e80 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/CallAwait.kt @@ -0,0 +1,56 @@ +package de.gesellix.docker.engine.client.infrastructure + +import kotlinx.coroutines.suspendCancellableCoroutine +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Response +import java.io.IOException +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +/** + * Suspend extension that allows suspend [Call] inside coroutine. + * + * [recordStack] enables track recording, so in case of exception stacktrace will contain call stacktrace, may be useful for debugging + * Not free! Creates exception on each request so disabled by default, but may be enabled using system properties: + * + * ``` + * System.setProperty(OKHTTP_STACK_RECORDER_PROPERTY, OKHTTP_STACK_RECORDER_ON) + * ``` + * see [README.md](https://github.com/gildor/kotlin-coroutines-okhttp/blob/master/README.md#Debugging) with details about debugging using this feature + * + * @return Result of request or throw exception + */ +suspend fun Call.await(recordStack: Boolean = isRecordStack): Response { + val callStack = if (recordStack) { + IOException().apply { + // Remove unnecessary lines from stacktrace + // This doesn't remove await$default, but better than nothing + stackTrace = stackTrace.copyOfRange(1, stackTrace.size) + } + } else { + null + } + return suspendCancellableCoroutine { continuation -> + enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + continuation.resume(response) + } + + override fun onFailure(call: Call, e: IOException) { + // Don't bother with resuming the continuation if it is already cancelled. + if (continuation.isCancelled) return + callStack?.initCause(e) + continuation.resumeWithException(callStack ?: e) + } + }) + + continuation.invokeOnCancellation { + try { + cancel() + } catch (ex: Throwable) { + //Ignore cancel exception + } + } + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/CallStackRecorder.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/CallStackRecorder.kt new file mode 100644 index 000000000..9f000e303 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/CallStackRecorder.kt @@ -0,0 +1,20 @@ +package de.gesellix.docker.engine.client.infrastructure + +const val OKHTTP_STACK_RECORDER_PROPERTY = "ru.gildor.coroutines.okhttp.stackrecorder" + +/** + * Debug turned on value for [DEBUG_PROPERTY_NAME]. See [newCoroutineContext][CoroutineScope.newCoroutineContext]. + */ +const val OKHTTP_STACK_RECORDER_ON = "on" + +/** + * Debug turned on value for [DEBUG_PROPERTY_NAME]. See [newCoroutineContext][CoroutineScope.newCoroutineContext]. + */ +const val OKHTTP_STACK_RECORDER_OFF = "off" + +@JvmField +val isRecordStack = when (System.getProperty(OKHTTP_STACK_RECORDER_PROPERTY)) { + OKHTTP_STACK_RECORDER_ON -> true + OKHTTP_STACK_RECORDER_OFF, null, "" -> false + else -> error("System property '$OKHTTP_STACK_RECORDER_PROPERTY' has unrecognized value '${System.getProperty(OKHTTP_STACK_RECORDER_PROPERTY)}'") +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Element.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Element.kt new file mode 100644 index 000000000..301f87853 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Element.kt @@ -0,0 +1,3 @@ +package de.gesellix.docker.engine.client.infrastructure + +data class Element(val type: ResponseType, val data: T? = null) diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/EnforceResponseContentTypeInterceptor.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/EnforceResponseContentTypeInterceptor.kt new file mode 100644 index 000000000..001c7c73a --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/EnforceResponseContentTypeInterceptor.kt @@ -0,0 +1,27 @@ +package de.gesellix.docker.engine.client.infrastructure + +import okhttp3.Interceptor +import okhttp3.Response +import java.net.HttpURLConnection.HTTP_NO_CONTENT + +data class EnforceResponseContentTypeConfig(val fallbackContentType: String = "") + +// This one would work automatically, when the response content-type would be set correctly :-/ +// - for /attach, /logs and similar endpoints see https://github.com/gesellix/docker-client/issues/21 +// - for /stats see (?) +class EnforceResponseContentTypeInterceptor : Interceptor { + + private val log by logger() + + override fun intercept(chain: Interceptor.Chain): Response { + val response = chain.proceed(chain.request()) + if (chain.request().tag(EnforceResponseContentTypeConfig::class.java)?.fallbackContentType?.isNotEmpty() == true) { + if (response.isSuccessful && response.code != HTTP_NO_CONTENT && response.headers("Content-Type").isEmpty()) { + val enforcedContentType = chain.request().tag(EnforceResponseContentTypeConfig::class.java)?.fallbackContentType!! + log.debug("Overriding Content-Type response header with $enforcedContentType") + return response.newBuilder().header("Content-Type", enforcedContentType).build() + } + } + return response + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/EnsureRawStreamContentTypeInterceptor.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/EnsureRawStreamContentTypeInterceptor.kt deleted file mode 100644 index 5f55f778a..000000000 --- a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/EnsureRawStreamContentTypeInterceptor.kt +++ /dev/null @@ -1,23 +0,0 @@ -package de.gesellix.docker.engine.client.infrastructure - -import okhttp3.Interceptor -import okhttp3.Response - -data class MultiplexedStreamConfig(val expectMultiplexedStream: Boolean) - -// This one would work automatically, when the response content-type would be set correctly :-/ -// see https://github.com/gesellix/docker-client/issues/21 -class EnsureRawStreamContentTypeInterceptor : Interceptor { - - override fun intercept(chain: Interceptor.Chain): Response { - val response = chain.proceed(chain.request()) - if (chain.request().tag(MultiplexedStreamConfig::class.java)?.expectMultiplexedStream == true) { - if (response.headers("Content-Type").isEmpty()) { - // TODO use a proper logger - println("Overriding Content-Type response header with application/vnd.docker.raw-stream") - return response.newBuilder().header("Content-Type", "application/vnd.docker.raw-stream").build() - } - } - return response - } -} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Errors.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Errors.kt new file mode 100644 index 000000000..4442b6bd0 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Errors.kt @@ -0,0 +1,25 @@ +package de.gesellix.docker.engine.client.infrastructure + +open class ClientException(message: String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) { + + companion object { + + private const val serialVersionUID: Long = 123L + } + + override fun toString(): String { + return (response as? ClientError<*>)?.body.toString() + } +} + +open class ServerException(message: String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) { + + companion object { + + private const val serialVersionUID: Long = 456L + } + + override fun toString(): String { + return (response as? ServerError<*>)?.body.toString() + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/FrameReader.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/FrameReader.kt index 70e8fd66d..0ec00fea6 100644 --- a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/FrameReader.kt +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/FrameReader.kt @@ -1,23 +1,29 @@ package de.gesellix.docker.engine.client.infrastructure +import de.gesellix.docker.engine.api.Frame import de.gesellix.docker.response.Reader import okio.BufferedSource import okio.Source import okio.buffer -class FrameReader(source: Source) : Reader { +class FrameReader(source: Source, private val expectMultiplexedResponse: Boolean = false) : Reader { private val buffer: BufferedSource = source.buffer() override fun readNext(type: Class?): Frame { - // Stream format: https://docs.docker.com/engine/api/v1.41/#operation/ContainerAttach - // header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4} + return if (expectMultiplexedResponse) { + // Stream format: https://docs.docker.com/engine/api/v1.41/#operation/ContainerAttach + // header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4} - val streamType = Frame.StreamType.valueOf(buffer.readByte()) - buffer.skip(3) - val frameSize = buffer.readInt() + val streamType = Frame.StreamType.valueOf(buffer.readByte()) + buffer.skip(3) + val frameSize = buffer.readInt() - return Frame(streamType, buffer.readByteArray(frameSize.toLong())) + Frame(streamType, buffer.readByteArray(frameSize.toLong())) + } else { + // TODO consider reading plain bytes, not line separated + Frame(Frame.StreamType.RAW, buffer.readUtf8Line()?.encodeToByteArray()) + } } override fun hasNext(): Boolean { diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/IdResponseAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/IdResponseAdapter.kt new file mode 100644 index 000000000..0c1bb72b4 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/IdResponseAdapter.kt @@ -0,0 +1,39 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonDataException +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.Moshi +import com.squareup.moshi.Types +import de.gesellix.docker.engine.model.IdResponse +import java.lang.reflect.Type + +class IdResponseAdapter : JsonAdapter.Factory { + + override fun create(type: Type, annotations: MutableSet, moshi: Moshi): JsonAdapter<*>? { + if (Types.getRawType(type) != IdResponse::class.java) { + return null + } + + val idAdapter = IdResponseHackJsonAdapter(moshi) + val delegate = moshi.nextAdapter(this, type, annotations) + + return object : JsonAdapter() { + override fun fromJson(reader: JsonReader): Any? { +// @Suppress("UNCHECKED_CAST") + val peekJson = reader.peekJson() + return try { + delegate.fromJson(reader) + } catch (e: JsonDataException) { + val idResponseHack = idAdapter.fromJson(peekJson) + IdResponse(id = idResponseHack.id) + } + } + + override fun toJson(writer: JsonWriter, value: Any?) { + return delegate.toJson(writer, value) + } + } + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/IdResponseHackJsonAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/IdResponseHackJsonAdapter.kt new file mode 100644 index 000000000..698549a76 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/IdResponseHackJsonAdapter.kt @@ -0,0 +1,48 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.Moshi +import com.squareup.moshi.internal.Util +import kotlin.String + +data class IdResponseHack(val id: String) + +class IdResponseHackJsonAdapter(moshi: Moshi) : JsonAdapter() { + + private val options: JsonReader.Options = JsonReader.Options.of("ID") + + private val stringAdapter: JsonAdapter = moshi.adapter(String::class.java, emptySet(), "ID") + + override fun toString(): String = "CustomJsonAdapter(IdResponseHack)" + + override fun fromJson(reader: JsonReader): IdResponseHack { + var id: String? = null + reader.beginObject() + while (reader.hasNext()) { + when (reader.selectName(options)) { + 0 -> id = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull("ID", "ID", reader) + -1 -> { + // Unknown name, skip it. + reader.skipName() + reader.skipValue() + } + } + } + reader.endObject() + return IdResponseHack( + id = id ?: throw Util.missingProperty("ID", "ID", reader) + ) + } + + override fun toJson(writer: JsonWriter, value: IdResponseHack?) { + if (value == null) { + throw NullPointerException("value_ was null! Wrap in .nullSafe() to write nullable values.") + } + writer.beginObject() + writer.name("ID") + stringAdapter.toJson(writer, value.id) + writer.endObject() + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LocalDateAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LocalDateAdapter.kt new file mode 100644 index 000000000..765a99614 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LocalDateAdapter.kt @@ -0,0 +1,19 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +class LocalDateAdapter { + + @ToJson + fun toJson(value: LocalDate): String { + return DateTimeFormatter.ISO_LOCAL_DATE.format(value) + } + + @FromJson + fun fromJson(value: String): LocalDate { + return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LocalDateTimeAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LocalDateTimeAdapter.kt new file mode 100644 index 000000000..b0cc43917 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LocalDateTimeAdapter.kt @@ -0,0 +1,19 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +class LocalDateTimeAdapter { + + @ToJson + fun toJson(value: LocalDateTime): String { + return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value) + } + + @FromJson + fun fromJson(value: String): LocalDateTime { + return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LoggingCallback.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LoggingCallback.kt new file mode 100644 index 000000000..5078ef263 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LoggingCallback.kt @@ -0,0 +1,18 @@ +package de.gesellix.docker.engine.client.infrastructure + +import de.gesellix.docker.engine.api.Cancellable +import de.gesellix.docker.engine.api.StreamCallback + +class LoggingCallback : StreamCallback { + + private val log by logger() + + var job: Cancellable? = null + override fun onStarting(cancellable: Cancellable) { + job = cancellable + } + + override fun onNext(event: Any?) { + log.info("$event") + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LoggingExtensions.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LoggingExtensions.kt new file mode 100644 index 000000000..b514ea9f9 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/LoggingExtensions.kt @@ -0,0 +1,12 @@ +package de.gesellix.docker.engine.client.infrastructure + +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +fun R.logger(): Lazy { + return logger(this.javaClass.name) +} + +fun logger(name: String): Lazy { + return lazy { LoggerFactory.getLogger(name) } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/NullIfEmptyEnumAdapterFactory.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/NullIfEmptyEnumAdapterFactory.kt new file mode 100644 index 000000000..5e7ebeb43 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/NullIfEmptyEnumAdapterFactory.kt @@ -0,0 +1,45 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.Moshi +import com.squareup.moshi.Types +import java.lang.reflect.Type + +// inspired by https://github.com/square/moshi/issues/843#issuecomment-584842727 +class NullIfEmptyEnumAdapterFactory : JsonAdapter.Factory { + + override fun create( + type: Type, + annotations: MutableSet, + moshi: Moshi + ): JsonAdapter<*>? { +// if (!Types.getRawType(type).isAnnotationPresent( +// DefaultIfEmpty::class.java)) { +// return null +// } + if (!Types.getRawType(type).isEnum) { + return null + } + + val delegate = moshi.nextAdapter(this, type, annotations) + + return object : JsonAdapter() { + override fun fromJson(reader: JsonReader): Any? { +// @Suppress("UNCHECKED_CAST") + val blob = reader.readJsonValue() as String? +// val blob = reader.readJsonValue() as Map + val nullOrValue = when { + (blob.isNullOrEmpty()) -> null + else -> blob + } + return delegate.fromJsonValue(nullOrValue) + } + + override fun toJson(writer: JsonWriter, value: Any?) { + return delegate.toJson(writer, value) + } + } + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/OffsetDateTimeAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/OffsetDateTimeAdapter.kt new file mode 100644 index 000000000..b8439be50 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/OffsetDateTimeAdapter.kt @@ -0,0 +1,19 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter + +class OffsetDateTimeAdapter { + + @ToJson + fun toJson(value: OffsetDateTime): String { + return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value) + } + + @FromJson + fun fromJson(value: String): OffsetDateTime { + return OffsetDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE_TIME) + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/RequestConfig.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/RequestConfig.kt new file mode 100644 index 000000000..058d13dfc --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/RequestConfig.kt @@ -0,0 +1,21 @@ +package de.gesellix.docker.engine.client.infrastructure + +import de.gesellix.docker.engine.RequestMethod +import java.lang.reflect.Type + +/** + * Defines a config object for a given request. + * NOTE: This object doesn't include 'body' because it + * allows for caching of the constructed object + * for many request definitions. + * NOTE: Headers is a Map because rfc2616 defines + * multi-valued headers as csv-only. + */ +data class RequestConfig( + val method: RequestMethod, + val path: String, + val headers: MutableMap = mutableMapOf(), + val query: MutableMap> = mutableMapOf(), + val body: Any? = null, + val elementType: Type? = null +) diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/RequestExtensions.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/RequestExtensions.kt new file mode 100644 index 000000000..702fb5d60 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/RequestExtensions.kt @@ -0,0 +1,29 @@ +package de.gesellix.docker.engine.client.infrastructure + +import okhttp3.MediaType +import okhttp3.RequestBody +import okio.BufferedSink +import okio.Source + +// See https://github.com/square/okhttp/pull/3912 for a possible implementation +// Would we have issues with non-closed InputStreams? +// More details/examples: +// - https://github.com/minio/minio-java/issues/924 +// - https://github.com/square/okhttp/issues/2424 +// mediaType == OctetStreamMediaType && content is InputStream -> RequestBody.create(content.source().buffer(), mediaType.toMediaTypeOrNull()) +fun Source.asRequestBody(contentType: MediaType? = null): RequestBody { + return object : RequestBody() { + override fun contentType() = contentType + + override fun contentLength() = -1L + + override fun isOneShot(): Boolean { + // we shouldn't allow OkHttp to retry this request + return true + } + + override fun writeTo(sink: BufferedSink) { + use { source -> sink.writeAll(source) } + } + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ResponseConsumer.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ResponseConsumer.kt new file mode 100644 index 000000000..15009cbbc --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ResponseConsumer.kt @@ -0,0 +1,104 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Types +import de.gesellix.docker.engine.api.Frame +import de.gesellix.docker.response.JsonChunksReader +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flow +import okhttp3.ResponseBody +import okhttp3.internal.closeQuietly +import okio.appendingSink +import okio.buffer +import java.io.File +import java.lang.reflect.Type +import java.nio.file.Files + +fun ResponseBody?.consumeFile(): File? { + if (this == null) { + return null + } + val f = Files.createTempFile("tmp.de.gesellix.docker.client", null).toFile() + f.deleteOnExit() + val sink = f.appendingSink().buffer() + sink.writeAll(source()) + sink.close() + closeQuietly() + return f +} + +inline fun ResponseBody?.consumeStream(mediaType: String?): Flow { + if (this == null) { + return emptyFlow() + } + when (mediaType) { + "application/json" -> { + val reader = JsonChunksReader(source(), Serializer.moshi) + val events = flow { + while (reader.hasNext()) { + val next = reader.readNext(T::class.java) + emit(next) + } + this@consumeStream.closeQuietly() + } + return events + } + else -> { + throw UnsupportedOperationException("Can't handle media type $mediaType") + } + } +} + +inline fun ResponseBody?.consumeFrames(mediaType: String?, expectMultiplexedResponse: Boolean = false): Flow { + if (this == null) { + return emptyFlow() + } + when (mediaType) { + "application/vnd.docker.raw-stream" -> { + val reader = FrameReader(source(), expectMultiplexedResponse) + val events = flow { + while (reader.hasNext()) { + val next = reader.readNext(Frame::class.java) + emit(next) + } + this@consumeFrames.closeQuietly() + } + return events + } + else -> { + throw UnsupportedOperationException("Can't handle media type $mediaType") + } + } +} + +inline fun ResponseBody.consumeJson(): T? { + val content = string() + return Serializer.moshi.adapter(T::class.java).fromJson(content) +} + +inline fun ResponseBody.consumeJson(type: Type): T? { + val content = string() + val adapterType: Type = Types.newParameterizedType(T::class.java, type) + val adapter: JsonAdapter = Serializer.moshi.adapter(adapterType) + return adapter.fromJson(content) +} + +//fun Flow.takeUntilSignal(signal: Flow): Flow = flow { +// try { +// coroutineScope { +// launch { +// signal.take(1).collect() +// println("signalled") +// this@coroutineScope.cancel() +// } +// +// collect { +// emit(it) +// } +// } +// +// } catch (e: CancellationException) { +// //ignore +// } +//} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ResponseExtensions.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ResponseExtensions.kt new file mode 100644 index 000000000..6cca8d15c --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/ResponseExtensions.kt @@ -0,0 +1,25 @@ +package de.gesellix.docker.engine.client.infrastructure + +import okhttp3.Response + +/** + * Provides an extension to evaluation whether the response is a 1xx code + */ +val Response.isInformational: Boolean get() = this.code in 100..199 + +/** + * Provides an extension to evaluation whether the response is a 3xx code + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +val Response.isRedirect: Boolean + get() = this.code in 300..399 + +/** + * Provides an extension to evaluation whether the response is a 4xx code + */ +val Response.isClientError: Boolean get() = this.code in 400..499 + +/** + * Provides an extension to evaluation whether the response is a 5xx (Standard) through 999 (non-standard) code + */ +val Response.isServerError: Boolean get() = this.code in 500..999 diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Serializer.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Serializer.kt new file mode 100644 index 000000000..ca85e5077 --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/Serializer.kt @@ -0,0 +1,23 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.Moshi + +object Serializer { + + @JvmStatic + val moshiBuilder: Moshi.Builder = Moshi.Builder() + .add(IdResponseAdapter()) + .add(NullIfEmptyEnumAdapterFactory()) + .add(OffsetDateTimeAdapter()) + .add(LocalDateTimeAdapter()) + .add(LocalDateAdapter()) + .add(UUIDAdapter()) + .add(ByteArrayAdapter()) + .add(BigDecimalAdapter()) + .add(BigIntegerAdapter()) + + @JvmStatic + val moshi: Moshi by lazy { + moshiBuilder.build() + } +} diff --git a/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/UUIDAdapter.kt b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/UUIDAdapter.kt new file mode 100644 index 000000000..ec4ca173e --- /dev/null +++ b/engine-api/src/main/kotlin/de/gesellix/docker/engine/client/infrastructure/UUIDAdapter.kt @@ -0,0 +1,14 @@ +package de.gesellix.docker.engine.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.util.* + +class UUIDAdapter { + + @ToJson + fun toJson(uuid: UUID) = uuid.toString() + + @FromJson + fun fromJson(s: String) = UUID.fromString(s) +} diff --git a/explore/build.gradle.kts b/explore/build.gradle.kts index 670b365f7..1d23fc7ee 100644 --- a/explore/build.gradle.kts +++ b/explore/build.gradle.kts @@ -8,10 +8,6 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -repositories { - mavenCentral() -} - dependencies { constraints { implementation("org.slf4j:slf4j-api") { diff --git a/integration-test/build.gradle.kts b/integration-test/build.gradle.kts index 5698b305e..0bd619d77 100644 --- a/integration-test/build.gradle.kts +++ b/integration-test/build.gradle.kts @@ -8,10 +8,6 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -repositories { - mavenCentral() -} - dependencies { constraints { implementation("org.slf4j:slf4j-api") { diff --git a/settings.gradle.kts b/settings.gradle.kts index 35c3f482b..c8874d641 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1,4 @@ rootProject.name = "docker-client" include("client", "integration-test", "explore") +include("engine-api") +include("typesafe-client") diff --git a/typesafe-client/build.gradle.kts b/typesafe-client/build.gradle.kts new file mode 100644 index 000000000..e5e8fceab --- /dev/null +++ b/typesafe-client/build.gradle.kts @@ -0,0 +1,73 @@ +plugins { + id("org.jetbrains.kotlin.jvm") + id("org.jetbrains.kotlin.kapt") + id("com.github.ben-manes.versions") +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + constraints { + implementation("org.slf4j:slf4j-api") { + version { + strictly("[1.7,1.8)") + prefer("1.7.32") + } + } + implementation("com.squareup.okio:okio") { + version { + strictly("[2.5,3)") + prefer("2.10.0") + } + } + listOf( + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains.kotlin:kotlin-stdlib-common", + "org.jetbrains.kotlin:kotlin-test" + ).onEach { + implementation(it) { + version { + strictly("[1.3,1.6)") + prefer("1.5.30") + } + } + } + listOf( + "org.codehaus.groovy:groovy", + "org.codehaus.groovy:groovy-json" + ).onEach { + implementation(it) { + version { + strictly("[2.5,)") + prefer("2.5.14") + } + } + } + } + implementation(project(":engine-api")) + implementation("de.gesellix:docker-engine:2021-08-27-18-17-00") + implementation("de.gesellix:docker-api-model:2021-08-27-18-17-00") + implementation("com.squareup.moshi:moshi:1.12.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1") + + implementation("org.slf4j:slf4j-api") + testRuntimeOnly("ch.qos.logback:logback-classic:1.2.5") + + testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.2") + testRuntimeOnly("cglib:cglib-nodep:3.3.0") + testImplementation("org.junit.platform:junit-platform-launcher:1.7.2") + testImplementation("org.junit.platform:junit-platform-commons:1.7.2") + testImplementation("org.apache.commons:commons-compress:1.21") + testImplementation(project(":client")) + testImplementation("de.gesellix:testutil:[2021-08-05T22-09-32,)") +} + +tasks.withType(Test::class.java) { + useJUnitPlatform() +} diff --git a/typesafe-client/src/main/java/de/gesellix/docker/client/TypeSafeDockerClient.java b/typesafe-client/src/main/java/de/gesellix/docker/client/TypeSafeDockerClient.java new file mode 100644 index 000000000..a9a29493c --- /dev/null +++ b/typesafe-client/src/main/java/de/gesellix/docker/client/TypeSafeDockerClient.java @@ -0,0 +1,5 @@ +package de.gesellix.docker.client; + +public interface TypeSafeDockerClient { + +} diff --git a/typesafe-client/src/main/kotlin/de/gesellix/docker/client/TypeSafeDockerClientImpl.kt b/typesafe-client/src/main/kotlin/de/gesellix/docker/client/TypeSafeDockerClientImpl.kt new file mode 100644 index 000000000..d5ac59d06 --- /dev/null +++ b/typesafe-client/src/main/kotlin/de/gesellix/docker/client/TypeSafeDockerClientImpl.kt @@ -0,0 +1,36 @@ +package de.gesellix.docker.client + +import de.gesellix.docker.engine.api.ConfigApi +import de.gesellix.docker.engine.api.ContainerApi +import de.gesellix.docker.engine.api.DistributionApi +import de.gesellix.docker.engine.api.ExecApi +import de.gesellix.docker.engine.api.ImageApi +import de.gesellix.docker.engine.api.NetworkApi +import de.gesellix.docker.engine.api.NodeApi +import de.gesellix.docker.engine.api.PluginApi +import de.gesellix.docker.engine.api.SecretApi +import de.gesellix.docker.engine.api.ServiceApi +import de.gesellix.docker.engine.api.SessionApi +import de.gesellix.docker.engine.api.SwarmApi +import de.gesellix.docker.engine.api.SystemApi +import de.gesellix.docker.engine.api.TaskApi +import de.gesellix.docker.engine.api.VolumeApi + +class TypeSafeDockerClientImpl : TypeSafeDockerClient { + + val configApi: ConfigApi = ConfigApi() + val containerApi: ContainerApi = ContainerApi() + val distributionApi: DistributionApi = DistributionApi() + val execApi: ExecApi = ExecApi() + val imageApi: ImageApi = ImageApi() + val networkApi: NetworkApi = NetworkApi() + val nodeApi: NodeApi = NodeApi() + val pluginApi: PluginApi = PluginApi() + val secretApi: SecretApi = SecretApi() + val serviceApi: ServiceApi = ServiceApi() + val sessionApi: SessionApi = SessionApi() + val swarmApi: SwarmApi = SwarmApi() + val systemApi: SystemApi = SystemApi() + val taskApi: TaskApi = TaskApi() + val volumeApi: VolumeApi = VolumeApi() +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/ConfigApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/ConfigApiIntegrationTest.java new file mode 100644 index 000000000..01ffbeb25 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/ConfigApiIntegrationTest.java @@ -0,0 +1,86 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.engine.api.ConfigApi; +import de.gesellix.docker.engine.model.Config; +import de.gesellix.docker.engine.model.ConfigSpec; +import de.gesellix.docker.engine.model.IdResponse; +import de.gesellix.docker.engine.model.LocalNodeState; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable(requiredSwarmMode = LocalNodeState.Active) +class ConfigApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + ConfigApi configApi; + + IdResponse defaultConfig; + + @BeforeEach + public void setup() { + configApi = typeSafeDockerClient.getConfigApi(); + + String encoded = Base64.getEncoder().encodeToString("config-data".getBytes()); + defaultConfig = configApi.configCreate(new ConfigSpec("config-name", Collections.emptyMap(), encoded, null)); + } + + @AfterEach + public void cleanup() { + configApi.configDelete(defaultConfig.getId()); + } + + @Test + public void configCreate() { + String encoded = Base64.getEncoder().encodeToString("config-data".getBytes()); + IdResponse response = configApi.configCreate(new ConfigSpec("my-config", Collections.emptyMap(), encoded, null)); + assertTrue(response.getId().matches("\\w{5,}")); + + configApi.configDelete(response.getId()); + } + + @Test + public void configDelete() { + String encoded = Base64.getEncoder().encodeToString("config-data".getBytes()); + IdResponse response = configApi.configCreate(new ConfigSpec("my-config", Collections.emptyMap(), encoded, null)); + + assertDoesNotThrow(() -> configApi.configDelete(response.getId())); + } + + @Test + public void configInspect() { + Config inspect = configApi.configInspect(defaultConfig.getId()); + assertEquals("config-name", inspect.getSpec().getName()); + assertEquals("config-data", new String(Base64.getDecoder().decode(inspect.getSpec().getData()))); + } + + @Test + public void configList() { + List configs = configApi.configList(null); + Stream filtered = configs.stream().filter(c -> Objects.equals(c.getID(), defaultConfig.getId())); + assertEquals(defaultConfig.getId(), filtered.findFirst().orElse(new Config()).getID()); + } + + @Test + public void configUpdate() { + Config inspect = configApi.configInspect(defaultConfig.getId()); + ConfigSpec configSpec = inspect.getSpec(); + assertNotNull(configSpec); + assertDoesNotThrow(() -> configApi.configUpdate(defaultConfig.getId(), inspect.getVersion().getIndex(), new ConfigSpec(configSpec.getName(), Collections.singletonMap("foo", "bar"), configSpec.getData(), configSpec.getTemplating()))); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/ContainerApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/ContainerApiIntegrationTest.java new file mode 100644 index 000000000..ca70837d3 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/ContainerApiIntegrationTest.java @@ -0,0 +1,736 @@ +package de.gesellix.docker.client; + +import com.squareup.moshi.Moshi; +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.TestImage; +import de.gesellix.docker.engine.api.Cancellable; +import de.gesellix.docker.engine.api.ContainerApi; +import de.gesellix.docker.engine.api.Frame; +import de.gesellix.docker.engine.api.ImageApi; +import de.gesellix.docker.engine.api.StreamCallback; +import de.gesellix.docker.engine.client.infrastructure.ClientException; +import de.gesellix.docker.engine.client.infrastructure.LoggingExtensionsKt; +import de.gesellix.docker.engine.model.ContainerCreateRequest; +import de.gesellix.docker.engine.model.ContainerCreateResponse; +import de.gesellix.docker.engine.model.ContainerInspectResponse; +import de.gesellix.docker.engine.model.ContainerPruneResponse; +import de.gesellix.docker.engine.model.ContainerTopResponse; +import de.gesellix.docker.engine.model.ContainerUpdateRequest; +import de.gesellix.docker.engine.model.ContainerUpdateResponse; +import de.gesellix.docker.engine.model.RestartPolicy; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.stream.Collectors; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable +class ContainerApiIntegrationTest { + + private static final Logger log = LoggingExtensionsKt.logger(ContainerApiIntegrationTest.class.getName()).getValue(); + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + private TestImage testImage; + + ContainerApi containerApi; + ImageApi imageApi; + + @BeforeEach + public void setup() { + containerApi = typeSafeDockerClient.getContainerApi(); + imageApi = typeSafeDockerClient.getImageApi(); + testImage = new TestImage(typeSafeDockerClient); + } + + @Test + public void containerList() { + List> containers = containerApi.containerList(null, null, null, null); + assertNotNull(containers); + } + + @Test + public void containerCreate() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + singletonList("-"), + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + ContainerCreateResponse container = containerApi.containerCreate(containerCreateRequest, "container-create-test"); + assertTrue(container.getId().matches("\\w+")); + containerApi.containerDelete("container-create-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerDelete() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + singletonList("-"), + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-delete-test"); + assertDoesNotThrow(() -> containerApi.containerDelete("container-delete-test", null, null, null)); + assertDoesNotThrow(() -> containerApi.containerDelete("container-delete-missing", null, null, null)); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerInspect() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + singletonList("-"), + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-inspect-test"); + ContainerInspectResponse container = containerApi.containerInspect("container-inspect-test", false); + assertEquals("/container-inspect-test", container.getName()); + containerApi.containerDelete("container-inspect-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerInspectMissing() { + ClientException clientException = assertThrows(ClientException.class, () -> containerApi.containerInspect("random-" + UUID.randomUUID(), false)); + assertEquals(404, clientException.getStatusCode()); + } + + @Test + public void containerRename() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + singletonList("-"), + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-rename-test"); + assertDoesNotThrow(() -> containerApi.containerRename("container-rename-test", "fancy-name")); + containerApi.containerDelete("fancy-name", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerStartStopWait() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-start-test"); + containerApi.containerStart("container-start-test", null); + ContainerInspectResponse container = containerApi.containerInspect("container-start-test", false); + assertTrue(container.getState().getRunning()); + containerApi.containerStop("container-start-test", 5); + containerApi.containerWait("container-start-test", null); + containerApi.containerDelete("container-start-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerLogsWithoutTty() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-logs-test"); + containerApi.containerStart("container-logs-test", null); + + Duration timeout = Duration.of(5, SECONDS); + LogFrameStreamCallback callback = new LogFrameStreamCallback(); + + new Thread(() -> containerApi.containerLogs( + "container-logs-test", + false, true, true, null, null, null, null, + callback, timeout.toMillis())).start(); + + CountDownLatch wait = new CountDownLatch(1); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + callback.job.cancel(); + wait.countDown(); + } + }, 5000); + + try { + wait.await(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + assertSame(callback.frames.stream().findAny().get().getStreamType(), Frame.StreamType.STDOUT); + + containerApi.containerStop("container-logs-test", 5); + containerApi.containerWait("container-logs-test", null); + containerApi.containerDelete("container-logs-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerLogsWithTty() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + true, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-logs-with-tty-test"); + containerApi.containerStart("container-logs-with-tty-test", null); + + Duration timeout = Duration.of(5, SECONDS); + LogFrameStreamCallback callback = new LogFrameStreamCallback(); + + new Thread(() -> containerApi.containerLogs( + "container-logs-with-tty-test", + false, true, true, null, null, null, null, + callback, timeout.toMillis())).start(); + + CountDownLatch wait = new CountDownLatch(1); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + callback.job.cancel(); + wait.countDown(); + } + }, 5000); + + try { + wait.await(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + assertSame(callback.frames.stream().findAny().get().getStreamType(), Frame.StreamType.RAW); + + containerApi.containerStop("container-logs-with-tty-test", 5); + containerApi.containerWait("container-logs-with-tty-test", null); + containerApi.containerDelete("container-logs-with-tty-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerUpdate() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-update-test"); + containerApi.containerStart("container-update-test", null); + ContainerUpdateRequest updateRequest = new ContainerUpdateRequest( + null, null, null, + null, null, null, null, null, null, + null, null, null, null, null, null, + null, null, null, + null, null, null, null, null, + null, null, null, null, null, + null, null, null, null, + new RestartPolicy(RestartPolicy.Name.UnlessMinusStopped, null)); + ContainerUpdateResponse updateResponse = containerApi.containerUpdate("container-update-test", updateRequest); + assertTrue(updateResponse.getWarnings() == null || updateResponse.getWarnings().isEmpty()); + containerApi.containerStop("container-update-test", 5); + containerApi.containerWait("container-update-test", null); + containerApi.containerDelete("container-update-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerRestart() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-restart-test"); + containerApi.containerStart("container-restart-test", null); + assertDoesNotThrow(() -> containerApi.containerRestart("container-restart-test", 5)); + containerApi.containerStop("container-restart-test", 5); + containerApi.containerWait("container-restart-test", null); + containerApi.containerDelete("container-restart-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerKill() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-kill-test"); + containerApi.containerStart("container-kill-test", null); + assertDoesNotThrow(() -> containerApi.containerKill("container-kill-test", null)); + containerApi.containerWait("container-kill-test", null); + containerApi.containerDelete("container-kill-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerPauseUnpause() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-pause-test"); + containerApi.containerStart("container-pause-test", null); + assertDoesNotThrow(() -> containerApi.containerPause("container-pause-test")); + ContainerInspectResponse pausedContainer = containerApi.containerInspect("container-pause-test", false); + assertTrue(pausedContainer.getState().getPaused()); + assertDoesNotThrow(() -> containerApi.containerUnpause("container-pause-test")); + ContainerInspectResponse unpausedContainer = containerApi.containerInspect("container-pause-test", false); + assertFalse(unpausedContainer.getState().getPaused()); + containerApi.containerStop("container-pause-test", 5); + containerApi.containerWait("container-pause-test", null); + containerApi.containerDelete("container-pause-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerPrune() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-prune-test"); + + Map> filter = new HashMap<>(); + filter.put("label", singletonList(LABEL_KEY)); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + + Optional> toBePruned = containerApi.containerList(true, null, null, filterJson).stream().filter((c) -> ((List) c.get("Names")).contains("/container-prune-test")).findFirst(); + assertTrue(toBePruned.isPresent()); + + ContainerPruneResponse pruneResponse = containerApi.containerPrune(filterJson); + assertTrue(pruneResponse.getContainersDeleted().contains(toBePruned.get().get("Id"))); + + Optional> shouldBeMissing = containerApi.containerList(true, null, null, filterJson).stream().filter((c) -> ((List) c.get("Names")).contains("/container-prune-test")).findFirst(); + assertFalse(shouldBeMissing.isPresent()); + + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + // the api reference v1.41 says: "On Unix systems, this is done by running the ps command. This endpoint is not supported on Windows." + @Test + public void containerTop() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-top-test"); + containerApi.containerStart("container-top-test", null); + + ContainerTopResponse processes = containerApi.containerTop("container-top-test", null); + List> mainProcesses = processes.getProcesses().stream().filter((p) -> p.get(processes.getTitles().indexOf("CMD")).contains("main -listen-addr=0.0.0.0:")).collect(Collectors.toList()).stream().collect(Collectors.toList()); + assertEquals(1, mainProcesses.size()); + + containerApi.containerStop("container-top-test", 5); + containerApi.containerWait("container-top-test", null); + containerApi.containerDelete("container-top-test", null, null, null); + + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerStatsStream() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-stats-test"); + containerApi.containerStart("container-stats-test", null); + + Duration timeout = Duration.of(5, SECONDS); + LogObjectStreamCallback callback = new LogObjectStreamCallback(); + + containerApi.containerStats("container-stats-test", null, null, callback, timeout.toMillis()); + assertFalse(callback.elements.isEmpty()); + + containerApi.containerStop("container-stats-test", 5); + containerApi.containerWait("container-stats-test", null); + containerApi.containerDelete("container-stats-test", null, null, null); + + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerStatsOnce() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-stats-test"); + containerApi.containerStart("container-stats-test", null); + + Duration timeout = Duration.of(5, SECONDS); + LogObjectStreamCallback callback = new LogObjectStreamCallback(); + + containerApi.containerStats("container-stats-test", false, null, callback, timeout.toMillis()); + assertFalse(callback.elements.isEmpty()); + + containerApi.containerStop("container-stats-test", 5); + containerApi.containerWait("container-stats-test", null); + containerApi.containerDelete("container-stats-test", null, null, null); + + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + @Test + public void containerAttachNonInteractive() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-attach-non-interactive-test"); + containerApi.containerStart("container-attach-non-interactive-test", null); + + Duration timeout = Duration.of(5, SECONDS); + LogFrameStreamCallback callback = new LogFrameStreamCallback(); + + new Thread(() -> containerApi.containerAttach( + "container-attach-non-interactive-test", + null, true, true, null, true, true, + callback, timeout.toMillis())).start(); + + CountDownLatch wait = new CountDownLatch(1); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + callback.job.cancel(); + wait.countDown(); + } + }, 5000); + + try { + wait.await(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + assertSame(callback.frames.stream().findAny().get().getStreamType(), Frame.StreamType.STDOUT); + + containerApi.containerStop("container-attach-non-interactive-test", 5); + containerApi.containerWait("container-attach-non-interactive-test", null); + containerApi.containerDelete("container-attach-non-interactive-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } + + static class LogFrameStreamCallback implements StreamCallback { + + List frames = new ArrayList<>(); + Cancellable job = null; + + @Override + public void onStarting(Cancellable cancellable) { + job = cancellable; + } + + @Override + public void onNext(Frame frame) { + frames.add(frame); + log.info("next: {}", frame); + } + } + + static class LogObjectStreamCallback implements StreamCallback { + + List elements = new ArrayList<>(); + Cancellable job = null; + + @Override + public void onStarting(Cancellable cancellable) { + job = cancellable; + } + + @Override + public void onNext(Object element) { + elements.add(element); + log.info("next: {}", element); + } + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/DistributionApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/DistributionApiIntegrationTest.java new file mode 100644 index 000000000..49ca5ca11 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/DistributionApiIntegrationTest.java @@ -0,0 +1,32 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.engine.api.DistributionApi; +import de.gesellix.docker.engine.model.DistributionInspect; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable +class DistributionApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + DistributionApi distributionApi; + + @BeforeEach + public void setup() { + distributionApi = typeSafeDockerClient.getDistributionApi(); + } + + @Test + public void distributionInspect() { + DistributionInspect response = distributionApi.distributionInspect("alpine:3.5"); + assertNotNull(response.getDescriptor().getDigest()); + assertTrue(response.getDescriptor().getDigest().startsWith("sha256:")); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/ExecApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/ExecApiIntegrationTest.java new file mode 100644 index 000000000..14fb07848 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/ExecApiIntegrationTest.java @@ -0,0 +1,88 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.TestImage; +import de.gesellix.docker.engine.api.ContainerApi; +import de.gesellix.docker.engine.api.ExecApi; +import de.gesellix.docker.engine.api.ImageApi; +import de.gesellix.docker.engine.model.ContainerCreateRequest; +import de.gesellix.docker.engine.model.ExecConfig; +import de.gesellix.docker.engine.model.ExecInspectResponse; +import de.gesellix.docker.engine.model.ExecStartConfig; +import de.gesellix.docker.engine.model.IdResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@DockerEngineAvailable +class ExecApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + private TestImage testImage; + + ExecApi execApi; + ContainerApi containerApi; + ImageApi imageApi; + + @BeforeEach + public void setup() { + execApi = typeSafeDockerClient.getExecApi(); + containerApi = typeSafeDockerClient.getContainerApi(); + imageApi = typeSafeDockerClient.getImageApi(); + testImage = new TestImage(typeSafeDockerClient); + } + + @Test + public void containerExec() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-exec-test"); + containerApi.containerStart("container-exec-test", null); + + IdResponse exec = execApi.containerExec( + "container-exec-test", + new ExecConfig(null, true, true, null, null, + null, + asList("echo", "'aus dem Wald'"), + null, null, null)); + assertNotNull(exec.getId()); + + execApi.execStart(exec.getId(), new ExecStartConfig(false, null)); + + ExecInspectResponse execInspect = execApi.execInspect(exec.getId()); + assertFalse(execInspect.getRunning()); + + containerApi.containerStop("container-exec-test", 5); + containerApi.containerWait("container-exec-test", null); + containerApi.containerDelete("container-exec-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/ImageApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/ImageApiIntegrationTest.java new file mode 100644 index 000000000..8e1585c13 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/ImageApiIntegrationTest.java @@ -0,0 +1,279 @@ +package de.gesellix.docker.client; + +import com.squareup.moshi.Moshi; +import de.gesellix.docker.builder.BuildContextBuilder; +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.DockerRegistry; +import de.gesellix.docker.client.testutil.HttpTestServer; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.NetworkInterfaces; +import de.gesellix.docker.engine.api.ContainerApi; +import de.gesellix.docker.engine.api.ImageApi; +import de.gesellix.docker.engine.model.BuildPruneResponse; +import de.gesellix.docker.engine.model.ContainerCreateRequest; +import de.gesellix.docker.engine.model.ContainerCreateResponse; +import de.gesellix.docker.engine.model.HistoryResponseItem; +import de.gesellix.docker.engine.model.IdResponse; +import de.gesellix.docker.engine.model.Image; +import de.gesellix.docker.engine.model.ImageDeleteResponseItem; +import de.gesellix.docker.engine.model.ImageSearchResponseItem; +import de.gesellix.docker.engine.model.ImageSummary; +import de.gesellix.testutil.ResourceReader; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static java.nio.file.Files.readAttributes; +import static java.nio.file.LinkOption.NOFOLLOW_LINKS; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable +class ImageApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + ImageApi imageApi; + ContainerApi containerApi; + + @BeforeEach + public void setup() { + imageApi = typeSafeDockerClient.getImageApi(); + containerApi = typeSafeDockerClient.getContainerApi(); + } + + @Test + public void buildPrune() { + BuildPruneResponse response = imageApi.buildPrune(null, null, null); + assertTrue(response.getSpaceReclaimed() >= 0); + } + + @Test + public void imageBuild() throws IOException { + String dockerfile = "/images/builder/Dockerfile"; + File inputDirectory = ResourceReader.getClasspathResourceAsFile(dockerfile, ImageApi.class).getParentFile(); + InputStream buildContext = newBuildContext(inputDirectory); + assertDoesNotThrow(() -> imageApi.imageBuild(null, "test:build", null, null, null, null, null, null, + null, null, null, null, null, null, null, + null, null, null, null, null, null, null, + null, null, null, null, buildContext)); + imageApi.imageDelete("test:build", null, null); + } + + InputStream newBuildContext(File baseDirectory) throws IOException { + ByteArrayOutputStream buildContext = new ByteArrayOutputStream(); + BuildContextBuilder.archiveTarFilesRecursively(baseDirectory, buildContext); + return new ByteArrayInputStream(buildContext.toByteArray()); + } + + @Test + public void imageCreatePullFromRemote() { + assertDoesNotThrow(() -> imageApi.imageCreate("alpine", null, null, "edge", null, null, null, null, null)); + } + + @Test + public void imageCreateImportFromUrl() throws IOException { + URL importUrl = getClass().getResource("/images/importUrl/import-from-url.tar"); + HttpTestServer server = new HttpTestServer(); + InetSocketAddress serverAddress = server.start("/images/", new HttpTestServer.FileServer(importUrl)); + int port = serverAddress.getPort(); + List addresses = new NetworkInterfaces().getInet4Addresses(); + String url = String.format("http://%s:%s/images/%s", addresses.get(0), port, importUrl.getPath()); + + assertDoesNotThrow(() -> imageApi.imageCreate(null, url, "test", "from-url", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, null)); + + server.stop(); + imageApi.imageDelete("test:from-url", null, null); + } + + @Test + public void imageCreateImportFromInputStream() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + assertDoesNotThrow(() -> imageApi.imageCreate(null, "-", "test", "from-stream", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source)); + } + imageApi.imageDelete("test:from-stream", null, null); + } + + @Test + public void imageCommit() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + assertDoesNotThrow(() -> imageApi.imageCreate(null, "-", "test", "commit", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source)); + } + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + singletonList("-"), + null, + null, + "test:commit", + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + ContainerCreateResponse container = containerApi.containerCreate(containerCreateRequest, "container-commit-test"); + IdResponse image = imageApi.imageCommit(container.getId(), "test", "commited", null, null, null, null, null); + assertTrue(image.getId().matches("sha256:\\w+")); + imageApi.imageDelete("test:commited", null, null); + containerApi.containerDelete("container-commit-test", null, null, null); + imageApi.imageDelete("test:commit", null, null); + } + + @Test + public void imageList() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "list", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + List images = imageApi.imageList(null, null, null); + assertEquals(1, images.stream().filter((i) -> i.getRepoTags() != null && i.getRepoTags().stream().filter((t) -> t.equals("test:list")).count() > 0).count()); + imageApi.imageDelete("test:list", null, null); + } + + @Test + public void imageDelete() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "delete", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + List deletedImages = imageApi.imageDelete("test:delete", null, null); + assertTrue(deletedImages.stream().filter((e) -> e.getDeleted() != null).count() > 1); + } + + @Test + public void imagePrune() throws IOException { + Map> filter = new HashMap<>(); + filter.put("label", singletonList(LABEL_KEY)); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "prune", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + assertDoesNotThrow(() -> imageApi.imagePrune(filterJson)); + imageApi.imageDelete("test:prune", null, null); + } + + @Test + public void imageGet() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "export", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + File exportedImage = imageApi.imageGet("test:export"); + assertEquals("16896", readAttributes(exportedImage.toPath(), "size", NOFOLLOW_LINKS).get("size").toString()); + + imageApi.imageDelete("test:export", null, null); + } + + @Test + public void imageGetAll() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "export-all-1", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "export-all-2", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + + File exportedImages = imageApi.imageGetAll(asList("test:export-all-1", "test:export-all-2")); + assertEquals("22016", readAttributes(exportedImages.toPath(), "size", NOFOLLOW_LINKS).get("size").toString()); + + imageApi.imageDelete("test:export-all-1", null, null); + imageApi.imageDelete("test:export-all-2", null, null); + } + + @Test + public void imageLoad() { + File tarFile = new File(getClass().getResource("/images/loadImage/load-from-file.tar").getPath()); + assertDoesNotThrow(() -> imageApi.imageLoad(false, tarFile)); + assertEquals(LABEL_VALUE, imageApi.imageInspect("test:load-image").getConfig().getLabels().get(LABEL_KEY)); + this.imageApi.imageDelete("test:load-image", null, null); + } + + @Test + public void imageHistory() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "history", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + + List history = imageApi.imageHistory("test:history"); + assertEquals(1, history.size()); + assertEquals("Imported from -", history.get(0).getComment()); + + imageApi.imageDelete("test:history", null, null); + } + + @Test + public void imageInspect() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "inspect", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + + Image image = imageApi.imageInspect("test:inspect"); + assertEquals("Imported from -", image.getComment()); + + imageApi.imageDelete("test:inspect", null, null); + } + + @Test + public void imageSearch() { + List searchResult = imageApi.imageSearch("alpine", 1, null); + assertEquals(1, searchResult.size()); + assertEquals("alpine", searchResult.get(0).getName()); + } + + @Test + public void imageTag() throws IOException { + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "tag", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + imageApi.imageTag("test:tag", "test/image", "test-tag"); + Image image1 = imageApi.imageInspect("test:tag"); + Image image2 = imageApi.imageInspect("test/image:test-tag"); + assertFalse(image1.getId().isEmpty()); + assertEquals(image1.getId(), image2.getId()); + + imageApi.imageDelete("test:tag", null, null); + imageApi.imageDelete("test/image:test-tag", null, null); + } + + @Test + public void imagePushToCustomRegistry() throws IOException { + DockerRegistry registry = new DockerRegistry(typeSafeDockerClient); + registry.run(); + String registryUrl = registry.url(); + + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "push", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + } + imageApi.imageTag("test:push", registryUrl + "/test", "push"); + + imageApi.imagePush(registryUrl + "/test", "", "push"); + + registry.rm(); + + imageApi.imageDelete("test:push", null, null); + imageApi.imageDelete(registryUrl + "/test:push", null, null); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/NetworkApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/NetworkApiIntegrationTest.java new file mode 100644 index 000000000..86445c92d --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/NetworkApiIntegrationTest.java @@ -0,0 +1,135 @@ +package de.gesellix.docker.client; + +import com.squareup.moshi.Moshi; +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.TestImage; +import de.gesellix.docker.engine.api.ContainerApi; +import de.gesellix.docker.engine.api.ImageApi; +import de.gesellix.docker.engine.api.NetworkApi; +import de.gesellix.docker.engine.model.ContainerCreateRequest; +import de.gesellix.docker.engine.model.Network; +import de.gesellix.docker.engine.model.NetworkConnectRequest; +import de.gesellix.docker.engine.model.NetworkCreateRequest; +import de.gesellix.docker.engine.model.NetworkCreateResponse; +import de.gesellix.docker.engine.model.NetworkDisconnectRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable +class NetworkApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + private TestImage testImage; + + NetworkApi networkApi; + ContainerApi containerApi; + ImageApi imageApi; + + @BeforeEach + public void setup() { + networkApi = typeSafeDockerClient.getNetworkApi(); + containerApi = typeSafeDockerClient.getContainerApi(); + imageApi = typeSafeDockerClient.getImageApi(); + testImage = new TestImage(typeSafeDockerClient); + } + + @Test + public void networkList() { + List networks = networkApi.networkList(null); + assertFalse(networks.isEmpty()); + Network firstNetwork = networks.get(0); + assertTrue(firstNetwork.getName().matches("\\w+")); + } + + @Test + public void networkInspect() { + List networks = networkApi.networkList(null); + Network firstNetwork = networks.get(0); + Network network = networkApi.networkInspect(firstNetwork.getId(), true, firstNetwork.getScope()); + assertEquals(firstNetwork.getScope(), network.getScope()); + } + + @Test + public void networkCreateDelete() { + NetworkCreateResponse response = networkApi.networkCreate(new NetworkCreateRequest("test-network", null, null, null, null, null, null, null, null, singletonMap(LABEL_KEY, LABEL_VALUE))); + + Map> filter = new HashMap<>(); + filter.put("label", singletonList(LABEL_KEY)); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + List networks = networkApi.networkList(filterJson); + Optional testNetwork = networks.stream().filter((n) -> n.getName().equals("test-network")).findFirst(); + + assertTrue(testNetwork.isPresent()); + assertEquals(response.getId(), testNetwork.get().getId()); + networkApi.networkDelete("test-network"); + } + + @Test + public void networkPrune() { + networkApi.networkCreate(new NetworkCreateRequest("test-network", null, null, null, null, null, null, null, null, singletonMap(LABEL_KEY, LABEL_VALUE))); + + Map> filter = new HashMap<>(); + filter.put("label", singletonList(LABEL_KEY)); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + + networkApi.networkPrune(filterJson); + + List networks = networkApi.networkList(filterJson); + Optional testNetwork = networks.stream().filter((n) -> n.getName().equals("test-network")).findAny(); + assertFalse(testNetwork.isPresent()); + + assertDoesNotThrow(() -> networkApi.networkDelete("test-network")); + } + + @Test + public void networkConnectDisconnect() { + imageApi.imageCreate(testImage.getImageName(), null, null, testImage.getImageTag(), null, null, null, null, null); + + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + null, + false, null, null, + null, + null, + null, + null, + testImage.getImageWithTag(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + null, + null + ); + containerApi.containerCreate(containerCreateRequest, "container-network-test"); + + networkApi.networkCreate(new NetworkCreateRequest("test-network", null, null, null, null, null, null, null, null, singletonMap(LABEL_KEY, LABEL_VALUE))); + + assertDoesNotThrow(() -> networkApi.networkConnect("test-network", new NetworkConnectRequest("container-network-test", null))); + assertDoesNotThrow(() -> networkApi.networkDisconnect("test-network", new NetworkDisconnectRequest("container-network-test", null))); + + networkApi.networkDelete("test-network"); + containerApi.containerDelete("container-network-test", null, null, null); + imageApi.imageDelete(testImage.getImageWithTag(), null, null); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/NodeApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/NodeApiIntegrationTest.java new file mode 100644 index 000000000..828ed8c82 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/NodeApiIntegrationTest.java @@ -0,0 +1,68 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.engine.api.NodeApi; +import de.gesellix.docker.engine.client.infrastructure.ClientException; +import de.gesellix.docker.engine.model.LocalNodeState; +import de.gesellix.docker.engine.model.Node; +import de.gesellix.docker.engine.model.NodeSpec; +import de.gesellix.docker.engine.model.NodeState; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable(requiredSwarmMode = LocalNodeState.Active) +class NodeApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + NodeApi nodeApi; + + @BeforeEach + public void setup() { + nodeApi = typeSafeDockerClient.getNodeApi(); + } + + @Test + public void nodeListInspectUpdate() { + List nodes = nodeApi.nodeList(null); + assertFalse(nodes.isEmpty()); + Node firstNode = nodes.get(0); + assertEquals(NodeState.Ready, firstNode.getStatus().getState()); + + Node node = nodeApi.nodeInspect(firstNode.getID()); + assertEquals(firstNode.getID(), node.getID()); + + NodeSpec originalSpec = node.getSpec(); + assertFalse(originalSpec.getLabels().containsKey(LABEL_KEY)); + + Map labels = new HashMap<>(originalSpec.getLabels()); + labels.put(LABEL_KEY, "temporary"); + NodeSpec spec = new NodeSpec(originalSpec.getName(), labels, originalSpec.getRole(), originalSpec.getAvailability()); + nodeApi.nodeUpdate(firstNode.getID(), node.getVersion().getIndex().longValue(), spec); + + node = nodeApi.nodeInspect(firstNode.getID()); + assertEquals(node.getSpec().getLabels().get(LABEL_KEY), "temporary"); + + nodeApi.nodeUpdate(firstNode.getID(), node.getVersion().getIndex().longValue(), originalSpec); + } + + @Test + public void nodeDelete() { + List nodes = nodeApi.nodeList(null); + Node firstNode = nodes.get(0); + String error = assertThrows(ClientException.class, () -> nodeApi.nodeDelete(firstNode.getID(), false)).toString(); + assertTrue(error.contains("FailedPrecondition")); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/PluginApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/PluginApiIntegrationTest.java new file mode 100644 index 000000000..b351f86c4 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/PluginApiIntegrationTest.java @@ -0,0 +1,41 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.engine.api.PluginApi; +import de.gesellix.docker.engine.model.Plugin; +import de.gesellix.docker.engine.model.PluginPrivilege; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@DockerEngineAvailable +class PluginApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + PluginApi pluginApi; + + @BeforeEach + public void setup() { + pluginApi = typeSafeDockerClient.getPluginApi(); + } + + @Test + public void pluginList() { + List plugins = pluginApi.pluginList(null); + assertNotNull(plugins); + } + + @Test + public void pluginPrivileges() { + List privileges = pluginApi.getPluginPrivileges("vieux/sshfs"); + assertEquals("host", privileges.stream().filter((p) -> Objects.equals(p.getName(), "network")).findFirst().get().getValue().get(0)); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/SecretApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/SecretApiIntegrationTest.java new file mode 100644 index 000000000..15d6aa56d --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/SecretApiIntegrationTest.java @@ -0,0 +1,97 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.SwarmUtil; +import de.gesellix.docker.engine.api.SecretApi; +import de.gesellix.docker.engine.model.IdResponse; +import de.gesellix.docker.engine.model.LocalNodeState; +import de.gesellix.docker.engine.model.Secret; +import de.gesellix.docker.engine.model.SecretSpec; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable(requiredSwarmMode = LocalNodeState.Active) +class SecretApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + SecretApi secretApi; + + IdResponse defaultSecret; + + SwarmUtil swarmUtil; + + @BeforeEach + public void setup() { + secretApi = typeSafeDockerClient.getSecretApi(); + + swarmUtil = new SwarmUtil(typeSafeDockerClient); + + String encoded = Base64.getEncoder().encodeToString("secret-data".getBytes()); + defaultSecret = secretApi.secretCreate(new SecretSpec("secret-name", Collections.emptyMap(), encoded, null, null)); + } + + @AfterEach + public void cleanup() { + if (defaultSecret != null) { + secretApi.secretDelete(defaultSecret.getId()); + } + } + + @Test + public void secretCreate() { + String encoded = Base64.getEncoder().encodeToString("secret-data".getBytes()); + IdResponse response = secretApi.secretCreate(new SecretSpec("my-secret", Collections.emptyMap(), encoded, null, null)); + assertTrue(response.getId().matches("\\w{5,}")); + + secretApi.secretDelete(response.getId()); + } + + @Test + public void secretDelete() { + String encoded = Base64.getEncoder().encodeToString("secret-data".getBytes()); + IdResponse response = secretApi.secretCreate(new SecretSpec("my-secret", Collections.emptyMap(), encoded, null, null)); + + assertDoesNotThrow(() -> secretApi.secretDelete(response.getId())); + } + + @Test + public void secretInspect() { + Secret inspect = secretApi.secretInspect(defaultSecret.getId()); + assertEquals("secret-name", inspect.getSpec().getName()); + assertNull(inspect.getSpec().getData()); + } + + @Test + public void secretList() { + List secrets = secretApi.secretList(null); + Stream filtered = secrets.stream().filter(c -> Objects.equals(c.getID(), defaultSecret.getId())); + assertEquals(defaultSecret.getId(), filtered.findFirst().orElse(new Secret()).getID()); + } + + @Test + public void secretUpdate() { + Secret inspect = secretApi.secretInspect(defaultSecret.getId()); + SecretSpec secretSpec = inspect.getSpec(); + assertNotNull(secretSpec); + assertDoesNotThrow(() -> secretApi.secretUpdate(defaultSecret.getId(), inspect.getVersion().getIndex(), new SecretSpec(secretSpec.getName(), singletonMap(LABEL_KEY, LABEL_VALUE), secretSpec.getData(), secretSpec.getDriver(), secretSpec.getTemplating()))); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/ServiceApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/ServiceApiIntegrationTest.java new file mode 100644 index 000000000..335f060dc --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/ServiceApiIntegrationTest.java @@ -0,0 +1,211 @@ +package de.gesellix.docker.client; + +import com.squareup.moshi.Moshi; +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.TestImage; +import de.gesellix.docker.engine.api.Cancellable; +import de.gesellix.docker.engine.api.Frame; +import de.gesellix.docker.engine.api.ServiceApi; +import de.gesellix.docker.engine.api.StreamCallback; +import de.gesellix.docker.engine.client.infrastructure.LoggingExtensionsKt; +import de.gesellix.docker.engine.model.EndpointPortConfig; +import de.gesellix.docker.engine.model.EndpointSpec; +import de.gesellix.docker.engine.model.LocalNodeState; +import de.gesellix.docker.engine.model.Service; +import de.gesellix.docker.engine.model.ServiceServiceStatus; +import de.gesellix.docker.engine.model.ServiceSpec; +import de.gesellix.docker.engine.model.ServiceSpecMode; +import de.gesellix.docker.engine.model.ServiceSpecModeReplicated; +import de.gesellix.docker.engine.model.ServiceSpecUpdateConfig; +import de.gesellix.docker.engine.model.ServiceUpdateResponse; +import de.gesellix.docker.engine.model.ServiceUpdateStatus; +import de.gesellix.docker.engine.model.TaskSpec; +import de.gesellix.docker.engine.model.TaskSpecContainerSpec; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static de.gesellix.docker.engine.model.EndpointPortConfig.Protocol.Tcp; +import static de.gesellix.docker.engine.model.EndpointPortConfig.PublishMode.Ingress; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable(requiredSwarmMode = LocalNodeState.Active) +class ServiceApiIntegrationTest { + + private static final Logger log = LoggingExtensionsKt.logger(ServiceApiIntegrationTest.class.getName()).getValue(); + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + private TestImage testImage; + + ServiceApi serviceApi; + + @BeforeEach + public void setup() { + serviceApi = typeSafeDockerClient.getServiceApi(); + testImage = new TestImage(typeSafeDockerClient); + } + + @Test + public void serviceList() { + List services = serviceApi.serviceList(null, null); + assertNotNull(services); + } + + @Test + public void serviceLogs() throws InterruptedException { + serviceApi.serviceCreate( + new ServiceSpec("test-service", singletonMap(LABEL_KEY, LABEL_VALUE), + new TaskSpec(null, new TaskSpecContainerSpec(testImage.getImageWithTag(), singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, null, null, null), + null, null, null, null, null, null, null, null), + new ServiceSpecMode(new ServiceSpecModeReplicated(1L), null, null, null), + new ServiceSpecUpdateConfig(1L, null, null, null, null, null), + null, null, + new EndpointSpec(null, singletonList(new EndpointPortConfig(null, Tcp, 8080, 8080, Ingress)))), + null); + + CountDownLatch wait1 = new CountDownLatch(1); + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + Map> filter = new HashMap<>(); + filter.put("name", singletonList("test-service")); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + ServiceServiceStatus serviceStatus = serviceApi.serviceList(filterJson, true).get(0).getServiceStatus(); + if (serviceStatus != null && serviceStatus.getRunningTasks() > 0) { + wait1.countDown(); + timer.cancel(); + } + } + }, 500, 500); + wait1.await(10, TimeUnit.SECONDS); + timer.cancel(); + + Duration timeout = Duration.of(5, SECONDS); + LogStreamCallback callback = new LogStreamCallback(); + + new Thread(() -> serviceApi.serviceLogs( + "test-service", + null, null, true, true, null, null, null, + callback, timeout.toMillis())).start(); + + CountDownLatch wait = new CountDownLatch(1); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + callback.job.cancel(); + wait.countDown(); + } + }, 5000); + + try { + wait.await(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + serviceApi.serviceDelete("test-service"); + assertSame(callback.frames.stream().findAny().get().getStreamType(), Frame.StreamType.STDOUT); + } + + @Test + public void serviceCreateInspectUpdateDelete() throws InterruptedException { + serviceApi.serviceCreate(new ServiceSpec("test-service", singletonMap(LABEL_KEY, LABEL_VALUE), + new TaskSpec(null, new TaskSpecContainerSpec(testImage.getImageWithTag(), singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, null, null, null), + null, null, null, null, null, null, null, null), + new ServiceSpecMode(new ServiceSpecModeReplicated(1L), null, null, null), + new ServiceSpecUpdateConfig(1L, null, null, null, null, null), + null, null, + new EndpointSpec(null, singletonList(new EndpointPortConfig(null, Tcp, 8080, 8080, Ingress)))), + null); + Service serviceInspect = serviceApi.serviceInspect("test-service", false); + Integer serviceVersion = serviceInspect.getVersion().getIndex(); + assertTrue(serviceVersion > 0); + + Map labels = new HashMap<>(); + labels.putAll(serviceInspect.getSpec().getLabels()); + labels.put("another-label", "another-value"); + ServiceSpec spec = new ServiceSpec("test-service", labels, + new TaskSpec(null, new TaskSpecContainerSpec(testImage.getImageWithTag(), labels, + null, null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, null, null, null), + null, null, null, null, null, null, null, null), + new ServiceSpecMode(new ServiceSpecModeReplicated(1L), null, null, null), + new ServiceSpecUpdateConfig(1L, null, null, null, null, null), + null, null, + new EndpointSpec(null, singletonList(new EndpointPortConfig(null, Tcp, 8080, 8080, Ingress)))); + ServiceUpdateResponse updateResponse = serviceApi.serviceUpdate("test-service", serviceVersion, spec, null, null, null); + assertTrue(updateResponse.getWarnings() == null || updateResponse.getWarnings().isEmpty()); + + CountDownLatch wait = new CountDownLatch(1); + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + ServiceUpdateStatus updateStatus = serviceApi.serviceInspect("test-service", false).getUpdateStatus(); + if (updateStatus.getState() == ServiceUpdateStatus.State.Completed) { + wait.countDown(); + timer.cancel(); + } + } + }, 500, 500); + wait.await(10, TimeUnit.SECONDS); + Service serviceInspect2 = serviceApi.serviceInspect("test-service", false); + assertEquals("another-value", serviceInspect2.getSpec().getLabels().get("another-label")); + serviceApi.serviceDelete("test-service"); + } + + static class LogStreamCallback implements StreamCallback { + + List frames = new ArrayList<>(); + Cancellable job = null; + + @Override + public void onStarting(Cancellable cancellable) { + job = cancellable; + } + + @Override + public void onNext(Frame frame) { + frames.add(frame); + log.info("next: {}", frame); + } + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/SwarmApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/SwarmApiIntegrationTest.java new file mode 100644 index 000000000..2aeaa91a2 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/SwarmApiIntegrationTest.java @@ -0,0 +1,71 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.SwarmUtil; +import de.gesellix.docker.engine.api.SwarmApi; +import de.gesellix.docker.engine.api.SystemApi; +import de.gesellix.docker.engine.model.LocalNodeState; +import de.gesellix.docker.engine.model.Swarm; +import de.gesellix.docker.engine.model.SwarmInitRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable +class SwarmApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + SwarmApi swarmApi; + SystemApi systemApi; + + SwarmUtil swarmUtil; + + @BeforeEach + public void setup() { + swarmApi = typeSafeDockerClient.getSwarmApi(); + systemApi = typeSafeDockerClient.getSystemApi(); + + swarmUtil = new SwarmUtil(typeSafeDockerClient); + } + + @Test + public void swarmLocalState() { + swarmUtil.runWithInactiveSwarm(() -> { + assertEquals(LocalNodeState.Inactive, systemApi.systemInfo().getSwarm().getLocalNodeState()); + }); + } + + @Test + public void swarmInit() { + swarmUtil.runWithInactiveSwarm(() -> { + String initResult = swarmApi.swarmInit(new SwarmInitRequest("0.0.0.0:2377", "127.0.0.1", null, null, null, false, null, null)); + assertTrue(initResult.matches("\\w+")); + }); + } + + @Test + public void swarmLeave() { + swarmUtil.runWithActiveSwarm(() -> { + assertDoesNotThrow(() -> swarmApi.swarmLeave(true)); + }); + } + + @Test + public void swarmInspect() { + swarmUtil.runWithActiveSwarm(() -> { + Swarm swarmInspect = swarmApi.swarmInspect(); + assertEquals("default", swarmInspect.getSpec().getName()); + }); + } + + @Test + public void swarmUnlockKey() { + swarmUtil.runWithActiveSwarm(() -> assertDoesNotThrow(swarmApi::swarmUnlockkey)); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/SystemApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/SystemApiIntegrationTest.java new file mode 100644 index 000000000..ba88f8234 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/SystemApiIntegrationTest.java @@ -0,0 +1,161 @@ +package de.gesellix.docker.client; + +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.engine.api.Cancellable; +import de.gesellix.docker.engine.api.ContainerApi; +import de.gesellix.docker.engine.api.ImageApi; +import de.gesellix.docker.engine.api.StreamCallback; +import de.gesellix.docker.engine.api.SystemApi; +import de.gesellix.docker.engine.client.infrastructure.ClientException; +import de.gesellix.docker.engine.client.infrastructure.LoggingExtensionsKt; +import de.gesellix.docker.engine.model.AuthConfig; +import de.gesellix.docker.engine.model.EventMessage; +import de.gesellix.docker.engine.model.SystemAuthResponse; +import de.gesellix.docker.engine.model.SystemInfo; +import de.gesellix.docker.engine.model.SystemVersion; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; + +import java.io.IOException; +import java.io.InputStream; +import java.time.Duration; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable +class SystemApiIntegrationTest { + + private static final Logger log = LoggingExtensionsKt.logger(SystemApiIntegrationTest.class.getName()).getValue(); + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + SystemApi systemApi; + ImageApi imageApi; + ContainerApi containerApi; + + @BeforeEach + public void setup() { + systemApi = typeSafeDockerClient.getSystemApi(); + imageApi = typeSafeDockerClient.getImageApi(); + containerApi = typeSafeDockerClient.getContainerApi(); + } + + @Test + public void systemAuthWhenUnauthorized() { + assertThrows(ClientException.class, () -> systemApi.systemAuth(new AuthConfig("unknown-username", "a-secret", "user@example.com", null))); + } + + @Test + public void systemAuthWhenAuthorized() { + de.gesellix.docker.client.authentication.AuthConfig defaultAuthConfig = new DockerClientImpl().readDefaultAuthConfig(); + SystemAuthResponse authResponse = systemApi.systemAuth(new AuthConfig(defaultAuthConfig.getUsername(), defaultAuthConfig.getPassword(), null, null)); + assertEquals("Login Succeeded", authResponse.getStatus()); + } + + @Test + public void systemDataUsage() { + assertDoesNotThrow(() -> systemApi.systemDataUsage()); + } + + @Test + public void systemEvents() throws IOException { + Duration timeout = Duration.of(20, SECONDS); + Instant since = ZonedDateTime.now().toInstant(); + Instant until = ZonedDateTime.now().plus(timeout).plusSeconds(10).toInstant(); + SystemEventsCallback callback = new SystemEventsCallback(); + + new Thread(() -> systemApi.systemEvents( + "" + since.getEpochSecond(), + "" + until.getEpochSecond(), + null, + callback, + timeout.toMillis())).start(); + + try (InputStream source = getClass().getResourceAsStream("/images/importUrl/import-from-url.tar")) { + imageApi.imageCreate(null, "-", "test", "system-events", null, null, singletonList(String.format("LABEL %1$s=\"%2$s\"", LABEL_KEY, LABEL_VALUE)), null, source); + imageApi.imageDelete("test:system-events", null, null); + } + + CountDownLatch wait = new CountDownLatch(1); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + callback.job.cancel(); + wait.countDown(); + } + }, 1000); + try { + wait.await(); + } + catch (InterruptedException e) { + log.warn("interrupted", e); + } + + EventMessage event = callback.events.stream().filter(e -> Objects.equals(e.getAction(), "delete")).findFirst().orElse(new EventMessage()); + log.info("actual {}", event); + assertEquals(EventMessage.Type.Image, event.getType()); + } + + @Test + public void systemInfo() { + SystemInfo systemInfo = systemApi.systemInfo(); + assertEquals("docker.io", systemInfo.getRegistryConfig().getIndexConfigs().get("docker.io").getName()); + assertTrue(systemInfo.getRegistryConfig().getIndexConfigs().get("docker.io").getOfficial()); + assertTrue(systemInfo.getRegistryConfig().getIndexConfigs().get("docker.io").getSecure()); + assertTrue(null == systemInfo.getIsolation() || systemInfo.getIsolation() == SystemInfo.Isolation.Hyperv); + } + + @Test + public void systemPing() { + String systemPing = systemApi.systemPing(); + assertEquals("OK", systemPing); + } + + @Test + public void systemPingHead() { + String systemPing = systemApi.systemPingHead(); + assertEquals("", systemPing); + } + + @Test + public void systemVersion() { + SystemVersion systemVersion = systemApi.systemVersion(); + // will break on CI or in other environments - TODO fixme + assertEquals("1.41", systemVersion.getApiVersion()); + } + + static class SystemEventsCallback implements StreamCallback { + + List events = new ArrayList<>(); + Cancellable job = null; + + @Override + public void onStarting(Cancellable cancellable) { + job = cancellable; + } + + @Override + public void onNext(EventMessage event) { + events.add(event); + log.info("{}", event); + } + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/TaskApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/TaskApiIntegrationTest.java new file mode 100644 index 000000000..232765348 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/TaskApiIntegrationTest.java @@ -0,0 +1,203 @@ +package de.gesellix.docker.client; + +import com.squareup.moshi.Moshi; +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.client.testutil.TestImage; +import de.gesellix.docker.engine.api.Cancellable; +import de.gesellix.docker.engine.api.Frame; +import de.gesellix.docker.engine.api.ServiceApi; +import de.gesellix.docker.engine.api.StreamCallback; +import de.gesellix.docker.engine.api.TaskApi; +import de.gesellix.docker.engine.client.infrastructure.LoggingExtensionsKt; +import de.gesellix.docker.engine.model.EndpointPortConfig; +import de.gesellix.docker.engine.model.EndpointSpec; +import de.gesellix.docker.engine.model.LocalNodeState; +import de.gesellix.docker.engine.model.ServiceCreateResponse; +import de.gesellix.docker.engine.model.ServiceServiceStatus; +import de.gesellix.docker.engine.model.ServiceSpec; +import de.gesellix.docker.engine.model.ServiceSpecMode; +import de.gesellix.docker.engine.model.ServiceSpecModeReplicated; +import de.gesellix.docker.engine.model.ServiceSpecUpdateConfig; +import de.gesellix.docker.engine.model.Task; +import de.gesellix.docker.engine.model.TaskSpec; +import de.gesellix.docker.engine.model.TaskSpecContainerSpec; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static de.gesellix.docker.engine.model.EndpointPortConfig.Protocol.Tcp; +import static de.gesellix.docker.engine.model.EndpointPortConfig.PublishMode.Ingress; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable(requiredSwarmMode = LocalNodeState.Active) +class TaskApiIntegrationTest { + + private static final Logger log = LoggingExtensionsKt.logger(TaskApiIntegrationTest.class.getName()).getValue(); + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + private TestImage testImage; + + TaskApi taskApi; + ServiceApi serviceApi; + + @BeforeEach + public void setup() { + taskApi = typeSafeDockerClient.getTaskApi(); + serviceApi = typeSafeDockerClient.getServiceApi(); + testImage = new TestImage(typeSafeDockerClient); + } + + @Test + public void taskListInspect() throws InterruptedException { + ServiceCreateResponse service = serviceApi.serviceCreate( + new ServiceSpec("test-service", singletonMap(LABEL_KEY, LABEL_VALUE), + new TaskSpec(null, new TaskSpecContainerSpec(testImage.getImageWithTag(), singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, null, null, null), + null, null, null, null, null, null, null, null), + new ServiceSpecMode(new ServiceSpecModeReplicated(1L), null, null, null), + new ServiceSpecUpdateConfig(1L, null, null, null, null, null), + null, null, + new EndpointSpec(null, singletonList(new EndpointPortConfig(null, Tcp, 8080, 8080, Ingress)))), + null); + + CountDownLatch wait1 = new CountDownLatch(1); + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + Map> filter = new HashMap<>(); + filter.put("name", singletonList("test-service")); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + ServiceServiceStatus serviceStatus = serviceApi.serviceList(filterJson, true).get(0).getServiceStatus(); + if (serviceStatus != null && serviceStatus.getRunningTasks() > 0) { + wait1.countDown(); + timer.cancel(); + } + } + }, 500, 500); + wait1.await(10, TimeUnit.SECONDS); + timer.cancel(); + + Map> filter = new HashMap<>(); + filter.put("service", singletonList("test-service")); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + List tasks = taskApi.taskList(filterJson); + assertEquals(1, tasks.size()); + assertTrue(tasks.stream().findFirst().isPresent()); + + Task task = taskApi.taskInspect(tasks.stream().findFirst().get().getID()); + assertEquals(service.getID(), task.getServiceID()); + + serviceApi.serviceDelete("test-service"); + } + + @Test + public void taskLogs() throws InterruptedException { + ServiceCreateResponse service = serviceApi.serviceCreate( + new ServiceSpec("test-service", singletonMap(LABEL_KEY, LABEL_VALUE), + new TaskSpec(null, new TaskSpecContainerSpec(testImage.getImageWithTag(), singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, + null, null, null, null, + null, null, null, null, null, null), + null, null, null, null, null, null, null, null), + new ServiceSpecMode(new ServiceSpecModeReplicated(1L), null, null, null), + new ServiceSpecUpdateConfig(1L, null, null, null, null, null), + null, null, + new EndpointSpec(null, singletonList(new EndpointPortConfig(null, Tcp, 8080, 8080, Ingress)))), + null); + + CountDownLatch wait1 = new CountDownLatch(1); + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + Map> filter = new HashMap<>(); + filter.put("name", singletonList("test-service")); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + ServiceServiceStatus serviceStatus = serviceApi.serviceList(filterJson, true).get(0).getServiceStatus(); + if (serviceStatus != null && serviceStatus.getRunningTasks() > 0) { + wait1.countDown(); + timer.cancel(); + } + } + }, 500, 500); + wait1.await(10, TimeUnit.SECONDS); + timer.cancel(); + + Map> filter = new HashMap<>(); + filter.put("service", singletonList("test-service")); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + List tasks = taskApi.taskList(filterJson); + Task task = tasks.stream().findFirst().get(); + + Duration timeout = Duration.of(5, SECONDS); + LogStreamCallback callback = new LogStreamCallback(); + + new Thread(() -> taskApi.taskLogs(task.getID(), + null, null, true, true, null, null, null, + callback, timeout.toMillis())).start(); + + CountDownLatch wait = new CountDownLatch(1); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + callback.job.cancel(); + wait.countDown(); + } + }, 5000); + + try { + wait.await(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + serviceApi.serviceDelete("test-service"); + assertSame(callback.frames.stream().findAny().get().getStreamType(), Frame.StreamType.STDOUT); + } + + static class LogStreamCallback implements StreamCallback { + + List frames = new ArrayList<>(); + Cancellable job = null; + + @Override + public void onStarting(Cancellable cancellable) { + job = cancellable; + } + + @Override + public void onNext(Frame frame) { + frames.add(frame); + log.info("frame: {}", frame); + } + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/VolumeApiIntegrationTest.java b/typesafe-client/src/test/java/de/gesellix/docker/client/VolumeApiIntegrationTest.java new file mode 100644 index 000000000..1b7123a8a --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/VolumeApiIntegrationTest.java @@ -0,0 +1,78 @@ +package de.gesellix.docker.client; + +import com.squareup.moshi.Moshi; +import de.gesellix.docker.client.testutil.DockerEngineAvailable; +import de.gesellix.docker.client.testutil.InjectDockerClient; +import de.gesellix.docker.engine.api.VolumeApi; +import de.gesellix.docker.engine.model.Volume; +import de.gesellix.docker.engine.model.VolumeConfig; +import de.gesellix.docker.engine.model.VolumePruneResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DockerEngineAvailable +class VolumeApiIntegrationTest { + + @InjectDockerClient + private TypeSafeDockerClientImpl typeSafeDockerClient; + + VolumeApi volumeApi; + + @BeforeEach + public void setup() { + volumeApi = typeSafeDockerClient.getVolumeApi(); + } + + @Test + public void volumeCreate() { + Volume volume = volumeApi.volumeCreate(new VolumeConfig("my-volume", null, Collections.emptyMap(), Collections.emptyMap())); + assertTrue(volume.getMountpoint().endsWith("/my-volume/_data")); + volumeApi.volumeDelete(volume.getName(), false); + } + + @Test + public void volumeDelete() { + Volume volume = volumeApi.volumeCreate(new VolumeConfig("my-volume", null, Collections.emptyMap(), Collections.emptyMap())); + assertDoesNotThrow(() -> volumeApi.volumeDelete(volume.getName(), false)); + } + + @Test + public void volumeInspect() { + volumeApi.volumeCreate(new VolumeConfig("my-volume", null, Collections.emptyMap(), Collections.emptyMap())); + Volume volume = volumeApi.volumeInspect("my-volume"); + assertTrue(volume.getMountpoint().endsWith("/my-volume/_data")); + volumeApi.volumeDelete(volume.getName(), false); + } + + @Test + public void volumeList() { + Volume volume = volumeApi.volumeCreate(new VolumeConfig("my-volume", null, Collections.emptyMap(), Collections.emptyMap())); + Optional myVolume = volumeApi.volumeList(null).getVolumes().stream().filter((v) -> v.getName().equals(volume.getName())).findFirst(); + assertEquals(volume.getMountpoint(), myVolume.orElse(new Volume("none", "none", "none", Collections.emptyMap(), Volume.Scope.Local, Collections.emptyMap(), "none", Collections.emptyMap(), null)).getMountpoint()); + volumeApi.volumeDelete(volume.getName(), false); + } + + @Test + public void volumePrune() { + Map> filter = new HashMap<>(); + filter.put("label", Collections.singletonList(LABEL_KEY)); + String filterJson = new Moshi.Builder().build().adapter(Map.class).toJson(filter); + + Volume volume = volumeApi.volumeCreate(new VolumeConfig("my-volume", null, Collections.emptyMap(), Collections.singletonMap(LABEL_KEY, LABEL_VALUE))); + VolumePruneResponse pruneResponse = volumeApi.volumePrune(filterJson); + assertTrue(Objects.requireNonNull(pruneResponse.getVolumesDeleted()).stream().allMatch((v) -> v.equals(volume.getName()))); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/Constants.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/Constants.java new file mode 100644 index 000000000..0431a5513 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/Constants.java @@ -0,0 +1,7 @@ +package de.gesellix.docker.client.testutil; + +public interface Constants { + + String LABEL_KEY = "de.gesellix.docker-client.test"; + String LABEL_VALUE = "1"; +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/DockerEngineAvailable.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/DockerEngineAvailable.java new file mode 100644 index 000000000..9ba27c255 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/DockerEngineAvailable.java @@ -0,0 +1,115 @@ +package de.gesellix.docker.client.testutil; + +import de.gesellix.docker.client.TypeSafeDockerClientImpl; +import de.gesellix.docker.engine.client.infrastructure.LoggingExtensionsKt; +import de.gesellix.docker.engine.model.LocalNodeState; +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionConfigurationException; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; +import org.junit.jupiter.api.extension.TestInstancePreDestroyCallback; +import org.junit.platform.commons.support.HierarchyTraversalMode; +import org.junit.platform.commons.support.ReflectionSupport; +import org.slf4j.Logger; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.util.List; + +import static org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled; +import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +@ExtendWith(DockerEngineAvailable.DockerEngineAvailableCondition.class) +public @interface DockerEngineAvailable { + + Logger log = LoggingExtensionsKt.logger(DockerEngineAvailable.class.getName()).getValue(); + + LocalNodeState requiredSwarmMode() default LocalNodeState.EMPTY; + + class DockerEngineAvailableCondition implements ExecutionCondition, TestInstancePostProcessor, TestInstancePreDestroyCallback { + + private final TypeSafeDockerClientImpl dockerClient; + private final SwarmUtil swarmUtil; + private LocalNodeState requiredSwarmMode; + private LocalNodeState previousNodeState = LocalNodeState.EMPTY; + + public DockerEngineAvailableCondition() { + dockerClient = new TypeSafeDockerClientImpl(); + swarmUtil = new SwarmUtil(dockerClient); + } + + @Override + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + return available() + ? enabled("Docker Engine is available") + : disabled("Docker Engine is not available"); + } + + boolean available() { + try { + dockerClient.getSystemApi().systemPing(); + return true; + } + catch (Exception e) { + log.warn("Docker not available"); + return false; + } + } + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { + initDockerClientField(testInstance); + + requiredSwarmMode = testInstance.getClass().getAnnotation(DockerEngineAvailable.class).requiredSwarmMode(); + switch (requiredSwarmMode) { + case Active: + previousNodeState = swarmUtil.ensureActiveSwarm(); + break; + case Inactive: + previousNodeState = swarmUtil.ensureInactiveSwarm(); + break; + case EMPTY: + // don't change anything + break; + default: + throw new ExtensionConfigurationException("Not supported: " + requiredSwarmMode); + } + } + + private void initDockerClientField(Object testInstance) throws IllegalAccessException { + List fields = ReflectionSupport.findFields(testInstance.getClass(), (Field f) -> f.getAnnotation(InjectDockerClient.class) != null, HierarchyTraversalMode.TOP_DOWN); + if (fields.isEmpty()) { + throw new ExtensionConfigurationException(String.format("No %1$s annotated field found in %2$s.", InjectDockerClient.class, testInstance.getClass())); + } + if (fields.size() > 1) { + throw new ExtensionConfigurationException(String.format("Multiple fields annotated with %1$s found in %2$s.", InjectDockerClient.class, testInstance.getClass())); + } + Field dockerClientField = fields.get(0); + dockerClientField.setAccessible(true); + dockerClientField.set(testInstance, dockerClient); + } + + @Override + public void preDestroyTestInstance(ExtensionContext context) { + if (previousNodeState != requiredSwarmMode) { + switch (previousNodeState) { + case Active: + swarmUtil.ensureActiveSwarm(); + break; + case Inactive: + swarmUtil.ensureInactiveSwarm(); + break; + default: + log.warn("Won't revert LocalNodeState back to {}", previousNodeState); + } + } + } + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/DockerRegistry.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/DockerRegistry.java new file mode 100644 index 000000000..c1f88dfcd --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/DockerRegistry.java @@ -0,0 +1,96 @@ +package de.gesellix.docker.client.testutil; + +import de.gesellix.docker.client.TypeSafeDockerClientImpl; +import de.gesellix.docker.engine.model.ContainerCreateRequest; +import de.gesellix.docker.engine.model.ContainerCreateResponse; +import de.gesellix.docker.engine.model.ContainerInspectResponse; +import de.gesellix.docker.engine.model.HostConfig; +import de.gesellix.docker.engine.model.PortBinding; + +import java.util.List; +import java.util.Objects; + +import static de.gesellix.docker.client.testutil.Constants.LABEL_KEY; +import static de.gesellix.docker.client.testutil.Constants.LABEL_VALUE; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + +public class DockerRegistry { + + TypeSafeDockerClientImpl dockerClient; + String registryId; + + public static void main(String[] args) throws InterruptedException { + DockerRegistry registry = new DockerRegistry(new TypeSafeDockerClientImpl()); + registry.run(); + Thread.sleep(10000); + registry.rm(); + } + + public DockerRegistry(TypeSafeDockerClientImpl dockerClient) { + this.dockerClient = dockerClient; + } + + String getImage() { +// dockerClient.getSystemApi().systemInfo().getOsType() + boolean isWindows = Objects.requireNonNull(dockerClient.getSystemApi().systemVersion().getOs()).equalsIgnoreCase("windows"); + return isWindows ? "gesellix/registry:2.7.1-windows" : "registry:2.7.1"; + } + + public void run() { + ContainerCreateRequest containerCreateRequest = new ContainerCreateRequest( + null, null, null, + false, false, false, + singletonMap("5000/tcp", emptyMap()), + false, null, null, + null, + null, + null, + null, + getImage(), + null, null, null, + null, null, + null, + singletonMap(LABEL_KEY, LABEL_VALUE), + null, null, + null, + new HostConfig(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, true, null, null, null, null, null, null, null, null, null, null, null, null, null), + null + ); + dockerClient.getImageApi().imageCreate(containerCreateRequest.getImage().split(":")[0], null, null, containerCreateRequest.getImage().split(":")[1], null, null, null, null, null); + ContainerCreateResponse createResponse = dockerClient.getContainerApi().containerCreate(containerCreateRequest, null); + dockerClient.getContainerApi().containerStart(createResponse.getId(), null); + registryId = createResponse.getId(); + } + + String address() { +// String dockerHost = dockerClient.config.dockerHost +// return dockerHost.replaceAll("^(tcp|http|https)://", "").replaceAll(":\\d+\$", "") + +// def registryContainer = dockerClient.inspectContainer(registryId).content +// def portBinding = registryContainer.NetworkSettings.Ports["5000/tcp"] +// return portBinding[0].HostIp as String + + // 'localhost' allows to use the registry without TLS + return "localhost"; + } + + int port() { + ContainerInspectResponse registryContainer = dockerClient.getContainerApi().containerInspect(registryId, false); + List portBinding = registryContainer.getNetworkSettings().getPorts().get("5000/tcp"); + return Integer.parseInt(portBinding.stream().findFirst().get().getHostPort()); + } + + public String url() { + return address() + ":" + port(); + } + + public void rm() { + dockerClient.getContainerApi().containerStop(registryId, null); + dockerClient.getContainerApi().containerWait(registryId, null); + dockerClient.getContainerApi().containerDelete(registryId, null, null, null); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/HttpTestServer.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/HttpTestServer.java new file mode 100644 index 000000000..e09a6a9e7 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/HttpTestServer.java @@ -0,0 +1,183 @@ +package de.gesellix.docker.client.testutil; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +import okio.Okio; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +public class HttpTestServer { + + private HttpServer httpServer; + private final SSLContext sslContext; + + public HttpTestServer() { + this(null); + } + + public HttpTestServer(SSLContext sslContext) { + this.sslContext = sslContext; + } + + public InetSocketAddress start() throws IOException { + return start("/test/", new ReverseHandler()); + } + + public InetSocketAddress start(final String context, final HttpHandler handler) throws IOException { + InetSocketAddress address = new InetSocketAddress(0); + + if (sslContext != null) { + // using the VM param `-Djavax.net.debug=all` helps debugging SSL issues + httpServer = HttpsServer.create(address, address.getPort()); + ((HttpsServer) httpServer).setHttpsConfigurator(new DefaultHttpsConfigurator(sslContext)); + } + else { + httpServer = HttpServer.create(address, address.getPort()); + } + + httpServer.createContext(context, handler); + httpServer.setExecutor(Executors.newCachedThreadPool()); + httpServer.start(); + return httpServer.getAddress(); + } + + public void stop() { + if (httpServer != null) { + httpServer.stop(0); + } + } + + /** + * Given your KeyStore is located in the classpath at "/de/gesellix/docker/testutil/test.jks", + * you may call the method like in this example: + * + *
+   * 
+   * SSLContext ctx = HttpTestServer.createDefaultSSLContext("/de/gesellix/docker/testutil/test.jks", "changeit")
+   * 
+   * 
+ * + * If you need a new KeyStore from scratch you can use this command: + * + *
+   * 
+   * keytool -genkey -alias alias -keypass changeit -keystore test.jks -storepass changeit
+   * 
+   * 
+ * + * Please note that you should enter a valid domain (e.g. "localhost") + * when being asked for your first and last name ("CN"). + */ + public static SSLContext createDefaultSSLContext(String jksResource, String jksPassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { + InputStream jksInputStream = HttpTestServer.class.getResourceAsStream(jksResource); + char[] password = jksPassword.toCharArray(); + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(jksInputStream, password); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, password); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); + return sslContext; + } + + public static class DefaultHttpsConfigurator extends HttpsConfigurator { + + public DefaultHttpsConfigurator(SSLContext sslContext) { + super(sslContext); + } + } + + public static class ReverseHandler implements HttpHandler { + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + if (httpExchange.getRequestMethod().equals("GET")) { + httpExchange.getResponseHeaders().set("Content-Type", "text/plain"); + final String query = httpExchange.getRequestURI().getRawQuery(); + + if (query == null || !query.contains("string")) { + httpExchange.sendResponseHeaders(400, 0); + return; + } + + final String[] param = query.split("="); + assert param.length == 2 && param[0].equals("string"); + + httpExchange.sendResponseHeaders(200, 0); + httpExchange.getResponseBody().write(new StringBuilder(param[1]).reverse().toString().getBytes()); + httpExchange.getResponseBody().close(); + } + } + } + + public static class RecordingRequestsHandler implements HttpHandler { + + private final List recordedRequests = new ArrayList<>(); + private final Map>> recordedHeadersByRequest = new HashMap<>(); + + @Override + public void handle(final HttpExchange httpExchange) throws IOException { + String request = httpExchange.getRequestMethod() + " " + httpExchange.getRequestURI(); + recordedRequests.add(request); + recordedHeadersByRequest.put(request, httpExchange.getRequestHeaders()); + + httpExchange.sendResponseHeaders(200, 0); + } + + public List getRecordedRequests() { + return recordedRequests; + } + + public Map>> getRecordedHeadersByRequest() { + return recordedHeadersByRequest; + } + } + + public static class FileServer implements HttpHandler { + + private final URL file; + + public FileServer(URL file) { + this.file = file; + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + if (httpExchange.getRequestMethod().equals("GET")) { + httpExchange.sendResponseHeaders(200, 0); + httpExchange.getResponseBody().write(toString((file).openStream()).getBytes()); + httpExchange.getResponseBody().close(); + } + } + + private String toString(InputStream source) throws IOException { + return Okio.buffer(Okio.source(source)).readUtf8(); + } + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/InjectDockerClient.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/InjectDockerClient.java new file mode 100644 index 000000000..3b51d8d9d --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/InjectDockerClient.java @@ -0,0 +1,12 @@ +package de.gesellix.docker.client.testutil; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InjectDockerClient { + +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/NetworkInterfaces.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/NetworkInterfaces.java new file mode 100644 index 000000000..ad897b967 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/NetworkInterfaces.java @@ -0,0 +1,43 @@ +package de.gesellix.docker.client.testutil; + +import de.gesellix.docker.engine.client.infrastructure.LoggingExtensionsKt; +import org.slf4j.Logger; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// https://docs.oracle.com/javase/tutorial/networking/nifs/listing.html +public class NetworkInterfaces { + + private static final Logger log = LoggingExtensionsKt.logger(NetworkInterfaces.class.getName()).getValue(); + + public static void main(String[] args) throws SocketException { + log.info(new NetworkInterfaces().getFirstInet4Address()); + } + + public String getFirstInet4Address() throws SocketException { + return getInet4Addresses().stream().findFirst().get(); + } + + public List getInet4Addresses() throws SocketException { + List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); + return interfaces.stream() + .flatMap((i) -> getInet4Addresses(i)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + public static Stream getInet4Addresses(NetworkInterface netint) { + List addresses = Collections.list(netint.getInetAddresses()); + return addresses.stream() + .filter((it) -> it instanceof Inet4Address && !it.isLoopbackAddress()) + .map((it) -> it.getHostAddress()); + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/SwarmUtil.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/SwarmUtil.java new file mode 100644 index 000000000..e1c0f01f9 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/SwarmUtil.java @@ -0,0 +1,70 @@ +package de.gesellix.docker.client.testutil; + +import de.gesellix.docker.client.TypeSafeDockerClientImpl; +import de.gesellix.docker.engine.api.SwarmApi; +import de.gesellix.docker.engine.api.SystemApi; +import de.gesellix.docker.engine.model.LocalNodeState; +import de.gesellix.docker.engine.model.SwarmInitRequest; + +public class SwarmUtil { + + SwarmApi swarmApi; + SystemApi systemApi; + + public SwarmUtil(TypeSafeDockerClientImpl dockerClient) { + this.swarmApi = dockerClient.getSwarmApi(); + this.systemApi = dockerClient.getSystemApi(); + } + + public void runWithInactiveSwarm(Runnable action) { + LocalNodeState previousState = ensureInactiveSwarm(); + try { + action.run(); + } + finally { + if (previousState != LocalNodeState.Inactive) { + ensureActiveSwarm(); + } + } + } + + public void runWithActiveSwarm(Runnable action) { + LocalNodeState previousState = ensureActiveSwarm(); + try { + action.run(); + } + finally { + if (previousState != LocalNodeState.Active) { + ensureInactiveSwarm(); + } + } + } + + LocalNodeState ensureInactiveSwarm() { + LocalNodeState currentState = null; + try { + currentState = systemApi.systemInfo().getSwarm().getLocalNodeState(); + if (currentState != LocalNodeState.Inactive) { + swarmApi.swarmLeave(true); + } + } + catch (Exception ignored) { + // + } + return currentState; + } + + LocalNodeState ensureActiveSwarm() { + LocalNodeState currentState = null; + try { + currentState = systemApi.systemInfo().getSwarm().getLocalNodeState(); + if (currentState != LocalNodeState.Active) { + swarmApi.swarmInit(new SwarmInitRequest("0.0.0.0:2377", "127.0.0.1", null, null, null, false, null, null)); + } + } + catch (Exception ignored) { + // + } + return currentState; + } +} diff --git a/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/TestImage.java b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/TestImage.java new file mode 100644 index 000000000..51c42da11 --- /dev/null +++ b/typesafe-client/src/test/java/de/gesellix/docker/client/testutil/TestImage.java @@ -0,0 +1,30 @@ +package de.gesellix.docker.client.testutil; + +import de.gesellix.docker.client.TypeSafeDockerClientImpl; + +import java.util.Objects; + +public class TestImage { + + private final String repository; + private final String tag; + + public TestImage(TypeSafeDockerClientImpl dockerClient) { + boolean isWindows = Objects.requireNonNull(dockerClient.getSystemApi().systemVersion().getOs()).equalsIgnoreCase("windows"); + + this.repository = "gesellix/echo-server"; + this.tag = isWindows ? "os-windows" : "os-linux"; + } + + public String getImageWithTag() { + return getImageName() + ":" + getImageTag(); + } + + public String getImageName() { + return repository; + } + + public String getImageTag() { + return tag; + } +} diff --git a/typesafe-client/src/test/resources/images/builder/Dockerfile b/typesafe-client/src/test/resources/images/builder/Dockerfile new file mode 100644 index 000000000..1525fe480 --- /dev/null +++ b/typesafe-client/src/test/resources/images/builder/Dockerfile @@ -0,0 +1,3 @@ +FROM scratch +LABEL de.gesellix.docker-client.test="1" +COPY payload.txt /payload.txt diff --git a/typesafe-client/src/test/resources/images/builder/payload.txt b/typesafe-client/src/test/resources/images/builder/payload.txt new file mode 100644 index 000000000..f24474752 --- /dev/null +++ b/typesafe-client/src/test/resources/images/builder/payload.txt @@ -0,0 +1 @@ +the wind caught it diff --git a/typesafe-client/src/test/resources/images/importUrl/Dockerfile b/typesafe-client/src/test/resources/images/importUrl/Dockerfile new file mode 100644 index 000000000..b375934fe --- /dev/null +++ b/typesafe-client/src/test/resources/images/importUrl/Dockerfile @@ -0,0 +1,2 @@ +FROM scratch +COPY ./something.txt / diff --git a/typesafe-client/src/test/resources/images/importUrl/import-from-url.tar b/typesafe-client/src/test/resources/images/importUrl/import-from-url.tar new file mode 100644 index 000000000..a5633e6ee Binary files /dev/null and b/typesafe-client/src/test/resources/images/importUrl/import-from-url.tar differ diff --git a/typesafe-client/src/test/resources/images/importUrl/something.txt b/typesafe-client/src/test/resources/images/importUrl/something.txt new file mode 100644 index 000000000..f24474752 --- /dev/null +++ b/typesafe-client/src/test/resources/images/importUrl/something.txt @@ -0,0 +1 @@ +the wind caught it diff --git a/typesafe-client/src/test/resources/images/loadImage/Dockerfile b/typesafe-client/src/test/resources/images/loadImage/Dockerfile new file mode 100644 index 000000000..837bcaa63 --- /dev/null +++ b/typesafe-client/src/test/resources/images/loadImage/Dockerfile @@ -0,0 +1,3 @@ +FROM scratch +LABEL de.gesellix.docker-client.test="1" +COPY ./something.txt / diff --git a/typesafe-client/src/test/resources/images/loadImage/load-from-file.tar b/typesafe-client/src/test/resources/images/loadImage/load-from-file.tar new file mode 100644 index 000000000..4b71b66b3 Binary files /dev/null and b/typesafe-client/src/test/resources/images/loadImage/load-from-file.tar differ diff --git a/typesafe-client/src/test/resources/images/loadImage/something.txt b/typesafe-client/src/test/resources/images/loadImage/something.txt new file mode 100644 index 000000000..f24474752 --- /dev/null +++ b/typesafe-client/src/test/resources/images/loadImage/something.txt @@ -0,0 +1 @@ +the wind caught it diff --git a/typesafe-client/src/test/resources/images/loadImage/update.sh b/typesafe-client/src/test/resources/images/loadImage/update.sh new file mode 100755 index 000000000..72c727d19 --- /dev/null +++ b/typesafe-client/src/test/resources/images/loadImage/update.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +docker build -t test:load-image . +docker save test:load-image -o load-from-file.tar diff --git a/typesafe-client/src/test/resources/logback-test.xml b/typesafe-client/src/test/resources/logback-test.xml new file mode 100644 index 000000000..1f5a4721f --- /dev/null +++ b/typesafe-client/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + +