diff --git a/.editorconfig b/.editorconfig index 137af4fbf..5bbffc51f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,3 +16,8 @@ ij_java_names_count_to_use_import_on_demand = 9999 [{*.pom,*.xml}] indent_style = tab ij_xml_attribute_wrap = off + + +[*.{yaml,yml}] +indent_size = 2 +ij_yaml_keep_indents_on_empty_lines = false diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..e5a6b0376 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +* @docker-java/team + diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..9bcef2d88 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: +- package-ecosystem: maven + directory: "/" + schedule: + interval: weekly + day: monday + open-pull-requests-limit: 99 + rebase-strategy: disabled + ignore: + - dependency-name: "org.glassfish.jersey.connectors:jersey-apache-connector" + update-types: [ "version-update:semver-major" ] + - dependency-name: "org.glassfish.jersey.core:jersey-client" + update-types: [ "version-update:semver-major" ] + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + update-types: [ "version-update:semver-major" ] diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index d03efd7d9..f570cce43 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,17 +1,17 @@ tag-template: $NEXT_PATCH_VERSION -name-template: '$NEXT_PATCH_VERSION 🌈' +name-template: '$NEXT_PATCH_VERSION' categories: - title: '🚀 Features' labels: - - 'feature' - - 'enhancement' + - 'type/feature' + - title: '📈 Enhancements' + labels: + - 'type/enhancement' - title: '🐛 Bug Fixes' labels: - - 'fix' - - 'bugfix' - - 'bug' + - 'type/bug' - title: '🧰 Maintenance' - label: 'chore' + label: 'type/housekeeping' change-template: '- $TITLE @$AUTHOR (#$NUMBER)' template: | ## Changes diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..23aefd1f3 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,16 @@ + +daysUntilStale: 90 + +daysUntilClose: 30 + +exemptLabels: + - resolution/acknowledged + +staleLabel: resolution/stale + +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +closeComment: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72e32d7d9..d7b105d1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,55 @@ name: CI -on: [push, pull_request] +on: + pull_request: {} + push: { branches: [ main ] } + workflow_dispatch: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + include: + - { name: "default", javaVersion: 8 } + - { name: "default", javaVersion: 17 } + - { name: "default", javaVersion: 21 } + steps: + - uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: ${{matrix.javaVersion}} + distribution: temurin + cache: maven + - name: Configure Docker + id: setup_docker + uses: docker/setup-docker-action@v4 + with: + channel: stable + - name: Build with Maven + env: + DOCKER_HOST: ${{steps.setup_docker.outputs.sock}} + run: ./mvnw --no-transfer-progress verify + tcp: + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v1 - - name: Set up JDK 8 - uses: actions/setup-java@v1 - with: - java-version: 8 - - name: Prepare ws - run: rm -f "docker-java/src/test/resources/logback.xml" && mv "docker-java/src/test/resources/travis-logback.xml" "docker-java/src/test/resources/logback-test.xml" - - name: Build with Maven - run: ./mvnw --no-transfer-progress verify + - uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: 8 + distribution: temurin + cache: maven + - name: Configure Docker + id: setup_docker + uses: docker/setup-docker-action@v4 + with: + channel: stable + tcp-port: 2375 + - name: Build with Maven + env: + DOCKER_HOST: ${{steps.setup_docker.outputs.tcp}} + run: ./mvnw --no-transfer-progress verify diff --git a/.github/workflows/main.yml b/.github/workflows/release-drafter.yml similarity index 96% rename from .github/workflows/main.yml rename to .github/workflows/release-drafter.yml index 2c30bcdb1..99cd01cfc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/release-drafter.yml @@ -4,7 +4,7 @@ on: push: # branches to consider in the event; optional, defaults to all branches: - - master + - main jobs: update_release_draft: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..16777daa6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,32 @@ +name: Release + +on: + release: + types: + - prereleased + - released + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 8 + uses: actions/setup-java@v4 + with: + java-version: 8 + distribution: temurin + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_CENTRAL_TOKEN + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + - name: Set version + run: ./mvnw versions:set -DnewVersion="${{github.event.release.tag_name}}" + # TODO check main's CI status + - name: Deploy with Maven + env: + MAVEN_USERNAME: ${{ secrets.SONATYPE_CENTRAL_USERNAME }} + MAVEN_CENTRAL_TOKEN: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + run: ./mvnw -Prelease deploy -DskipTests diff --git a/.gitignore b/.gitignore index cc29f27cb..006641e8c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,11 @@ .project .settings .classpath +.factorypath # Ignore all build/dist directories target +dependency-reduced-pom.xml # Ignore InteliJ Idea project files .idea/ diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2..000000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 2cc7d4a55..000000000 Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 642d572ce..8dea6c227 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,3 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b671e87f6..000000000 --- a/.travis.yml +++ /dev/null @@ -1,39 +0,0 @@ -sudo: required -dist: xenial -language: java - -services: - - docker - -jdk: - - openjdk8 - -install: true - -env: - global: - - DOCKER_TLS_VERIFY="" - - matrix: - - DEPLOY=true - - # TCP transport - - DOCKER_HOST="tcp://127.0.0.1:2375" - - # Older versions of Docker - - DOCKER_VERSION="17.06.2~ce-0~ubuntu" - - DOCKER_VERSION="18.06.3~ce~3-0~ubuntu" - - # Swarm - - SWARM_VERSION="1.2.8" - -cache: - directories: - - $HOME/.travis_cache - - $HOME/.m2 # install will pollute it - -before_install: - - ./.travis/travis-before-install.sh - -script: - - mvn verify diff --git a/.travis/get-docker-com.sh b/.travis/get-docker-com.sh deleted file mode 100755 index d9c0142a2..000000000 --- a/.travis/get-docker-com.sh +++ /dev/null @@ -1,313 +0,0 @@ -#!/bin/sh -set -e -# -# This script is meant for quick & easy install via: -# 'curl -sSL https://get.docker.com/ | sh' -# or: -# 'wget -qO- https://get.docker.com/ | sh' -# -# For test builds (ie. release candidates): -# 'curl -fsSL https://test.docker.com/ | sh' -# or: -# 'wget -qO- https://test.docker.com/ | sh' -# -# For experimental builds: -# 'curl -fsSL https://experimental.docker.com/ | sh' -# or: -# 'wget -qO- https://experimental.docker.com/ | sh' -# -# Docker Maintainers: -# To update this script on https://get.docker.com, -# use hack/release.sh during a normal release, -# or the following one-liner for script hotfixes: -# aws s3 cp --acl public-read hack/install.sh s3://get.docker.com/index -# - -url="https://get.docker.com/" -apt_url="https://apt.dockerproject.org" -yum_url="https://yum.dockerproject.org" -gpg_fingerprint="58118E89F3A912897C070ADBF76221572C52609D" - -key_servers=" -ha.pool.sks-keyservers.net -pgp.mit.edu -keyserver.ubuntu.com -" - -command_exists() { - command -v "$@" > /dev/null 2>&1 -} - -semverParse() { - major="${1%%.*}" - minor="${1#$major.}" - minor="${minor%%.*}" - patch="${1#$major.$minor.}" - patch="${patch%%[-.]*}" -} - -do_install() { - case "$(uname -m)" in - *64) - ;; - *) - cat >&2 <<-'EOF' - Error: you are not using a 64bit platform. - Docker currently only supports 64bit platforms. - EOF - exit 1 - ;; - esac - - user="$(id -un 2>/dev/null || true)" - - sh_c='sh -c' - if [ "$user" != 'root' ]; then - if command_exists sudo; then - sh_c='sudo -E sh -c' - elif command_exists su; then - sh_c='su -c' - else - cat >&2 <<-'EOF' - Error: this installer needs the ability to run commands as root. - We are unable to find either "sudo" or "su" available to make this happen. - EOF - exit 1 - fi - fi - - curl='' - if command_exists curl; then - curl='curl -sSL' - elif command_exists wget; then - curl='wget -qO-' - elif command_exists busybox && busybox --list-modules | grep -q wget; then - curl='busybox wget -qO-' - fi - - # check to see which repo they are trying to install from - if [ -z "$repo" ]; then - repo='main' - if [ "https://test.docker.com/" = "$url" ]; then - repo='testing' - elif [ "https://experimental.docker.com/" = "$url" ]; then - repo='experimental' - fi - fi - - # perform some very rudimentary platform detection - lsb_dist='' - dist_version='' - if command_exists lsb_release; then - lsb_dist="$(lsb_release -si)" - fi - if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then - lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")" - fi - if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then - lsb_dist='debian' - fi - if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then - lsb_dist='fedora' - fi - if [ -z "$lsb_dist" ] && [ -r /etc/oracle-release ]; then - lsb_dist='oracleserver' - fi - if [ -z "$lsb_dist" ]; then - if [ -r /etc/centos-release ] || [ -r /etc/redhat-release ]; then - lsb_dist='centos' - fi - fi - if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then - lsb_dist="$(. /etc/os-release && echo "$ID")" - fi - - lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')" - - case "$lsb_dist" in - - ubuntu) - if command_exists lsb_release; then - dist_version="$(lsb_release --codename | cut -f2)" - fi - if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then - dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")" - fi - ;; - - debian) - dist_version="$(cat /etc/debian_version | sed 's/\/.*//' | sed 's/\..*//')" - case "$dist_version" in - 8) - dist_version="jessie" - ;; - 7) - dist_version="wheezy" - ;; - esac - ;; - - oracleserver) - # need to switch lsb_dist to match yum repo URL - lsb_dist="oraclelinux" - dist_version="$(rpm -q --whatprovides redhat-release --queryformat "%{VERSION}\n" | sed 's/\/.*//' | sed 's/\..*//' | sed 's/Server*//')" - ;; - - fedora|centos) - dist_version="$(rpm -q --whatprovides redhat-release --queryformat "%{VERSION}\n" | sed 's/\/.*//' | sed 's/\..*//' | sed 's/Server*//')" - ;; - - *) - if command_exists lsb_release; then - dist_version="$(lsb_release --codename | cut -f2)" - fi - if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then - dist_version="$(. /etc/os-release && echo "$VERSION_ID")" - fi - ;; - - - esac - - - # Run setup for each distro accordingly - case "$lsb_dist" in - ubuntu|debian) - export DEBIAN_FRONTEND=noninteractive - - did_apt_get_update= - apt_get_update() { - if [ -z "$did_apt_get_update" ]; then - ( set -x; $sh_c 'sleep 3; apt-get update' ) - did_apt_get_update=1 - fi - } - - # aufs is preferred over devicemapper; try to ensure the driver is available. - if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then - if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -qE '^ii|^hi' 2>/dev/null; then - kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual" - - apt_get_update - ( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true - - if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then - echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)' - echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!' - ( set -x; sleep 10 ) - fi - else - echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual' - echo >&2 ' package. We have no AUFS support. Consider installing the packages' - echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.' - ( set -x; sleep 10 ) - fi - fi - - # install apparmor utils if they're missing and apparmor is enabled in the kernel - # otherwise Docker will fail to start - if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then - if command -v apparmor_parser >/dev/null 2>&1; then - echo 'apparmor is enabled in the kernel and apparmor utils were already installed' - else - echo 'apparmor is enabled in the kernel, but apparmor_parser missing' - apt_get_update - ( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' ) - fi - fi - - if [ ! -e /usr/lib/apt/methods/https ]; then - apt_get_update - ( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' ) - fi - if [ -z "$curl" ]; then - apt_get_update - ( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' ) - curl='curl -sSL' - fi - ( - set -x - for key_server in $key_servers ; do - $sh_c "apt-key adv --keyserver hkp://${key_server}:80 --recv-keys ${gpg_fingerprint}" && break - done - $sh_c "apt-key adv -k ${gpg_fingerprint} >/dev/null" - $sh_c "mkdir -p /etc/apt/sources.list.d" - $sh_c "echo deb [arch=$(dpkg --print-architecture)] ${apt_url}/repo ${lsb_dist}-${dist_version} ${repo} > /etc/apt/sources.list.d/docker.list" - $sh_c 'sleep 3; apt-get update' - if [ -z "$DOCKER_VERSION" ]; then - $sh_c 'apt-get -o Dpkg::Options::="--force-confnew" install -y -q docker-engine' - else - $sh_c "apt-get -o Dpkg::Options::=\"--force-confnew\" install -y -q docker-engine=$DOCKER_VERSION" - fi - ) - exit 0 - ;; - - fedora|centos|oraclelinux) - $sh_c "cat >/etc/yum.repos.d/docker-${repo}.repo" <<-EOF - [docker-${repo}-repo] - name=Docker ${repo} Repository - baseurl=${yum_url}/repo/${repo}/${lsb_dist}/${dist_version} - enabled=1 - gpgcheck=1 - gpgkey=${yum_url}/gpg - EOF - if [ "$lsb_dist" = "fedora" ] && [ "$dist_version" -ge "22" ]; then - ( - set -x - $sh_c 'sleep 3; dnf -y -q install docker-engine' - ) - else - ( - set -x - $sh_c 'sleep 3; yum -y -q install docker-engine' - ) - fi - exit 0 - ;; - gentoo) - if [ "$url" = "https://test.docker.com/" ]; then - # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output - cat >&2 <<-'EOF' - - You appear to be trying to install the latest nightly build in Gentoo.' - The portage tree should contain the latest stable release of Docker, but' - if you want something more recent, you can always use the live ebuild' - provided in the "docker" overlay available via layman. For more' - instructions, please see the following URL:' - - https://github.com/tianon/docker-overlay#using-this-overlay' - - After adding the "docker" overlay, you should be able to:' - - emerge -av =app-emulation/docker-9999' - - EOF - exit 1 - fi - - ( - set -x - $sh_c 'sleep 3; emerge app-emulation/docker' - ) - exit 0 - ;; - esac - - # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output - cat >&2 <<-'EOF' - - Either your platform is not easily detectable, is not supported by this - installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have - a package for Docker. Please visit the following URL for more detailed - installation instructions: - - https://docs.docker.com/engine/installation/ - - EOF - exit 1 -} - -# wrapped up in a function so that we have some protection against only getting -# half the file during "curl | sh" -do_install diff --git a/.travis/travis-before-install.sh b/.travis/travis-before-install.sh deleted file mode 100755 index 592b3fcdf..000000000 --- a/.travis/travis-before-install.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash - -set -exu - -SWARM_VERSION="${SWARM_VERSION:-}" -DOCKER_VERSION="${DOCKER_VERSION:-}" -DOCKER_HOST="${DOCKER_HOST:-}" - -export HOST_PORT="2375" - -rm -f "docker-java/src/test/resources/logback.xml" -mv "docker-java/src/test/resources/travis-logback.xml" "docker-java/src/test/resources/logback-test.xml" - -if [[ -n $DOCKER_VERSION ]]; then - sudo -E apt-get -q -y --purge remove docker-engine docker-ce - - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - sudo apt-get update - sudo apt-cache madison docker-ce - sudo apt-get install "docker-ce=$DOCKER_VERSION" -fi - -if [[ -n $DOCKER_HOST ]]; then - sudo mkdir -p /etc/systemd/system/docker.service.d/ - - echo " -[Service] -ExecStart= -ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:${HOST_PORT} - " | sudo tee -a /etc/systemd/system/docker.service.d/override.conf - - sudo systemctl daemon-reload - sudo service docker restart || sudo journalctl -xe - sudo service docker status -fi - -while (! docker ps ); do - # Docker takes a few seconds to initialize - echo "Waiting for Docker to launch..." - sleep 1 -done - -docker version -docker info - -set +u - -cat < "${HOME}/.docker-java.properties" -registry.username=${registry_username} -registry.password=${registry_password} -registry.email=${registry_email} -registry.url=https://index.docker.io/v1/ - -EOF - -if [[ -n $SWARM_VERSION ]]; then - export SWARM_PORT="2377" - export HOST_IP="$(ip a show dev eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)" - - docker pull swarm - - docker run \ - -d \ - -p ${SWARM_PORT}:2375 \ - --name=swarm_manager \ - "swarm:${SWARM_VERSION}" \ - manage --engine-refresh-min-interval "3s" --engine-refresh-max-interval "6s" "nodes://${HOST_IP}:${HOST_PORT}" - - # join engine to swarm - docker run \ - -d \ - "--name=swarm_join" \ - "swarm:${SWARM_VERSION}" \ - join --advertise="${HOST_IP}:${HOST_PORT}" --delay="0s" --heartbeat "5s" "nodes://${HOST_IP}:${HOST_PORT}" - - docker run --rm \ - "swarm:${SWARM_VERSION}" \ - list "nodes://${HOST_IP}:${HOST_PORT}" - - docker ps -a - - sleep 30 - - docker logs swarm_join - docker logs swarm_manager - - # switch to swarm connection - export DOCKER_HOST="tcp://127.0.0.1:${SWARM_PORT}" - - docker version - docker info - - NODES=$(docker info | grep "Nodes:" | awk '{ print $2 }') - if [[ $NODES -eq "0" ]]; then - echo "Swarm didn't connect" - exit 1 - fi - - # test via swarm - docker pull busybox -fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ca44ee2e..5d344d93b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -301,7 +301,7 @@ v2.0.0 Release notes * Some commands APIs has been changed to be callback-driven now to simplify the processing of the result streams for the client application. This affects namely the events, stats, log, attach, build, push and pull commands. Look at the Wiki how to [process events](https://github.com/docker-java/docker-java/wiki#handle-events) or how to [build an image](https://github.com/docker-java/docker-java/wiki#build-image-from-dockerfile) from dockerfile for example. -* The `DockerClientConfig` API has changed to free it from implementation specific configuration options like `readTimeout`, `maxTotalConnections`, `maxPerRouteConnections` and `enableLoggingFilter`. Most options can be configured via `DockerCmdExecFactoryImpl` [programmatically](https://github.com/docker-java/docker-java/wiki#intialize-docker-client-advanced) now. Logging is configurable via [logback](https://github.com/docker-java/docker-java/blob/master/src/test/resources/logback.xml) configuration file in the classpath. +* The `DockerClientConfig` API has changed to free it from implementation specific configuration options like `readTimeout`, `maxTotalConnections`, `maxPerRouteConnections` and `enableLoggingFilter`. Most options can be configured via `DockerCmdExecFactoryImpl` [programmatically](https://github.com/docker-java/docker-java/wiki#intialize-docker-client-advanced) now. Logging is configurable via [logback](https://github.com/docker-java/docker-java/blob/main/src/test/resources/logback.xml) configuration file in the classpath. All changes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..5072b0864 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,58 @@ +# Build with Maven + +#### Prerequisites: + +* Java min 1.8 +* Maven 3 + +Build and run integration tests as follows: + + $ mvn clean install + +If you do not have access to a Docker server or just want to execute the build quickly, you can run the build without the integration tests: + + $ mvn clean install -DskipITs + +By default the docker engine is using local UNIX sockets for communication with the docker CLI so docker-java +client also uses UNIX domain sockets to connect to the docker daemon by default. To make the docker daemon listening on a TCP (http/https) port you have to configure it by setting the DOCKER_OPTS environment variable to something like the following: + + DOCKER_OPTS="-H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock" + +More details about setting up Docker Engine can be found in the official documentation: https://docs.docker.com/engine/admin/ + +To force docker-java to use TCP (http) configure the following (see [Configuration](https://github.com/docker-java/docker-java#configuration) for details): + + DOCKER_HOST=tcp://127.0.0.1:2375 + +For secure tls (https) communication: + + DOCKER_HOST=tcp://127.0.0.1:2376 + DOCKER_TLS_VERIFY=1 + DOCKER_CERT_PATH=/Users/marcus/.docker/machine/machines/docker-1.11.2 + + +# Code Design + * Model is based on Objects and not primitives that allows nullify requests and have null values for data + that wasn't provided by docker daemon. + * For null safeness findbugs annotations are used. + ** Every method that may return `null` (and we are unsure in any fields as docker daemon may change something) + should be annotated with `@CheckForNull` return qualifier from `javax.annotation` package. + ** Methods that can't return `null` must be annotated with `@Nonnull`. + ** The same for Arguments. + ** `@Nullable` must be used only for changing inherited (other typed) qualifier. + * Setters in builder style must be prefixed with `withXX`. + * All classes should provide `toString()` `equals()` and `hashCode()` defined methods. + * Javadocs + ** Provide full information on field: + *** For models define API version with `@since {@link RemoteApiVersion#VERSION_1_X}`. + ** getters/setters should refernce to field `@see #$field`. + * If it is `Serializable` it shall have a `serialVersionUID` field. Unless code has shipped to users, the initial value of the `serialVersionUID` field shall be `1L`. + +# Coding style + * Some initial styling already enforced with checkstyle. Please aim for consistency with the existing code. + +# Testing + * Unit tests for serder (serialization-deserialization). + * Integration tests for commands. + * If model object has builders, then fill it with data and compare by `equals()` with expected response + from docker daemon. If failed, then some fields mappings are wrong. \ No newline at end of file diff --git a/README.md b/README.md index a67905b35..b1fa9c89e 100644 --- a/README.md +++ b/README.md @@ -1,143 +1,9 @@ [![Join the chat at https://gitter.im/docker-java/docker-java](https://badges.gitter.im/docker-java/docker-java.svg)](https://gitter.im/docker-java/docker-java?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Maven Central](https://img.shields.io/maven-central/v/com.github.docker-java/docker-java.svg)](https://mvnrepository.com/artifact/com.github.docker-java/docker-java) -[![Bintray](https://api.bintray.com/packages/kostyasha/maven/com.github.docker-java%3Adocker-java/images/download.svg)](https://bintray.com/kostyasha/maven/com.github.docker-java%3Adocker-java/_latestVersion) -[![Build Status](https://travis-ci.org/docker-java/docker-java.svg?branch=master)](https://travis-ci.org/docker-java/docker-java) -[![Coverity Scan Build Status](https://scan.coverity.com/projects/9177/badge.svg?flat=1)](https://scan.coverity.com/projects/9177) -[![codecov.io](http://codecov.io/github/docker-java/docker-java/coverage.svg?branch=master)](http://codecov.io/github/docker-java/docker-java?branch=master) -[![License](http://img.shields.io/:license-apache-blue.svg?style=flat)](https://github.com/docker-java/docker-java/blob/master/LICENSE) - - +[![codecov.io](http://codecov.io/github/docker-java/docker-java/coverage.svg?branch=main)](http://codecov.io/github/docker-java/docker-java?branch=master) +[![License](http://img.shields.io/:license-apache-blue.svg?style=flat)](https://github.com/docker-java/docker-java/blob/main/LICENSE) # docker-java Java API client for [Docker](http://docs.docker.io/ "Docker") -[Changelog](https://github.com/docker-java/docker-java/blob/master/CHANGELOG.md)
-[Wiki](https://github.com/docker-java/docker-java/wiki) - -## Build with Maven - -###### Prerequisites: - -* Java min 1.8 -* Maven 3 - -Build and run integration tests as follows: - - $ mvn clean install - -If you do not have access to a Docker server or just want to execute the build quickly, you can run the build without the integration tests: - - $ mvn clean install -DskipITs - -By default the docker engine is using local UNIX sockets for communication with the docker CLI so docker-java -client also uses UNIX domain sockets to connect to the docker daemon by default. To make the docker daemon listening on a TCP (http/https) port you have to configure it by setting the DOCKER_OPTS environment variable to something like the following: - - DOCKER_OPTS="-H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock" - -More details about setting up Docker Engine can be found in the official documentation: https://docs.docker.com/engine/admin/ - -To force docker-java to use TCP (http) configure the following (see [Configuration](https://github.com/docker-java/docker-java#configuration) for details): - - DOCKER_HOST=tcp://127.0.0.1:2375 - -For secure tls (https) communication: - - DOCKER_HOST=tcp://127.0.0.1:2376 - DOCKER_TLS_VERIFY=1 - DOCKER_CERT_PATH=/Users/marcus/.docker/machine/machines/docker-1.11.2 - -### Latest release version -[Maven repository modules](https://mvnrepository.com/artifact/com.github.docker-java) - -Since 3.2.0 project provides 3 transports: -- `docker-java-transport-jersey` (doesn't support streams) -- `docker-java-transport-netty` -- `docker-java-transport-okhttp` - -For backward compatibility `docker-java` module keeping dependency only on jersey and netty transports. - - - com.github.docker-java - docker-java - - 3.X.Y - - -### Latest development version -May contain new features while they are not released. - -You can find the latest development version including javadoc and source files on [Sonatypes OSS repository](https://oss.sonatype.org/content/groups/public/com/github/docker-java/docker-java/). - - - com.github.docker-java - docker-java - 3.X.Y-SNAPSHOT - - - -## Documentation - -For code examples, please look at the [Wiki](https://github.com/docker-java/docker-java/wiki) or [Test cases](https://github.com/docker-java/docker-java/tree/master/docker-java/src/test/java/com/github/dockerjava/core/command "Test cases") - -## Configuration - -There are a couple of configuration items, all of which have sensible defaults: - -* `DOCKER_HOST` The Docker Host URL, e.g. `tcp://localhost:2376` or `unix:///var/run/docker.sock` -* `DOCKER_TLS_VERIFY` enable/disable TLS verification (switch between `http` and `https` protocol) -* `DOCKER_CERT_PATH` Path to the certificates needed for TLS verification -* `DOCKER_CONFIG` Path for additional docker configuration files (like `.dockercfg`) -* `api.version` The API version, e.g. `1.23`. -* `registry.url` Your registry's address. -* `registry.username` Your registry username (required to push containers). -* `registry.password` Your registry password. -* `registry.email` Your registry email. - -There are three ways to configure, in descending order of precedence: - -#### Programmatic: -In your application, e.g. - - DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withDockerHost("tcp://my-docker-host.tld:2376") - .withDockerTlsVerify(true) - .withDockerCertPath("/home/user/.docker/certs") - .withDockerConfig("/home/user/.docker") - .withApiVersion("1.30") // optional - .withRegistryUrl("https://index.docker.io/v1/") - .withRegistryUsername("dockeruser") - .withRegistryPassword("ilovedocker") - .withRegistryEmail("dockeruser@github.com") - .build(); - DockerClient docker = DockerClientBuilder.getInstance(config).build(); - -#### Properties (docker-java.properties) - - DOCKER_HOST=tcp://localhost:2376 - DOCKER_TLS_VERIFY=1 - DOCKER_CERT_PATH=/home/user/.docker/certs - DOCKER_CONFIG=/home/user/.docker - api.version=1.23 - registry.url=https://index.docker.io/v1/ - registry.username=dockeruser - registry.password=ilovedocker - registry.email=dockeruser@github.com - -##### System Properties: - - java -DDOCKER_HOST=tcp://localhost:2375 -Dregistry.username=dockeruser pkg.Main - -##### System Environment - - export DOCKER_HOST=tcp://localhost:2376 - export DOCKER_TLS_VERIFY=1 - export DOCKER_CERT_PATH=/home/user/.docker/certs - export DOCKER_CONFIG=/home/user/.docker - -##### File System - -In `$HOME/.docker-java.properties` - -##### Class Path - -In the class path at `/docker-java.properties` +# [Read the documentation here](docs/README.md) diff --git a/circle.sh b/circle.sh index c84ca3fe6..b5b7cdbb0 100755 --- a/circle.sh +++ b/circle.sh @@ -6,7 +6,7 @@ case "$1" in mkdir .docker cp $CIRCLE_PROJECT_REPONAME/etc/certs/* .docker - # configure docker deamon to use SSL and provide the path to the certificates + # configure docker daemon to use SSL and provide the path to the certificates docker_opts='DOCKER_OPTS="$DOCKER_OPTS -H tcp://127.0.0.1:2376 --tlsverify --tlscacert='$HOME'/.docker/ca.pem --tlscert='$HOME'/.docker/server-cert.pem --tlskey='$HOME'/.docker/server-key.pem"' sudo sh -c "echo '$docker_opts' >> /etc/default/docker" diff --git a/docker-java-api/pom.xml b/docker-java-api/pom.xml index f23df928c..dda682ab1 100644 --- a/docker-java-api/pom.xml +++ b/docker-java-api/pom.xml @@ -4,7 +4,7 @@ com.github.docker-java docker-java-parent - 3.2.2-SNAPSHOT + 0-SNAPSHOT ../pom.xml @@ -15,11 +15,15 @@ https://github.com/docker-java/docker-java Java API Client for Docker + + com.github.dockerjava.api + + com.fasterxml.jackson.core jackson-annotations - ${jackson.version} + 2.20 @@ -38,9 +42,31 @@ org.projectlombok lombok - 1.18.12 + 1.18.38 provided + + + + org.junit.jupiter + junit-jupiter + 5.13.4 + test + + + + com.tngtech.archunit + archunit-junit5 + 1.4.1 + test + + + + com.tngtech.archunit + archunit + 0.18.0 + test + @@ -55,6 +81,22 @@ + + com.github.siom79.japicmp + japicmp-maven-plugin + + + + com.github.dockerjava.api.command.UpdateContainerCmd#getCpuPeriod() + com.github.dockerjava.api.command.UpdateContainerCmd#withCpuPeriod(java.lang.Integer) + com.github.dockerjava.api.command.UpdateContainerCmd#getCpuQuota() + com.github.dockerjava.api.command.UpdateContainerCmd#withCpuQuota(java.lang.Integer) + com.github.dockerjava.api.command.InspectContainerResponse#getSizeRootFs() + com.github.dockerjava.api.command.InspectContainerResponse#getSizeRw() + + + + diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java b/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java index 3857f2fa2..441decad3 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClient.java @@ -9,6 +9,7 @@ import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.api.command.CreateConfigCmd; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateImageCmd; import com.github.dockerjava.api.command.CreateNetworkCmd; @@ -21,9 +22,11 @@ import com.github.dockerjava.api.command.ExecStartCmd; import com.github.dockerjava.api.command.InfoCmd; import com.github.dockerjava.api.command.InitializeSwarmCmd; +import com.github.dockerjava.api.command.InspectConfigCmd; import com.github.dockerjava.api.command.InspectContainerCmd; import com.github.dockerjava.api.command.InspectExecCmd; import com.github.dockerjava.api.command.InspectImageCmd; +import com.github.dockerjava.api.command.ImageHistoryCmd; import com.github.dockerjava.api.command.InspectNetworkCmd; import com.github.dockerjava.api.command.InspectServiceCmd; import com.github.dockerjava.api.command.InspectSwarmCmd; @@ -31,6 +34,7 @@ import com.github.dockerjava.api.command.JoinSwarmCmd; import com.github.dockerjava.api.command.KillContainerCmd; import com.github.dockerjava.api.command.LeaveSwarmCmd; +import com.github.dockerjava.api.command.ListConfigsCmd; import com.github.dockerjava.api.command.ListContainersCmd; import com.github.dockerjava.api.command.ListImagesCmd; import com.github.dockerjava.api.command.ListNetworksCmd; @@ -39,6 +43,7 @@ import com.github.dockerjava.api.command.ListSwarmNodesCmd; import com.github.dockerjava.api.command.ListTasksCmd; import com.github.dockerjava.api.command.ListVolumesCmd; +import com.github.dockerjava.api.command.LoadImageAsyncCmd; import com.github.dockerjava.api.command.LoadImageCmd; import com.github.dockerjava.api.command.LogContainerCmd; import com.github.dockerjava.api.command.LogSwarmObjectCmd; @@ -47,13 +52,17 @@ import com.github.dockerjava.api.command.PruneCmd; import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.command.PushImageCmd; +import com.github.dockerjava.api.command.RemoveConfigCmd; import com.github.dockerjava.api.command.RemoveContainerCmd; import com.github.dockerjava.api.command.RemoveImageCmd; import com.github.dockerjava.api.command.RemoveNetworkCmd; import com.github.dockerjava.api.command.RemoveSecretCmd; import com.github.dockerjava.api.command.RemoveServiceCmd; +import com.github.dockerjava.api.command.RemoveSwarmNodeCmd; import com.github.dockerjava.api.command.RemoveVolumeCmd; import com.github.dockerjava.api.command.RenameContainerCmd; +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.command.ResizeExecCmd; import com.github.dockerjava.api.command.RestartContainerCmd; import com.github.dockerjava.api.command.SaveImageCmd; import com.github.dockerjava.api.command.SaveImagesCmd; @@ -124,6 +133,8 @@ public interface DockerClient extends Closeable { */ LoadImageCmd loadImageCmd(@Nonnull InputStream imageStream); + LoadImageAsyncCmd loadImageAsyncCmd(@Nonnull InputStream imageStream); + SearchImagesCmd searchImagesCmd(@Nonnull String term); RemoveImageCmd removeImageCmd(@Nonnull String imageId); @@ -132,6 +143,8 @@ public interface DockerClient extends Closeable { InspectImageCmd inspectImageCmd(@Nonnull String imageId); + ImageHistoryCmd imageHistoryCmd(@Nonnull String imageId); + /** * @param name * The name, e.g. "alexec/busybox" or just "busybox" if you want to default. Not null. @@ -165,6 +178,8 @@ public interface DockerClient extends Closeable { ExecCreateCmd execCreateCmd(@Nonnull String containerId); + ResizeExecCmd resizeExecCmd(@Nonnull String execId); + InspectContainerCmd inspectContainerCmd(@Nonnull String containerId); RemoveContainerCmd removeContainerCmd(@Nonnull String containerId); @@ -242,6 +257,8 @@ public interface DockerClient extends Closeable { RestartContainerCmd restartContainerCmd(@Nonnull String containerId); + ResizeContainerCmd resizeContainerCmd(@Nonnull String containerId); + CommitCmd commitCmd(@Nonnull String containerId); BuildImageCmd buildImageCmd(); @@ -332,6 +349,15 @@ public interface DockerClient extends Closeable { */ UpdateSwarmNodeCmd updateSwarmNodeCmd(); + /** + * Remove the swarm node + * + * @param swarmNodeId swarmNodeId + * @return the command + * @since 1.24 + */ + RemoveSwarmNodeCmd removeSwarmNodeCmd(String swarmNodeId); + /** * List nodes in swarm * @@ -429,12 +455,47 @@ public interface DockerClient extends Closeable { /** * Command to remove a secret + * + * @since {@link RemoteApiVersion#VERSION_1_25} * @param secretId secret id or secret name * @return command */ RemoveSecretCmd removeSecretCmd(String secretId); + /** + * Command to list all configs. Only applicable if docker runs in swarm mode. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + * @return command + */ + ListConfigsCmd listConfigsCmd(); + + /** + * Command to create a config in a docker swarm. Only applicable if docker runs in swarm mode. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + * @return command + */ + CreateConfigCmd createConfigCmd(); + + /** + * Command to inspect a service + * + * @since {@link RemoteApiVersion#VERSION_1_30} + * @param configId config id or config name + * @return command + */ + InspectConfigCmd inspectConfigCmd(String configId); + + /** + * Command to remove a config + * @since {@link RemoteApiVersion#VERSION_1_30} + * @param configId config id or config name + * @return command + */ + RemoveConfigCmd removeConfigCmd(String configId); + @Override void close() throws IOException; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClientDelegate.java b/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClientDelegate.java new file mode 100644 index 000000000..fe1f72670 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/DockerClientDelegate.java @@ -0,0 +1,533 @@ +package com.github.dockerjava.api; + +import com.github.dockerjava.api.command.AttachContainerCmd; +import com.github.dockerjava.api.command.AuthCmd; +import com.github.dockerjava.api.command.BuildImageCmd; +import com.github.dockerjava.api.command.CommitCmd; +import com.github.dockerjava.api.command.ConnectToNetworkCmd; +import com.github.dockerjava.api.command.ContainerDiffCmd; +import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; +import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; +import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.api.command.CreateConfigCmd; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateImageCmd; +import com.github.dockerjava.api.command.CreateNetworkCmd; +import com.github.dockerjava.api.command.CreateSecretCmd; +import com.github.dockerjava.api.command.CreateServiceCmd; +import com.github.dockerjava.api.command.CreateVolumeCmd; +import com.github.dockerjava.api.command.DisconnectFromNetworkCmd; +import com.github.dockerjava.api.command.EventsCmd; +import com.github.dockerjava.api.command.ExecCreateCmd; +import com.github.dockerjava.api.command.ExecStartCmd; +import com.github.dockerjava.api.command.InfoCmd; +import com.github.dockerjava.api.command.InitializeSwarmCmd; +import com.github.dockerjava.api.command.InspectConfigCmd; +import com.github.dockerjava.api.command.InspectContainerCmd; +import com.github.dockerjava.api.command.InspectExecCmd; +import com.github.dockerjava.api.command.InspectImageCmd; +import com.github.dockerjava.api.command.ImageHistoryCmd; +import com.github.dockerjava.api.command.InspectNetworkCmd; +import com.github.dockerjava.api.command.InspectServiceCmd; +import com.github.dockerjava.api.command.InspectSwarmCmd; +import com.github.dockerjava.api.command.InspectVolumeCmd; +import com.github.dockerjava.api.command.JoinSwarmCmd; +import com.github.dockerjava.api.command.KillContainerCmd; +import com.github.dockerjava.api.command.LeaveSwarmCmd; +import com.github.dockerjava.api.command.ListConfigsCmd; +import com.github.dockerjava.api.command.ListContainersCmd; +import com.github.dockerjava.api.command.ListImagesCmd; +import com.github.dockerjava.api.command.ListNetworksCmd; +import com.github.dockerjava.api.command.ListSecretsCmd; +import com.github.dockerjava.api.command.ListServicesCmd; +import com.github.dockerjava.api.command.ListSwarmNodesCmd; +import com.github.dockerjava.api.command.ListTasksCmd; +import com.github.dockerjava.api.command.ListVolumesCmd; +import com.github.dockerjava.api.command.LoadImageAsyncCmd; +import com.github.dockerjava.api.command.LoadImageCmd; +import com.github.dockerjava.api.command.LogContainerCmd; +import com.github.dockerjava.api.command.LogSwarmObjectCmd; +import com.github.dockerjava.api.command.PauseContainerCmd; +import com.github.dockerjava.api.command.PingCmd; +import com.github.dockerjava.api.command.PruneCmd; +import com.github.dockerjava.api.command.PullImageCmd; +import com.github.dockerjava.api.command.PushImageCmd; +import com.github.dockerjava.api.command.RemoveConfigCmd; +import com.github.dockerjava.api.command.RemoveContainerCmd; +import com.github.dockerjava.api.command.RemoveImageCmd; +import com.github.dockerjava.api.command.RemoveNetworkCmd; +import com.github.dockerjava.api.command.RemoveSecretCmd; +import com.github.dockerjava.api.command.RemoveServiceCmd; +import com.github.dockerjava.api.command.RemoveSwarmNodeCmd; +import com.github.dockerjava.api.command.RemoveVolumeCmd; +import com.github.dockerjava.api.command.RenameContainerCmd; +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.command.ResizeExecCmd; +import com.github.dockerjava.api.command.RestartContainerCmd; +import com.github.dockerjava.api.command.SaveImageCmd; +import com.github.dockerjava.api.command.SaveImagesCmd; +import com.github.dockerjava.api.command.SearchImagesCmd; +import com.github.dockerjava.api.command.StartContainerCmd; +import com.github.dockerjava.api.command.StatsCmd; +import com.github.dockerjava.api.command.StopContainerCmd; +import com.github.dockerjava.api.command.TagImageCmd; +import com.github.dockerjava.api.command.TopContainerCmd; +import com.github.dockerjava.api.command.UnpauseContainerCmd; +import com.github.dockerjava.api.command.UpdateContainerCmd; +import com.github.dockerjava.api.command.UpdateServiceCmd; +import com.github.dockerjava.api.command.UpdateSwarmCmd; +import com.github.dockerjava.api.command.UpdateSwarmNodeCmd; +import com.github.dockerjava.api.command.VersionCmd; +import com.github.dockerjava.api.command.WaitContainerCmd; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.api.model.Identifier; +import com.github.dockerjava.api.model.PruneType; +import com.github.dockerjava.api.model.SecretSpec; +import com.github.dockerjava.api.model.ServiceSpec; +import com.github.dockerjava.api.model.SwarmSpec; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * @apiNote implementations MUST override {{@link #getDockerClient()}} + * @implNote We're not using an abstract class here because we want + * Java compiler to force us to implement every {@link DockerClient}'s method, + * especially when new methods are added + */ +@SuppressWarnings("unused") +public class DockerClientDelegate implements DockerClient { + + protected DockerClient getDockerClient() { + throw new IllegalStateException("Implement me!"); + } + + @Override + public AuthConfig authConfig() throws DockerException { + return getDockerClient().authConfig(); + } + + @Override + public AuthCmd authCmd() { + return getDockerClient().authCmd(); + } + + @Override + public InfoCmd infoCmd() { + return getDockerClient().infoCmd(); + } + + @Override + public PingCmd pingCmd() { + return getDockerClient().pingCmd(); + } + + @Override + public VersionCmd versionCmd() { + return getDockerClient().versionCmd(); + } + + @Override + public PullImageCmd pullImageCmd(@Nonnull String repository) { + return getDockerClient().pullImageCmd(repository); + } + + @Override + public PushImageCmd pushImageCmd(@Nonnull String name) { + return getDockerClient().pushImageCmd(name); + } + + @Override + public PushImageCmd pushImageCmd(@Nonnull Identifier identifier) { + return getDockerClient().pushImageCmd(identifier); + } + + @Override + public CreateImageCmd createImageCmd(@Nonnull String repository, @Nonnull InputStream imageStream) { + return getDockerClient().createImageCmd(repository, imageStream); + } + + @Override + public LoadImageCmd loadImageCmd(@Nonnull InputStream imageStream) { + return getDockerClient().loadImageCmd(imageStream); + } + + @Override + public LoadImageAsyncCmd loadImageAsyncCmd(@Nonnull InputStream imageStream) { + return getDockerClient().loadImageAsyncCmd(imageStream); + } + + @Override + public SearchImagesCmd searchImagesCmd(@Nonnull String term) { + return getDockerClient().searchImagesCmd(term); + } + + @Override + public RemoveImageCmd removeImageCmd(@Nonnull String imageId) { + return getDockerClient().removeImageCmd(imageId); + } + + @Override + public ListImagesCmd listImagesCmd() { + return getDockerClient().listImagesCmd(); + } + + @Override + public InspectImageCmd inspectImageCmd(@Nonnull String imageId) { + return getDockerClient().inspectImageCmd(imageId); + } + + @Override + public ImageHistoryCmd imageHistoryCmd(@Nonnull String imageId) { + return getDockerClient().imageHistoryCmd(imageId); + } + + @Override + public SaveImageCmd saveImageCmd(@Nonnull String name) { + return getDockerClient().saveImageCmd(name); + } + + @Override + public SaveImagesCmd saveImagesCmd() { + return getDockerClient().saveImagesCmd(); + } + + @Override + public ListContainersCmd listContainersCmd() { + return getDockerClient().listContainersCmd(); + } + + @Override + public CreateContainerCmd createContainerCmd(@Nonnull String image) { + return getDockerClient().createContainerCmd(image); + } + + @Override + public StartContainerCmd startContainerCmd(@Nonnull String containerId) { + return getDockerClient().startContainerCmd(containerId); + } + + @Override + public ExecCreateCmd execCreateCmd(@Nonnull String containerId) { + return getDockerClient().execCreateCmd(containerId); + } + + @Override + public ResizeExecCmd resizeExecCmd(@Nonnull String execId) { + return getDockerClient().resizeExecCmd(execId); + } + + @Override + public InspectContainerCmd inspectContainerCmd(@Nonnull String containerId) { + return getDockerClient().inspectContainerCmd(containerId); + } + + @Override + public RemoveContainerCmd removeContainerCmd(@Nonnull String containerId) { + return getDockerClient().removeContainerCmd(containerId); + } + + @Override + public WaitContainerCmd waitContainerCmd(@Nonnull String containerId) { + return getDockerClient().waitContainerCmd(containerId); + } + + @Override + public AttachContainerCmd attachContainerCmd(@Nonnull String containerId) { + return getDockerClient().attachContainerCmd(containerId); + } + + @Override + public ExecStartCmd execStartCmd(@Nonnull String execId) { + return getDockerClient().execStartCmd(execId); + } + + @Override + public InspectExecCmd inspectExecCmd(@Nonnull String execId) { + return getDockerClient().inspectExecCmd(execId); + } + + @Override + public LogContainerCmd logContainerCmd(@Nonnull String containerId) { + return getDockerClient().logContainerCmd(containerId); + } + + @Override + public CopyArchiveFromContainerCmd copyArchiveFromContainerCmd(@Nonnull String containerId, @Nonnull String resource) { + return getDockerClient().copyArchiveFromContainerCmd(containerId, resource); + } + + @Override + @Deprecated + public CopyFileFromContainerCmd copyFileFromContainerCmd(@Nonnull String containerId, @Nonnull String resource) { + return getDockerClient().copyFileFromContainerCmd(containerId, resource); + } + + @Override + public CopyArchiveToContainerCmd copyArchiveToContainerCmd(@Nonnull String containerId) { + return getDockerClient().copyArchiveToContainerCmd(containerId); + } + + @Override + public ContainerDiffCmd containerDiffCmd(@Nonnull String containerId) { + return getDockerClient().containerDiffCmd(containerId); + } + + @Override + public StopContainerCmd stopContainerCmd(@Nonnull String containerId) { + return getDockerClient().stopContainerCmd(containerId); + } + + @Override + public KillContainerCmd killContainerCmd(@Nonnull String containerId) { + return getDockerClient().killContainerCmd(containerId); + } + + @Override + public UpdateContainerCmd updateContainerCmd(@Nonnull String containerId) { + return getDockerClient().updateContainerCmd(containerId); + } + + @Override + public RenameContainerCmd renameContainerCmd(@Nonnull String containerId) { + return getDockerClient().renameContainerCmd(containerId); + } + + @Override + public RestartContainerCmd restartContainerCmd(@Nonnull String containerId) { + return getDockerClient().restartContainerCmd(containerId); + } + + @Override + public ResizeContainerCmd resizeContainerCmd(@Nonnull String containerId) { + return getDockerClient().resizeContainerCmd(containerId); + } + + @Override + public CommitCmd commitCmd(@Nonnull String containerId) { + return getDockerClient().commitCmd(containerId); + } + + @Override + public BuildImageCmd buildImageCmd() { + return getDockerClient().buildImageCmd(); + } + + @Override + public BuildImageCmd buildImageCmd(File dockerFileOrFolder) { + return getDockerClient().buildImageCmd(dockerFileOrFolder); + } + + @Override + public BuildImageCmd buildImageCmd(InputStream tarInputStream) { + return getDockerClient().buildImageCmd(tarInputStream); + } + + @Override + public TopContainerCmd topContainerCmd(String containerId) { + return getDockerClient().topContainerCmd(containerId); + } + + @Override + public TagImageCmd tagImageCmd(String imageId, String imageNameWithRepository, String tag) { + return getDockerClient().tagImageCmd(imageId, imageNameWithRepository, tag); + } + + @Override + public PauseContainerCmd pauseContainerCmd(String containerId) { + return getDockerClient().pauseContainerCmd(containerId); + } + + @Override + public UnpauseContainerCmd unpauseContainerCmd(String containerId) { + return getDockerClient().unpauseContainerCmd(containerId); + } + + @Override + public EventsCmd eventsCmd() { + return getDockerClient().eventsCmd(); + } + + @Override + public StatsCmd statsCmd(String containerId) { + return getDockerClient().statsCmd(containerId); + } + + @Override + public CreateVolumeCmd createVolumeCmd() { + return getDockerClient().createVolumeCmd(); + } + + @Override + public InspectVolumeCmd inspectVolumeCmd(String name) { + return getDockerClient().inspectVolumeCmd(name); + } + + @Override + public RemoveVolumeCmd removeVolumeCmd(String name) { + return getDockerClient().removeVolumeCmd(name); + } + + @Override + public ListVolumesCmd listVolumesCmd() { + return getDockerClient().listVolumesCmd(); + } + + @Override + public ListNetworksCmd listNetworksCmd() { + return getDockerClient().listNetworksCmd(); + } + + @Override + public InspectNetworkCmd inspectNetworkCmd() { + return getDockerClient().inspectNetworkCmd(); + } + + @Override + public CreateNetworkCmd createNetworkCmd() { + return getDockerClient().createNetworkCmd(); + } + + @Override + public RemoveNetworkCmd removeNetworkCmd(@Nonnull String networkId) { + return getDockerClient().removeNetworkCmd(networkId); + } + + @Override + public ConnectToNetworkCmd connectToNetworkCmd() { + return getDockerClient().connectToNetworkCmd(); + } + + @Override + public DisconnectFromNetworkCmd disconnectFromNetworkCmd() { + return getDockerClient().disconnectFromNetworkCmd(); + } + + @Override + public InitializeSwarmCmd initializeSwarmCmd(SwarmSpec swarmSpec) { + return getDockerClient().initializeSwarmCmd(swarmSpec); + } + + @Override + public InspectSwarmCmd inspectSwarmCmd() { + return getDockerClient().inspectSwarmCmd(); + } + + @Override + public JoinSwarmCmd joinSwarmCmd() { + return getDockerClient().joinSwarmCmd(); + } + + @Override + public LeaveSwarmCmd leaveSwarmCmd() { + return getDockerClient().leaveSwarmCmd(); + } + + @Override + public UpdateSwarmCmd updateSwarmCmd(SwarmSpec swarmSpec) { + return getDockerClient().updateSwarmCmd(swarmSpec); + } + + @Override + public UpdateSwarmNodeCmd updateSwarmNodeCmd() { + return getDockerClient().updateSwarmNodeCmd(); + } + + @Override + public RemoveSwarmNodeCmd removeSwarmNodeCmd(String swarmNodeId) { + return getDockerClient().removeSwarmNodeCmd(swarmNodeId); + } + + @Override + public ListSwarmNodesCmd listSwarmNodesCmd() { + return getDockerClient().listSwarmNodesCmd(); + } + + @Override + public ListServicesCmd listServicesCmd() { + return getDockerClient().listServicesCmd(); + } + + @Override + public CreateServiceCmd createServiceCmd(ServiceSpec serviceSpec) { + return getDockerClient().createServiceCmd(serviceSpec); + } + + @Override + public InspectServiceCmd inspectServiceCmd(String serviceId) { + return getDockerClient().inspectServiceCmd(serviceId); + } + + @Override + public UpdateServiceCmd updateServiceCmd(String serviceId, ServiceSpec serviceSpec) { + return getDockerClient().updateServiceCmd(serviceId, serviceSpec); + } + + @Override + public RemoveServiceCmd removeServiceCmd(String serviceId) { + return getDockerClient().removeServiceCmd(serviceId); + } + + @Override + public ListTasksCmd listTasksCmd() { + return getDockerClient().listTasksCmd(); + } + + @Override + public LogSwarmObjectCmd logServiceCmd(String serviceId) { + return getDockerClient().logServiceCmd(serviceId); + } + + @Override + public LogSwarmObjectCmd logTaskCmd(String taskId) { + return getDockerClient().logTaskCmd(taskId); + } + + @Override + public PruneCmd pruneCmd(PruneType pruneType) { + return getDockerClient().pruneCmd(pruneType); + } + + @Override + public ListSecretsCmd listSecretsCmd() { + return getDockerClient().listSecretsCmd(); + } + + @Override + public CreateSecretCmd createSecretCmd(SecretSpec secretSpec) { + return getDockerClient().createSecretCmd(secretSpec); + } + + @Override + public RemoveSecretCmd removeSecretCmd(String secretId) { + return getDockerClient().removeSecretCmd(secretId); + } + + @Override + public ListConfigsCmd listConfigsCmd() { + return getDockerClient().listConfigsCmd(); + } + + @Override + public CreateConfigCmd createConfigCmd() { + return getDockerClient().createConfigCmd(); + } + + @Override + public InspectConfigCmd inspectConfigCmd(String configId) { + return getDockerClient().inspectConfigCmd(configId); + } + + @Override + public RemoveConfigCmd removeConfigCmd(String configId) { + return getDockerClient().removeConfigCmd(configId); + } + + @Override + public void close() throws IOException { + getDockerClient().close(); + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/async/ResultCallbackTemplate.java b/docker-java-api/src/main/java/com/github/dockerjava/api/async/ResultCallbackTemplate.java index 8c56ab093..911e67826 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/async/ResultCallbackTemplate.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/async/ResultCallbackTemplate.java @@ -87,10 +87,18 @@ public void close() throws IOException { */ @SuppressWarnings("unchecked") public RC_T awaitCompletion() throws InterruptedException { - completed.await(); - // eventually (re)throws RuntimeException - throwFirstError(); - return (RC_T) this; + try { + completed.await(); + // eventually (re)throws RuntimeException + throwFirstError(); + return (RC_T) this; + } finally { + try { + close(); + } catch (IOException e) { + LOGGER.debug("Failed to close", e); + } + } } /** @@ -99,9 +107,17 @@ public RC_T awaitCompletion() throws InterruptedException { * before {@link ResultCallback#onComplete()} was called. */ public boolean awaitCompletion(long timeout, TimeUnit timeUnit) throws InterruptedException { - boolean result = completed.await(timeout, timeUnit); - throwFirstError(); - return result; + try { + boolean result = completed.await(timeout, timeUnit); + throwFirstError(); + return result; + } finally { + try { + close(); + } catch (IOException e) { + LOGGER.debug("Failed to close", e); + } + } } /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/BuildImageResultCallback.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/BuildImageResultCallback.java index 0bb0f0884..9db21a6c4 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/BuildImageResultCallback.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/BuildImageResultCallback.java @@ -31,7 +31,7 @@ public void onNext(BuildResponseItem item) { } else if (item.isErrorIndicated()) { this.error = item.getError(); } - LOGGER.debug(item.toString()); + LOGGER.debug("{}", item); } /** @@ -67,14 +67,14 @@ public String awaitImageId(long timeout, TimeUnit timeUnit) { } private String getImageId() { - if (imageId != null) { - return imageId; + if (error != null) { + throw new DockerClientException("Could not build image: " + error); } - if (error == null) { - throw new DockerClientException("Could not build image"); + if (imageId != null) { + return imageId; } - throw new DockerClientException("Could not build image: " + error); + throw new DockerClientException("Could not build image"); } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java index a4dfb5c03..19b3c3843 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CopyArchiveToContainerCmd.java @@ -16,6 +16,7 @@ public interface CopyArchiveToContainerCmd extends SyncDockerCmd { boolean isDirChildrenOnly(); + boolean isCopyUIDGID(); /** * Set container's id * @@ -49,6 +50,14 @@ public interface CopyArchiveToContainerCmd extends SyncDockerCmd { */ CopyArchiveToContainerCmd withNoOverwriteDirNonDir(boolean noOverwriteDirNonDir); + /** + * If set to true then ownership is set to the user and primary group at the destination + * + * @param copyUIDGID + * flag to know if ownership should be set to the user and primary group at the destination + */ + CopyArchiveToContainerCmd withCopyUIDGID(boolean copyUIDGID); + /** * If this flag is set to true, all children of the local directory will be copied to the remote without the root directory. For ex: if * I have root/titi and root/tata and the remote path is /var/data. dirChildrenOnly = true will create /var/data/titi and /var/data/tata diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateConfigCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateConfigCmd.java new file mode 100644 index 000000000..205bc7a7d --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateConfigCmd.java @@ -0,0 +1,51 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.exception.ConflictException; + +import javax.annotation.CheckForNull; +import java.util.Map; + +/** + * Command to create a new config + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ +public interface CreateConfigCmd extends SyncDockerCmd { + + @CheckForNull + String getName(); + + @CheckForNull + String getData(); + + @CheckForNull + Map getLabels(); + + /** + * @param name + * - The new config name. + */ + CreateConfigCmd withName(String name); + + /** + * @param data + * - The new config data. + */ + CreateConfigCmd withData(byte[] data); + + /** + * @param labels + * - A mapping of labels keys and values. Labels are a mechanism for applying metadata to Docker objects. + */ + CreateConfigCmd withLabels(Map labels); + + /** + * @throws ConflictException Named config already exists + */ + @Override + CreateConfigResponse exec() throws ConflictException; + + interface Exec extends DockerCmdSyncExec { + } + +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateConfigResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateConfigResponse.java new file mode 100644 index 000000000..5836275ff --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateConfigResponse.java @@ -0,0 +1,20 @@ +package com.github.dockerjava.api.command; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * The response of a {@link CreateConfigCmd} + */ +@EqualsAndHashCode +@ToString +public class CreateConfigResponse extends DockerObject { + @JsonProperty("ID") + private String id; + + public String getId() { + return id; + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java index d9b9503ad..fba83f50c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java @@ -44,6 +44,10 @@ public interface CreateContainerCmd extends SyncDockerCmd getAliases(); + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -51,6 +55,10 @@ default Bind[] getBinds() { return getHostConfig().getBinds(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withBinds(Bind... binds) { Objects.requireNonNull(binds, "binds was not specified"); @@ -58,6 +66,10 @@ default CreateContainerCmd withBinds(Bind... binds) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withBinds(List binds) { Objects.requireNonNull(binds, "binds was not specified"); @@ -158,6 +170,10 @@ default CreateContainerCmd withBinds(List binds) { CreateContainerCmd withIpv4Address(String ipv4Address); + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -167,6 +183,8 @@ default Link[] getLinks() { /** * Add link to another container. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withLinks(Link... links) { @@ -177,6 +195,8 @@ default CreateContainerCmd withLinks(Link... links) { /** * Add link to another container. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withLinks(List links) { @@ -199,6 +219,10 @@ default CreateContainerCmd withLinks(List links) { CreateContainerCmd withMacAddress(String macAddress); + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -206,6 +230,10 @@ default Long getMemory() { return getHostConfig().getMemory(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withMemory(Long memory) { Objects.requireNonNull(memory, "memory was not specified"); @@ -213,6 +241,10 @@ default CreateContainerCmd withMemory(Long memory) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -220,6 +252,10 @@ default Long getMemorySwap() { return getHostConfig().getMemorySwap(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withMemorySwap(Long memorySwap) { Objects.requireNonNull(memorySwap, "memorySwap was not specified"); @@ -230,6 +266,10 @@ default CreateContainerCmd withMemorySwap(Long memorySwap) { @CheckForNull String getName(); + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -246,6 +286,8 @@ default String getNetworkMode() { *
  • 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system * services such as D-bus and is therefore considered insecure.
  • * + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withNetworkMode(String networkMode) { @@ -254,6 +296,10 @@ default CreateContainerCmd withNetworkMode(String networkMode) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -264,6 +310,8 @@ default Ports getPortBindings() { /** * Add one or more {@link PortBinding}s. This corresponds to the --publish (-p) option of the * docker run CLI command. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withPortBindings(PortBinding... portBindings) { @@ -275,6 +323,8 @@ default CreateContainerCmd withPortBindings(PortBinding... portBindings) { /** * Add one or more {@link PortBinding}s. This corresponds to the --publish (-p) option of the * docker run CLI command. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withPortBindings(List portBindings) { @@ -285,7 +335,7 @@ default CreateContainerCmd withPortBindings(List portBindings) { /** * Add the port bindings that are contained in the given {@link Ports} object. * - * @see #withPortBindings(PortBinding...) + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withPortBindings(Ports portBindings) { @@ -303,6 +353,10 @@ default CreateContainerCmd withPortBindings(Ports portBindings) { CreateContainerCmd withPortSpecs(List portSpecs); + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -310,6 +364,10 @@ default Boolean getPrivileged() { return getHostConfig().getPrivileged(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withPrivileged(Boolean privileged) { Objects.requireNonNull(privileged, "no privileged was specified"); @@ -329,6 +387,10 @@ default CreateContainerCmd withPrivileged(Boolean privileged) { CreateContainerCmd withVolumes(List volumes); + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -336,6 +398,10 @@ default VolumesFrom[] getVolumesFrom() { return getHostConfig().getVolumesFrom(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withVolumesFrom(VolumesFrom... volumesFrom) { Objects.requireNonNull(volumesFrom, "volumesFrom was not specified"); @@ -343,6 +409,10 @@ default CreateContainerCmd withVolumesFrom(VolumesFrom... volumesFrom) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withVolumesFrom(List volumesFrom) { requireNonNull(volumesFrom, "volumesFrom was not specified"); @@ -389,6 +459,10 @@ default CreateContainerCmd withVolumesFrom(List volumesFrom) { CreateContainerCmd withTty(Boolean tty); + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -396,6 +470,10 @@ default Boolean getPublishAllPorts() { return getHostConfig().getPublishAllPorts(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withPublishAllPorts(Boolean publishAllPorts) { requireNonNull(publishAllPorts, "no publishAllPorts was specified"); @@ -403,6 +481,10 @@ default CreateContainerCmd withPublishAllPorts(Boolean publishAllPorts) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @CheckForNull @Deprecated @JsonIgnore @@ -412,6 +494,8 @@ default String[] getExtraHosts() { /** * Add hostnames to /etc/hosts in the container + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withExtraHosts(String... extraHosts) { @@ -422,6 +506,8 @@ default CreateContainerCmd withExtraHosts(String... extraHosts) { /** * Add hostnames to /etc/hosts in the container + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withExtraHosts(List extraHosts) { @@ -429,6 +515,10 @@ default CreateContainerCmd withExtraHosts(List extraHosts) { return withExtraHosts(extraHosts.toArray(new String[extraHosts.size()])); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @CheckForNull @Deprecated @JsonIgnore @@ -439,6 +529,8 @@ default Capability[] getCapAdd() { /** * Add linux kernel capability to the container. For example: * adding {@link Capability#MKNOD} allows the container to create special files using the 'mknod' command. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withCapAdd(Capability... capAdd) { @@ -450,6 +542,8 @@ default CreateContainerCmd withCapAdd(Capability... capAdd) { /** * Add linux kernel capability to the container. For example: * adding {@link Capability#MKNOD} allows the container to create special files using the 'mknod' command. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withCapAdd(List capAdd) { @@ -457,6 +551,10 @@ default CreateContainerCmd withCapAdd(List capAdd) { return withCapAdd(capAdd.toArray(new Capability[capAdd.size()])); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @CheckForNull @Deprecated @JsonIgnore @@ -467,6 +565,8 @@ default Capability[] getCapDrop() { /** * Drop linux kernel capability from the container. For example: * dropping {@link Capability#CHOWN} prevents the container from changing the owner of any files. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withCapDrop(Capability... capDrop) { @@ -478,6 +578,8 @@ default CreateContainerCmd withCapDrop(Capability... capDrop) { /** * Drop linux kernel capability from the container. For example: * dropping {@link Capability#CHOWN} prevents the container from changing the owner of any files. + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withCapDrop(List capDrop) { @@ -499,6 +601,10 @@ default CreateContainerCmd withCapDrop(List capDrop) { // The following methods are deprecated and should be set on {@link #getHostConfig()} instead. // TODO remove in the next big release + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -506,6 +612,10 @@ default Integer getBlkioWeight() { return getHostConfig().getBlkioWeight(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @CheckForNull @Deprecated @JsonIgnore @@ -513,6 +623,10 @@ default String getCgroupParent() { return getHostConfig().getCgroupParent(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -521,6 +635,10 @@ default Integer getCpuPeriod() { return result != null ? result.intValue() : null; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -528,6 +646,10 @@ default Integer getCpuShares() { return getHostConfig().getCpuShares(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -535,6 +657,10 @@ default String getCpusetCpus() { return getHostConfig().getCpusetCpus(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -542,6 +668,10 @@ default String getCpusetMems() { return getHostConfig().getCpusetMems(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -549,6 +679,10 @@ default Device[] getDevices() { return getHostConfig().getDevices(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -556,6 +690,10 @@ default String[] getDns() { return getHostConfig().getDns(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -563,6 +701,10 @@ default String[] getDnsSearch() { return getHostConfig().getDnsSearch(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -570,6 +712,10 @@ default LogConfig getLogConfig() { return getHostConfig().getLogConfig(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -577,6 +723,10 @@ default LxcConf[] getLxcConf() { return getHostConfig().getLxcConf(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -584,6 +734,10 @@ default Boolean getOomKillDisable() { return getHostConfig().getOomKillDisable(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -591,6 +745,10 @@ default String getPidMode() { return getHostConfig().getPidMode(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -598,6 +756,10 @@ default Boolean getReadonlyRootfs() { return getHostConfig().getReadonlyRootfs(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -605,6 +767,10 @@ default RestartPolicy getRestartPolicy() { return getHostConfig().getRestartPolicy(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @CheckForNull @JsonIgnore @@ -612,48 +778,80 @@ default Ulimit[] getUlimits() { return getHostConfig().getUlimits(); } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withBlkioWeight(Integer blkioWeight) { getHostConfig().withBlkioWeight(blkioWeight); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withCgroupParent(String cgroupParent) { getHostConfig().withCgroupParent(cgroupParent); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withContainerIDFile(String containerIDFile) { getHostConfig().withContainerIDFile(containerIDFile); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withCpuPeriod(Integer cpuPeriod) { getHostConfig().withCpuPeriod(cpuPeriod != null ? cpuPeriod.longValue() : null); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withCpuShares(Integer cpuShares) { getHostConfig().withCpuShares(cpuShares); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withCpusetCpus(String cpusetCpus) { getHostConfig().withCpusetCpus(cpusetCpus); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withCpusetMems(String cpusetMems) { getHostConfig().withCpusetMems(cpusetMems); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withDevices(Device... devices) { getHostConfig().withDevices(devices); @@ -662,6 +860,8 @@ default CreateContainerCmd withDevices(Device... devices) { /** * Add host devices to the container + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withDevices(List devices) { @@ -671,6 +871,8 @@ default CreateContainerCmd withDevices(List devices) { /** * Set custom DNS servers + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withDns(String... dns) { @@ -680,6 +882,8 @@ default CreateContainerCmd withDns(String... dns) { /** * Set custom DNS servers + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withDns(List dns) { @@ -689,6 +893,8 @@ default CreateContainerCmd withDns(List dns) { /** * Set custom DNS search domains + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withDnsSearch(String... dnsSearch) { @@ -698,6 +904,8 @@ default CreateContainerCmd withDnsSearch(String... dnsSearch) { /** * Set custom DNS search domains + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withDnsSearch(List dnsSearch) { @@ -705,24 +913,40 @@ default CreateContainerCmd withDnsSearch(List dnsSearch) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withLogConfig(LogConfig logConfig) { getHostConfig().withLogConfig(logConfig); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withLxcConf(LxcConf... lxcConf) { getHostConfig().withLxcConf(lxcConf); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withLxcConf(List lxcConf) { getHostConfig().withLxcConf(lxcConf.toArray(new LxcConf[0])); return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withOomKillDisable(Boolean oomKillDisable) { getHostConfig().withOomKillDisable(oomKillDisable); @@ -731,6 +955,8 @@ default CreateContainerCmd withOomKillDisable(Boolean oomKillDisable) { /** * Set the PID (Process) Namespace mode for the container, 'host': use the host's PID namespace inside the container + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withPidMode(String pidMode) { @@ -738,6 +964,10 @@ default CreateContainerCmd withPidMode(String pidMode) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withReadonlyRootfs(Boolean readonlyRootfs) { getHostConfig().withReadonlyRootfs(readonlyRootfs); @@ -746,6 +976,8 @@ default CreateContainerCmd withReadonlyRootfs(Boolean readonlyRootfs) { /** * Set custom {@link RestartPolicy} for the container. Defaults to {@link RestartPolicy#noRestart()} + * + * @deprecated see {@link #getHostConfig()} */ @Deprecated default CreateContainerCmd withRestartPolicy(RestartPolicy restartPolicy) { @@ -753,6 +985,10 @@ default CreateContainerCmd withRestartPolicy(RestartPolicy restartPolicy) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated @JsonIgnore default CreateContainerCmd withUlimits(Ulimit... ulimits) { @@ -760,12 +996,23 @@ default CreateContainerCmd withUlimits(Ulimit... ulimits) { return this; } + /** + * + * @deprecated see {@link #getHostConfig()} + */ @Deprecated default CreateContainerCmd withUlimits(List ulimits) { getHostConfig().withUlimits(ulimits); return this; } + @CheckForNull + default String getPlatform() { + return null; + } + + CreateContainerCmd withPlatform(String platform); + /** * @throws NotFoundException No such container * @throws ConflictException Named container already exists diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerResponse.java index b19f8c6ae..ad24d7ec8 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerResponse.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -11,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class CreateContainerResponse { +public class CreateContainerResponse extends DockerObject { @JsonProperty("Id") private String id; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateImageResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateImageResponse.java index 09b1929c0..53b2b5367 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateImageResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateImageResponse.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -12,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class CreateImageResponse { +public class CreateImageResponse extends DockerObject { @JsonProperty("status") private String id; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkCmd.java index 544ac2083..56b9df17a 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkCmd.java @@ -47,7 +47,7 @@ public interface CreateNetworkCmd extends SyncDockerCmd { /** Name of the network driver to use. Defaults to bridge. */ CreateNetworkCmd withDriver(String driver); - /** Ipam config, such es subnet, gateway and ip range of the network */ + /** Ipam config, such as subnet, gateway and ip range of the network */ CreateNetworkCmd withIpam(Ipam ipam); /** Driver specific options */ diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkResponse.java index a816f3f3a..3f6f219e1 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateNetworkResponse.java @@ -1,12 +1,13 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @EqualsAndHashCode @ToString -public class CreateNetworkResponse { +public class CreateNetworkResponse extends DockerObject { @JsonProperty("Id") private String id; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateSecretResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateSecretResponse.java index c9da4c3ba..2c1b6f11b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateSecretResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateSecretResponse.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -9,7 +10,7 @@ */ @EqualsAndHashCode @ToString -public class CreateSecretResponse { +public class CreateSecretResponse extends DockerObject { @JsonProperty("ID") private String id; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateServiceResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateServiceResponse.java index 1cbd421b9..b68343f55 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateServiceResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateServiceResponse.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -9,7 +10,7 @@ */ @EqualsAndHashCode @ToString -public class CreateServiceResponse { +public class CreateServiceResponse extends DockerObject { @JsonProperty("ID") private String id; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateVolumeResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateVolumeResponse.java index 9c31b8dc4..4afc6f6ba 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateVolumeResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateVolumeResponse.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -12,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class CreateVolumeResponse { +public class CreateVolumeResponse extends DockerObject { @JsonProperty("Name") private String name; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java index dbd691974..8f102a10e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DelegatingDockerCmdExecFactory.java @@ -25,11 +25,21 @@ public PingCmd.Exec createPingCmdExec() { return getDockerCmdExecFactory().createPingCmdExec(); } + @Override + public ResizeContainerCmd.Exec createResizeContainerCmdExec() { + return getDockerCmdExecFactory().createResizeContainerCmdExec(); + } + @Override public ExecCreateCmd.Exec createExecCmdExec() { return getDockerCmdExecFactory().createExecCmdExec(); } + @Override + public ResizeExecCmd.Exec createResizeExecCmdExec() { + return getDockerCmdExecFactory().createResizeExecCmdExec(); + } + @Override public VersionCmd.Exec createVersionCmdExec() { return getDockerCmdExecFactory().createVersionCmdExec(); @@ -65,6 +75,11 @@ public LoadImageCmd.Exec createLoadImageCmdExec() { return getDockerCmdExecFactory().createLoadImageCmdExec(); } + @Override + public LoadImageAsyncCmd.Exec createLoadImageAsyncCmdExec() { + return getDockerCmdExecFactory().createLoadImageAsyncCmdExec(); + } + @Override public SearchImagesCmd.Exec createSearchImagesCmdExec() { return getDockerCmdExecFactory().createSearchImagesCmdExec(); @@ -85,6 +100,11 @@ public InspectImageCmd.Exec createInspectImageCmdExec() { return getDockerCmdExecFactory().createInspectImageCmdExec(); } + @Override + public ImageHistoryCmd.Exec createImageHistoryCmdExec() { + return getDockerCmdExecFactory().createImageHistoryCmdExec(); + } + @Override public ListContainersCmd.Exec createListContainersCmdExec() { return getDockerCmdExecFactory().createListContainersCmdExec(); @@ -370,6 +390,26 @@ public RemoveSecretCmd.Exec createRemoveSecretCmdExec() { return getDockerCmdExecFactory().createRemoveSecretCmdExec(); } + @Override + public ListConfigsCmd.Exec createListConfigsCmdExec() { + return getDockerCmdExecFactory().createListConfigsCmdExec(); + } + + @Override + public CreateConfigCmd.Exec createCreateConfigCmdExec() { + return getDockerCmdExecFactory().createCreateConfigCmdExec(); + } + + @Override + public InspectConfigCmd.Exec createInspectConfigCmdExec() { + return getDockerCmdExecFactory().createInspectConfigCmdExec(); + } + + @Override + public RemoveConfigCmd.Exec createRemoveConfigCmdExec() { + return getDockerCmdExecFactory().createRemoveConfigCmdExec(); + } + @Override public void close() throws IOException { getDockerCmdExecFactory().close(); diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java index e01d9239f..29c001737 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java @@ -27,6 +27,8 @@ public interface DockerCmdExecFactory extends Closeable { LoadImageCmd.Exec createLoadImageCmdExec(); + LoadImageAsyncCmd.Exec createLoadImageAsyncCmdExec(); + SearchImagesCmd.Exec createSearchImagesCmdExec(); RemoveImageCmd.Exec createRemoveImageCmdExec(); @@ -35,6 +37,8 @@ public interface DockerCmdExecFactory extends Closeable { InspectImageCmd.Exec createInspectImageCmdExec(); + ImageHistoryCmd.Exec createImageHistoryCmdExec(); + ListContainersCmd.Exec createListContainersCmdExec(); CreateContainerCmd.Exec createCreateContainerCmdExec(); @@ -49,8 +53,12 @@ public interface DockerCmdExecFactory extends Closeable { AttachContainerCmd.Exec createAttachContainerCmdExec(); + ResizeContainerCmd.Exec createResizeContainerCmdExec(); + ExecStartCmd.Exec createExecStartCmdExec(); + ResizeExecCmd.Exec createResizeExecCmdExec(); + InspectExecCmd.Exec createInspectExecCmdExec(); LogContainerCmd.Exec createLogContainerCmdExec(); @@ -232,6 +240,35 @@ public interface DockerCmdExecFactory extends Closeable { */ RemoveSecretCmd.Exec createRemoveSecretCmdExec(); + /** + * Command to list all configs. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ + ListConfigsCmd.Exec createListConfigsCmdExec(); + + /** + * Command to inspect a config in a docker swarm. Only applicable if docker runs in swarm mode. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ + InspectConfigCmd.Exec createInspectConfigCmdExec(); + + /** + * Command to create a new config in a docker swarm. Only applicable if docker runs in swarm mode. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ + CreateConfigCmd.Exec createCreateConfigCmdExec(); + + /** + * Command to remove a config in a docker swarm. Only applicable if docker runs in swarm mode. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ + RemoveConfigCmd.Exec createRemoveConfigCmdExec(); + + @Override void close() throws IOException; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/EventsCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/EventsCmd.java index c52706226..34a0c5ad5 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/EventsCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/EventsCmd.java @@ -2,10 +2,12 @@ import java.util.List; import java.util.Map; +import java.util.stream.Stream; import javax.annotation.CheckForNull; import com.github.dockerjava.api.model.Event; +import com.github.dockerjava.api.model.EventType; /** * Get events @@ -33,6 +35,24 @@ public interface EventsCmd extends AsyncDockerCmd { */ EventsCmd withEventFilter(String... event); + /** + * @param eventTypes event types to filter + */ + EventsCmd withEventTypeFilter(String... eventTypes); + + /** + * This provides a type safe version of {@link #withEventTypeFilter(String...)}. + * + * @param eventTypes event types to filter + */ + default EventsCmd withEventTypeFilter(EventType... eventTypes) { + return withEventTypeFilter( + Stream.of(eventTypes) + .map(EventType::getValue) + .toArray(String[]::new) + ); + } + /** * @param image * - image to filter diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java index e751896de..449803236 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ExecCreateCmdResponse.java @@ -1,12 +1,13 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @EqualsAndHashCode @ToString -public class ExecCreateCmdResponse { +public class ExecCreateCmdResponse extends DockerObject { @JsonProperty("Id") private String id; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphData.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphData.java index 7852e8d59..44abc176d 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphData.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphData.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -12,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class GraphData { +public class GraphData extends DockerObject { @JsonProperty("RootDir") private String rootDir; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphDriver.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphDriver.java index 5ba4d456e..4d6679416 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphDriver.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/GraphDriver.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -14,7 +15,7 @@ */ @EqualsAndHashCode @ToString -public class GraphDriver { +public class GraphDriver extends DockerObject { /** * @since {@link com.github.dockerjava.core.RemoteApiVersion#VERSION_1_21} */ diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthState.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthState.java index cd7290785..0d8e399c1 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthState.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthState.java @@ -1,9 +1,15 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; +import lombok.EqualsAndHashCode; +import lombok.ToString; + import java.util.List; -public class HealthState { +@EqualsAndHashCode +@ToString +public class HealthState extends DockerObject { @JsonProperty("Status") private String status; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthStateLog.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthStateLog.java index d68dcb74f..71939f872 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthStateLog.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/HealthStateLog.java @@ -1,8 +1,13 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; +import lombok.EqualsAndHashCode; +import lombok.ToString; -public class HealthStateLog { +@EqualsAndHashCode +@ToString +public class HealthStateLog extends DockerObject { @JsonProperty("Start") private String start; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ImageHistoryCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ImageHistoryCmd.java new file mode 100644 index 000000000..d93796ad2 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ImageHistoryCmd.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.api.command; + +import java.util.List; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.ImageHistory; + +/** + * Get the history of an image. + */ +public interface ImageHistoryCmd extends SyncDockerCmd> { + + @CheckForNull + String getImageId(); + + ImageHistoryCmd withImageId(@Nonnull String imageId); + + /** + * @throws NotFoundException + * No such image + */ + @Override + List exec() throws NotFoundException; + + interface Exec extends DockerCmdSyncExec> { + } + +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectConfigCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectConfigCmd.java new file mode 100644 index 000000000..96374d795 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectConfigCmd.java @@ -0,0 +1,25 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Config; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +public interface InspectConfigCmd extends SyncDockerCmd { + + @CheckForNull + String getConfigId(); + + InspectConfigCmd withConfigId(@Nonnull String configId); + + /** + * @throws NotFoundException + * No such config + */ + @Override + Config exec() throws NotFoundException; + + interface Exec extends DockerCmdSyncExec { + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java index 06e18fa21..f06bd4ed9 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectContainerResponse.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.model.ContainerConfig; +import com.github.dockerjava.api.model.DockerObject; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.NetworkSettings; import com.github.dockerjava.api.model.Volume; @@ -24,7 +25,7 @@ */ @EqualsAndHashCode @ToString -public class InspectContainerResponse { +public class InspectContainerResponse extends DockerObject { @JsonProperty("Args") private String[] args; @@ -60,7 +61,10 @@ public class InspectContainerResponse { private String id; @JsonProperty("SizeRootFs") - private Integer sizeRootFs; + private Long sizeRootFs; + + @JsonProperty("SizeRw") + private Long sizeRw; @JsonProperty("Image") private String imageId; @@ -120,10 +124,14 @@ public String getId() { return id; } - public Integer getSizeRootFs() { + public Long getSizeRootFs() { return sizeRootFs; } + public Long getSizeRw() { + return sizeRw; + } + public String getCreated() { return created; } @@ -251,7 +259,7 @@ public String getPlatform() { @EqualsAndHashCode @ToString - public class ContainerState { + public class ContainerState extends DockerObject { /** * @since {@link RemoteApiVersion#VERSION_1_20} @@ -456,7 +464,7 @@ public HealthState getHealth() { @EqualsAndHashCode @ToString - public static class Mount { + public static class Mount extends DockerObject { /** * @since {@link RemoteApiVersion#VERSION_1_20} @@ -581,7 +589,7 @@ public Mount withSource(String source) { @EqualsAndHashCode @ToString - public class Node { + public class Node extends DockerObject { @JsonProperty("ID") private String id; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectExecResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectExecResponse.java index 06d904dc8..307fdd873 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectExecResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectExecResponse.java @@ -3,6 +3,7 @@ import java.util.List; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import com.github.dockerjava.api.model.NetworkSettings; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -11,7 +12,7 @@ @EqualsAndHashCode @ToString -public class InspectExecResponse { +public class InspectExecResponse extends DockerObject { @JsonProperty("ID") private String id; @@ -152,7 +153,7 @@ public Long getPidLong() { @EqualsAndHashCode @ToString - public class ProcessConfig { + public class ProcessConfig extends DockerObject { @JsonProperty("arguments") private List arguments; @@ -190,7 +191,9 @@ public String getUser() { } } - public class Container { + @EqualsAndHashCode + @ToString + public class Container extends DockerObject { @JsonProperty("NetworkSettings") private NetworkSettings networkSettings; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectImageResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectImageResponse.java index b8590bfc6..bf48ba8f0 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectImageResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectImageResponse.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.model.ContainerConfig; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -15,7 +16,7 @@ */ @EqualsAndHashCode @ToString -public class InspectImageResponse { +public class InspectImageResponse extends DockerObject { @JsonProperty("Architecture") private String arch; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectVolumeResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectVolumeResponse.java index c79232811..bc0008817 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectVolumeResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/InspectVolumeResponse.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -12,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class InspectVolumeResponse { +public class InspectVolumeResponse extends DockerObject { @JsonProperty("Name") private String name; @@ -26,6 +27,9 @@ public class InspectVolumeResponse { @JsonProperty("Mountpoint") private String mountpoint; + @JsonProperty("Options") + private Map options; + public String getName() { return name; } @@ -41,4 +45,9 @@ public String getDriver() { public String getMountpoint() { return mountpoint; } + + public Map getOptions() { + return options; + } + } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListConfigsCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListConfigsCmd.java new file mode 100644 index 000000000..38d34816a --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListConfigsCmd.java @@ -0,0 +1,21 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.model.Config; + +import java.util.List; +import java.util.Map; + +/** + * Command to list all configs in a docker swarm. Only applicable if docker runs in swarm mode. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ +public interface ListConfigsCmd extends SyncDockerCmd> { + + Map> getFilters(); + + ListConfigsCmd withFilters(Map> filters); + + interface Exec extends DockerCmdSyncExec> { + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListImagesCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListImagesCmd.java index 7741df743..cc60a5bcc 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListImagesCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListImagesCmd.java @@ -1,5 +1,6 @@ package com.github.dockerjava.api.command; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -44,6 +45,15 @@ public interface ListImagesCmd extends SyncDockerCmd> { */ ListImagesCmd withLabelFilter(Map labels); + /** + * Filter images by reference + * + * @param reference string in the form {@code [:]} + */ + ListImagesCmd withReferenceFilter(String reference); + + ListImagesCmd withFilter(String key, Collection values); + interface Exec extends DockerCmdSyncExec> { } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListVolumesResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListVolumesResponse.java index 4e1b449f8..7c434a48d 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListVolumesResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ListVolumesResponse.java @@ -3,6 +3,7 @@ import java.util.List; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -12,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ListVolumesResponse { +public class ListVolumesResponse extends DockerObject { @JsonProperty("Volumes") private List volumes; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/LoadImageAsyncCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/LoadImageAsyncCmd.java new file mode 100644 index 000000000..4f054db22 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/LoadImageAsyncCmd.java @@ -0,0 +1,22 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.model.LoadResponseItem; + +import java.io.InputStream; + +public interface LoadImageAsyncCmd extends AsyncDockerCmd { + InputStream getImageStream(); + + /** + * @param imageStream the InputStream of the tar file + */ + LoadImageAsyncCmd withImageStream(InputStream imageStream); + + @Override + default LoadImageCallback start() { + return exec(new LoadImageCallback()); + } + + interface Exec extends DockerCmdAsyncExec { + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/LoadImageCallback.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/LoadImageCallback.java new file mode 100644 index 000000000..80cca18de --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/LoadImageCallback.java @@ -0,0 +1,49 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.async.ResultCallbackTemplate; +import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.api.model.LoadResponseItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LoadImageCallback extends ResultCallbackTemplate { + + private static final Logger LOGGER = LoggerFactory.getLogger(LoadImageCallback.class); + + private String message; + + private String error; + + @Override + public void onNext(LoadResponseItem item) { + if (item.isBuildSuccessIndicated()) { + this.message = item.getMessage(); + } else if (item.isErrorIndicated()) { + this.error = item.getError(); + } + + LOGGER.debug("{}", item); + } + + public String awaitMessage() { + try { + awaitCompletion(); + } catch (InterruptedException e) { + throw new DockerClientException("", e); + } + + return getMessage(); + } + + private String getMessage() { + if (this.message != null) { + return this.message; + } + + if (this.error == null) { + throw new DockerClientException("Could not build image"); + } + + throw new DockerClientException("Could not build image: " + this.error); + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java index 53674cbaa..29c4516cd 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/LogContainerCmd.java @@ -25,6 +25,8 @@ * @param since * - UNIX timestamp (integer) to filter logs. Specifying a timestamp will only output log-entries since that timestamp. Default: * 0 (unfiltered) + * @param until + * - Only return logs before this time, as a UNIX timestamp. Default: 0 */ public interface LogContainerCmd extends AsyncDockerCmd { @@ -49,6 +51,9 @@ public interface LogContainerCmd extends AsyncDockerCmd @CheckForNull Integer getSince(); + @CheckForNull + Integer getUntil(); + LogContainerCmd withContainerId(@Nonnull String containerId); /** @@ -69,6 +74,8 @@ public interface LogContainerCmd extends AsyncDockerCmd LogContainerCmd withSince(Integer since); + LogContainerCmd withUntil(Integer until); + /** * @throws com.github.dockerjava.api.NotFoundException * No such container diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/PullImageResultCallback.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/PullImageResultCallback.java index 2c2b48b24..5980ce3df 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/PullImageResultCallback.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/PullImageResultCallback.java @@ -41,7 +41,7 @@ public void onNext(PullResponseItem item) { handleDockerClientResponse(item); } - LOGGER.debug(item.toString()); + LOGGER.debug("{}", item); } private void checkForDockerSwarmResponse(PullResponseItem item) { @@ -90,8 +90,10 @@ private void checkDockerSwarmPullSuccessful() { private void checkDockerClientPullSuccessful() { if (latestItem == null) { - throw new DockerClientException("Could not pull image"); - } else if (!latestItem.isPullSuccessIndicated()) { + return; + } + + if (!latestItem.isPullSuccessIndicated()) { throw new DockerClientException("Could not pull image: " + messageFromPullResult(latestItem)); } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/RemoveConfigCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RemoveConfigCmd.java new file mode 100644 index 000000000..741fe32c0 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RemoveConfigCmd.java @@ -0,0 +1,28 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.exception.NotFoundException; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +/** + * Remove a config. + */ +public interface RemoveConfigCmd extends SyncDockerCmd { + + @CheckForNull + String getConfigId(); + + RemoveConfigCmd withConfigId(@Nonnull String secretId); + + /** + * @throws NotFoundException + * No such config + */ + @Override + Void exec() throws NotFoundException; + + interface Exec extends DockerCmdSyncExec { + } + +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/RemoveSwarmNodeCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RemoveSwarmNodeCmd.java index 198e7b8df..603c610b3 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/RemoveSwarmNodeCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RemoveSwarmNodeCmd.java @@ -18,7 +18,7 @@ public interface RemoveSwarmNodeCmd extends SyncDockerCmd { @CheckForNull Boolean hasForceEnabled(); - RemoveSwarmNodeCmd withContainerId(@Nonnull String containerId); + RemoveSwarmNodeCmd withSwarmNodeId(@Nonnull String swarmNodeId); RemoveSwarmNodeCmd withForce(Boolean force); diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeContainerCmd.java new file mode 100644 index 000000000..fef0087ed --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeContainerCmd.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.exception.NotFoundException; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +public interface ResizeContainerCmd extends SyncDockerCmd { + + @CheckForNull + String getContainerId(); + + Integer getHeight(); + + Integer getWidth(); + + ResizeContainerCmd withContainerId(@Nonnull String execId); + + ResizeContainerCmd withSize(int height, int width); + + /** + * @throws NotFoundException no such container instance + */ + @Override + Void exec() throws NotFoundException; + + interface Exec extends DockerCmdSyncExec { + } + +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeExecCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeExecCmd.java new file mode 100644 index 000000000..5910705e0 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/ResizeExecCmd.java @@ -0,0 +1,29 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.exception.NotFoundException; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +public interface ResizeExecCmd extends SyncDockerCmd { + @CheckForNull + String getExecId(); + + Integer getHeight(); + + Integer getWidth(); + + ResizeExecCmd withExecId(@Nonnull String execId); + + ResizeExecCmd withSize(int height, int width); + + /** + * @throws NotFoundException no such exec instance + */ + @Override + Void exec() throws NotFoundException; + + interface Exec extends DockerCmdSyncExec { + } + +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/RestartContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RestartContainerCmd.java index 5dcc59c24..372456813 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/RestartContainerCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RestartContainerCmd.java @@ -8,9 +8,8 @@ /** * Restart a running container. * - * @param timeout - * - Timeout in seconds before killing the container. Defaults to 10 seconds. - * + * @param signal - Signal to send to the container as an integer or string (e.g. SIGINT). + * @param timeout - Timeout in seconds before killing the container. Defaults to 10 seconds. */ public interface RestartContainerCmd extends SyncDockerCmd { @@ -20,13 +19,28 @@ public interface RestartContainerCmd extends SyncDockerCmd { @CheckForNull Integer getTimeout(); + /** + * @since {@link com.github.dockerjava.core.RemoteApiVersion#VERSION_1_42} + */ + @CheckForNull + String getSignal(); + RestartContainerCmd withContainerId(@Nonnull String containerId); - RestartContainerCmd withtTimeout(Integer timeout); + /** + * @deprecated wrong name, use {@link #withTimeout(Integer)} + */ + @Deprecated + default RestartContainerCmd withtTimeout(Integer timeout) { + return withTimeout(timeout); + } + + RestartContainerCmd withTimeout(Integer timeout); + + RestartContainerCmd withSignal(String signal); /** - * @throws NotFoundException - * No such container + * @throws NotFoundException No such container */ @Override Void exec() throws NotFoundException; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/RootFS.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RootFS.java index e4cc0ec54..c190852af 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/RootFS.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/RootFS.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -14,7 +15,7 @@ */ @EqualsAndHashCode @ToString -public class RootFS { +public class RootFS extends DockerObject { @JsonProperty("Type") private String type; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java index 6f7b1d49f..e604c20ae 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/TopContainerResponse.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.command; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.dockerjava.api.model.DockerObject; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -11,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class TopContainerResponse { +public class TopContainerResponse extends DockerObject { @JsonProperty("Titles") private String[] titles; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/UpdateContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/UpdateContainerCmd.java index 82fbca5f8..d53bcdcdf 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/UpdateContainerCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/UpdateContainerCmd.java @@ -1,9 +1,16 @@ package com.github.dockerjava.api.command; +import com.github.dockerjava.api.model.BlkioRateDevice; +import com.github.dockerjava.api.model.BlkioWeightDevice; +import com.github.dockerjava.api.model.Device; +import com.github.dockerjava.api.model.DeviceRequest; +import com.github.dockerjava.api.model.RestartPolicy; +import com.github.dockerjava.api.model.Ulimit; import com.github.dockerjava.api.model.UpdateContainerResponse; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; +import java.util.List; /** * @author Kanstantsin Shautsou @@ -13,22 +20,47 @@ public interface UpdateContainerCmd extends SyncDockerCmd getBlkioWeightDevice(); + + UpdateContainerCmd withBlkioWeightDevice(List blkioWeightDevice); @CheckForNull - Integer getCpuPeriod(); + List getBlkioDeviceReadBps(); - UpdateContainerCmd withCpuPeriod(Integer cpuPeriod); + UpdateContainerCmd withBlkioDeviceReadBps(List blkioDeviceReadBps); @CheckForNull - Integer getCpuQuota(); + List getBlkioDeviceWriteBps(); - UpdateContainerCmd withCpuQuota(Integer cpuQuota); + UpdateContainerCmd withBlkioDeviceWriteBps(List blkioDeviceWriteBps); + + @CheckForNull + List getBlkioDeviceReadIOps(); + + UpdateContainerCmd withBlkioDeviceReadIOps(List blkioDeviceReadIOps); + + @CheckForNull + List getBlkioDeviceWriteIOps(); + + UpdateContainerCmd withBlkioDeviceWriteIOps(List blkioDeviceWriteIOps); + + @CheckForNull + Long getCpuPeriod(); + + UpdateContainerCmd withCpuPeriod(Long cpuPeriod); + + @CheckForNull + Long getCpuQuota(); + + UpdateContainerCmd withCpuQuota(Long cpuQuota); @CheckForNull String getCpusetCpus(); @@ -45,6 +77,31 @@ public interface UpdateContainerCmd extends SyncDockerCmd getDevices(); + + UpdateContainerCmd withDevices(List devices); + + @CheckForNull + List getDeviceCgroupRules(); + + UpdateContainerCmd withDeviceCgroupRules(List deviceCgroupRules); + + @CheckForNull + List getDeviceRequests(); + + UpdateContainerCmd withDeviceRequests(List deviceRequests); + @CheckForNull Long getKernelMemory(); @@ -65,6 +122,36 @@ public interface UpdateContainerCmd extends SyncDockerCmd getUlimits(); + + UpdateContainerCmd withUlimits(List ulimits); + + @CheckForNull + RestartPolicy getRestartPolicy(); + + UpdateContainerCmd withRestartPolicy(RestartPolicy restartPolicy); + interface Exec extends DockerCmdSyncExec { } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java index 3117cf7e4..7b910cd69 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerCmd.java @@ -2,9 +2,11 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.WaitContainerCondition; import com.github.dockerjava.api.model.WaitResponse; /** @@ -20,8 +22,20 @@ public interface WaitContainerCmd extends AsyncDockerCmd> T exec(T resultCallback); diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerResultCallback.java b/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerResultCallback.java index b4a6d3cc6..6cb160151 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerResultCallback.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/command/WaitContainerResultCallback.java @@ -27,7 +27,7 @@ public class WaitContainerResultCallback extends ResultCallbackTemplate */ AUDIT_CONTROL, + /** + * Allow reading the audit log via multicast netlink socket. + */ + AUDIT_READ, /** * Write records to kernel auditing log. */ @@ -26,6 +32,14 @@ public enum Capability { * Employ features that can block system suspend. */ BLOCK_SUSPEND, + /** + * Allow creating BPF maps, loading BPF Type Format (BTF) data, retrieve JITed code of BPF programs, and more. + */ + BPF, + /** + * Allow checkpoint/restore related operations. Introduced in kernel 5.9. + */ + CHECKPOINT_RESTORE, /** * Make arbitrary changes to file UIDs and GIDs (see chown(2)). */ @@ -120,6 +134,10 @@ public enum Capability { * */ NET_RAW, + /** + * Allow system performance and observability privileged operations using perf_events, i915_perf and other kernel subsystems + */ + PERFMON, /** * Set file capabilities. */ @@ -283,5 +301,11 @@ public enum Capability { /** * Trigger something that will wake up the system (set CLOCK_REALTIME_ALARM and CLOCK_BOOTTIME_ALARM timers). */ - WAKE_ALARM + WAKE_ALARM; + + @JsonCreator + public static Capability fromValue(String cap) { + String result = !cap.startsWith("CAP_") ? cap : cap.split("_", 2)[1]; + return Capability.valueOf(result); + } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ChangeLog.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ChangeLog.java index 922e2e2b3..c8a5be890 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ChangeLog.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ChangeLog.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ChangeLog implements Serializable { +public class ChangeLog extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Path") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ClusterInfo.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ClusterInfo.java index 40055106b..b6e1e5566 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ClusterInfo.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ClusterInfo.java @@ -16,7 +16,7 @@ */ @EqualsAndHashCode @ToString -public class ClusterInfo implements Serializable { +public class ClusterInfo extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Config.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Config.java new file mode 100644 index 000000000..2c5b87aa8 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Config.java @@ -0,0 +1,90 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.util.Date; + +/** + * Used for Listing config. + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ +@ToString +@EqualsAndHashCode +public class Config extends DockerObject implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * @since 1.30 + */ + @JsonProperty("ID") + private String id; + + /** + * @since 1.30 + */ + @JsonProperty("CreatedAt") + private Date createdAt; + + /** + * @since 1.30 + */ + @JsonProperty("UpdatedAt") + private Date updatedAt; + + /** + * @since 1.30 + */ + @JsonProperty("Spec") + private ConfigSpec spec; + + /** + * @since 1.30 + */ + @JsonProperty("Version") + private ResourceVersion version; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public ConfigSpec getSpec() { + return spec; + } + + public void setSpec(ConfigSpec spec) { + this.spec = spec; + } + + public ResourceVersion getVersion() { + return version; + } + + public void setVersion(ResourceVersion version) { + this.version = version; + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ConfigSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ConfigSpec.java new file mode 100644 index 000000000..62e525d0b --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ConfigSpec.java @@ -0,0 +1,24 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * @since {@link RemoteApiVersion#VERSION_1_30} + */ +@EqualsAndHashCode +@ToString +public class ConfigSpec extends DockerObject implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("Name") + private String name; + + public String getName() { + return name; + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Container.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Container.java index e2723a96b..3b4bdf394 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Container.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Container.java @@ -17,7 +17,7 @@ */ @EqualsAndHashCode @ToString -public class Container implements Serializable { +public class Container extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Command") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java index a84835277..db5437220 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerConfig.java @@ -16,7 +16,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerConfig implements Serializable { +public class ContainerConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("AttachStderr") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerDNSConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerDNSConfig.java index c60414f81..63d3cae11 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerDNSConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerDNSConfig.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerDNSConfig implements Serializable { +public class ContainerDNSConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Nameservers") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerHostConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerHostConfig.java index 590d22a92..cdc446282 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerHostConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerHostConfig.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerHostConfig implements Serializable { +public class ContainerHostConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("NetworkMode") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerMount.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerMount.java index 48b4c9f47..a08a6ea3f 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerMount.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerMount.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerMount implements Serializable { +public class ContainerMount extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Name") @@ -106,7 +106,7 @@ public ContainerMount withDriver(String driver) { */ @CheckForNull public String getMode() { - return driver; + return mode; } /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetwork.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetwork.java index 6433e15f6..823828900 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetwork.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetwork.java @@ -20,7 +20,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerNetwork implements Serializable { +public class ContainerNetwork extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** @@ -283,7 +283,9 @@ public ContainerNetwork withNetworkID(String networkID) { /** * Docker named it EndpointIPAMConfig */ - public static class Ipam implements Serializable { + @EqualsAndHashCode + @ToString + public static class Ipam extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("IPv4Address") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetworkSettings.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetworkSettings.java index 19e249e29..9e8381500 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetworkSettings.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerNetworkSettings.java @@ -15,7 +15,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerNetworkSettings implements Serializable { +public class ContainerNetworkSettings extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerPort.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerPort.java index b22aecc0e..35f9f6ab9 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerPort.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerPort.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerPort implements Serializable { +public class ContainerPort extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("IP") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpec.java index f56399ce8..0a26e54fd 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpec.java @@ -16,7 +16,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerSpec implements Serializable { +public class ContainerSpec extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** @@ -137,7 +137,7 @@ public class ContainerSpec implements Serializable { * @since 1.26 * A test to perform to check that the container is healthy. */ - @JsonProperty("HealthCheck") + @JsonProperty("Healthcheck") private HealthCheck healthCheck; /** @@ -161,6 +161,14 @@ public class ContainerSpec implements Serializable { @JsonProperty("Configs") private List configs; + /** + * @since 1.38 + * Run an init inside the container that forwards signals and reaps processes. + * This field is omitted if empty, and the default (as configured on the daemon) is used. + */ + @JsonProperty("Init") + private Boolean init; + /** * @see #image */ @@ -435,4 +443,13 @@ public ContainerSpec withConfigs(List configs) { this.configs = configs; return this; } + + public Boolean getInit() { + return init; + } + + public ContainerSpec withInit(Boolean init) { + this.init = init; + return this; + } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecConfig.java index 274ad8f55..fbd93b606 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecConfig.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerSpecConfig implements Serializable { +public class ContainerSpecConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("File") private ContainerSpecFile file; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecFile.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecFile.java index cf8471d7c..ac9ef4d81 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecFile.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecFile.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerSpecFile implements Serializable { +public class ContainerSpecFile extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Name") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivileges.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivileges.java index a5bb69391..5d8d7cd55 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivileges.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivileges.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerSpecPrivileges implements Serializable { +public class ContainerSpecPrivileges extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("CredentialSpec") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesCredential.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesCredential.java index 8a4294f01..e6ca62fd4 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesCredential.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesCredential.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerSpecPrivilegesCredential implements Serializable { +public class ContainerSpecPrivilegesCredential extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesSELinuxContext.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesSELinuxContext.java index c7fa68af8..d1b2cc15b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesSELinuxContext.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecPrivilegesSELinuxContext.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerSpecPrivilegesSELinuxContext implements Serializable { +public class ContainerSpecPrivilegesSELinuxContext extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Disable") private Boolean disable; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecSecret.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecSecret.java index e92b2b07f..742272e16 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecSecret.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ContainerSpecSecret.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ContainerSpecSecret implements Serializable { +public class ContainerSpecSecret extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("File") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuStatsConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuStatsConfig.java index fce6e610d..04d91c826 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuStatsConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuStatsConfig.java @@ -1,6 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.annotation.CheckForNull; import java.io.Serializable; @@ -10,7 +12,9 @@ * * @author Yuting Liu */ -public class CpuStatsConfig implements Serializable { +@EqualsAndHashCode +@ToString +public class CpuStatsConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("cpu_usage") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuUsageConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuUsageConfig.java index e9e4d2212..f87afeec8 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuUsageConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/CpuUsageConfig.java @@ -1,6 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.annotation.CheckForNull; import java.io.Serializable; @@ -11,7 +13,9 @@ * * @author Yuting Liu */ -public class CpuUsageConfig implements Serializable { +@EqualsAndHashCode +@ToString +public class CpuUsageConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("total_usage") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Device.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Device.java index 09223e52a..b6f16029e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Device.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Device.java @@ -14,7 +14,7 @@ @EqualsAndHashCode @ToString -public class Device implements Serializable { +public class Device extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("CgroupPermissions") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DeviceRequest.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DeviceRequest.java index 9f8942182..549d51b57 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DeviceRequest.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DeviceRequest.java @@ -10,7 +10,7 @@ @EqualsAndHashCode @ToString -public class DeviceRequest implements Serializable { +public class DeviceRequest extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; @JsonProperty("Driver") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DiscreteResourceSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DiscreteResourceSpec.java index 0771fb180..80feee509 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DiscreteResourceSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DiscreteResourceSpec.java @@ -2,6 +2,7 @@ import java.io.Serializable; +@Deprecated public class DiscreteResourceSpec extends GenericResource implements Serializable { private static final long serialVersionUID = 1L; } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DockerObject.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DockerObject.java new file mode 100644 index 000000000..463dc15a1 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DockerObject.java @@ -0,0 +1,20 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @see DockerObjectAccessor + */ +public abstract class DockerObject { + + HashMap rawValues = new HashMap<>(); + + @JsonAnyGetter + public Map getRawValues() { + return Collections.unmodifiableMap(this.rawValues); + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DockerObjectAccessor.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DockerObjectAccessor.java new file mode 100644 index 000000000..0827c4a34 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DockerObjectAccessor.java @@ -0,0 +1,27 @@ +package com.github.dockerjava.api.model; + +import java.util.HashMap; + +public final class DockerObjectAccessor { + + /** + * @deprecated not for public usage, unless you _really_ understand what you're doing + */ + @Deprecated + public static void overrideRawValues(DockerObject o, HashMap rawValues) { + o.rawValues = rawValues != null ? rawValues : new HashMap<>(); + } + + /** + * This is an advanced method for setting raw values on the resulting object + * that will fully overwrite any previously set value for given key. + * + * Make sure to check Docker's API before using it. + */ + public static void overrideRawValue(DockerObject o, String key, Object value) { + o.rawValues.put(key, value); + } + + private DockerObjectAccessor() { + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Driver.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Driver.java index cde23cb2b..bdc05e53b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Driver.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Driver.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class Driver implements Serializable { +public class Driver extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DriverStatus.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DriverStatus.java index cca52f1d0..57fe32247 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/DriverStatus.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/DriverStatus.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class DriverStatus implements Serializable { +public class DriverStatus extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Root Dir") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Endpoint.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Endpoint.java index eb6c982ed..cebbfea1c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Endpoint.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Endpoint.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class Endpoint implements Serializable { +public class Endpoint extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointSpec.java index 75b5056f0..c0ce386fa 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointSpec.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class EndpointSpec implements Serializable { +public class EndpointSpec extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointVirtualIP.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointVirtualIP.java index fad960fb7..0babfba4c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointVirtualIP.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EndpointVirtualIP.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class EndpointVirtualIP implements Serializable { +public class EndpointVirtualIP extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java index 10c3310d1..63e670772 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ErrorDetail.java @@ -1,10 +1,14 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.io.Serializable; -public class ErrorDetail implements Serializable { +@EqualsAndHashCode +@ToString +public class ErrorDetail extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Event.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Event.java index 59ecc67bd..0eedbc553 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Event.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Event.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class Event implements Serializable { +public class Event extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventActor.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventActor.java index e05414d34..fbcf088f7 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventActor.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventActor.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class EventActor implements Serializable { +public class EventActor extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventType.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventType.java index 697c1e429..b7c64ecc5 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventType.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/EventType.java @@ -11,6 +11,7 @@ * @since 1.24 */ public enum EventType { + CONFIG("config"), /** * @since 1.24 */ @@ -26,7 +27,10 @@ public enum EventType { */ IMAGE("image"), NETWORK("network"), + NODE("node"), PLUGIN("plugin"), + SECRET("secret"), + SERVICE("service"), VOLUME("volume"); private static final Map EVENT_TYPES = new HashMap<>(); diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExposedPorts.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExposedPorts.java index 445cba2de..6f5ae9ebd 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExposedPorts.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExposedPorts.java @@ -1,14 +1,16 @@ package com.github.dockerjava.api.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.ToString; + import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; - +@ToString public class ExposedPorts implements Serializable { private static final long serialVersionUID = 1L; @@ -36,8 +38,9 @@ public static ExposedPorts fromPrimitive(Map object) { @JsonValue public Map toPrimitive() { return Stream.of(exposedPorts).collect(Collectors.toMap( - ExposedPort::toString, - __ -> new Object() + ExposedPort::toString, + __ -> new Object(), + (a, b) -> a )); } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExternalCA.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExternalCA.java index 95a80eb03..3a68410d8 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExternalCA.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ExternalCA.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ExternalCA implements Serializable { +public class ExternalCA extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Frame.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Frame.java index 041e22423..fdd5dd62e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Frame.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Frame.java @@ -8,7 +8,7 @@ * Represents a logging frame. */ @EqualsAndHashCode -public class Frame implements Serializable { +public class Frame extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; private final StreamType streamType; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/GenericResource.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/GenericResource.java index 9b994d8dd..f6ddfabe5 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/GenericResource.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/GenericResource.java @@ -1,10 +1,14 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.io.Serializable; -public abstract class GenericResource implements Serializable { +@EqualsAndHashCode +@ToString +public abstract class GenericResource extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Kind") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/HealthCheck.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/HealthCheck.java index e21a0763f..0e41b873f 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/HealthCheck.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/HealthCheck.java @@ -28,7 +28,7 @@ */ @EqualsAndHashCode @ToString -public class HealthCheck implements Serializable { +public class HealthCheck extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Interval") @@ -55,6 +55,12 @@ public class HealthCheck implements Serializable { @JsonProperty("StartPeriod") private Long startPeriod; + /** + * @since 1.44 + */ + @JsonProperty("StartInterval") + private Long startInterval; + public Long getInterval() { return interval; } @@ -63,11 +69,19 @@ public Long getTimeout() { return timeout; } + /** + * Set interval in nanoseconds + * @return this {@link HealthCheck} instance + */ public HealthCheck withInterval(Long interval) { this.interval = interval; return this; } + /** + * Set timeout in nanoseconds + * @return this {@link HealthCheck} instance + */ public HealthCheck withTimeout(Long timeout) { this.timeout = timeout; return this; @@ -95,8 +109,25 @@ public Long getStartPeriod() { return startPeriod; } + /** + * Set startPeriod in nanoseconds + * @return this {@link HealthCheck} instance + */ public HealthCheck withStartPeriod(Long startPeriod) { this.startPeriod = startPeriod; return this; } + + public Long getStartInterval() { + return startInterval; + } + + /** + * Set startInterval in nanoseconds + * @return this {@link HealthCheck} instance + */ + public HealthCheck withStartInterval(Long startInterval) { + this.startInterval = startInterval; + return this; + } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/HostConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/HostConfig.java index afe38d245..603bc6347 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/HostConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/HostConfig.java @@ -19,7 +19,7 @@ */ @EqualsAndHashCode @ToString -public class HostConfig implements Serializable { +public class HostConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; private static final List PREDEFINED_NETWORKS = Arrays.asList("bridge", "host", "none"); @@ -70,9 +70,12 @@ public static HostConfig newHostConfig() { @JsonProperty("MemorySwappiness") private Long memorySwappiness; - @JsonProperty("NanoCPUs") + @JsonProperty("NanoCpus") private Long nanoCPUs; + @JsonProperty("Annotations") + private Map annotations; + @JsonProperty("CapAdd") private Capability[] capAdd; @@ -292,6 +295,9 @@ public static HostConfig newHostConfig() { @JsonProperty("ConsoleSize") private List consoleSize; + @JsonProperty("CgroupnsMode") + private String cgroupnsMode; + @JsonIgnore public Bind[] getBinds() { return (binds == null) ? new Bind[0] : binds.getBinds(); @@ -301,6 +307,11 @@ public Integer getBlkioWeight() { return blkioWeight; } + @CheckForNull + public Map getAnnotations() { + return annotations; + } + public Capability[] getCapAdd() { return capAdd; } @@ -633,6 +644,11 @@ public HostConfig withBlkioWeightDevice(List blkioWeightDevic return this; } + public HostConfig withAnnotations(Map annotations) { + this.annotations = annotations; + return this; + } + /** * @see #capAdd */ @@ -845,6 +861,7 @@ public HostConfig withMemorySwappiness(Long memorySwappiness) { *
  • 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system * services such as D-bus and is therefore considered insecure.
  • * + * Any other value is interpreted as a custom network's name for this container to connect to. */ public HostConfig withNetworkMode(String networkMode) { this.networkMode = networkMode; @@ -1193,6 +1210,16 @@ public HostConfig withUsernsMode(String usernsMode) { return this; } + @CheckForNull + public String getCgroupnsMode() { + return cgroupnsMode; + } + + public HostConfig withCgroupnsMode(String cgroupnsMode) { + this.cgroupnsMode = cgroupnsMode; + return this; + } + @CheckForNull public Map getSysctls() { return sysctls; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Identifier.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Identifier.java index c214a8b16..a690548b4 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Identifier.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Identifier.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class Identifier implements Serializable { +public class Identifier extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; public final Repository repository; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Image.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Image.java index e6552eb35..732dcfe4f 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Image.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Image.java @@ -1,10 +1,12 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; + import lombok.EqualsAndHashCode; import lombok.ToString; import java.io.Serializable; +import java.util.Map; /** * @@ -13,7 +15,7 @@ */ @EqualsAndHashCode @ToString -public class Image implements Serializable { +public class Image extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Created") @@ -28,12 +30,24 @@ public class Image implements Serializable { @JsonProperty("RepoTags") private String[] repoTags; + @JsonProperty("RepoDigests") + private String[] repoDigests; + @JsonProperty("Size") private Long size; @JsonProperty("VirtualSize") private Long virtualSize; + @JsonProperty("SharedSize") + private Long sharedSize; + + @JsonProperty("Labels") + public Map labels; + + @JsonProperty("Containers") + private Integer containers; + public String getId() { return id; } @@ -42,6 +56,10 @@ public String[] getRepoTags() { return repoTags; } + public String[] getRepoDigests() { + return repoDigests; + } + public String getParentId() { return parentId; } @@ -57,4 +75,17 @@ public Long getSize() { public Long getVirtualSize() { return virtualSize; } + + + public Long getSharedSize() { + return sharedSize; + } + + public Map getLabels() { + return labels; + } + + public Integer getContainers() { + return containers; + } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ImageHistory.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ImageHistory.java new file mode 100644 index 000000000..fb8f5d95c --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ImageHistory.java @@ -0,0 +1,97 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.annotation.CheckForNull; +import java.io.Serializable; +import java.util.List; + +/** + * Represents an individual image layer information in response to the ImageHistory operation. + */ +@EqualsAndHashCode +@ToString +public class ImageHistory extends DockerObject implements Serializable { + + private static final long serialVersionUID = 1L; + + @JsonProperty("Id") + private String id; + + @JsonProperty("Created") + private Long created; + + @JsonProperty("CreatedBy") + private String createdBy; + + @JsonProperty("Tags") + private List tags; + + @JsonProperty("Size") + private Long size; + + @JsonProperty("Comment") + private String comment; + + @CheckForNull + public String getId() { + return id; + } + + public ImageHistory withId(String id) { + this.id = id; + return this; + } + + @CheckForNull + public Long getCreated() { + return created; + } + + public ImageHistory withCreated(Long created) { + this.created = created; + return this; + } + + @CheckForNull + public String getCreatedBy() { + return createdBy; + } + + public ImageHistory withCreatedBy(String createdBy) { + this.createdBy = createdBy; + return this; + } + + @CheckForNull + public List getTags() { + return tags; + } + + public ImageHistory withTags(List tags) { + this.tags = tags; + return this; + } + + @CheckForNull + public Long getSize() { + return size; + } + + public ImageHistory withSize(Long size) { + this.size = size; + return this; + } + + @CheckForNull + public String getComment() { + return comment; + } + + public ImageHistory withComment(String comment) { + this.comment = comment; + return this; + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ImageOptions.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ImageOptions.java new file mode 100644 index 000000000..bc8b89acb --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ImageOptions.java @@ -0,0 +1,27 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * @since {@link RemoteApiVersion#VERSION_1_48} + */ +@EqualsAndHashCode +@ToString +public class ImageOptions extends DockerObject implements Serializable { + private static final long serialVersionUID = 1L; + @JsonProperty("Subpath") + private String subpath; + + public String getSubpath() { + return subpath; + } + + public ImageOptions withSubpath(String subpath) { + this.subpath = subpath; + return this; + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Info.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Info.java index e472fa622..67348b86b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Info.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Info.java @@ -16,7 +16,7 @@ */ @EqualsAndHashCode @ToString -public class Info implements Serializable { +public class Info extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** @@ -97,6 +97,12 @@ public class Info implements Serializable { @JsonProperty("LoggingDriver") private String loggingDriver; + @JsonProperty("CgroupDriver") + private String cGroupDriver; + + @JsonProperty("CgroupVersion") + private String cGroupVersion; + /** * @since {@link com.github.dockerjava.core.RemoteApiVersion#VERSION_1_20} */ @@ -232,6 +238,12 @@ public class Info implements Serializable { @JsonProperty("Isolation") private String isolation; + @JsonProperty("SecurityOptions") + private List securityOptions; + + @JsonProperty("Runtimes") + private Map runtimes; + /** * @see #architecture */ @@ -480,6 +492,22 @@ public String getLoggingDriver() { return loggingDriver; } + /** + * @see #cGroupDriver + */ + @CheckForNull + public String getCGroupDriver() { + return cGroupDriver; + } + + /** + * @see #cGroupVersion + */ + @CheckForNull + public String getCGroupVersion() { + return cGroupVersion; + } + /** * @see #loggingDriver */ @@ -488,6 +516,22 @@ public Info withLoggingDriver(String loggingDriver) { return this; } + /** + * @see #cGroupDriver + */ + public Info withCGroupDriver(String cGroupDriver) { + this.cGroupDriver = cGroupDriver; + return this; + } + + /** + * @see #cGroupVersion + */ + public Info withCGroupVersion(String cGroupVersion) { + this.cGroupVersion = cGroupVersion; + return this; + } + /** * @see #experimentalBuild */ @@ -1063,4 +1107,34 @@ public Info withIsolation(String isolation) { this.isolation = isolation; return this; } + + /** + * @see #securityOptions + */ + public List getSecurityOptions() { + return securityOptions; + } + + /** + * @see #securityOptions + */ + public Info withSecurityOptions(List securityOptions) { + this.securityOptions = securityOptions; + return this; + } + + /** + * @see #runtimes + */ + public Map getRuntimes() { + return runtimes; + } + + /** + * @see #runtimes + */ + public Info withRuntimes(Map runtimes) { + this.runtimes = runtimes; + return this; + } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/InfoRegistryConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/InfoRegistryConfig.java index 113a4af0a..80bf803d8 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/InfoRegistryConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/InfoRegistryConfig.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public final class InfoRegistryConfig implements Serializable { +public final class InfoRegistryConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("IndexConfigs") @@ -82,7 +82,7 @@ public InfoRegistryConfig withMirrors(Object mirrors) { */ @EqualsAndHashCode @ToString - public static final class IndexConfig implements Serializable { + public static final class IndexConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Mirrors") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Link.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Link.java index 20b2c1b26..4b9b27acf 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Link.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Link.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.model; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.io.Serializable; @@ -10,7 +11,8 @@ * variables in the target container as well as creating a network bridge between both containers. */ @EqualsAndHashCode -public class Link implements Serializable { +@ToString +public class Link extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; private final String name; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/LoadResponseItem.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/LoadResponseItem.java new file mode 100644 index 000000000..bf90c69bf --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/LoadResponseItem.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class LoadResponseItem extends ResponseItem { + + private static final long serialVersionUID = 1L; + + private static final String IMPORT_SUCCESS = "Loaded image:"; + + /** + * Returns whether the stream field indicates a successful build operation + */ + @JsonIgnore + public boolean isBuildSuccessIndicated() { + if (isErrorIndicated() || getStream() == null) { + return false; + } + + return getStream().contains(IMPORT_SUCCESS); + } + + @JsonIgnore + public String getMessage() { + if (!isBuildSuccessIndicated()) { + return null; + } else if (getStream().contains(IMPORT_SUCCESS)) { + return getStream(); + } + + return null; + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/LogConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/LogConfig.java index c2cd0efc8..218cdd827 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/LogConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/LogConfig.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.annotation.CheckForNull; import java.io.Serializable; @@ -18,7 +20,9 @@ * docker will ignore them. In most cases setting the config option to null will suffice. Consult the docker remote API for a more detailed * and up-to-date explanation of the available types and their options. */ -public class LogConfig implements Serializable { +@EqualsAndHashCode +@ToString +public class LogConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Type") @@ -72,7 +76,8 @@ public enum LoggingType { AWSLOGS("awslogs"), DB("db"), // Synology specific driver SPLUNK("splunk"), - GCPLOGS("gcplogs"); + GCPLOGS("gcplogs"), + LOKI("loki"); private String type; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/LxcConf.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/LxcConf.java index ddf1bbae0..36fc1a9cb 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/LxcConf.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/LxcConf.java @@ -1,10 +1,14 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.io.Serializable; -public class LxcConf implements Serializable { +@EqualsAndHashCode +@ToString +public class LxcConf extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Key") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/MemoryStatsConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/MemoryStatsConfig.java index 12e6abccf..b57f05135 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/MemoryStatsConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/MemoryStatsConfig.java @@ -1,6 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.annotation.CheckForNull; import java.io.Serializable; @@ -10,7 +12,9 @@ * * @author Yuting Liu */ -public class MemoryStatsConfig implements Serializable { +@EqualsAndHashCode +@ToString +public class MemoryStatsConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("stats") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Mount.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Mount.java index 7254ccb19..3f17343c3 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Mount.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Mount.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class Mount implements Serializable { +public class Mount extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** @@ -57,6 +57,12 @@ public class Mount implements Serializable { @JsonProperty("TmpfsOptions") private TmpfsOptions tmpfsOptions; + /** + * @since 1.48 + */ + @JsonProperty("ImageOptions") + private ImageOptions imageOptions; + /** * @see #type */ @@ -177,4 +183,23 @@ public Mount withTmpfsOptions(TmpfsOptions tmpfsOptions) { } return this; } + + /** + * @see #imageOptions + */ + @CheckForNull + public ImageOptions getImageOptions() { + return imageOptions; + } + + /** + * @see #imageOptions + */ + public Mount withImageOptions(ImageOptions imageOptions) { + this.imageOptions = imageOptions; + if (imageOptions != null) { + this.type = MountType.IMAGE; + } + return this; + } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/MountType.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/MountType.java index 62557df47..b522c9612 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/MountType.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/MountType.java @@ -14,6 +14,14 @@ public enum MountType { //@since 1.29 @JsonProperty("tmpfs") - TMPFS + TMPFS, + + //@since 1.40 + @JsonProperty("npipe") + NPIPE, + + //@since 1.48 + @JsonProperty("image") + IMAGE, } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/NamedResourceSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/NamedResourceSpec.java index e06f69d01..198c75543 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/NamedResourceSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/NamedResourceSpec.java @@ -5,6 +5,7 @@ /** * @since {@link RemoteApiVersion#VERSION_1_24} */ +@Deprecated public class NamedResourceSpec extends GenericResource implements Serializable { private static final long serialVersionUID = 1L; } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Network.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Network.java index 852746924..7e9d3b2fd 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Network.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Network.java @@ -7,17 +7,21 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.List; import java.util.Map; @EqualsAndHashCode @ToString -public class Network implements Serializable { +public class Network extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Id") private String id; + @JsonProperty("Created") + private Date created; + @JsonProperty("Name") private String name; @@ -52,6 +56,10 @@ public String getId() { return id; } + public Date getCreated() { + return created; + } + public String getName() { return name; } @@ -94,9 +102,15 @@ public Map getLabels() { @EqualsAndHashCode @ToString - public static class ContainerNetworkConfig implements Serializable { + public static class ContainerNetworkConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; + /** + * @since {@link RemoteApiVersion#VERSION_1_22} + */ + @JsonProperty("Name") + private String name; + @JsonProperty("EndpointID") private String endpointId; @@ -109,6 +123,10 @@ public static class ContainerNetworkConfig implements Serializable { @JsonProperty("IPv6Address") private String ipv6Address; + public String getName() { + return name; + } + public String getEndpointId() { return endpointId; } @@ -128,7 +146,7 @@ public String getIpv6Address() { @EqualsAndHashCode @ToString - public static class Ipam implements Serializable { + public static class Ipam extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Driver") @@ -167,7 +185,9 @@ public Ipam withDriver(String driver) { return this; } - public static class Config implements Serializable { + @EqualsAndHashCode + @ToString + public static class Config extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Subnet") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkAttachmentConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkAttachmentConfig.java index 2afa87b73..db0eb1ded 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkAttachmentConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkAttachmentConfig.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class NetworkAttachmentConfig implements Serializable { +public class NetworkAttachmentConfig extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkSettings.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkSettings.java index 3ef92ac64..e28d8f52c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkSettings.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/NetworkSettings.java @@ -17,7 +17,7 @@ */ @EqualsAndHashCode @ToString -public class NetworkSettings implements Serializable { +public class NetworkSettings extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Bridge") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Node.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Node.java index 2b12ab48f..2bb832e48 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Node.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Node.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class Node implements Serializable { +public class Node extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Name") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ObjectVersion.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ObjectVersion.java index 0b0259049..5fa361977 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ObjectVersion.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ObjectVersion.java @@ -1,6 +1,7 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; import java.io.Serializable; @@ -13,7 +14,8 @@ * same base version, only one of the requests can succeed. As a result, two separate update requests that * happen at the same time will not unintentionally overwrite each other. */ -public class ObjectVersion implements Serializable { +@EqualsAndHashCode +public class ObjectVersion extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Index") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PeerNode.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PeerNode.java index e20af63b9..8937b9593 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PeerNode.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PeerNode.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class PeerNode implements Serializable { +public class PeerNode extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PidsStatsConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PidsStatsConfig.java index c3d13596f..df953e140 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PidsStatsConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PidsStatsConfig.java @@ -1,6 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.annotation.CheckForNull; import java.io.Serializable; @@ -10,7 +12,9 @@ * * @author Yuting Liu */ -public class PidsStatsConfig implements Serializable { +@EqualsAndHashCode +@ToString +public class PidsStatsConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("current") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortBinding.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortBinding.java index 47655079b..2b7901e92 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortBinding.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortBinding.java @@ -17,7 +17,7 @@ */ @EqualsAndHashCode @ToString -public class PortBinding implements Serializable { +public class PortBinding extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; private final Binding binding; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortConfig.java index 57f2f61b0..cec07d9cd 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PortConfig.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class PortConfig implements Serializable { +public class PortConfig extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ports.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ports.java index 897261a09..0411ca218 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ports.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ports.java @@ -21,7 +21,6 @@ * @see HostConfig#getPortBindings() * @see NetworkSettings#getPorts() */ -@SuppressWarnings(value = "checkstyle:equalshashcode") public class Ports implements Serializable { private static final long serialVersionUID = 1L; @@ -107,7 +106,7 @@ public Map getBindings() { * @see ExposedPort */ @EqualsAndHashCode - public static class Binding implements Serializable { + public static class Binding extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PropagationMode.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PropagationMode.java index 9be7d6e43..3e1db4438 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PropagationMode.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PropagationMode.java @@ -13,11 +13,20 @@ public enum PropagationMode { /** shared */ SHARED("shared"), + /** rshared */ + RSHARED("rshared"), + /** slave */ SLAVE("slave"), + /** rslave */ + RSLAVE("rslave"), + /** private */ - PRIVATE("private"); + PRIVATE("private"), + + /** rprivate */ + RPRIVATE("rprivate"); /** * The default {@link PropagationMode}: {@link #DEFAULT} @@ -39,10 +48,16 @@ public static PropagationMode fromString(String v) { switch (v) { case "shared": return SHARED; + case "rshared": + return RSHARED; case "slave": return SLAVE; + case "rslave": + return RSLAVE; case "private": return PRIVATE; + case "rprivate": + return RPRIVATE; default: return DEFAULT; } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PruneResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PruneResponse.java index 3efaf47c1..2ccdf72c4 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PruneResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PruneResponse.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class PruneResponse implements Serializable { +public class PruneResponse extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("SpaceReclaimed") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PullResponseItem.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PullResponseItem.java index 66a559934..1d3f33c8e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/PullResponseItem.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/PullResponseItem.java @@ -19,6 +19,8 @@ public class PullResponseItem extends ResponseItem { private static final String DOWNLOADED_SWARM = ": downloaded"; + private static final String ALREADY_EXISTS = "Already exists"; + /** * Returns whether the status indicates a successful pull operation * @@ -34,7 +36,8 @@ public boolean isPullSuccessIndicated() { getStatus().contains(IMAGE_UP_TO_DATE) || getStatus().contains(DOWNLOADED_NEWER_IMAGE) || getStatus().contains(LEGACY_REGISTRY) || - getStatus().contains(DOWNLOADED_SWARM) + getStatus().contains(DOWNLOADED_SWARM) || + getStatus().contains(ALREADY_EXISTS) ); } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Repository.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Repository.java index 750eb6f4d..5dd636981 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Repository.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Repository.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class Repository implements Serializable { +public class Repository extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; public final String name; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceRequirements.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceRequirements.java index 463b22011..54e3001b8 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceRequirements.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceRequirements.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class ResourceRequirements implements Serializable { +public class ResourceRequirements extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceSpecs.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceSpecs.java index 86ab24b52..00f2de7e1 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceSpecs.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceSpecs.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class ResourceSpecs implements Serializable { +public class ResourceSpecs extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceVersion.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceVersion.java index 4838b78d7..babee6a50 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceVersion.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResourceVersion.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class ResourceVersion implements Serializable { +public class ResourceVersion extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResponseItem.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResponseItem.java index d0f797a71..cd90b78f3 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResponseItem.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ResponseItem.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ResponseItem implements Serializable { +public class ResponseItem extends DockerObject implements Serializable { private static final long serialVersionUID = -5187169652557467828L; @JsonProperty("stream") @@ -118,7 +118,7 @@ public boolean isErrorIndicated() { @EqualsAndHashCode @ToString - public static class ProgressDetail implements Serializable { + public static class ProgressDetail extends DockerObject implements Serializable { private static final long serialVersionUID = -1954994695645715264L; @JsonProperty("current") @@ -148,7 +148,7 @@ public Long getStart() { @EqualsAndHashCode @ToString - public static class ErrorDetail implements Serializable { + public static class ErrorDetail extends DockerObject implements Serializable { private static final long serialVersionUID = -9136704865403084083L; @JsonProperty("code") @@ -170,7 +170,7 @@ public String getMessage() { @EqualsAndHashCode @ToString - public static class AuxDetail implements Serializable { + public static class AuxDetail extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Size") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java index 114d9f0d8..53453915c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/RestartPolicy.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.io.Serializable; @@ -27,7 +28,8 @@ * */ @EqualsAndHashCode -public class RestartPolicy implements Serializable { +@ToString +public class RestartPolicy extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("MaximumRetryCount") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/RuntimeInfo.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/RuntimeInfo.java new file mode 100644 index 000000000..c64511cda --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/RuntimeInfo.java @@ -0,0 +1,23 @@ +package com.github.dockerjava.api.model; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +@EqualsAndHashCode +@ToString +public class RuntimeInfo extends DockerObject implements Serializable { + private static final long serialVersionUID = 1L; + + private String path; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SearchItem.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SearchItem.java index a77f38053..23a5c3bbf 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SearchItem.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SearchItem.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SearchItem implements Serializable { +public class SearchItem extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("star_count") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Secret.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Secret.java index 20680f5fb..bfbd7caf4 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Secret.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Secret.java @@ -1,6 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.io.Serializable; import java.util.Date; @@ -10,7 +12,9 @@ * * @since {@link RemoteApiVersion#VERSION_1_25} */ -public class Secret implements Serializable { +@EqualsAndHashCode +@ToString +public class Secret extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SecretSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SecretSpec.java index 572c0c90e..6b10239b9 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SecretSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SecretSpec.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class SecretSpec implements Serializable { +public class SecretSpec extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Service.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Service.java index 63b3b4757..fd76be259 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Service.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Service.java @@ -15,7 +15,7 @@ */ @EqualsAndHashCode @ToString -public class Service implements Serializable { +public class Service extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceGlobalModeOptions.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceGlobalModeOptions.java index ccd9b4bea..37feec292 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceGlobalModeOptions.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceGlobalModeOptions.java @@ -11,7 +11,7 @@ @EqualsAndHashCode @ToString @SuppressWarnings("checkstyle:hideutilityclassconstructor") -public class ServiceGlobalModeOptions implements Serializable { +public class ServiceGlobalModeOptions extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; // Intentionally left blank, there are no options for this mode diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceModeConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceModeConfig.java index c179271bf..82d1b3b20 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceModeConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceModeConfig.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class ServiceModeConfig implements Serializable { +public class ServiceModeConfig extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServicePlacement.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServicePlacement.java index 9c2f0223a..4c0953508 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServicePlacement.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServicePlacement.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ServicePlacement implements Serializable { +public class ServicePlacement extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** @@ -28,6 +28,12 @@ public class ServicePlacement implements Serializable { @JsonProperty("Platforms") private List platforms; + /** + * @since 1.40 + */ + @JsonProperty("MaxReplicas") + private Integer maxReplicas; + /** * @see #constraints */ @@ -54,4 +60,31 @@ public List getPlatforms() { public void setPlatforms(List platforms) { this.platforms = platforms; } + + /** + * Specifies the maximum amount of replicas / tasks that can run on one node. + * 0 means unlimited replicas per node. + * + * @param maxReplicas Max number of replicas + * @return This instance of ServicePlacement + * @throws IllegalArgumentException if maxReplicas is less than 0 + */ + public ServicePlacement withMaxReplicas(int maxReplicas) { + if (maxReplicas < 0) { + throw new IllegalArgumentException("The Value for MaxReplicas must be greater or equal to 0"); + } + + this.maxReplicas = maxReplicas; + return this; + } + + /** + * Getter for maxReplicas + * + * @return The maximum amount of replicas / tasks that can run on one node. + */ + public Integer getMaxReplicas() { + return this.maxReplicas; + } + } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceReplicatedModeOptions.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceReplicatedModeOptions.java index c28a09370..eea2a5211 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceReplicatedModeOptions.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceReplicatedModeOptions.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class ServiceReplicatedModeOptions implements Serializable { +public class ServiceReplicatedModeOptions extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceRestartPolicy.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceRestartPolicy.java index 8b55315e0..11b54f666 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceRestartPolicy.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceRestartPolicy.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class ServiceRestartPolicy implements Serializable { +public class ServiceRestartPolicy extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceSpec.java index b5ca4a5dd..a1fbec916 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceSpec.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class ServiceSpec implements Serializable { +public class ServiceSpec extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateState.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateState.java index e748bbd4a..d22f8999e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateState.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateState.java @@ -6,6 +6,9 @@ * @since {@link RemoteApiVersion#VERSION_1_24} */ public enum ServiceUpdateState { + @JsonProperty("unknown") + UNKNOWN, + @JsonProperty("updating") UPDATING, @@ -15,6 +18,12 @@ public enum ServiceUpdateState { @JsonProperty("completed") COMPLETED, + @JsonProperty("rollback_started") + ROLLBACK_STARTED, + + @JsonProperty("rollback_paused") + ROLLBACK_PAUSED, + @JsonProperty("rollback_completed") ROLLBACK_COMPLETED } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateStatus.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateStatus.java index ee457d9f8..18cb54603 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateStatus.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ServiceUpdateStatus.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class ServiceUpdateStatus implements Serializable { +public class ServiceUpdateStatus extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatisticNetworksConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatisticNetworksConfig.java index d22b6a787..2ba57d76b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatisticNetworksConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatisticNetworksConfig.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class StatisticNetworksConfig implements Serializable { +public class StatisticNetworksConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("rx_bytes") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Statistics.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Statistics.java index f28ea983a..3800363eb 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Statistics.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Statistics.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class Statistics implements Serializable { +public class Statistics extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("read") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatsConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatsConfig.java index 19b95a7ff..8afbc34d9 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatsConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/StatsConfig.java @@ -1,11 +1,15 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.annotation.CheckForNull; import java.io.Serializable; -public class StatsConfig implements Serializable { +@EqualsAndHashCode +@ToString +public class StatsConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("active_anon") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmCAConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmCAConfig.java index 6f632aa1b..8ebc97ffd 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmCAConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmCAConfig.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmCAConfig implements Serializable { +public class SwarmCAConfig extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmDispatcherConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmDispatcherConfig.java index bc8fd4305..2a45b84cd 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmDispatcherConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmDispatcherConfig.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmDispatcherConfig implements Serializable { +public class SwarmDispatcherConfig extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmInfo.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmInfo.java index 3fd8e8704..faed0fcf3 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmInfo.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmInfo.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmInfo implements Serializable { +public class SwarmInfo extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmJoinTokens.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmJoinTokens.java index 06b1f3a78..9e5f63aea 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmJoinTokens.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmJoinTokens.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmJoinTokens implements Serializable { +public class SwarmJoinTokens extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNode.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNode.java index cdb17c20d..9b5aff96c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNode.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNode.java @@ -16,7 +16,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNode implements Serializable { +public class SwarmNode extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeDescription.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeDescription.java index d0c35c873..f929327d1 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeDescription.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeDescription.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodeDescription implements Serializable { +public class SwarmNodeDescription extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeEngineDescription.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeEngineDescription.java index 41c369d09..a2f38531e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeEngineDescription.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeEngineDescription.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodeEngineDescription implements Serializable { +public class SwarmNodeEngineDescription extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeManagerStatus.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeManagerStatus.java index 07a0e448b..0307d18e7 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeManagerStatus.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeManagerStatus.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodeManagerStatus implements Serializable { +public class SwarmNodeManagerStatus extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePlatform.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePlatform.java index 3b3747d5f..9688f10b0 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePlatform.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePlatform.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodePlatform implements Serializable { +public class SwarmNodePlatform extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePluginDescription.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePluginDescription.java index d05bfb9c9..aa051aaa3 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePluginDescription.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodePluginDescription.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodePluginDescription implements Serializable { +public class SwarmNodePluginDescription extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeResources.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeResources.java index 05f6d0203..c9586e921 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeResources.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeResources.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodeResources implements Serializable { +public class SwarmNodeResources extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeSpec.java index 5162bdff7..241c2be58 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeSpec.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodeSpec implements Serializable { +public class SwarmNodeSpec extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeStatus.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeStatus.java index ba99a194a..34f40e80b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeStatus.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeStatus.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodeStatus implements Serializable { +public class SwarmNodeStatus extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** @@ -22,6 +22,12 @@ public class SwarmNodeStatus implements Serializable { @JsonProperty("State") private SwarmNodeState state; + /** + * @since 1.25 + */ + @JsonProperty("Addr") + private String address; + /** * @see #state */ @@ -37,4 +43,20 @@ public SwarmNodeStatus withState(SwarmNodeState state) { this.state = state; return this; } + + /** + * @see #address + */ + @CheckForNull + public String getAddress() { + return address; + } + + /** + * @see #address + */ + public SwarmNodeStatus withAddress(String address) { + this.address = address; + return this; + } } diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeVersion.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeVersion.java index 35cbba491..4182c120e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeVersion.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmNodeVersion.java @@ -14,7 +14,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmNodeVersion implements Serializable { +public class SwarmNodeVersion extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmOrchestration.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmOrchestration.java index 60cc1f32d..0479a3a6c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmOrchestration.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmOrchestration.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmOrchestration implements Serializable { +public class SwarmOrchestration extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmRaftConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmRaftConfig.java index 16553defc..69138ed2d 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmRaftConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmRaftConfig.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmRaftConfig implements Serializable { +public class SwarmRaftConfig extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmSpec.java index bbc8f6db6..ee041a2a7 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmSpec.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmSpec implements Serializable { +public class SwarmSpec extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmVersion.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmVersion.java index 2d7fc3e43..161c0d7e5 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmVersion.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/SwarmVersion.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class SwarmVersion implements Serializable { +public class SwarmVersion extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Task.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Task.java index 46585eed8..0f1e77a2a 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Task.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Task.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class Task implements Serializable { +public class Task extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("ID") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskDefaults.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskDefaults.java index c385bd1b9..ae03c2136 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskDefaults.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskDefaults.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class TaskDefaults implements Serializable { +public class TaskDefaults extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskSpec.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskSpec.java index bef5e579d..c60ca3b8d 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskSpec.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskSpec.java @@ -13,7 +13,7 @@ */ @EqualsAndHashCode @ToString -public class TaskSpec implements Serializable { +public class TaskSpec extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatus.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatus.java index a335350e4..9ae2a72ad 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatus.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatus.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class TaskStatus implements Serializable { +public class TaskStatus extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Timestamp") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatusContainerStatus.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatusContainerStatus.java index 0349e301f..1f6f61d1d 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatusContainerStatus.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TaskStatusContainerStatus.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class TaskStatusContainerStatus implements Serializable { +public class TaskStatusContainerStatus extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("ContainerID") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ThrottlingDataConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ThrottlingDataConfig.java index ce29b7057..e908ce8de 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/ThrottlingDataConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/ThrottlingDataConfig.java @@ -1,6 +1,8 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import javax.annotation.CheckForNull; import java.io.Serializable; @@ -10,7 +12,9 @@ * * @author Yuting Liu */ -public class ThrottlingDataConfig implements Serializable { +@EqualsAndHashCode +@ToString +public class ThrottlingDataConfig extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("periods") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TmpfsOptions.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TmpfsOptions.java index b2dc02a30..e64adaac2 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/TmpfsOptions.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/TmpfsOptions.java @@ -11,7 +11,7 @@ */ @EqualsAndHashCode @ToString -public class TmpfsOptions implements Serializable { +public class TmpfsOptions extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("SizeBytes") //The size for the tmpfs mount in bytes. diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ulimit.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ulimit.java index ab21cb36f..24dbd764e 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ulimit.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Ulimit.java @@ -17,7 +17,7 @@ @JsonPropertyOrder({"Name", "Soft", "Hard"}) @EqualsAndHashCode @ToString -public class Ulimit implements Serializable { +public class Ulimit extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("Name") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/UpdateConfig.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/UpdateConfig.java index ee5d4a740..a70e137a9 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/UpdateConfig.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/UpdateConfig.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class UpdateConfig implements Serializable { +public class UpdateConfig extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Version.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Version.java index 2ac89e88b..1a05726fc 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Version.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Version.java @@ -17,7 +17,7 @@ */ @EqualsAndHashCode @ToString -public class Version implements Serializable { +public class Version extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("ApiVersion") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionComponent.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionComponent.java index bee6774ba..9a9fb9071 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionComponent.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionComponent.java @@ -16,7 +16,7 @@ */ @EqualsAndHashCode @ToString -public class VersionComponent implements Serializable { +public class VersionComponent extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; @JsonProperty("Details") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionPlatform.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionPlatform.java index 96b389ef6..72d29a44b 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionPlatform.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VersionPlatform.java @@ -15,7 +15,7 @@ */ @EqualsAndHashCode @ToString -public class VersionPlatform implements Serializable { +public class VersionPlatform extends DockerObject implements Serializable { public static final long serialVersionUID = 1L; @JsonProperty("Name") diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBind.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBind.java index f78fc587e..93c106070 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBind.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBind.java @@ -1,8 +1,11 @@ package com.github.dockerjava.api.model; +import lombok.EqualsAndHashCode; + import java.io.Serializable; -public class VolumeBind implements Serializable { +@EqualsAndHashCode +public class VolumeBind extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; private final String hostPath; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBinds.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBinds.java index 6de15ee38..1fbc0ca12 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBinds.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeBinds.java @@ -7,7 +7,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import lombok.ToString; +@ToString public class VolumeBinds implements Serializable { private static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeOptions.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeOptions.java index f0d98fc25..740ffcd51 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeOptions.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumeOptions.java @@ -12,7 +12,7 @@ */ @EqualsAndHashCode @ToString -public class VolumeOptions implements Serializable { +public class VolumeOptions extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; /** diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Volumes.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Volumes.java index 2badd1ca8..825b8481a 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/Volumes.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/Volumes.java @@ -8,7 +8,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import lombok.ToString; +@ToString public class Volumes implements Serializable { private static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumesRW.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumesRW.java index 8afd3e230..93e95b68c 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumesRW.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/VolumesRW.java @@ -7,8 +7,10 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import lombok.ToString; // This is not going to be serialized +@ToString public class VolumesRW implements Serializable { private static final long serialVersionUID = 1L; diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/WaitContainerCondition.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/WaitContainerCondition.java new file mode 100644 index 000000000..8af0efa35 --- /dev/null +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/WaitContainerCondition.java @@ -0,0 +1,26 @@ +package com.github.dockerjava.api.model; + +import javax.annotation.Nonnull; + +/** + * Docker Engine API wait conditions (added in v1.30). + * + * @since {@link RemoteApiVersion#VERSION_1_30} + */ +public enum WaitContainerCondition { + NOT_RUNNING("not-running"), + NEXT_EXIT("next-exit"), + REMOVED("removed"); + + @Nonnull + private final String value; + + WaitContainerCondition(@Nonnull String value) { + this.value = value; + } + + @Nonnull + public String getValue() { + return value; + } +} diff --git a/docker-java-api/src/main/java/com/github/dockerjava/api/model/WaitResponse.java b/docker-java-api/src/main/java/com/github/dockerjava/api/model/WaitResponse.java index d80343057..eed22870f 100644 --- a/docker-java-api/src/main/java/com/github/dockerjava/api/model/WaitResponse.java +++ b/docker-java-api/src/main/java/com/github/dockerjava/api/model/WaitResponse.java @@ -1,13 +1,17 @@ package com.github.dockerjava.api.model; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.io.Serializable; /** * Represents a wait container command response */ -public class WaitResponse implements Serializable { +@EqualsAndHashCode +@ToString +public class WaitResponse extends DockerObject implements Serializable { private static final long serialVersionUID = 1L; @JsonProperty("StatusCode") diff --git a/docker-java-api/src/test/java/com/github/dockerjava/api/model/DockerObjectArchTest.java b/docker-java-api/src/test/java/com/github/dockerjava/api/model/DockerObjectArchTest.java new file mode 100644 index 000000000..2df7051e9 --- /dev/null +++ b/docker-java-api/src/test/java/com/github/dockerjava/api/model/DockerObjectArchTest.java @@ -0,0 +1,46 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.CreateConfigResponse; +import com.github.dockerjava.api.command.DockerCmdExecFactory; +import com.tngtech.archunit.base.DescribedPredicate; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.core.importer.ImportOption; +import org.junit.jupiter.api.Test; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; + +class DockerObjectArchTest { + + static JavaClasses CLASSES = new ClassFileImporter() + .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) + .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) + .importPackagesOf( + Container.class, + CreateConfigResponse.class + ); + + @Test + void modelClassMustExtendDockerObject() { + classes() + .that().areNotEnums() + .and().areNotInterfaces() + .and().areNotAnnotatedWith(Deprecated.class) + .and().doNotImplement(ResultCallback.class) + .and().doNotImplement(DockerCmdExecFactory.class) + .and().doNotBelongToAnyOf(DockerObjectAccessor.class) + .and(new DescribedPredicate("not @JsonCreator-based object") { + @Override + public boolean apply(JavaClass input) { + return input.getAllMethods().stream().noneMatch(method -> { + return method.isAnnotatedWith(JsonCreator.class); + }); + } + }) + .should().beAssignableTo(DockerObject.class) + .check(CLASSES); + } +} diff --git a/docker-java-bom/pom.xml b/docker-java-bom/pom.xml new file mode 100644 index 000000000..7066b3a67 --- /dev/null +++ b/docker-java-bom/pom.xml @@ -0,0 +1,67 @@ + + 4.0.0 + + + com.github.docker-java + docker-java-parent + 0-SNAPSHOT + ../pom.xml + + + docker-java-bom + pom + + docker-java + https://github.com/docker-java/docker-java + Java API Client for Docker + + + + + ${project.groupId} + docker-java + ${project.version} + + + ${project.groupId} + docker-java-api + ${project.version} + + + ${project.groupId} + docker-java-core + ${project.version} + + + ${project.groupId} + docker-java-transport + ${project.version} + + + ${project.groupId} + docker-java-transport-httpclient5 + ${project.version} + + + ${project.groupId} + docker-java-transport-jersey + ${project.version} + + + ${project.groupId} + docker-java-transport-netty + ${project.version} + + + ${project.groupId} + docker-java-transport-okhttp + ${project.version} + + + ${project.groupId} + docker-java-transport-zerodep + ${project.version} + + + + diff --git a/docker-java-core/pom.xml b/docker-java-core/pom.xml index ed77c9db7..89c72c024 100644 --- a/docker-java-core/pom.xml +++ b/docker-java-core/pom.xml @@ -4,7 +4,7 @@ com.github.docker-java docker-java-parent - 3.2.2-SNAPSHOT + 0-SNAPSHOT ../pom.xml @@ -15,12 +15,21 @@ https://github.com/docker-java/docker-java Java API Client for Docker + + com.github.dockerjava.core + + ${project.groupId} docker-java-api ${project.version} + + ${project.groupId} + docker-java-transport + ${project.version} + org.slf4j @@ -41,15 +50,15 @@ - commons-lang - commons-lang - ${commons-lang.version} + org.apache.commons + commons-lang3 + ${commons-lang3.version} com.fasterxml.jackson.core jackson-databind - ${jackson.version} + 2.20.1 @@ -60,7 +69,7 @@ org.bouncycastle - bcpkix-jdk15on + bcpkix-jdk18on ${bouncycastle.version} @@ -70,13 +79,6 @@ 3.0.1u2 provided - - - org.immutables - value - 2.8.2 - provided - @@ -97,6 +99,7 @@ 8 8 + true diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java b/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java index e93260b8a..5b908dff4 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/AbstractDockerCmdExecFactory.java @@ -1,5 +1,7 @@ package com.github.dockerjava.core; +import java.util.Objects; + import com.github.dockerjava.api.command.AttachContainerCmd; import com.github.dockerjava.api.command.AuthCmd; import com.github.dockerjava.api.command.BuildImageCmd; @@ -9,6 +11,7 @@ import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.api.command.CreateConfigCmd; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateImageCmd; import com.github.dockerjava.api.command.CreateNetworkCmd; @@ -22,9 +25,11 @@ import com.github.dockerjava.api.command.ExecStartCmd; import com.github.dockerjava.api.command.InfoCmd; import com.github.dockerjava.api.command.InitializeSwarmCmd; +import com.github.dockerjava.api.command.InspectConfigCmd; import com.github.dockerjava.api.command.InspectContainerCmd; import com.github.dockerjava.api.command.InspectExecCmd; import com.github.dockerjava.api.command.InspectImageCmd; +import com.github.dockerjava.api.command.ImageHistoryCmd; import com.github.dockerjava.api.command.InspectNetworkCmd; import com.github.dockerjava.api.command.InspectServiceCmd; import com.github.dockerjava.api.command.InspectSwarmCmd; @@ -33,6 +38,7 @@ import com.github.dockerjava.api.command.JoinSwarmCmd; import com.github.dockerjava.api.command.KillContainerCmd; import com.github.dockerjava.api.command.LeaveSwarmCmd; +import com.github.dockerjava.api.command.ListConfigsCmd; import com.github.dockerjava.api.command.ListContainersCmd; import com.github.dockerjava.api.command.ListImagesCmd; import com.github.dockerjava.api.command.ListNetworksCmd; @@ -41,6 +47,7 @@ import com.github.dockerjava.api.command.ListSwarmNodesCmd; import com.github.dockerjava.api.command.ListTasksCmd; import com.github.dockerjava.api.command.ListVolumesCmd; +import com.github.dockerjava.api.command.LoadImageAsyncCmd; import com.github.dockerjava.api.command.LoadImageCmd; import com.github.dockerjava.api.command.LogContainerCmd; import com.github.dockerjava.api.command.LogSwarmObjectCmd; @@ -49,6 +56,7 @@ import com.github.dockerjava.api.command.PruneCmd; import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.command.PushImageCmd; +import com.github.dockerjava.api.command.RemoveConfigCmd; import com.github.dockerjava.api.command.RemoveContainerCmd; import com.github.dockerjava.api.command.RemoveImageCmd; import com.github.dockerjava.api.command.RemoveNetworkCmd; @@ -57,6 +65,8 @@ import com.github.dockerjava.api.command.RemoveSwarmNodeCmd; import com.github.dockerjava.api.command.RemoveVolumeCmd; import com.github.dockerjava.api.command.RenameContainerCmd; +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.command.ResizeExecCmd; import com.github.dockerjava.api.command.RestartContainerCmd; import com.github.dockerjava.api.command.SaveImageCmd; import com.github.dockerjava.api.command.SaveImagesCmd; @@ -82,6 +92,7 @@ import com.github.dockerjava.core.exec.CopyArchiveFromContainerCmdExec; import com.github.dockerjava.core.exec.CopyArchiveToContainerCmdExec; import com.github.dockerjava.core.exec.CopyFileFromContainerCmdExec; +import com.github.dockerjava.core.exec.CreateConfigCmdExec; import com.github.dockerjava.core.exec.CreateContainerCmdExec; import com.github.dockerjava.core.exec.CreateImageCmdExec; import com.github.dockerjava.core.exec.CreateNetworkCmdExec; @@ -92,11 +103,18 @@ import com.github.dockerjava.core.exec.EventsCmdExec; import com.github.dockerjava.core.exec.ExecCreateCmdExec; import com.github.dockerjava.core.exec.ExecStartCmdExec; +import com.github.dockerjava.core.exec.InspectConfigCmdExec; +import com.github.dockerjava.core.exec.ListConfigsCmdExec; +import com.github.dockerjava.core.exec.LoadImageAsyncCmdExec; +import com.github.dockerjava.core.exec.RemoveConfigCmdExec; +import com.github.dockerjava.core.exec.ResizeContainerCmdExec; +import com.github.dockerjava.core.exec.ResizeExecCmdExec; import com.github.dockerjava.core.exec.InfoCmdExec; import com.github.dockerjava.core.exec.InitializeSwarmCmdExec; import com.github.dockerjava.core.exec.InspectContainerCmdExec; import com.github.dockerjava.core.exec.InspectExecCmdExec; import com.github.dockerjava.core.exec.InspectImageCmdExec; +import com.github.dockerjava.core.exec.ImageHistoryCmdExec; import com.github.dockerjava.core.exec.InspectNetworkCmdExec; import com.github.dockerjava.core.exec.InspectServiceCmdExec; import com.github.dockerjava.core.exec.InspectSwarmCmdExec; @@ -146,8 +164,6 @@ import com.github.dockerjava.core.exec.VersionCmdExec; import com.github.dockerjava.core.exec.WaitContainerCmdExec; -import static com.google.common.base.Preconditions.checkNotNull; - public abstract class AbstractDockerCmdExecFactory implements DockerCmdExecFactory, DockerClientConfigAware { private DockerClientConfig dockerClientConfig; @@ -156,15 +172,14 @@ public abstract class AbstractDockerCmdExecFactory implements DockerCmdExecFacto protected Integer readTimeout; protected DockerClientConfig getDockerClientConfig() { - checkNotNull(dockerClientConfig, + Objects.requireNonNull(dockerClientConfig, "Factor not initialized, dockerClientConfig not set. You probably forgot to call init()!"); return dockerClientConfig; } @Override public void init(DockerClientConfig dockerClientConfig) { - checkNotNull(dockerClientConfig, "config was not specified"); - this.dockerClientConfig = dockerClientConfig; + this.dockerClientConfig = Objects.requireNonNull(dockerClientConfig, "config was not specified"); } @Override @@ -243,6 +258,11 @@ public LoadImageCmd.Exec createLoadImageCmdExec() { return new LoadImageCmdExec(getBaseResource(), getDockerClientConfig()); } + @Override + public LoadImageAsyncCmd.Exec createLoadImageAsyncCmdExec() { + return new LoadImageAsyncCmdExec(getBaseResource(), getDockerClientConfig()); + } + @Override public SearchImagesCmd.Exec createSearchImagesCmdExec() { return new SearchImagesCmdExec(getBaseResource(), getDockerClientConfig()); @@ -263,6 +283,11 @@ public InspectImageCmd.Exec createInspectImageCmdExec() { return new InspectImageCmdExec(getBaseResource(), getDockerClientConfig()); } + @Override + public ImageHistoryCmd.Exec createImageHistoryCmdExec() { + return new ImageHistoryCmdExec(getBaseResource(), getDockerClientConfig()); + } + @Override public ListContainersCmd.Exec createListContainersCmdExec() { return new ListContainersCmdExec(getBaseResource(), getDockerClientConfig()); @@ -303,11 +328,21 @@ public AttachContainerCmd.Exec createAttachContainerCmdExec() { return new AttachContainerCmdExec(getBaseResource(), getDockerClientConfig()); } + @Override + public ResizeContainerCmd.Exec createResizeContainerCmdExec() { + return new ResizeContainerCmdExec(getBaseResource(), getDockerClientConfig()); + } + @Override public ExecStartCmd.Exec createExecStartCmdExec() { return new ExecStartCmdExec(getBaseResource(), getDockerClientConfig()); } + @Override + public ResizeExecCmd.Exec createResizeExecCmdExec() { + return new ResizeExecCmdExec(getBaseResource(), getDockerClientConfig()); + } + @Override public InspectExecCmd.Exec createInspectExecCmdExec() { return new InspectExecCmdExec(getBaseResource(), getDockerClientConfig()); @@ -546,5 +581,26 @@ public RemoveSecretCmd.Exec createRemoveSecretCmdExec() { return new RemoveSecretCmdExec(getBaseResource(), getDockerClientConfig()); } + @Override + public ListConfigsCmd.Exec createListConfigsCmdExec() { + return new ListConfigsCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public CreateConfigCmd.Exec createCreateConfigCmdExec() { + return new CreateConfigCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public InspectConfigCmd.Exec createInspectConfigCmdExec() { + return new InspectConfigCmdExec(getBaseResource(), getDockerClientConfig()); + } + + @Override + public RemoveConfigCmd.Exec createRemoveConfigCmdExec() { + return new RemoveConfigCmdExec(getBaseResource(), getDockerClientConfig()); + } + + protected abstract WebTarget getBaseResource(); } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerClientConfig.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerClientConfig.java index be00cd7ea..dad75b360 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerClientConfig.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerClientConfig.java @@ -5,11 +5,15 @@ import com.github.dockerjava.api.model.AuthConfigurations; import com.github.dockerjava.core.NameParser.HostnameReposName; import com.github.dockerjava.core.NameParser.ReposTag; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; + +import java.util.Map.Entry; +import java.util.Optional; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -21,11 +25,11 @@ import java.net.URI; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.Set; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.apache.commons.lang.BooleanUtils.isTrue; +import static org.apache.commons.lang3.BooleanUtils.isTrue; /** * Respects some of the docker CLI options. See https://docs.docker.com/engine/reference/commandline/cli/#environment-variables @@ -36,6 +40,8 @@ public class DefaultDockerClientConfig implements Serializable, DockerClientConf public static final String DOCKER_HOST = "DOCKER_HOST"; + public static final String DOCKER_CONTEXT = "DOCKER_CONTEXT"; + public static final String DOCKER_TLS_VERIFY = "DOCKER_TLS_VERIFY"; public static final String DOCKER_CONFIG = "DOCKER_CONFIG"; @@ -56,7 +62,11 @@ public class DefaultDockerClientConfig implements Serializable, DockerClientConf private static final Set CONFIG_KEYS = new HashSet<>(); - private static final Properties DEFAULT_PROPERTIES = new Properties(); + static final Properties DEFAULT_PROPERTIES = new Properties(); + + static final String DEFAULT_DOCKER_HOST = "unix:///var/run/docker.sock"; + + static final String WINDOWS_DEFAULT_DOCKER_HOST = "npipe:////./pipe/docker_engine"; static { CONFIG_KEYS.add(DOCKER_HOST); @@ -69,7 +79,6 @@ public class DefaultDockerClientConfig implements Serializable, DockerClientConf CONFIG_KEYS.add(REGISTRY_EMAIL); CONFIG_KEYS.add(REGISTRY_URL); - DEFAULT_PROPERTIES.put(DOCKER_HOST, "unix:///var/run/docker.sock"); DEFAULT_PROPERTIES.put(DOCKER_CONFIG, "${user.home}/.docker"); DEFAULT_PROPERTIES.put(REGISTRY_URL, "https://index.docker.io/v1/"); DEFAULT_PROPERTIES.put(REGISTRY_USERNAME, "${user.name}"); @@ -83,11 +92,13 @@ public class DefaultDockerClientConfig implements Serializable, DockerClientConf private final RemoteApiVersion apiVersion; - private DockerConfigFile dockerConfig = null; + private final DockerConfigFile dockerConfig; - DefaultDockerClientConfig(URI dockerHost, String dockerConfigPath, String apiVersion, String registryUrl, - String registryUsername, String registryPassword, String registryEmail, SSLConfig sslConfig) { + DefaultDockerClientConfig(URI dockerHost, DockerConfigFile dockerConfigFile, String dockerConfigPath, String apiVersion, + String registryUrl, String registryUsername, String registryPassword, String registryEmail, + SSLConfig sslConfig) { this.dockerHost = checkDockerHostScheme(dockerHost); + this.dockerConfig = dockerConfigFile; this.dockerConfigPath = dockerConfigPath; this.apiVersion = RemoteApiVersion.parseConfigWithDefault(apiVersion); this.sslConfig = sslConfig; @@ -98,14 +109,10 @@ public class DefaultDockerClientConfig implements Serializable, DockerClientConf } private URI checkDockerHostScheme(URI dockerHost) { - switch (dockerHost.getScheme()) { - case "tcp": - case "unix": - case "npipe": - return dockerHost; - default: - throw new DockerClientException("Unsupported protocol scheme found: '" + dockerHost); + if (dockerHost == null) { + throw new DockerClientException("'dockerHost' is null"); } + return dockerHost; } private static Properties loadIncludedDockerProperties(Properties systemProperties) { @@ -123,9 +130,11 @@ private static Properties loadIncludedDockerProperties(Properties systemProperti } private static void replaceProperties(Properties properties, Properties replacements) { - for (Object objectKey : properties.keySet()) { - String key = objectKey.toString(); - properties.setProperty(key, replaceProperties(properties.getProperty(key), replacements)); + for (Entry entry : properties.entrySet()) { + final String key = entry.getKey().toString(); + // no entry.getValue here because it does not have the same semantics as getProperty (defaults handling) + final String value = properties.getProperty(key); + entry.setValue(replaceProperties(value, replacements)); } } @@ -168,13 +177,26 @@ private static Properties overrideDockerPropertiesWithEnv(Properties properties, // special case which is a sensible default if (env.containsKey(DOCKER_HOST)) { - overriddenProperties.setProperty(DOCKER_HOST, env.get(DOCKER_HOST)); + String value = env.get(DOCKER_HOST); + if (value != null && value.trim().length() != 0) { + overriddenProperties.setProperty(DOCKER_HOST, value); + } + } + + if (env.containsKey(DOCKER_CONTEXT)) { + String value = env.get(DOCKER_CONTEXT); + if (value != null && value.trim().length() != 0) { + overriddenProperties.setProperty(DOCKER_CONTEXT, value); + } } for (Map.Entry envEntry : env.entrySet()) { String envKey = envEntry.getKey(); if (CONFIG_KEYS.contains(envKey)) { - overriddenProperties.setProperty(envKey, envEntry.getValue()); + String value = envEntry.getValue(); + if (value != null && value.trim().length() != 0) { + overriddenProperties.setProperty(envKey, value); + } } } @@ -252,13 +274,6 @@ public String getDockerConfigPath() { @Nonnull public DockerConfigFile getDockerConfig() { - if (dockerConfig == null) { - try { - dockerConfig = DockerConfigFile.loadConfig(getObjectMapper(), getDockerConfigPath()); - } catch (IOException e) { - throw new DockerClientException("Failed to parse docker configuration file", e); - } - } return dockerConfig; } @@ -319,7 +334,7 @@ public static class Builder { private URI dockerHost; private String apiVersion, registryUsername, registryPassword, registryEmail, registryUrl, dockerConfig, - dockerCertPath; + dockerCertPath, dockerContext; private Boolean dockerTlsVerify; @@ -331,8 +346,13 @@ public static class Builder { * registry.email, DOCKER_CERT_PATH, and DOCKER_CONFIG. */ public Builder withProperties(Properties p) { - return withDockerHost(p.getProperty(DOCKER_HOST)) - .withDockerTlsVerify(p.getProperty(DOCKER_TLS_VERIFY)) + + if (p.getProperty(DOCKER_HOST) != null) { + withDockerHost(p.getProperty(DOCKER_HOST)); + } + + return withDockerTlsVerify(p.getProperty(DOCKER_TLS_VERIFY)) + .withDockerContext(p.getProperty(DOCKER_CONTEXT)) .withDockerConfig(p.getProperty(DOCKER_CONFIG)) .withDockerCertPath(p.getProperty(DOCKER_CERT_PATH)) .withApiVersion(p.getProperty(API_VERSION)) @@ -346,7 +366,7 @@ public Builder withProperties(Properties p) { * configure DOCKER_HOST */ public final Builder withDockerHost(String dockerHost) { - checkNotNull(dockerHost, "uri was not specified"); + Objects.requireNonNull(dockerHost, "uri was not specified"); this.dockerHost = URI.create(dockerHost); return this; } @@ -391,6 +411,11 @@ public final Builder withDockerConfig(String dockerConfig) { return this; } + public final Builder withDockerContext(String dockerContext) { + this.dockerContext = dockerContext; + return this; + } + public final Builder withDockerTlsVerify(String dockerTlsVerify) { if (dockerTlsVerify != null) { String trimmed = dockerTlsVerify.trim(); @@ -406,6 +431,10 @@ public final Builder withDockerTlsVerify(Boolean dockerTlsVerify) { return this; } + public final boolean isDockerHostSetExplicitly() { + return dockerHost != null; + } + /** * Overrides the default {@link SSLConfig} that is used when calling {@link Builder#withDockerTlsVerify(java.lang.Boolean)} and * {@link Builder#withDockerCertPath(String)}. This way it is possible to pass a custom {@link SSLConfig} to the resulting @@ -416,7 +445,32 @@ public final Builder withCustomSslConfig(SSLConfig customSslConfig) { return this; } + private void applyContextConfiguration(final String context) { + final Optional dockerContextMetaFile = + Optional.ofNullable(context) + .flatMap(ctx -> DockerContextMetaFile.resolveContextMetaFile(DockerClientConfig.getDefaultObjectMapper(), + new File(this.dockerConfig), ctx)); + final Optional dockerContextTLSFile = + Optional.ofNullable(context) + .flatMap(ctx -> DockerContextMetaFile.resolveContextTLSFile(new File(this.dockerConfig), ctx)); + + if (dockerContextMetaFile.isPresent()) { + final Optional dockerEndpoint = + dockerContextMetaFile.map(metaFile -> metaFile.endpoints).map(endpoint -> endpoint.docker); + if (this.dockerHost == null) { + this.dockerHost = dockerEndpoint.map(endpoint -> endpoint.host).map(URI::create).orElse(null); + } + } + if (dockerContextTLSFile.isPresent() && this.dockerCertPath == null) { + this.dockerCertPath = dockerContextTLSFile.get().getAbsolutePath(); + this.dockerTlsVerify = true; + } + } + public DefaultDockerClientConfig build() { + final DockerConfigFile dockerConfigFile = readDockerConfig(); + final String context = (dockerContext != null) ? dockerContext : dockerConfigFile.getCurrentContext(); + applyContextConfiguration(context); SSLConfig sslConfig = null; @@ -429,14 +483,26 @@ public DefaultDockerClientConfig build() { sslConfig = customSslConfig; } - return new DefaultDockerClientConfig(dockerHost, dockerConfig, apiVersion, registryUrl, registryUsername, + URI dockerHostUri = dockerHost != null + ? dockerHost + : URI.create(SystemUtils.IS_OS_WINDOWS ? WINDOWS_DEFAULT_DOCKER_HOST : DEFAULT_DOCKER_HOST); + + return new DefaultDockerClientConfig(dockerHostUri, dockerConfigFile, dockerConfig, apiVersion, registryUrl, registryUsername, registryPassword, registryEmail, sslConfig); } + private DockerConfigFile readDockerConfig() { + try { + return DockerConfigFile.loadConfig(DockerClientConfig.getDefaultObjectMapper(), dockerConfig); + } catch (IOException e) { + throw new DockerClientException("Failed to parse docker configuration file", e); + } + } + private String checkDockerCertPath(String dockerCertPath) { if (StringUtils.isEmpty(dockerCertPath)) { throw new DockerClientException( - "Enabled TLS verification (DOCKER_TLS_VERIFY=1) but certifate path (DOCKER_CERT_PATH) is not defined."); + "Enabled TLS verification (DOCKER_TLS_VERIFY=1) but certificate path (DOCKER_CERT_PATH) is not defined."); } File certPath = new File(dockerCertPath); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerCmdExecFactory.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerCmdExecFactory.java index 5e13824ef..54722e6c7 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerCmdExecFactory.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultDockerCmdExecFactory.java @@ -2,13 +2,14 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.transport.DockerHttpClient; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.MultimapBuilder; import com.google.common.collect.SetMultimap; import com.google.common.escape.Escaper; import com.google.common.net.UrlEscapers; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.util.Map; @@ -78,6 +79,11 @@ public InvocationBuilder request() { resource = "/" + resource; } + RemoteApiVersion apiVersion = getDockerClientConfig().getApiVersion(); + if (apiVersion != RemoteApiVersion.UNKNOWN_VERSION) { + resource = "/" + apiVersion.asWebPathPart() + resource; + } + if (!queryParams.isEmpty()) { Escaper urlFormParameterEscaper = UrlEscapers.urlFormParameterEscaper(); resource = queryParams.asMap().entrySet().stream() diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultInvocationBuilder.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultInvocationBuilder.java index 50bd4612b..c7525279c 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultInvocationBuilder.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DefaultInvocationBuilder.java @@ -14,9 +14,10 @@ import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.exception.UnauthorizedException; import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.transport.DockerHttpClient; import org.apache.commons.io.IOUtils; -import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -95,10 +96,20 @@ public InputStream post(Object entity) { DockerHttpClient.Request request = requestBuilder .method(DockerHttpClient.Request.Method.POST) .putHeader("content-type", "application/json") - .body(encode(entity)) + .bodyBytes(encode(entity)) .build(); - return execute(request).getBody(); + DockerHttpClient.Response response = execute(request); + return new FilterInputStream(response.getBody()) { + @Override + public void close() throws IOException { + try { + super.close(); + } finally { + response.close(); + } + } + }; } @Override @@ -107,7 +118,7 @@ public T post(Object entity, TypeReference typeReference) { DockerHttpClient.Request request = requestBuilder .method(DockerHttpClient.Request.Method.POST) .putHeader("content-type", "application/json") - .body(new ByteArrayInputStream(objectMapper.writeValueAsBytes(entity))) + .bodyBytes(encode(entity)) .build(); try (DockerHttpClient.Response response = execute(request)) { @@ -120,11 +131,17 @@ public T post(Object entity, TypeReference typeReference) { @Override public void post(Object entity, TypeReference typeReference, ResultCallback resultCallback) { - try { - post(typeReference, resultCallback, new ByteArrayInputStream(objectMapper.writeValueAsBytes(entity))); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } + DockerHttpClient.Request request = requestBuilder + .method(DockerHttpClient.Request.Method.POST) + .putHeader("content-type", "application/json") + .bodyBytes(encode(entity)) + .build(); + + executeAndStream( + request, + resultCallback, + new JsonSink<>(typeReference, resultCallback) + ); } @Override @@ -138,17 +155,12 @@ public T post(TypeReference typeReference, InputStream body) { @Override public void post(Object entity, InputStream stdin, ResultCallback resultCallback) { - final DockerHttpClient.Request request; - try { - request = requestBuilder - .method(DockerHttpClient.Request.Method.POST) - .putHeader("content-type", "application/json") - .body(new ByteArrayInputStream(objectMapper.writeValueAsBytes(entity))) - .hijackedInput(stdin) - .build(); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } + DockerHttpClient.Request request = requestBuilder + .method(DockerHttpClient.Request.Method.POST) + .putHeader("content-type", "application/json") + .bodyBytes(encode(entity)) + .hijackedInput(stdin) + .build(); executeAndStream( request, @@ -187,7 +199,17 @@ public InputStream get() { .method(DockerHttpClient.Request.Method.GET) .build(); - return execute(request).getBody(); + DockerHttpClient.Response response = execute(request); + return new FilterInputStream(response.getBody()) { + @Override + public void close() throws IOException { + try { + super.close(); + } finally { + response.close(); + } + } + }; } @Override @@ -243,8 +265,12 @@ protected void executeAndStream( Consumer sourceConsumer ) { Thread thread = new Thread(() -> { + Thread streamingThread = Thread.currentThread(); try (DockerHttpClient.Response response = execute(request)) { - callback.onStart(response); + callback.onStart(() -> { + streamingThread.interrupt(); + response.close(); + }); sourceConsumer.accept(response); callback.onComplete(); @@ -257,13 +283,13 @@ protected void executeAndStream( thread.start(); } - private InputStream encode(Object entity) { + private byte[] encode(Object entity) { if (entity == null) { return null; } try { - return new ByteArrayInputStream(objectMapper.writeValueAsBytes(entity)); + return objectMapper.writeValueAsBytes(entity); } catch (JsonProcessingException e) { throw new RuntimeException(e); } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientConfig.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientConfig.java index b64c0e7e6..e3961661a 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientConfig.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientConfig.java @@ -3,13 +3,26 @@ */ package com.github.dockerjava.core; -import java.net.URI; - +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; +import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.AuthConfigurations; +import com.github.dockerjava.api.model.DockerObject; +import com.github.dockerjava.api.model.DockerObjectAccessor; + +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; /** * Interface that describes the docker client configuration. @@ -19,6 +32,10 @@ */ public interface DockerClientConfig { + static ObjectMapper getDefaultObjectMapper() { + return DefaultObjectMapperHolder.INSTANCE.getObjectMapper().copy(); + } + URI getDockerHost(); RemoteApiVersion getApiVersion(); @@ -41,7 +58,7 @@ public interface DockerClientConfig { SSLConfig getSSLConfig(); default ObjectMapper getObjectMapper() { - return DefaultObjectMapperHolder.INSTANCE.getObjectMapper().copy(); + return getDefaultObjectMapper(); } } @@ -53,7 +70,74 @@ enum DefaultObjectMapperHolder { .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + { + ObjectMapper originalObjectMapper = objectMapper.copy(); + objectMapper.registerModule(new SimpleModule("docker-java") { + @Override + public void setupModule(SetupContext context) { + super.setupModule(context); + context.addBeanDeserializerModifier(new BeanDeserializerModifier() { + @Override + public JsonDeserializer modifyDeserializer( + DeserializationConfig config, + BeanDescription beanDescription, + JsonDeserializer originalDeserializer + ) { + if (!beanDescription.getType().isTypeOrSubTypeOf(DockerObject.class)) { + return originalDeserializer; + } + + return new DockerObjectDeserializer( + originalDeserializer, + beanDescription, + originalObjectMapper + ); + } + }); + } + }); + } + public ObjectMapper getObjectMapper() { return objectMapper; } } + +class DockerObjectDeserializer extends DelegatingDeserializer { + + private final BeanDescription beanDescription; + + private final ObjectMapper originalMapper; + + DockerObjectDeserializer( + JsonDeserializer delegate, + BeanDescription beanDescription, + ObjectMapper originalMapper + ) { + super(delegate); + this.beanDescription = beanDescription; + this.originalMapper = originalMapper; + } + + @Override + protected JsonDeserializer newDelegatingInstance(JsonDeserializer newDelegatee) { + return new DockerObjectDeserializer(newDelegatee, beanDescription, originalMapper); + } + + @Override + @SuppressWarnings({"deprecation", "unchecked"}) + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + JsonNode jsonNode = p.readValueAsTree(); + + Object deserializedObject = originalMapper.treeToValue(jsonNode, beanDescription.getBeanClass()); + + if (deserializedObject instanceof DockerObject) { + DockerObjectAccessor.overrideRawValues( + ((DockerObject) deserializedObject), + originalMapper.convertValue(jsonNode, HashMap.class) + ); + } + + return deserializedObject; + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientConfigDelegate.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientConfigDelegate.java new file mode 100644 index 000000000..86c6ac5de --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientConfigDelegate.java @@ -0,0 +1,57 @@ +package com.github.dockerjava.core; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.api.model.AuthConfigurations; + +import java.net.URI; + +@SuppressWarnings("unused") +public class DockerClientConfigDelegate implements DockerClientConfig { + + final DockerClientConfig original; + + public DockerClientConfigDelegate(DockerClientConfig original) { + this.original = original; + } + + public URI getDockerHost() { + return original.getDockerHost(); + } + + public RemoteApiVersion getApiVersion() { + return original.getApiVersion(); + } + + public String getRegistryUsername() { + return original.getRegistryUsername(); + } + + public String getRegistryPassword() { + return original.getRegistryPassword(); + } + + public String getRegistryEmail() { + return original.getRegistryEmail(); + } + + public String getRegistryUrl() { + return original.getRegistryUrl(); + } + + public AuthConfig effectiveAuthConfig(String imageName) { + return original.effectiveAuthConfig(imageName); + } + + public AuthConfigurations getAuthConfigurations() { + return original.getAuthConfigurations(); + } + + public SSLConfig getSSLConfig() { + return original.getSSLConfig(); + } + + public ObjectMapper getObjectMapper() { + return original.getObjectMapper(); + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java index 3e1b59b1e..b17c1b481 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerClientImpl.java @@ -10,6 +10,7 @@ import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; import com.github.dockerjava.api.command.CopyFileFromContainerCmd; +import com.github.dockerjava.api.command.CreateConfigCmd; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateImageCmd; import com.github.dockerjava.api.command.CreateNetworkCmd; @@ -23,9 +24,11 @@ import com.github.dockerjava.api.command.ExecStartCmd; import com.github.dockerjava.api.command.InfoCmd; import com.github.dockerjava.api.command.InitializeSwarmCmd; +import com.github.dockerjava.api.command.InspectConfigCmd; import com.github.dockerjava.api.command.InspectContainerCmd; import com.github.dockerjava.api.command.InspectExecCmd; import com.github.dockerjava.api.command.InspectImageCmd; +import com.github.dockerjava.api.command.ImageHistoryCmd; import com.github.dockerjava.api.command.InspectNetworkCmd; import com.github.dockerjava.api.command.InspectServiceCmd; import com.github.dockerjava.api.command.InspectSwarmCmd; @@ -33,6 +36,7 @@ import com.github.dockerjava.api.command.JoinSwarmCmd; import com.github.dockerjava.api.command.KillContainerCmd; import com.github.dockerjava.api.command.LeaveSwarmCmd; +import com.github.dockerjava.api.command.ListConfigsCmd; import com.github.dockerjava.api.command.ListContainersCmd; import com.github.dockerjava.api.command.ListImagesCmd; import com.github.dockerjava.api.command.ListNetworksCmd; @@ -41,6 +45,7 @@ import com.github.dockerjava.api.command.ListSwarmNodesCmd; import com.github.dockerjava.api.command.ListTasksCmd; import com.github.dockerjava.api.command.ListVolumesCmd; +import com.github.dockerjava.api.command.LoadImageAsyncCmd; import com.github.dockerjava.api.command.LoadImageCmd; import com.github.dockerjava.api.command.LogContainerCmd; import com.github.dockerjava.api.command.LogSwarmObjectCmd; @@ -49,13 +54,17 @@ import com.github.dockerjava.api.command.PruneCmd; import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.command.PushImageCmd; +import com.github.dockerjava.api.command.RemoveConfigCmd; import com.github.dockerjava.api.command.RemoveContainerCmd; import com.github.dockerjava.api.command.RemoveImageCmd; import com.github.dockerjava.api.command.RemoveNetworkCmd; import com.github.dockerjava.api.command.RemoveSecretCmd; import com.github.dockerjava.api.command.RemoveServiceCmd; +import com.github.dockerjava.api.command.RemoveSwarmNodeCmd; import com.github.dockerjava.api.command.RemoveVolumeCmd; import com.github.dockerjava.api.command.RenameContainerCmd; +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.command.ResizeExecCmd; import com.github.dockerjava.api.command.RestartContainerCmd; import com.github.dockerjava.api.command.SaveImageCmd; import com.github.dockerjava.api.command.SaveImagesCmd; @@ -87,6 +96,7 @@ import com.github.dockerjava.core.command.CopyArchiveFromContainerCmdImpl; import com.github.dockerjava.core.command.CopyArchiveToContainerCmdImpl; import com.github.dockerjava.core.command.CopyFileFromContainerCmdImpl; +import com.github.dockerjava.core.command.CreateConfigCmdImpl; import com.github.dockerjava.core.command.CreateContainerCmdImpl; import com.github.dockerjava.core.command.CreateImageCmdImpl; import com.github.dockerjava.core.command.CreateNetworkCmdImpl; @@ -100,15 +110,18 @@ import com.github.dockerjava.core.command.InfoCmdImpl; import com.github.dockerjava.core.command.InitializeSwarmCmdImpl; import com.github.dockerjava.core.command.InpectNetworkCmdImpl; +import com.github.dockerjava.core.command.InspectConfigCmdImpl; import com.github.dockerjava.core.command.InspectContainerCmdImpl; import com.github.dockerjava.core.command.InspectExecCmdImpl; import com.github.dockerjava.core.command.InspectImageCmdImpl; +import com.github.dockerjava.core.command.ImageHistoryCmdImpl; import com.github.dockerjava.core.command.InspectServiceCmdImpl; import com.github.dockerjava.core.command.InspectSwarmCmdImpl; import com.github.dockerjava.core.command.InspectVolumeCmdImpl; import com.github.dockerjava.core.command.JoinSwarmCmdImpl; import com.github.dockerjava.core.command.KillContainerCmdImpl; import com.github.dockerjava.core.command.LeaveSwarmCmdImpl; +import com.github.dockerjava.core.command.ListConfigsCmdImpl; import com.github.dockerjava.core.command.ListContainersCmdImpl; import com.github.dockerjava.core.command.ListImagesCmdImpl; import com.github.dockerjava.core.command.ListNetworksCmdImpl; @@ -117,6 +130,7 @@ import com.github.dockerjava.core.command.ListSwarmNodesCmdImpl; import com.github.dockerjava.core.command.ListTasksCmdImpl; import com.github.dockerjava.core.command.ListVolumesCmdImpl; +import com.github.dockerjava.core.command.LoadImageAsyncCmdImpl; import com.github.dockerjava.core.command.LoadImageCmdImpl; import com.github.dockerjava.core.command.LogContainerCmdImpl; import com.github.dockerjava.core.command.LogSwarmObjectImpl; @@ -125,13 +139,17 @@ import com.github.dockerjava.core.command.PruneCmdImpl; import com.github.dockerjava.core.command.PullImageCmdImpl; import com.github.dockerjava.core.command.PushImageCmdImpl; +import com.github.dockerjava.core.command.RemoveConfigCmdImpl; import com.github.dockerjava.core.command.RemoveContainerCmdImpl; import com.github.dockerjava.core.command.RemoveImageCmdImpl; import com.github.dockerjava.core.command.RemoveNetworkCmdImpl; import com.github.dockerjava.core.command.RemoveSecretCmdImpl; import com.github.dockerjava.core.command.RemoveServiceCmdImpl; +import com.github.dockerjava.core.command.RemoveSwarmNodeCmdImpl; import com.github.dockerjava.core.command.RemoveVolumeCmdImpl; import com.github.dockerjava.core.command.RenameContainerCmdImpl; +import com.github.dockerjava.core.command.ResizeContainerCmdImpl; +import com.github.dockerjava.core.command.ResizeExecCmdImpl; import com.github.dockerjava.core.command.RestartContainerCmdImpl; import com.github.dockerjava.core.command.SaveImageCmdImpl; import com.github.dockerjava.core.command.SaveImagesCmdImpl; @@ -148,6 +166,7 @@ import com.github.dockerjava.core.command.UpdateSwarmNodeCmdImpl; import com.github.dockerjava.core.command.VersionCmdImpl; import com.github.dockerjava.core.command.WaitContainerCmdImpl; +import com.github.dockerjava.transport.DockerHttpClient; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -155,8 +174,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * @author Konstantin Pelykh (kpelykh@gmail.com) @@ -166,38 +184,49 @@ public class DockerClientImpl implements Closeable, DockerClient { private final DockerClientConfig dockerClientConfig; - private DockerCmdExecFactory dockerCmdExecFactory; - - private DockerClientImpl() { - this(DefaultDockerClientConfig.createDefaultConfigBuilder().build()); - } - - private DockerClientImpl(String serverUrl) { - this(configWithServerUrl(serverUrl)); - } - - private DockerClientImpl(DockerClientConfig dockerClientConfig) { - checkNotNull(dockerClientConfig, "config was not specified"); - this.dockerClientConfig = dockerClientConfig; - } + DockerCmdExecFactory dockerCmdExecFactory; - private static DockerClientConfig configWithServerUrl(String serverUrl) { - return DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost(serverUrl).build(); + DockerClientImpl(DockerClientConfig dockerClientConfig) { + this.dockerClientConfig = Objects.requireNonNull(dockerClientConfig, "config was not specified"); } + /** + * + * @deprecated use {@link #getInstance(DockerClientConfig, DockerHttpClient)} + */ + @Deprecated public static DockerClientImpl getInstance() { - return new DockerClientImpl(); + return new DockerClientImpl(DefaultDockerClientConfig.createDefaultConfigBuilder().build()); } + /** + * + * @deprecated use {@link #getInstance(DockerClientConfig, DockerHttpClient)} + */ + @Deprecated public static DockerClientImpl getInstance(DockerClientConfig dockerClientConfig) { return new DockerClientImpl(dockerClientConfig); } + public static DockerClient getInstance(DockerClientConfig dockerClientConfig, DockerHttpClient dockerHttpClient) { + return new DockerClientImpl(dockerClientConfig) + .withHttpClient(dockerHttpClient); + } + + /** + * + * @deprecated use {@link #getInstance(DockerClientConfig, DockerHttpClient)} + */ + @Deprecated public static DockerClientImpl getInstance(String serverUrl) { - return new DockerClientImpl(serverUrl); + return new DockerClientImpl( + DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerHost(serverUrl) + .build() + ); } - public DockerClientImpl withHttpClient(DockerHttpClient httpClient) { + DockerClientImpl withHttpClient(DockerHttpClient httpClient) { return withDockerCmdExecFactory(new DefaultDockerCmdExecFactory(httpClient, dockerClientConfig.getObjectMapper())); } @@ -215,11 +244,11 @@ public DockerHttpClient getHttpClient() { } /** - * @deprecated use {{@link #withHttpClient(DockerHttpClient)}} + * @deprecated use {@link #getInstance(DockerClientConfig, DockerHttpClient)} */ @Deprecated public DockerClientImpl withDockerCmdExecFactory(DockerCmdExecFactory dockerCmdExecFactory) { - checkNotNull(dockerCmdExecFactory, "dockerCmdExecFactory was not specified"); + Objects.requireNonNull(dockerCmdExecFactory, "dockerCmdExecFactory was not specified"); this.dockerCmdExecFactory = dockerCmdExecFactory; if (dockerCmdExecFactory instanceof DockerClientConfigAware) { ((DockerClientConfigAware) dockerCmdExecFactory).init(dockerClientConfig); @@ -229,14 +258,14 @@ public DockerClientImpl withDockerCmdExecFactory(DockerCmdExecFactory dockerCmdE @Deprecated private DockerCmdExecFactory getDockerCmdExecFactory() { - checkNotNull(dockerCmdExecFactory, "dockerCmdExecFactory was not specified"); + Objects.requireNonNull(dockerCmdExecFactory, "dockerCmdExecFactory was not specified"); return dockerCmdExecFactory; } @Override public AuthConfig authConfig() { - checkNotNull(dockerClientConfig.getRegistryUsername(), "Configured username is null."); - checkNotNull(dockerClientConfig.getRegistryUrl(), "Configured serverAddress is null."); + Objects.requireNonNull(dockerClientConfig.getRegistryUsername(), "Configured username is null."); + Objects.requireNonNull(dockerClientConfig.getRegistryUrl(), "Configured serverAddress is null."); return new AuthConfig() .withUsername(dockerClientConfig.getRegistryUsername()) @@ -323,6 +352,11 @@ public LoadImageCmd loadImageCmd(@Nonnull InputStream imageStream) { return new LoadImageCmdImpl(getDockerCmdExecFactory().createLoadImageCmdExec(), imageStream); } + @Override + public LoadImageAsyncCmd loadImageAsyncCmd(@Nonnull InputStream imageStream) { + return new LoadImageAsyncCmdImpl(getDockerCmdExecFactory().createLoadImageAsyncCmdExec(), imageStream); + } + @Override public SearchImagesCmd searchImagesCmd(String term) { return new SearchImagesCmdImpl(getDockerCmdExecFactory().createSearchImagesCmdExec(), term); @@ -343,6 +377,11 @@ public InspectImageCmd inspectImageCmd(String imageId) { return new InspectImageCmdImpl(getDockerCmdExecFactory().createInspectImageCmdExec(), imageId); } + @Override + public ImageHistoryCmd imageHistoryCmd(String imageId) { + return new ImageHistoryCmdImpl(getDockerCmdExecFactory().createImageHistoryCmdExec(), imageId); + } + /** * * CONTAINER API * */ @@ -373,6 +412,11 @@ public ExecCreateCmd execCreateCmd(String containerId) { return new ExecCreateCmdImpl(getDockerCmdExecFactory().createExecCmdExec(), containerId); } + @Override + public ResizeExecCmd resizeExecCmd(@Nonnull String execId) { + return new ResizeExecCmdImpl(getDockerCmdExecFactory().createResizeExecCmdExec(), execId); + } + @Override public RemoveContainerCmd removeContainerCmd(String containerId) { return new RemoveContainerCmdImpl(getDockerCmdExecFactory().createRemoveContainerCmdExec(), containerId); @@ -451,6 +495,11 @@ public RestartContainerCmd restartContainerCmd(String containerId) { return new RestartContainerCmdImpl(getDockerCmdExecFactory().createRestartContainerCmdExec(), containerId); } + @Override + public ResizeContainerCmd resizeContainerCmd(@Nonnull String containerId) { + return new ResizeContainerCmdImpl(getDockerCmdExecFactory().createResizeContainerCmdExec(), containerId); + } + @Override public CommitCmd commitCmd(String containerId) { return new CommitCmdImpl(getDockerCmdExecFactory().createCommitCmdExec(), containerId); @@ -581,6 +630,11 @@ public UpdateSwarmNodeCmd updateSwarmNodeCmd() { return new UpdateSwarmNodeCmdImpl(getDockerCmdExecFactory().updateSwarmNodeCmdExec()); } + @Override + public RemoveSwarmNodeCmd removeSwarmNodeCmd(String swarmNodeId) { + return new RemoveSwarmNodeCmdImpl(getDockerCmdExecFactory().removeSwarmNodeCmdExec(), swarmNodeId); + } + @Override public ListSwarmNodesCmd listSwarmNodesCmd() { return new ListSwarmNodesCmdImpl(getDockerCmdExecFactory().listSwarmNodeCmdExec()); @@ -641,6 +695,28 @@ public RemoveSecretCmd removeSecretCmd(String secretId) { return new RemoveSecretCmdImpl(getDockerCmdExecFactory().createRemoveSecretCmdExec(), secretId); } + @Override + public ListConfigsCmd listConfigsCmd() { + return new ListConfigsCmdImpl(getDockerCmdExecFactory().createListConfigsCmdExec()); + } + + @Override + public CreateConfigCmd createConfigCmd() { + return new CreateConfigCmdImpl(getDockerCmdExecFactory().createCreateConfigCmdExec()); + } + + @Override + public InspectConfigCmd inspectConfigCmd(String configId) { + return new InspectConfigCmdImpl(getDockerCmdExecFactory().createInspectConfigCmdExec(), configId); + } + + + @Override + public RemoveConfigCmd removeConfigCmd(String configId) { + return new RemoveConfigCmdImpl(getDockerCmdExecFactory().createRemoveConfigCmdExec(), configId); + } + + @Override public ListTasksCmd listTasksCmd() { return new ListTasksCmdImpl(getDockerCmdExecFactory().listTasksCmdExec()); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerConfigFile.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerConfigFile.java index fd04a5aa6..39ef15271 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerConfigFile.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerConfigFile.java @@ -1,12 +1,14 @@ package com.github.dockerjava.core; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.AuthConfigurations; +import java.util.Objects; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -27,7 +29,10 @@ public class DockerConfigFile { }; @JsonProperty - private final Map auths; + private Map auths; + + @JsonProperty + private String currentContext; public DockerConfigFile() { this(new HashMap<>()); @@ -42,10 +47,23 @@ public Map getAuths() { return auths; } + @JsonSetter + public void setAuths(Map authConfigMap) { + auths = (authConfigMap == null || authConfigMap.size() == 0) ? new HashMap<>() : authConfigMap; + } + void addAuthConfig(AuthConfig config) { auths.put(config.getRegistryAddress(), config); } + void setCurrentContext(String currentContext) { + this.currentContext = currentContext; + } + + public String getCurrentContext() { + return currentContext; + } + @CheckForNull public AuthConfig resolveAuthConfig(@CheckForNull String hostname) { if (StringUtils.isEmpty(hostname) || AuthConfig.DEFAULT_SERVER_ADDRESS.equals(hostname)) { @@ -104,6 +122,9 @@ public boolean equals(Object obj) { return false; } else if (!auths.equals(other.auths)) return false; + if (!Objects.equals(currentContext, other.currentContext)) { + return false; + } return true; } @@ -111,7 +132,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return "DockerConfigFile [auths=" + auths + "]"; + return "DockerConfigFile [auths=" + auths + ", currentContext='" + currentContext + "']"; } @Nonnull diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerContextMetaFile.java b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerContextMetaFile.java new file mode 100644 index 000000000..e10db4498 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/DockerContextMetaFile.java @@ -0,0 +1,71 @@ +package com.github.dockerjava.core; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +public class DockerContextMetaFile { + private static HashFunction metaHashFunction = Hashing.sha256(); + + @JsonProperty("Name") + String name; + + @JsonProperty("Endpoints") + Endpoints endpoints; + + + public static class Endpoints { + @JsonProperty("docker") + Docker docker; + + public static class Docker { + @JsonProperty("Host") + String host; + + @JsonProperty("SkipTLSVerify") + boolean skipTLSVerify; + } + } + + + public static Optional resolveContextMetaFile(ObjectMapper objectMapper, File dockerConfigPath, String context) { + final File path = dockerConfigPath.toPath() + .resolve("contexts") + .resolve("meta") + .resolve(metaHashFunction.hashString(context, StandardCharsets.UTF_8).toString()) + .resolve("meta.json") + .toFile(); + return Optional.ofNullable(loadContextMetaFile(objectMapper, path)); + } + + public static Optional resolveContextTLSFile(File dockerConfigPath, String context) { + final File path = dockerConfigPath.toPath() + .resolve("contexts") + .resolve("tls") + .resolve(metaHashFunction.hashString(context, StandardCharsets.UTF_8).toString()) + .resolve("docker") + .toFile(); + return Optional.ofNullable(path).filter(File::exists); + } + + public static DockerContextMetaFile loadContextMetaFile(ObjectMapper objectMapper, File dockerContextMetaFile) { + try { + return parseContextMetaFile(objectMapper, dockerContextMetaFile); + } catch (Exception exception) { + return null; + } + } + + public static DockerContextMetaFile parseContextMetaFile(ObjectMapper objectMapper, File dockerContextMetaFile) throws IOException { + try { + return objectMapper.readValue(dockerContextMetaFile, DockerContextMetaFile.class); + } catch (IOException e) { + throw new IOException("Failed to parse docker context meta file " + dockerContextMetaFile, e); + } + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/FramedInputStreamConsumer.java b/docker-java-core/src/main/java/com/github/dockerjava/core/FramedInputStreamConsumer.java index fde82647e..c81521076 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/FramedInputStreamConsumer.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/FramedInputStreamConsumer.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.StreamType; +import com.github.dockerjava.transport.DockerHttpClient; import java.io.InputStream; import java.util.Arrays; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java b/docker-java-core/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java index 445c00120..811b60ce5 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java @@ -6,9 +6,15 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.UncheckedExecutionException; +import org.apache.commons.lang3.StringUtils; import com.github.dockerjava.core.exception.GoLangFileMatchException; @@ -52,6 +58,11 @@ private GoLangFileMatch() { private static final String PATTERN_CHARS_TO_ESCAPE = "\\.[]{}()*+-?^$|"; + private static final LoadingCache PATTERN_CACHE = CacheBuilder.newBuilder() + .expireAfterAccess(1, TimeUnit.HOURS) + .maximumSize(10_000) + .build(CacheLoader.from(GoLangFileMatch::buildPattern)); + public static boolean match(List patterns, File file) { return !match(patterns, file.getPath()).isEmpty(); } @@ -74,7 +85,11 @@ public static List match(List patterns, String name) { } public static boolean match(String pattern, String name) { - return buildPattern(pattern).matcher(name).matches(); + try { + return PATTERN_CACHE.get(pattern).matcher(name).matches(); + } catch (ExecutionException | UncheckedExecutionException e) { + throw new GoLangFileMatchException(e.getCause().getMessage()); + } } private static Pattern buildPattern(String pattern) { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/KeystoreSSLConfig.java b/docker-java-core/src/main/java/com/github/dockerjava/core/KeystoreSSLConfig.java index 43946a53b..73491bb43 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/KeystoreSSLConfig.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/KeystoreSSLConfig.java @@ -1,7 +1,5 @@ package com.github.dockerjava.core; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -14,6 +12,7 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.Objects; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; @@ -37,8 +36,7 @@ public class KeystoreSSLConfig implements SSLConfig, Serializable { */ public KeystoreSSLConfig(KeyStore keystore, String keystorePassword) { this.keystorePassword = keystorePassword; - checkNotNull(keystore); - this.keystore = keystore; + this.keystore = Objects.requireNonNull(keystore); } /** @@ -54,8 +52,8 @@ public KeystoreSSLConfig(KeyStore keystore, String keystorePassword) { */ public KeystoreSSLConfig(File pfxFile, String password) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException { - checkNotNull(pfxFile); - checkNotNull(password); + Objects.requireNonNull(pfxFile); + Objects.requireNonNull(password); keystore = KeyStore.getInstance("pkcs12"); try (FileInputStream fs = new FileInputStream(pfxFile)) { keystore.load(fs, password.toCharArray()); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java b/docker-java-core/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java index 6e39f4f94..0f50f561d 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/LocalDirectorySSLConfig.java @@ -1,7 +1,5 @@ package com.github.dockerjava.core; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.File; import java.io.Serializable; import java.nio.file.Files; @@ -9,6 +7,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.security.Security; +import java.util.Objects; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; @@ -29,8 +28,7 @@ public class LocalDirectorySSLConfig implements SSLConfig, Serializable { private final String dockerCertPath; public LocalDirectorySSLConfig(String dockerCertPath) { - checkNotNull(dockerCertPath); - this.dockerCertPath = dockerCertPath; + this.dockerCertPath = Objects.requireNonNull(dockerCertPath); } public String getDockerCertPath() { @@ -66,7 +64,8 @@ public SSLContext getSSLContext() { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm); trustManagerFactory.init(CertificateUtils.createTrustStore(capem)); - SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + SSLContext sslContext = SSLContext.getInstance(AccessController.doPrivileged(getSystemProperty("ssl.protocol", + "TLSv1.2"))); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); return sslContext; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/NameParser.java b/docker-java-core/src/main/java/com/github/dockerjava/core/NameParser.java index ffadb6656..f06adb6d8 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/NameParser.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/NameParser.java @@ -5,10 +5,10 @@ import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.core.exception.InvalidRepositoryNameException; @@ -22,6 +22,7 @@ private NameParser() { private static final int RepositoryNameTotalLengthMax = 255; private static final String SHA256_SEPARATOR = "@sha256:"; + private static final String COLON_SEPARATOR = ":"; private static final Pattern RepositoryNameComponentRegexp = Pattern.compile("[a-z0-9]+(?:[._-][a-z0-9]+)*"); @@ -106,6 +107,13 @@ public static HostnameReposName resolveRepositoryName(String reposName) { String[] nameParts = reposName.split("/", 2); if (nameParts.length == 1 || (!nameParts[0].contains(".") && !nameParts[0].contains(":") && !nameParts[0].equals("localhost"))) { + if (StringUtils.containsIgnoreCase(reposName, SHA256_SEPARATOR)) { + reposName = StringUtils.substringBeforeLast(reposName, SHA256_SEPARATOR); + } + + if (StringUtils.contains(reposName, COLON_SEPARATOR)) { + reposName = StringUtils.substringBeforeLast(reposName, COLON_SEPARATOR); + } return new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, reposName); } @@ -119,6 +127,10 @@ public static HostnameReposName resolveRepositoryName(String reposName) { reposName = StringUtils.substringBeforeLast(reposName, SHA256_SEPARATOR); } + if (StringUtils.contains(reposName, COLON_SEPARATOR)) { + reposName = StringUtils.substringBeforeLast(reposName, COLON_SEPARATOR); + } + validateRepoName(reposName); return new HostnameReposName(hostname, reposName); } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java b/docker-java-core/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java index a38930cb3..373a67332 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/RemoteApiVersion.java @@ -91,6 +91,10 @@ public class RemoteApiVersion implements Serializable { public static final RemoteApiVersion VERSION_1_37 = RemoteApiVersion.create(1, 37); public static final RemoteApiVersion VERSION_1_38 = RemoteApiVersion.create(1, 38); public static final RemoteApiVersion VERSION_1_40 = RemoteApiVersion.create(1, 40); + public static final RemoteApiVersion VERSION_1_41 = RemoteApiVersion.create(1, 41); + public static final RemoteApiVersion VERSION_1_42 = RemoteApiVersion.create(1, 42); + public static final RemoteApiVersion VERSION_1_43 = RemoteApiVersion.create(1, 43); + public static final RemoteApiVersion VERSION_1_44 = RemoteApiVersion.create(1, 44); /** diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/SSLConfig.java b/docker-java-core/src/main/java/com/github/dockerjava/core/SSLConfig.java index 0346aa610..c3a05efb2 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/SSLConfig.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/SSLConfig.java @@ -1,22 +1,10 @@ package com.github.dockerjava.core; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; - -import javax.net.ssl.SSLContext; - /** - * Get an SSL Config. Allows for various different implementations. + * + * @deprecated use {@link com.github.dockerjava.transport.SSLConfig} */ -public interface SSLConfig { +@Deprecated +public interface SSLConfig extends com.github.dockerjava.transport.SSLConfig { - /** - * Get the SSL Context, from wherever it comes (file, keystore). - * - * @return an SSL context. - */ - SSLContext getSSLContext() throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, - KeyStoreException; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java b/docker-java-core/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java index 64aabd999..6bc5ad385 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/async/JsonStreamProcessor.java @@ -13,7 +13,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.dockerjava.api.async.ResultCallback; -import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientConfig; /** * @@ -33,7 +33,7 @@ public class JsonStreamProcessor implements ResponseStreamProcessor { @Deprecated public JsonStreamProcessor(Class clazz) { this( - DefaultDockerClientConfig.createDefaultConfigBuilder().build().getObjectMapper(), + DockerClientConfig.getDefaultObjectMapper(), new TypeReference() { } ); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrAsyncDockerCmd.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrAsyncDockerCmd.java index b576d7a05..9f83c0b4f 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrAsyncDockerCmd.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrAsyncDockerCmd.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.AsyncDockerCmd; @@ -12,8 +12,7 @@ public abstract class AbstrAsyncDockerCmd execution; public AbstrAsyncDockerCmd(DockerCmdAsyncExec execution) { - checkNotNull(execution, "execution was not specified"); - this.execution = execution; + this.execution = Objects.requireNonNull(execution, "execution was not specified"); } @Override diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java index 10e6b5212..17ff9a88e 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AbstrDockerCmd.java @@ -1,12 +1,11 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.IOException; import java.util.Base64; +import java.util.Objects; -import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,8 +23,7 @@ public abstract class AbstrDockerCmd, RES_T> impl protected transient DockerCmdSyncExec execution; public AbstrDockerCmd(DockerCmdSyncExec execution) { - checkNotNull(execution, "execution was not specified"); - this.execution = execution; + this.execution = Objects.requireNonNull(execution, "execution was not specified"); } @Override diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java index 6c5103b27..30a411dba 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.InputStream; +import java.util.Objects; import com.github.dockerjava.api.command.AttachContainerCmd; import com.github.dockerjava.api.model.Frame; @@ -61,7 +60,7 @@ public InputStream getStdin() { @Override public AttachContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); + Objects.requireNonNull(containerId, "containerId was not specified"); this.containerId = containerId; return this; } @@ -92,8 +91,7 @@ public AttachContainerCmd withStdErr(Boolean stderr) { @Override public AttachContainerCmd withStdIn(InputStream stdin) { - checkNotNull(stdin, "stdin was not specified"); - this.stdin = stdin; + this.stdin = Objects.requireNonNull(stdin, "stdin was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerResultCallback.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerResultCallback.java index f445789fc..1e4d22cc8 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerResultCallback.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/AttachContainerResultCallback.java @@ -13,6 +13,7 @@ * * @author Marcus Linke * + * @deprecated use {@link com.github.dockerjava.api.async.ResultCallback.Adapter} */ @Deprecated public class AttachContainerResultCallback extends ResultCallbackTemplate { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java index 1bd1af576..5d9e62909 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageCmdImpl.java @@ -13,10 +13,9 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Set; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Build an image from Dockerfile. */ @@ -79,7 +78,7 @@ public BuildImageCmdImpl(BuildImageCmd.Exec exec) { public BuildImageCmdImpl(BuildImageCmd.Exec exec, File dockerFileOrFolder) { super(exec); - checkNotNull(dockerFileOrFolder, "dockerFolder is null"); + Objects.requireNonNull(dockerFileOrFolder, "dockerFolder is null"); if (dockerFileOrFolder.isDirectory()) { withBaseDirectory(dockerFileOrFolder); @@ -91,7 +90,7 @@ public BuildImageCmdImpl(BuildImageCmd.Exec exec, File dockerFileOrFolder) { public BuildImageCmdImpl(BuildImageCmd.Exec exec, InputStream tarInputStream) { super(exec); - checkNotNull(tarInputStream, "tarInputStream is null"); + Objects.requireNonNull(tarInputStream, "tarInputStream is null"); withTarInputStream(tarInputStream); } @@ -232,8 +231,7 @@ public Set getExtraHosts() { @Deprecated @Override public BuildImageCmdImpl withTag(String tag) { - checkNotNull(tag, "Tag is null"); - this.tag = tag; + this.tag = Objects.requireNonNull(tag, "Tag is null"); return this; } @@ -328,7 +326,7 @@ public BuildImageCmd withBaseDirectory(File baseDirectory) { @Override public BuildImageCmdImpl withDockerfile(File dockerfile) { - checkNotNull(dockerfile); + Objects.requireNonNull(dockerfile); if (!dockerfile.exists()) { throw new IllegalArgumentException("Dockerfile does not exist"); } @@ -353,22 +351,19 @@ public BuildImageCmdImpl withDockerfile(File dockerfile) { @Override public BuildImageCmd withDockerfilePath(String dockerfilePath) { - checkNotNull(dockerfilePath, "dockerfilePath is null"); - this.dockerFilePath = dockerfilePath; + this.dockerFilePath = Objects.requireNonNull(dockerfilePath, "dockerfilePath is null"); return this; } @Override public BuildImageCmdImpl withTarInputStream(InputStream tarInputStream) { - checkNotNull(tarInputStream, "tarInputStream is null"); - this.tarInputStream = tarInputStream; + this.tarInputStream = Objects.requireNonNull(tarInputStream, "tarInputStream is null"); return this; } @Override public BuildImageCmd withBuildAuthConfigs(AuthConfigurations authConfigs) { - checkNotNull(authConfigs, "authConfig is null"); - this.buildAuthConfigs = authConfigs; + this.buildAuthConfigs = Objects.requireNonNull(authConfigs, "authConfig is null"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java index fbe22170c..f94a751d4 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/BuildImageResultCallback.java @@ -3,19 +3,19 @@ */ package com.github.dockerjava.core.command; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.model.BuildResponseItem; import com.github.dockerjava.core.async.ResultCallbackTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; /** * * @author Marcus Linke * + * @deprecated use {@link com.github.dockerjava.api.command.BuildImageResultCallback} */ @Deprecated public class BuildImageResultCallback extends ResultCallbackTemplate { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java index 1c8ad26a4..8458c7f7e 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CommitCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.util.Map; +import java.util.Objects; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.CommitCmd; @@ -90,8 +89,7 @@ public String getContainerId() { @Override public CommitCmdImpl withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } @@ -140,8 +138,7 @@ public CommitCmdImpl withAttachStdout(Boolean attachStdout) { @Override public CommitCmdImpl withCmd(String... cmd) { - checkNotNull(cmd, "cmd was not specified"); - this.cmd = cmd; + this.cmd = Objects.requireNonNull(cmd, "cmd was not specified"); return this; } @@ -153,29 +150,25 @@ public CommitCmdImpl withDisableNetwork(Boolean disableNetwork) { @Override public CommitCmdImpl withAuthor(String author) { - checkNotNull(author, "author was not specified"); - this.author = author; + this.author = Objects.requireNonNull(author, "author was not specified"); return this; } @Override public CommitCmdImpl withMessage(String message) { - checkNotNull(message, "message was not specified"); - this.message = message; + this.message = Objects.requireNonNull(message, "message was not specified"); return this; } @Override public CommitCmdImpl withTag(String tag) { - checkNotNull(tag, "tag was not specified"); - this.tag = tag; + this.tag = Objects.requireNonNull(tag, "tag was not specified"); return this; } @Override public CommitCmdImpl withRepository(String repository) { - checkNotNull(repository, "repository was not specified"); - this.repository = repository; + this.repository = Objects.requireNonNull(repository, "repository was not specified"); return this; } @@ -192,8 +185,7 @@ public String[] getEnv() { @Override public CommitCmdImpl withEnv(String... env) { - checkNotNull(env, "env was not specified"); - this.env = env; + this.env = Objects.requireNonNull(env, "env was not specified"); return this; } @@ -215,8 +207,7 @@ public ExposedPorts getExposedPorts() { @Override public CommitCmdImpl withExposedPorts(ExposedPorts exposedPorts) { - checkNotNull(exposedPorts, "exposedPorts was not specified"); - this.exposedPorts = exposedPorts; + this.exposedPorts = Objects.requireNonNull(exposedPorts, "exposedPorts was not specified"); return this; } @@ -227,8 +218,7 @@ public String getHostname() { @Override public CommitCmdImpl withHostname(String hostname) { - checkNotNull(hostname, "hostname was not specified"); - this.hostname = hostname; + this.hostname = Objects.requireNonNull(hostname, "hostname was not specified"); return this; } @@ -239,8 +229,7 @@ public Integer getMemory() { @Override public CommitCmdImpl withMemory(Integer memory) { - checkNotNull(memory, "memory was not specified"); - this.memory = memory; + this.memory = Objects.requireNonNull(memory, "memory was not specified"); return this; } @@ -251,8 +240,7 @@ public Integer getMemorySwap() { @Override public CommitCmdImpl withMemorySwap(Integer memorySwap) { - checkNotNull(memorySwap, "memorySwap was not specified"); - this.memorySwap = memorySwap; + this.memorySwap = Objects.requireNonNull(memorySwap, "memorySwap was not specified"); return this; } @@ -263,8 +251,7 @@ public Boolean isOpenStdin() { @Override public CommitCmdImpl withOpenStdin(Boolean openStdin) { - checkNotNull(openStdin, "openStdin was not specified"); - this.openStdin = openStdin; + this.openStdin = Objects.requireNonNull(openStdin, "openStdin was not specified"); return this; } @@ -275,8 +262,7 @@ public String[] getPortSpecs() { @Override public CommitCmdImpl withPortSpecs(String... portSpecs) { - checkNotNull(portSpecs, "portSpecs was not specified"); - this.portSpecs = portSpecs; + this.portSpecs = Objects.requireNonNull(portSpecs, "portSpecs was not specified"); return this; } @@ -309,8 +295,7 @@ public String getUser() { @Override public CommitCmdImpl withUser(String user) { - checkNotNull(user, "user was not specified"); - this.user = user; + this.user = Objects.requireNonNull(user, "user was not specified"); return this; } @@ -321,8 +306,7 @@ public Volumes getVolumes() { @Override public CommitCmdImpl withVolumes(Volumes volumes) { - checkNotNull(volumes, "volumes was not specified"); - this.volumes = volumes; + this.volumes = Objects.requireNonNull(volumes, "volumes was not specified"); return this; } @@ -333,8 +317,7 @@ public String getWorkingDir() { @Override public CommitCmdImpl withWorkingDir(String workingDir) { - checkNotNull(workingDir, "workingDir was not specified"); - this.workingDir = workingDir; + this.workingDir = Objects.requireNonNull(workingDir, "workingDir was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java index eb6baa5ab..14fc683ce 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ContainerDiffCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.util.List; +import java.util.Objects; import com.github.dockerjava.api.command.ContainerDiffCmd; import com.github.dockerjava.api.exception.DockerException; @@ -33,8 +32,7 @@ public String getContainerId() { @Override public ContainerDiffCmdImpl withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveFromContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveFromContainerCmdImpl.java index 8ca305616..e827b37c8 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveFromContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveFromContainerCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.InputStream; +import java.util.Objects; import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -37,15 +36,13 @@ public String getResource() { @Override public CopyArchiveFromContainerCmdImpl withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } @Override public CopyArchiveFromContainerCmdImpl withResource(String resource) { - checkNotNull(resource, "resource was not specified"); - this.resource = resource; + this.resource = Objects.requireNonNull(resource, "resource was not specified"); return this; } @@ -56,8 +53,7 @@ public String getHostPath() { @Override public CopyArchiveFromContainerCmdImpl withHostPath(String hostPath) { - checkNotNull(hostPath, "hostPath was not specified"); - this.hostPath = hostPath; + this.hostPath = Objects.requireNonNull(hostPath, "hostPath was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java index 2eb5f5835..a9b42e921 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CopyArchiveToContainerCmdImpl.java @@ -1,15 +1,14 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; import com.github.dockerjava.api.exception.DockerClientException; @@ -31,6 +30,8 @@ public class CopyArchiveToContainerCmdImpl extends AbstrDockerCmd implements CreateConfigCmd { + + @JsonProperty("Name") + private String name; + + @JsonProperty("Data") + private String data; + + @JsonProperty("Labels") + private Map labels; + + @Override + public String getName() { + return name; + } + + @Override + public String getData() { + return data; + } + + @Override + public Map getLabels() { + return labels; + } + + public CreateConfigCmdImpl(CreateConfigCmd.Exec exec) { + super(exec); + } + + @Override + public CreateConfigCmd withName(String name) { + this.name = Objects.requireNonNull(name, "name was not specified"); + return this; + } + + @Override + public CreateConfigCmd withData(byte[] data) { + Objects.requireNonNull(data, "data was not specified"); + this.data = Base64.getEncoder().encodeToString(data); + return this; + } + + @Override + public CreateConfigCmd withLabels(Map labels) { + this.labels = Objects.requireNonNull(labels, "labels was not specified"); + return this; + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java index f3089486e..9b7f8a8fe 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateContainerResponse; @@ -14,22 +14,29 @@ import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.api.model.Volumes; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; import javax.annotation.CheckForNull; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; -import static com.google.common.base.Preconditions.checkNotNull; import static java.util.Collections.singletonMap; /** * Creates a new container. * `/containers/create` */ +@JsonAutoDetect( + fieldVisibility = JsonAutoDetect.Visibility.NONE, + setterVisibility = JsonAutoDetect.Visibility.NONE, + getterVisibility = JsonAutoDetect.Visibility.NONE, + isGetterVisibility = JsonAutoDetect.Visibility.NONE, + creatorVisibility = JsonAutoDetect.Visibility.NONE +) public class CreateContainerCmdImpl extends AbstrDockerCmd implements CreateContainerCmd { @@ -122,17 +129,16 @@ public class CreateContainerCmdImpl extends AbstrDockerCmd aliases = null; private AuthConfig authConfig; + private String platform; + public CreateContainerCmdImpl(CreateContainerCmd.Exec exec, AuthConfig authConfig, String image) { super(exec); withAuthConfig(authConfig); @@ -149,7 +155,6 @@ public CreateContainerCmd withAuthConfig(AuthConfig authConfig) { } @Override - @JsonIgnore public List getAliases() { return aliases; } @@ -162,7 +167,7 @@ public CreateContainerCmd withAliases(String... aliases) { @Override public CreateContainerCmd withAliases(List aliases) { - checkNotNull(aliases, "aliases was not specified"); + Objects.requireNonNull(aliases, "aliases was not specified"); this.aliases = aliases; return this; } @@ -175,14 +180,14 @@ public String[] getCmd() { @Override public CreateContainerCmd withCmd(String... cmd) { - checkNotNull(cmd, "cmd was not specified"); + Objects.requireNonNull(cmd, "cmd was not specified"); this.cmd = cmd; return this; } @Override public CreateContainerCmd withCmd(List cmd) { - checkNotNull(cmd, "cmd was not specified"); + Objects.requireNonNull(cmd, "cmd was not specified"); return withCmd(cmd.toArray(new String[0])); } @@ -212,7 +217,7 @@ public String getDomainName() { @Override public CreateContainerCmd withDomainName(String domainName) { - checkNotNull(domainName, "no domainName was specified"); + Objects.requireNonNull(domainName, "no domainName was specified"); this.domainName = domainName; return this; } @@ -224,14 +229,14 @@ public String[] getEntrypoint() { @Override public CreateContainerCmd withEntrypoint(String... entrypoint) { - checkNotNull(entrypoint, "entrypoint was not specified"); + Objects.requireNonNull(entrypoint, "entrypoint was not specified"); this.entrypoint = entrypoint; return this; } @Override public CreateContainerCmd withEntrypoint(List entrypoint) { - checkNotNull(entrypoint, "entrypoint was not specified"); + Objects.requireNonNull(entrypoint, "entrypoint was not specified"); return withEntrypoint(entrypoint.toArray(new String[0])); } @@ -242,40 +247,38 @@ public String[] getEnv() { @Override public CreateContainerCmd withEnv(String... env) { - checkNotNull(env, "env was not specified"); + Objects.requireNonNull(env, "env was not specified"); this.env = env; return this; } @Override public CreateContainerCmd withEnv(List env) { - checkNotNull(env, "env was not specified"); + Objects.requireNonNull(env, "env was not specified"); return withEnv(env.toArray(new String[0])); } @Override - @JsonIgnore public ExposedPort[] getExposedPorts() { return exposedPorts.getExposedPorts(); } @Override public CreateContainerCmd withExposedPorts(ExposedPort... exposedPorts) { - checkNotNull(exposedPorts, "exposedPorts was not specified"); + Objects.requireNonNull(exposedPorts, "exposedPorts was not specified"); this.exposedPorts = new ExposedPorts(exposedPorts); return this; } @Override public CreateContainerCmd withExposedPorts(List exposedPorts) { - checkNotNull(exposedPorts, "exposedPorts was not specified"); + Objects.requireNonNull(exposedPorts, "exposedPorts was not specified"); return withExposedPorts(exposedPorts.toArray(new ExposedPort[0])); } /** * @see #stopSignal */ - @JsonIgnore @Override public String getStopSignal() { return stopSignal; @@ -283,7 +286,7 @@ public String getStopSignal() { @Override public CreateContainerCmd withStopSignal(String stopSignal) { - checkNotNull(stopSignal, "stopSignal wasn't specified."); + Objects.requireNonNull(stopSignal, "stopSignal wasn't specified."); this.stopSignal = stopSignal; return this; } @@ -306,7 +309,7 @@ public String getHostName() { @Override public CreateContainerCmd withHostName(String hostName) { - checkNotNull(hostName, "no hostName was specified"); + Objects.requireNonNull(hostName, "no hostName was specified"); this.hostName = hostName; return this; } @@ -318,20 +321,19 @@ public String getImage() { @Override public CreateContainerCmd withImage(String image) { - checkNotNull(image, "no image was specified"); + Objects.requireNonNull(image, "no image was specified"); this.image = image; return this; } @Override - @JsonIgnore public Map getLabels() { return labels; } @Override public CreateContainerCmd withLabels(Map labels) { - checkNotNull(labels, "labels was not specified"); + Objects.requireNonNull(labels, "labels was not specified"); this.labels = labels; return this; } @@ -343,7 +345,7 @@ public String getMacAddress() { @Override public CreateContainerCmd withMacAddress(String macAddress) { - checkNotNull(macAddress, "macAddress was not specified"); + Objects.requireNonNull(macAddress, "macAddress was not specified"); this.macAddress = macAddress; return this; } @@ -356,7 +358,7 @@ public String getName() { @Override public CreateContainerCmd withName(String name) { - checkNotNull(name, "name was not specified"); + Objects.requireNonNull(name, "name was not specified"); this.name = name; return this; } @@ -368,14 +370,14 @@ public String[] getPortSpecs() { @Override public CreateContainerCmd withPortSpecs(String... portSpecs) { - checkNotNull(portSpecs, "portSpecs was not specified"); + Objects.requireNonNull(portSpecs, "portSpecs was not specified"); this.portSpecs = portSpecs; return this; } @Override public CreateContainerCmd withPortSpecs(List portSpecs) { - checkNotNull(portSpecs, "portSpecs was not specified"); + Objects.requireNonNull(portSpecs, "portSpecs was not specified"); return withPortSpecs(portSpecs.toArray(new String[0])); } @@ -386,7 +388,7 @@ public String getUser() { @Override public CreateContainerCmd withUser(String user) { - checkNotNull(user, "user was not specified"); + Objects.requireNonNull(user, "user was not specified"); this.user = user; return this; } @@ -398,7 +400,7 @@ public Boolean isAttachStderr() { @Override public CreateContainerCmd withAttachStderr(Boolean attachStderr) { - checkNotNull(attachStderr, "attachStderr was not specified"); + Objects.requireNonNull(attachStderr, "attachStderr was not specified"); this.attachStderr = attachStderr; return this; } @@ -410,7 +412,7 @@ public Boolean isAttachStdin() { @Override public CreateContainerCmd withAttachStdin(Boolean attachStdin) { - checkNotNull(attachStdin, "attachStdin was not specified"); + Objects.requireNonNull(attachStdin, "attachStdin was not specified"); this.attachStdin = attachStdin; return this; } @@ -422,27 +424,26 @@ public Boolean isAttachStdout() { @Override public CreateContainerCmd withAttachStdout(Boolean attachStdout) { - checkNotNull(attachStdout, "attachStdout was not specified"); + Objects.requireNonNull(attachStdout, "attachStdout was not specified"); this.attachStdout = attachStdout; return this; } @Override - @JsonIgnore public Volume[] getVolumes() { return volumes.getVolumes(); } @Override public CreateContainerCmd withVolumes(Volume... volumes) { - checkNotNull(volumes, "volumes was not specified"); + Objects.requireNonNull(volumes, "volumes was not specified"); this.volumes = new Volumes(volumes); return this; } @Override public CreateContainerCmd withVolumes(List volumes) { - checkNotNull(volumes, "volumes was not specified"); + Objects.requireNonNull(volumes, "volumes was not specified"); return withVolumes(volumes.toArray(new Volume[0])); } @@ -453,7 +454,7 @@ public String getWorkingDir() { @Override public CreateContainerCmd withWorkingDir(String workingDir) { - checkNotNull(workingDir, "workingDir was not specified"); + Objects.requireNonNull(workingDir, "workingDir was not specified"); this.workingDir = workingDir; return this; } @@ -465,7 +466,7 @@ public Boolean isNetworkDisabled() { @Override public CreateContainerCmd withNetworkDisabled(Boolean disableNetwork) { - checkNotNull(disableNetwork, "disableNetwork was not specified"); + Objects.requireNonNull(disableNetwork, "disableNetwork was not specified"); this.networkDisabled = disableNetwork; return this; } @@ -478,7 +479,7 @@ public Boolean isStdInOnce() { @Override public CreateContainerCmd withStdInOnce(Boolean stdInOnce) { - checkNotNull(stdInOnce, "no stdInOnce was specified"); + Objects.requireNonNull(stdInOnce, "no stdInOnce was specified"); this.stdInOnce = stdInOnce; return this; } @@ -490,7 +491,7 @@ public Boolean isStdinOpen() { @Override public CreateContainerCmd withStdinOpen(Boolean stdinOpen) { - checkNotNull(stdinOpen, "no stdinOpen was specified"); + Objects.requireNonNull(stdinOpen, "no stdinOpen was specified"); this.stdinOpen = stdinOpen; return this; } @@ -503,7 +504,7 @@ public Boolean isTty() { @Override public CreateContainerCmd withTty(Boolean tty) { - checkNotNull(tty, "no tty was specified"); + Objects.requireNonNull(tty, "no tty was specified"); this.tty = tty; return this; } @@ -526,7 +527,7 @@ public String getIpv4Address() { @Override public CreateContainerCmd withIpv4Address(String ipv4Address) { - checkNotNull(ipv4Address, "no ipv4Address was specified"); + Objects.requireNonNull(ipv4Address, "no ipv4Address was specified"); this.ipv4Address = ipv4Address; return this; } @@ -538,7 +539,7 @@ public String getIpv6Address() { @Override public CreateContainerCmd withIpv6Address(String ipv6Address) { - checkNotNull(ipv6Address, "no ipv6Address was specified"); + Objects.requireNonNull(ipv6Address, "no ipv6Address was specified"); this.ipv6Address = ipv6Address; return this; } @@ -553,6 +554,18 @@ public CreateContainerCmdImpl withOnBuild(List onBuild) { return this; } + @CheckForNull + @Override + public String getPlatform() { + return platform; + } + + @Override + public CreateContainerCmd withPlatform(String platform) { + this.platform = platform; + return this; + } + /** * @throws NotFoundException No such container * @throws ConflictException Named container already exists @@ -587,7 +600,7 @@ public CreateContainerResponse exec() throws NotFoundException, ConflictExceptio containerNetwork.withAliases(aliases); } - if (containerNetwork != null) { + if (containerNetwork != null && hostConfig.getNetworkMode() != null) { networkingConfig = new NetworkingConfig() .withEndpointsConfig(singletonMap(hostConfig.getNetworkMode(), containerNetwork)); } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateImageCmdImpl.java index 9ecf84430..cab9607d0 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateImageCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.InputStream; +import java.util.Objects; import com.github.dockerjava.api.command.CreateImageCmd; import com.github.dockerjava.api.command.CreateImageResponse; @@ -54,7 +53,7 @@ public InputStream getImageStream() { */ @Override public CreateImageCmdImpl withRepository(String repository) { - checkNotNull(repository, "repository was not specified"); + Objects.requireNonNull(repository, "repository was not specified"); this.repository = repository; return this; } @@ -65,7 +64,7 @@ public CreateImageCmdImpl withRepository(String repository) { */ @Override public CreateImageCmdImpl withImageStream(InputStream imageStream) { - checkNotNull(imageStream, "imageStream was not specified"); + Objects.requireNonNull(imageStream, "imageStream was not specified"); this.imageStream = imageStream; return this; } @@ -76,7 +75,7 @@ public CreateImageCmdImpl withImageStream(InputStream imageStream) { */ @Override public CreateImageCmdImpl withTag(String tag) { - checkNotNull(tag, "tag was not specified"); + Objects.requireNonNull(tag, "tag was not specified"); this.tag = tag; return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateNetworkCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateNetworkCmdImpl.java index e6cff4c09..db2766796 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateNetworkCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateNetworkCmdImpl.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Objects; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.CreateNetworkCmd; @@ -10,8 +11,6 @@ import com.github.dockerjava.api.model.Network; import com.github.dockerjava.api.model.Network.Ipam; -import static com.google.common.base.Preconditions.checkNotNull; - public class CreateNetworkCmdImpl extends AbstrDockerCmd implements CreateNetworkCmd { @@ -147,7 +146,7 @@ public Map getLabels() { */ @Override public CreateNetworkCmd withLabels(Map labels) { - checkNotNull(labels, "labels was not specified"); + Objects.requireNonNull(labels, "labels was not specified"); this.labels = labels; return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateSecretCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateSecretCmdImpl.java index d86b04855..19891325a 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateSecretCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/CreateSecretCmdImpl.java @@ -4,7 +4,7 @@ import com.github.dockerjava.api.command.CreateSecretResponse; import com.github.dockerjava.api.model.SecretSpec; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * Creates a new secret @@ -16,7 +16,7 @@ public class CreateSecretCmdImpl extends AbstrDockerCmd getDriverOpts() { @Override public CreateVolumeCmdImpl withName(String name) { - checkNotNull(name, "name was not specified"); + Objects.requireNonNull(name, "name was not specified"); this.name = name; return this; } @Override public CreateVolumeCmdImpl withLabels(Map labels) { - checkNotNull(labels, "labels was not specified"); + Objects.requireNonNull(labels, "labels was not specified"); this.labels = labels; return this; } @Override public CreateVolumeCmdImpl withDriver(String driver) { - checkNotNull(driver, "driver was not specified"); + Objects.requireNonNull(driver, "driver was not specified"); this.driver = driver; return this; } @Override public CreateVolumeCmd withDriverOpts(Map driverOpts) { - checkNotNull(driverOpts, "driverOpts was not specified"); + Objects.requireNonNull(driverOpts, "driverOpts was not specified"); this.driverOpts = driverOpts; return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsCmdImpl.java index 230f6dd5a..f578b3a19 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsCmdImpl.java @@ -1,9 +1,8 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.util.List; import java.util.Map; +import java.util.Objects; import com.github.dockerjava.api.command.EventsCmd; import com.github.dockerjava.api.model.Event; @@ -38,35 +37,42 @@ public EventsCmd withUntil(String until) { @Override public EventsCmd withContainerFilter(String... container) { - checkNotNull(container, "container have not been specified"); + Objects.requireNonNull(container, "container have not been specified"); this.filters.withContainers(container); return this; } @Override public EventsCmd withImageFilter(String... image) { - checkNotNull(image, "image have not been specified"); + Objects.requireNonNull(image, "image have not been specified"); this.filters.withImages(image); return this; } @Override public EventsCmd withEventFilter(String... event) { - checkNotNull(event, "event have not been specified"); + Objects.requireNonNull(event, "event have not been specified"); this.filters.withFilter("event", event); return this; } + @Override + public EventsCmd withEventTypeFilter(String... eventTypes) { + Objects.requireNonNull(eventTypes, "event types have not been specified"); + this.filters.withEventTypes(eventTypes); + return this; + } + @Override public EventsCmd withLabelFilter(String... label) { - checkNotNull(label, "label have not been specified"); + Objects.requireNonNull(label, "label have not been specified"); this.filters.withLabels(label); return this; } @Override public EventsCmd withLabelFilter(Map labels) { - checkNotNull(labels, "labels have not been specified"); + Objects.requireNonNull(labels, "labels have not been specified"); this.filters.withLabels(labels); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java index 45b5b83e9..e6df7fbc1 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/EventsResultCallback.java @@ -13,6 +13,7 @@ * * @author Marcus Linke * + * @deprecated use {@link com.github.dockerjava.api.async.ResultCallback.Adapter} */ @Deprecated public class EventsResultCallback extends ResultCallbackTemplate { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java index dc410f78b..8ea6e275f 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecCreateCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.util.List; +import java.util.Objects; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.ExecCreateCmd; @@ -59,8 +58,7 @@ public ExecCreateCmdImpl(ExecCreateCmd.Exec exec, String containerId) { @Override public ExecCreateCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java index 9ab3bfb8e..d5990ef80 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.InputStream; +import java.util.Objects; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -37,8 +36,7 @@ public String getExecId() { @Override public ExecStartCmd withExecId(String execId) { - checkNotNull(execId, "execId was not specified"); - this.execId = execId; + this.execId = Objects.requireNonNull(execId, "execId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartResultCallback.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartResultCallback.java index 8a8235ac6..39c0e1e8c 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartResultCallback.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ExecStartResultCallback.java @@ -1,18 +1,18 @@ package com.github.dockerjava.core.command; -import java.io.IOException; -import java.io.OutputStream; - +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.async.ResultCallbackTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.github.dockerjava.api.model.Frame; -import com.github.dockerjava.core.async.ResultCallbackTemplate; +import java.io.IOException; +import java.io.OutputStream; /** * * @author Marcus Linke * + * @deprecated use {@link com.github.dockerjava.api.async.ResultCallback.Adapter} */ @Deprecated public class ExecStartResultCallback extends ResultCallbackTemplate { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ImageHistoryCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ImageHistoryCmdImpl.java new file mode 100644 index 000000000..fafbd8da1 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ImageHistoryCmdImpl.java @@ -0,0 +1,42 @@ +package com.github.dockerjava.core.command; + +import java.util.List; +import java.util.Objects; + +import com.github.dockerjava.api.command.ImageHistoryCmd; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.ImageHistory; + +/** + * Get the history of an image. + */ +public class ImageHistoryCmdImpl extends AbstrDockerCmd> implements + ImageHistoryCmd { + + private String imageId; + + public ImageHistoryCmdImpl(ImageHistoryCmd.Exec exec, String imageId) { + super(exec); + withImageId(imageId); + } + + @Override + public String getImageId() { + return imageId; + } + + @Override + public ImageHistoryCmd withImageId(String imageId) { + this.imageId = Objects.requireNonNull(imageId, "imageId was not specified"); + return this; + } + + /** + * @throws NotFoundException + * No such image + */ + @Override + public List exec() throws NotFoundException { + return super.exec(); + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InitializeSwarmCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InitializeSwarmCmdImpl.java index 6f81f1bf0..f13f307ad 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InitializeSwarmCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InitializeSwarmCmdImpl.java @@ -4,9 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.InitializeSwarmCmd; import com.github.dockerjava.api.model.SwarmSpec; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; import javax.annotation.CheckForNull; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectConfigCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectConfigCmdImpl.java new file mode 100644 index 000000000..eff4170cb --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectConfigCmdImpl.java @@ -0,0 +1,40 @@ +package com.github.dockerjava.core.command; + +import java.util.Objects; + +import com.github.dockerjava.api.command.InspectConfigCmd; +import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Config; + +/** + * Inspect the details of a config. + */ +public class InspectConfigCmdImpl extends AbstrDockerCmd implements InspectConfigCmd { + + private String configId; + + public InspectConfigCmdImpl(Exec exec, String configId) { + super(exec); + withConfigId(configId); + } + + @Override + public String getConfigId() { + return configId; + } + + @Override + public InspectConfigCmd withConfigId(String configId) { + this.configId = Objects.requireNonNull(configId, "configId was not specified"); + return this; + } + + /** + * @throws NotFoundException + * No such config + */ + @Override + public Config exec() throws NotFoundException { + return super.exec(); + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java index ed3c01b00..ab8c2989a 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.InspectContainerCmd; import com.github.dockerjava.api.command.InspectContainerResponse; @@ -27,8 +27,7 @@ public String getContainerId() { @Override public InspectContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java index 22d6d70f4..36ad73e28 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectExecCmdImpl.java @@ -1,9 +1,10 @@ package com.github.dockerjava.core.command; +import java.util.Objects; + import com.github.dockerjava.api.command.InspectExecCmd; import com.github.dockerjava.api.command.InspectExecResponse; import com.github.dockerjava.api.exception.NotFoundException; -import com.google.common.base.Preconditions; public class InspectExecCmdImpl extends AbstrDockerCmd implements InspectExecCmd { private String execId; @@ -20,8 +21,7 @@ public String getExecId() { @Override public InspectExecCmd withExecId(String execId) { - Preconditions.checkNotNull(execId, "execId was not specified"); - this.execId = execId; + this.execId = Objects.requireNonNull(execId, "execId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java index 48dd30757..5ffa7c5d7 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectImageCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.InspectImageCmd; import com.github.dockerjava.api.command.InspectImageResponse; @@ -26,8 +26,7 @@ public String getImageId() { @Override public InspectImageCmd withImageId(String imageId) { - checkNotNull(imageId, "imageId was not specified"); - this.imageId = imageId; + this.imageId = Objects.requireNonNull(imageId, "imageId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectServiceCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectServiceCmdImpl.java index 5b7dcd895..804710ce1 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectServiceCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectServiceCmdImpl.java @@ -1,11 +1,11 @@ package com.github.dockerjava.core.command; +import java.util.Objects; + import com.github.dockerjava.api.command.InspectServiceCmd; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Service; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Inspect the details of a container. */ @@ -26,8 +26,7 @@ public String getServiceId() { @Override public InspectServiceCmd withServiceId(String serviceId) { - checkNotNull(serviceId, "serviceId was not specified"); - this.serviceId = serviceId; + this.serviceId = Objects.requireNonNull(serviceId, "serviceId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectSwarmNodeCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectSwarmNodeCmdImpl.java index bf5e5164f..9289878d1 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectSwarmNodeCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectSwarmNodeCmdImpl.java @@ -6,7 +6,7 @@ import javax.annotation.CheckForNull; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * Inspect the details of a swarmNode. @@ -29,8 +29,7 @@ public String getSwarmNodeId() { @Override public InspectSwarmNodeCmd withSwarmNodeId(String swarmNodeId) { - checkNotNull(swarmNodeId, "swarmNodeId was not specified"); - this.swarmNodeId = swarmNodeId; + this.swarmNodeId = Objects.requireNonNull(swarmNodeId, "swarmNodeId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectVolumeCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectVolumeCmdImpl.java index c789d91c9..5b76310db 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectVolumeCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/InspectVolumeCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.InspectVolumeCmd; import com.github.dockerjava.api.command.InspectVolumeResponse; @@ -26,8 +26,7 @@ public String getName() { @Override public InspectVolumeCmd withName(String name) { - checkNotNull(name, "name was not specified"); - this.name = name; + this.name = Objects.requireNonNull(name, "name was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/JoinSwarmCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/JoinSwarmCmdImpl.java index 72a1cdb82..d19ed8ea2 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/JoinSwarmCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/JoinSwarmCmdImpl.java @@ -3,9 +3,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.JoinSwarmCmd; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; import javax.annotation.CheckForNull; import java.util.List; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java index a23d0caa5..bc7207829 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/KillContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.KillContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -29,15 +29,13 @@ public String getSignal() { @Override public KillContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } @Override public KillContainerCmd withSignal(String signal) { - checkNotNull(signal, "signal was not specified"); - this.signal = signal; + this.signal = Objects.requireNonNull(signal, "signal was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListConfigsCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListConfigsCmdImpl.java new file mode 100644 index 000000000..f67dd30b8 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListConfigsCmdImpl.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.core.command; + +import com.github.dockerjava.api.command.ListConfigsCmd; +import com.github.dockerjava.api.model.Config; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * List configs. + */ +public class ListConfigsCmdImpl extends AbstrDockerCmd> implements ListConfigsCmd { + + private Map> filters = Collections.emptyMap(); + + public ListConfigsCmdImpl(Exec exec) { + super(exec); + } + + @Override + public Map> getFilters() { + return filters; + } + + public ListConfigsCmd withFilters(Map> filters) { + this.filters = Objects.requireNonNull(filters, "filters was not specified"); + return this; + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListContainersCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListContainersCmdImpl.java index 0d0323a65..94de5daff 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListContainersCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListContainersCmdImpl.java @@ -7,9 +7,9 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; /** * List containers. @@ -73,7 +73,7 @@ public ListContainersCmd withShowSize(Boolean showSize) { @Override public ListContainersCmd withLimit(Integer limit) { - checkNotNull(limit, "limit was not specified"); + Objects.requireNonNull(limit, "limit was not specified"); checkArgument(limit > 0, "limit must be greater 0"); this.limit = limit; return this; @@ -81,15 +81,13 @@ public ListContainersCmd withLimit(Integer limit) { @Override public ListContainersCmd withSince(String since) { - checkNotNull(since, "since was not specified"); - this.sinceId = since; + this.sinceId = Objects.requireNonNull(since, "since was not specified"); return this; } @Override public ListContainersCmd withBefore(String before) { - checkNotNull(before, "before was not specified"); - this.beforeId = before; + this.beforeId = Objects.requireNonNull(before, "before was not specified"); return this; } @@ -125,28 +123,28 @@ public ListContainersCmd withLabelFilter(Collection labels) { @Override public ListContainersCmd withLabelFilter(Map labels) { - checkNotNull(labels, "labels was not specified"); + Objects.requireNonNull(labels, "labels was not specified"); this.filters.withLabels(labels); return this; } @Override public ListContainersCmd withExitedFilter(Integer exited) { - checkNotNull(exited, "exited was not specified"); + Objects.requireNonNull(exited, "exited was not specified"); this.filters.withFilter("exited", exited.toString()); return this; } @Override public ListContainersCmd withFilter(String filterName, Collection filterValues) { - checkNotNull(filterValues, filterName + " was not specified"); + Objects.requireNonNull(filterValues, filterName + " was not specified"); this.filters.withFilter(filterName, filterValues); return this; } @Override public ListContainersCmd withStatusFilter(Collection status) { - checkNotNull(status, "status was not specified"); + Objects.requireNonNull(status, "status was not specified"); this.filters.withFilter("status", status); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListImagesCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListImagesCmdImpl.java index 1033b43ec..40d378c8c 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListImagesCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListImagesCmdImpl.java @@ -1,12 +1,13 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; -import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import com.github.dockerjava.api.command.ListImagesCmd; import com.github.dockerjava.api.model.Image; @@ -45,32 +46,47 @@ public ListImagesCmd withShowAll(Boolean showAll) { @Override public ListImagesCmd withDanglingFilter(Boolean dangling) { - checkNotNull(dangling, "dangling have not been specified"); - filters.withFilter("dangling", dangling.toString()); + Objects.requireNonNull(dangling, "dangling have not been specified"); + withFilter("dangling", Collections.singletonList(dangling.toString())); return this; } @Override public ListImagesCmd withLabelFilter(String... labels) { - checkNotNull(labels, "labels have not been specified"); + Objects.requireNonNull(labels, "labels have not been specified"); filters.withLabels(labels); return this; } @Override public ListImagesCmd withLabelFilter(Map labels) { - checkNotNull(labels, "labels have not been specified"); + Objects.requireNonNull(labels, "labels have not been specified"); filters.withLabels(labels); return this; } @Override public ListImagesCmd withImageNameFilter(String imageNameFilter) { - checkNotNull(imageNameFilter, "image name filter not specified"); + Objects.requireNonNull(imageNameFilter, "image name filter not specified"); this.imageNameFilter = imageNameFilter; return this; } + @Override + public ListImagesCmd withReferenceFilter(String reference) { + Objects.requireNonNull(reference, "reference filter not specified"); + withFilter("reference", Collections.singletonList(reference)); + return this; + } + + @Override + public ListImagesCmd withFilter(String key, Collection values) { + Objects.requireNonNull(key, "key not specified"); + Objects.requireNonNull(values, "values not specified"); + filters.withFilter(key, values); + return this; + } + @Override public String getImageNameFilter() { return this.imageNameFilter; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListNetworksCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListNetworksCmdImpl.java index 65c13e255..b3be94b8e 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListNetworksCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListNetworksCmdImpl.java @@ -7,8 +7,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; public class ListNetworksCmdImpl extends AbstrDockerCmd> implements ListNetworksCmd { @@ -37,7 +36,7 @@ public ListNetworksCmd withNameFilter(String... networkName) { @Override public ListNetworksCmd withFilter(String filterName, Collection filterValues) { - checkNotNull(filterValues, filterName + " was not specified"); + Objects.requireNonNull(filterValues, filterName + " was not specified"); this.filtersBuilder.withFilter(filterName, filterValues); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSecretsCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSecretsCmdImpl.java index 5c11a7a19..bed3f9e51 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSecretsCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSecretsCmdImpl.java @@ -6,8 +6,7 @@ import java.util.List; import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * List services. @@ -28,21 +27,21 @@ public Map> getFilters() { @Override public ListSecretsCmd withIdFilter(List ids) { - checkNotNull(ids, "ids was not specified"); + Objects.requireNonNull(ids, "ids was not specified"); this.filters.withFilter("id", ids); return this; } @Override public ListSecretsCmd withNameFilter(List names) { - checkNotNull(names, "names was not specified"); + Objects.requireNonNull(names, "names was not specified"); this.filters.withFilter("name", names); return this; } @Override public ListSecretsCmd withLabelFilter(Map labels) { - checkNotNull(labels, "labels was not specified"); + Objects.requireNonNull(labels, "labels was not specified"); this.filters.withLabels(labels); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListServicesCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListServicesCmdImpl.java index c68a0f6d7..1245d14b3 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListServicesCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListServicesCmdImpl.java @@ -6,8 +6,7 @@ import java.util.List; import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * List services. @@ -28,21 +27,21 @@ public Map> getFilters() { @Override public ListServicesCmd withIdFilter(List ids) { - checkNotNull(ids, "ids was not specified"); + Objects.requireNonNull(ids, "ids was not specified"); this.filters.withFilter("id", ids); return this; } @Override public ListServicesCmd withNameFilter(List names) { - checkNotNull(names, "names was not specified"); + Objects.requireNonNull(names, "names was not specified"); this.filters.withFilter("name", names); return this; } @Override public ListServicesCmd withLabelFilter(Map labels) { - checkNotNull(labels, "labels was not specified"); + Objects.requireNonNull(labels, "labels was not specified"); this.filters.withLabels(labels); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSwarmNodesCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSwarmNodesCmdImpl.java index 5b5c5801f..a35751627 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSwarmNodesCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListSwarmNodesCmdImpl.java @@ -7,8 +7,7 @@ import java.util.List; import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * List SwarmNodes @@ -29,29 +28,29 @@ public Map> getFilters() { @Override public ListSwarmNodesCmd withIdFilter(List ids) { - checkNotNull(ids, "ids was not specified"); + Objects.requireNonNull(ids, "ids was not specified"); this.filters.withIds(ids); return this; } @Override public ListSwarmNodesCmd withNameFilter(List names) { - checkNotNull(names, "names was not specified"); + Objects.requireNonNull(names, "names was not specified"); this.filters.withNames(names); return this; } @Override public ListSwarmNodesCmd withMembershipFilter(List memberships) { - checkNotNull(memberships, "memberships was not specified"); - this.filters.withNames(memberships); + Objects.requireNonNull(memberships, "memberships was not specified"); + this.filters.withMemberships(memberships); return this; } @Override public ListSwarmNodesCmd withRoleFilter(List roles) { - checkNotNull(roles, "roles was not specified"); - this.filters.withNames(roles); + Objects.requireNonNull(roles, "roles was not specified"); + this.filters.withRoles(roles); return this; } } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListVolumesCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListVolumesCmdImpl.java index b3a18d776..78d39c2c7 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListVolumesCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ListVolumesCmdImpl.java @@ -1,10 +1,9 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import com.github.dockerjava.api.command.ListVolumesCmd; import com.github.dockerjava.api.command.ListVolumesResponse; @@ -30,14 +29,14 @@ public Map> getFilters() { @Override public ListVolumesCmd withDanglingFilter(Boolean dangling) { - checkNotNull(dangling, "dangling have not been specified"); + Objects.requireNonNull(dangling, "dangling have not been specified"); this.filters.withFilter("dangling", dangling.toString()); return this; } @Override public ListVolumesCmd withFilter(String filterName, Collection filterValues) { - checkNotNull(filterValues, filterName + " was not specified"); + Objects.requireNonNull(filterValues, filterName + " was not specified"); this.filters.withFilter(filterName, filterValues); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/LoadImageAsyncCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/LoadImageAsyncCmdImpl.java new file mode 100644 index 000000000..3de1dfa4d --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/LoadImageAsyncCmdImpl.java @@ -0,0 +1,41 @@ +package com.github.dockerjava.core.command; + +import com.github.dockerjava.api.command.LoadImageAsyncCmd; +import com.github.dockerjava.api.model.LoadResponseItem; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; + +public class LoadImageAsyncCmdImpl extends AbstrAsyncDockerCmd implements LoadImageAsyncCmd { + + private InputStream inputStream; + + public LoadImageAsyncCmdImpl(LoadImageAsyncCmd.Exec exec, InputStream inputStream) { + super(exec); + this.inputStream = inputStream; + } + + @Override + public InputStream getImageStream() { + return this.inputStream; + } + + @Override + public LoadImageAsyncCmd withImageStream(InputStream imageStream) { + Objects.requireNonNull(imageStream, "imageStream was not specified"); + this.inputStream = imageStream; + return this; + } + + @Override + public void close() { + super.close(); + + try { + this.inputStream.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/LoadImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/LoadImageCmdImpl.java index 496ea3176..0b8cbea94 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/LoadImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/LoadImageCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.InputStream; +import java.util.Objects; import com.github.dockerjava.api.command.LoadImageCmd; @@ -32,8 +31,7 @@ public InputStream getImageStream() { */ @Override public LoadImageCmdImpl withImageStream(@Nonnull InputStream imageStream) { - checkNotNull(imageStream, "imageStream was not specified"); - this.imageStream = imageStream; + this.imageStream = Objects.requireNonNull(imageStream, "imageStream was not specified"); return this; } } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/LogContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/LogContainerCmdImpl.java index aa267fc8f..65321a318 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/LogContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/LogContainerCmdImpl.java @@ -1,9 +1,9 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; -import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import com.github.dockerjava.api.command.LogContainerCmd; import com.github.dockerjava.api.model.Frame; @@ -24,6 +24,8 @@ * @param since * - UNIX timestamp (integer) to filter logs. Specifying a timestamp will only output log-entries since that timestamp. Default: * 0 (unfiltered) + * @param until + * - Only return logs before this time, as a UNIX timestamp. Default: 0 */ public class LogContainerCmdImpl extends AbstrAsyncDockerCmd implements LogContainerCmd { @@ -31,7 +33,7 @@ public class LogContainerCmdImpl extends AbstrAsyncDockerCmd { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java index a8caf3091..f646e8ced 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PauseContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.PauseContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -28,8 +28,7 @@ public String getContainerId() { @Override public PauseContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PruneCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PruneCmdImpl.java index a191099ed..e08f64b02 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PruneCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PruneCmdImpl.java @@ -9,8 +9,7 @@ import javax.annotation.Nonnull; import java.util.List; import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * Delete unused content (containers, images, volumes, networks, build relicts) @@ -69,28 +68,28 @@ public Map> getFilters() { @Override public PruneCmd withPruneType(final PruneType pruneType) { - checkNotNull(pruneType, "pruneType has not been specified"); + Objects.requireNonNull(pruneType, "pruneType has not been specified"); this.pruneType = pruneType; return this; } @Override public PruneCmd withDangling(Boolean dangling) { - checkNotNull(dangling, "dangling has not been specified"); + Objects.requireNonNull(dangling, "dangling has not been specified"); filters.withFilter("dangling", dangling ? "1" : "0"); return this; } @Override public PruneCmd withUntilFilter(final String until) { - checkNotNull(until, "until has not been specified"); + Objects.requireNonNull(until, "until has not been specified"); filters.withUntil(until); return this; } @Override public PruneCmd withLabelFilter(final String... labels) { - checkNotNull(labels, "labels have not been specified"); + Objects.requireNonNull(labels, "labels have not been specified"); filters.withLabels(labels); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageCmdImpl.java index a3395c21b..7f70ac3b7 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageCmdImpl.java @@ -1,11 +1,11 @@ package com.github.dockerjava.core.command; +import java.util.Objects; + import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.PullResponseItem; -import static com.google.common.base.Preconditions.checkNotNull; - /** * * Pull image from repository. @@ -54,15 +54,13 @@ public String getRegistry() { @Override public PullImageCmd withRepository(String repository) { - checkNotNull(repository, "repository was not specified"); - this.repository = repository; + this.repository = Objects.requireNonNull(repository, "repository was not specified"); return this; } @Override public PullImageCmd withTag(String tag) { - checkNotNull(tag, "tag was not specified"); - this.tag = tag; + this.tag = Objects.requireNonNull(tag, "tag was not specified"); return this; } @@ -74,8 +72,7 @@ public PullImageCmd withPlatform(String platform) { @Override public PullImageCmd withRegistry(String registry) { - checkNotNull(registry, "registry was not specified"); - this.registry = registry; + this.registry = Objects.requireNonNull(registry, "registry was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java index d7bad3256..67b6b5e48 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java @@ -18,6 +18,7 @@ * * @author Marcus Linke * + * @deprecated use {@link com.github.dockerjava.api.command.PullImageResultCallback} */ @Deprecated public class PullImageResultCallback extends ResultCallbackTemplate { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageCmdImpl.java index b3026c841..8e1fa5cec 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.PushImageCmd; import com.github.dockerjava.api.model.AuthConfig; @@ -42,8 +42,7 @@ public String getTag() { */ @Override public PushImageCmd withName(String name) { - checkNotNull(name, "name was not specified"); - this.name = name; + this.name = Objects.requireNonNull(name, "name was not specified"); return this; } @@ -53,8 +52,7 @@ public PushImageCmd withName(String name) { */ @Override public PushImageCmd withTag(String tag) { - checkNotNull(tag, "tag was not specified"); - this.tag = tag; + this.tag = Objects.requireNonNull(tag, "tag was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java index 3e16eec2f..06f1fbc8d 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/PushImageResultCallback.java @@ -16,6 +16,7 @@ * * @author Marcus Linke * + * @deprecated use {@link com.github.dockerjava.api.async.ResultCallback.Adapter} */ @Deprecated public class PushImageResultCallback extends ResultCallbackTemplate { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveConfigCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveConfigCmdImpl.java new file mode 100644 index 000000000..e2e7d06fd --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveConfigCmdImpl.java @@ -0,0 +1,39 @@ +package com.github.dockerjava.core.command; + +import java.util.Objects; + +import com.github.dockerjava.api.command.RemoveConfigCmd; +import com.github.dockerjava.api.exception.NotFoundException; + +/** + * Remove a config. + */ +public class RemoveConfigCmdImpl extends AbstrDockerCmd implements RemoveConfigCmd { + + private String configId; + + public RemoveConfigCmdImpl(Exec exec, String configId) { + super(exec); + withConfigId(configId); + } + + @Override + public String getConfigId() { + return configId; + } + + @Override + public RemoveConfigCmd withConfigId(String configId) { + this.configId = Objects.requireNonNull(configId, "configId was not specified"); + return this; + } + + /** + * @throws NotFoundException + * No such secret + */ + @Override + public Void exec() throws NotFoundException { + return super.exec(); + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java index 0fc2ab626..cd8f4a9f3 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.RemoveContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -41,8 +41,7 @@ public Boolean hasForceEnabled() { @Override public RemoveContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java index 038a27f2d..a77357b59 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveImageCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.RemoveImageCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -38,8 +38,7 @@ public Boolean hasNoPruneEnabled() { @Override public RemoveImageCmd withImageId(String imageId) { - checkNotNull(imageId, "imageId was not specified"); - this.imageId = imageId; + this.imageId = Objects.requireNonNull(imageId, "imageId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSecretCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSecretCmdImpl.java index 6841d79bd..5c8d0e075 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSecretCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSecretCmdImpl.java @@ -3,7 +3,7 @@ import com.github.dockerjava.api.command.RemoveSecretCmd; import com.github.dockerjava.api.exception.NotFoundException; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * Remove a secret. @@ -24,8 +24,7 @@ public String getSecretId() { @Override public RemoveSecretCmd withSecretId(String secretId) { - checkNotNull(secretId, "secretId was not specified"); - this.secretId = secretId; + this.secretId = Objects.requireNonNull(secretId, "secretId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveServiceCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveServiceCmdImpl.java index 9da85847a..6fed721c7 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveServiceCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveServiceCmdImpl.java @@ -3,7 +3,7 @@ import com.github.dockerjava.api.command.RemoveServiceCmd; import com.github.dockerjava.api.exception.NotFoundException; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; /** * Remove a service. @@ -24,8 +24,7 @@ public String getServiceId() { @Override public RemoveServiceCmd withServiceId(String serviceId) { - checkNotNull(serviceId, "serviceId was not specified"); - this.serviceId = serviceId; + this.serviceId = Objects.requireNonNull(serviceId, "serviceId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSwarmNodeCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSwarmNodeCmdImpl.java index bf9029e72..ef8a86943 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSwarmNodeCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RemoveSwarmNodeCmdImpl.java @@ -3,11 +3,11 @@ import com.github.dockerjava.api.command.RemoveSwarmNodeCmd; import com.github.dockerjava.api.exception.NotFoundException; +import java.util.Objects; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Remove a container. */ @@ -17,9 +17,9 @@ public class RemoveSwarmNodeCmdImpl extends AbstrDockerCmd implements RenameContainerCmd { @@ -30,15 +30,13 @@ public String getName() { @Override public RenameContainerCmd withContainerId(@Nonnull String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } @Override public RenameContainerCmd withName(@Nonnull String name) { - checkNotNull(name, "name was not specified"); - this.name = name; + this.name = Objects.requireNonNull(name, "name was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeContainerCmdImpl.java new file mode 100644 index 000000000..188802a41 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeContainerCmdImpl.java @@ -0,0 +1,56 @@ +package com.github.dockerjava.core.command; + +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.api.exception.NotFoundException; + +import java.util.Objects; + +public class ResizeContainerCmdImpl extends AbstrDockerCmd implements ResizeContainerCmd { + + private String containerId; + + private Integer height; + + private Integer width; + + public ResizeContainerCmdImpl(ResizeContainerCmd.Exec exec, String execId) { + super(exec); + withContainerId(execId); + } + + @Override + public String getContainerId() { + return containerId; + } + + @Override + public Integer getHeight() { + return height; + } + + @Override + public Integer getWidth() { + return width; + } + + @Override + public ResizeContainerCmd withContainerId(String containerId) { + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); + return this; + } + + @Override + public ResizeContainerCmd withSize(int height, int width) { + this.height = height; + this.width = width; + return this; + } + + /** + * @throws NotFoundException no such exec instance + */ + @Override + public Void exec() throws NotFoundException { + return super.exec(); + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeExecCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeExecCmdImpl.java new file mode 100644 index 000000000..3aa02c7e9 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/ResizeExecCmdImpl.java @@ -0,0 +1,57 @@ +package com.github.dockerjava.core.command; + +import java.util.Objects; + +import com.github.dockerjava.api.command.ResizeExecCmd; +import com.github.dockerjava.api.exception.NotFoundException; + +public class ResizeExecCmdImpl extends AbstrDockerCmd implements ResizeExecCmd { + + private String execId; + + private Integer height; + + private Integer width; + + public ResizeExecCmdImpl(ResizeExecCmd.Exec exec, String execId) { + super(exec); + withExecId(execId); + } + + @Override + public String getExecId() { + return execId; + } + + @Override + public Integer getHeight() { + return height; + } + + @Override + public Integer getWidth() { + return width; + } + + @Override + public ResizeExecCmd withExecId(String execId) { + this.execId = Objects.requireNonNull(execId, "execId was not specified"); + return this; + } + + @Override + public ResizeExecCmd withSize(int height, int width) { + this.height = height; + this.width = width; + return this; + } + + /** + * @throws NotFoundException no such exec instance + */ + @Override + public Void exec() throws NotFoundException { + return super.exec(); + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java index e3621af4f..3b1df465b 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/RestartContainerCmdImpl.java @@ -1,17 +1,19 @@ package com.github.dockerjava.core.command; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; import com.github.dockerjava.api.command.RestartContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; +import javax.annotation.CheckForNull; + /** * Restart a running container. * - * @param timeout - * - Timeout in seconds before killing the container. Defaults to 10 seconds. - * + * @param signal - Signal to send to the container as an integer or string (e.g. SIGINT). + * @param timeout - Timeout in seconds before killing the container. Defaults to 10 seconds. */ public class RestartContainerCmdImpl extends AbstrDockerCmd implements RestartContainerCmd { @@ -19,6 +21,8 @@ public class RestartContainerCmdImpl extends AbstrDockerCmd= 0, "timeout must be greater or equal 0"); this.timeout = timeout; return this; } + @Override + public RestartContainerCmd withSignal(String signal) { + Objects.requireNonNull(signal, "signal was not specified"); + this.signal = signal; + return this; + } + /** - * @throws NotFoundException - * No such container + * @throws NotFoundException No such container */ @Override public Void exec() throws NotFoundException { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java index 333e32df7..0ec72bcc5 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImageCmdImpl.java @@ -1,8 +1,7 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; - import java.io.InputStream; +import java.util.Objects; import com.github.dockerjava.api.command.SaveImageCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -33,8 +32,7 @@ public String getTag() { */ @Override public SaveImageCmd withName(String name) { - checkNotNull(name, "name was not specified"); - this.name = name; + this.name = Objects.requireNonNull(name, "name was not specified"); return this; } @@ -44,8 +42,7 @@ public SaveImageCmd withName(String name) { */ @Override public SaveImageCmd withTag(String tag) { - checkNotNull(tag, "tag was not specified"); - this.tag = tag; + this.tag = Objects.requireNonNull(tag, "tag was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImagesCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImagesCmdImpl.java index 0563e16fe..43e11f609 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImagesCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/SaveImagesCmdImpl.java @@ -7,8 +7,7 @@ import javax.annotation.Nonnull; import java.io.InputStream; import java.util.List; - -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; public class SaveImagesCmdImpl extends AbstrDockerCmd implements SaveImagesCmd { @@ -17,10 +16,8 @@ private static class TaggedImageImpl implements TaggedImage { private final String tag; private TaggedImageImpl(String name, String tag) { - checkNotNull(name, "image name was not specified"); - checkNotNull(tag, "image tag was not specified"); - this.name = name; - this.tag = tag; + this.name = Objects.requireNonNull(name, "image name was not specified"); + this.tag = Objects.requireNonNull(tag, "image tag was not specified"); } @Override diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/SearchImagesCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/SearchImagesCmdImpl.java index dab946b1c..41b8cc844 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/SearchImagesCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/SearchImagesCmdImpl.java @@ -1,9 +1,9 @@ package com.github.dockerjava.core.command; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; import java.util.List; +import java.util.Objects; import com.github.dockerjava.api.command.SearchImagesCmd; import com.github.dockerjava.api.model.SearchItem; @@ -37,8 +37,7 @@ public String getTerm() { @Override public SearchImagesCmd withTerm(String term) { - checkNotNull(term, "term was not specified"); - this.term = term; + this.term = Objects.requireNonNull(term, "term was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java index c159c920e..2c0e2c2b8 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/StartContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.fasterxml.jackson.annotation.JsonIgnore; import com.github.dockerjava.api.command.StartContainerCmd; @@ -22,8 +22,7 @@ public StartContainerCmdImpl(StartContainerCmd.Exec exec, String containerId) { @Override public StartContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/StatsCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/StatsCmdImpl.java index e1cc86e68..3e24bd5af 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/StatsCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/StatsCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.StatsCmd; import com.github.dockerjava.api.model.Statistics; @@ -21,8 +21,7 @@ public StatsCmdImpl(StatsCmd.Exec exec, String containerId) { @Override public StatsCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java index 7b1e165f5..2cf5e37ae 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/StopContainerCmdImpl.java @@ -1,7 +1,8 @@ package com.github.dockerjava.core.command; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; import com.github.dockerjava.api.command.StopContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -39,14 +40,13 @@ public Integer getTimeout() { @Override public StopContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } @Override public StopContainerCmd withTimeout(Integer timeout) { - checkNotNull(timeout, "timeout was not specified"); + Objects.requireNonNull(timeout, "timeout was not specified"); checkArgument(timeout >= 0, "timeout must be greater or equal 0"); this.timeout = timeout; return this; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/TagImageCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/TagImageCmdImpl.java index c1337112d..f7eebb8a4 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/TagImageCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/TagImageCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.TagImageCmd; @@ -50,22 +50,19 @@ public Boolean hasForceEnabled() { @Override public TagImageCmd withImageId(String imageId) { - checkNotNull(imageId, "imageId was not specified"); - this.imageId = imageId; + this.imageId = Objects.requireNonNull(imageId, "imageId was not specified"); return this; } @Override public TagImageCmd withRepository(String repository) { - checkNotNull(repository, "repository was not specified"); - this.repository = repository; + this.repository = Objects.requireNonNull(repository, "repository was not specified"); return this; } @Override public TagImageCmd withTag(String tag) { - checkNotNull(tag, "tag was not specified"); - this.tag = tag; + this.tag = Objects.requireNonNull(tag, "tag was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java index 19faed3f2..5f5eee8d0 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/TopContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.TopContainerCmd; import com.github.dockerjava.api.command.TopContainerResponse; @@ -33,15 +33,13 @@ public String getPsArgs() { @Override public TopContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } @Override public TopContainerCmd withPsArgs(String psArgs) { - checkNotNull(psArgs, "psArgs was not specified"); - this.psArgs = psArgs; + this.psArgs = Objects.requireNonNull(psArgs, "psArgs was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java index 26e9992b0..ef94c1979 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UnpauseContainerCmdImpl.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; import com.github.dockerjava.api.command.UnpauseContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; @@ -28,8 +28,7 @@ public String getContainerId() { @Override public UnpauseContainerCmd withContainerId(String containerId) { - checkNotNull(containerId, "containerId was not specified"); - this.containerId = containerId; + this.containerId = Objects.requireNonNull(containerId, "containerId was not specified"); return this; } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateContainerCmdImpl.java index aad2b19e3..47ab710eb 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateContainerCmdImpl.java @@ -4,14 +4,21 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.github.dockerjava.api.command.UpdateContainerCmd; import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.BlkioRateDevice; +import com.github.dockerjava.api.model.BlkioWeightDevice; +import com.github.dockerjava.api.model.Device; +import com.github.dockerjava.api.model.DeviceRequest; +import com.github.dockerjava.api.model.RestartPolicy; +import com.github.dockerjava.api.model.Ulimit; import com.github.dockerjava.api.model.UpdateContainerResponse; import com.github.dockerjava.core.RemoteApiVersion; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; +import java.util.List; /** * @author Kanstantsin Shautsou @@ -28,14 +35,38 @@ public class UpdateContainerCmdImpl extends AbstrDockerCmd blkioWeightDevice; + + @JsonProperty("BlkioDeviceReadBps") + private List blkioDeviceReadBps; + + @JsonProperty("BlkioDeviceWriteBps") + private List blkioDeviceWriteBps; + + @JsonProperty("BlkioDeviceReadIOps") + private List blkioDeviceReadIOps; + + @JsonProperty("BlkioDeviceWriteIOps") + private List blkioDeviceWriteIOps; + @JsonProperty("CpuShares") private Integer cpuShares; @JsonProperty("CpuPeriod") - private Integer cpuPeriod; + private Long cpuPeriod; @JsonProperty("CpuQuota") - private Integer cpuQuota; + private Long cpuQuota; + + @JsonProperty("CpuRealtimePeriod") + private Long cpuRealtimePeriod; + + @JsonProperty("CpuRealtimeRuntime") + private Long cpuRealtimeRuntime; + + @JsonProperty("NanoCpus") + private Long nanoCPUs; @JsonProperty("CpusetCpus") private String cpusetCpus; @@ -43,6 +74,18 @@ public class UpdateContainerCmdImpl extends AbstrDockerCmd devices; + + @JsonProperty("DeviceCgroupRules") + private List deviceCgroupRules; + + /** + * @since {@link com.github.dockerjava.core.RemoteApiVersion#VERSION_1_40} + */ + @JsonProperty("DeviceRequests") + private List deviceRequests; + @JsonProperty("Memory") private Long memory; @@ -55,11 +98,43 @@ public class UpdateContainerCmdImpl extends AbstrDockerCmd ulimits; + + @JsonProperty("RestartPolicy") + private RestartPolicy restartPolicy; + public UpdateContainerCmdImpl(UpdateContainerCmd.Exec exec, String containerId) { super(exec); withContainerId(containerId); } + /** + * @see #containerId + */ + @CheckForNull + @JsonIgnore + public String getContainerId() { + return containerId; + } + + /** + * @see #containerId + */ + public UpdateContainerCmd withContainerId(@Nonnull String containerId) { + this.containerId = containerId; + return this; + } + /** * @see #blkioWeight */ @@ -77,19 +152,68 @@ public UpdateContainerCmd withBlkioWeight(Integer blkioWeight) { } /** - * @see #containerId + * @see #blkioWeightDevice */ @CheckForNull - @JsonIgnore - public String getContainerId() { - return containerId; + public List getBlkioWeightDevice() { + return blkioWeightDevice; + } + + public UpdateContainerCmd withBlkioWeightDevice(List blkioWeightDevice) { + this.blkioWeightDevice = blkioWeightDevice; + return this; } /** - * @see #containerId + * @see #blkioDeviceReadBps */ - public UpdateContainerCmd withContainerId(@Nonnull String containerId) { - this.containerId = containerId; + @CheckForNull + public List getBlkioDeviceReadBps() { + return blkioDeviceReadBps; + } + + public UpdateContainerCmd withBlkioDeviceReadBps(List blkioDeviceReadBps) { + this.blkioDeviceReadBps = blkioDeviceReadBps; + return this; + } + + /** + * @see #blkioDeviceWriteBps + */ + @CheckForNull + public List getBlkioDeviceWriteBps() { + return blkioDeviceWriteBps; + } + + public UpdateContainerCmd withBlkioDeviceWriteBps(List blkioDeviceWriteBps) { + this.blkioDeviceWriteBps = blkioDeviceWriteBps; + return this; + } + + /** + * @see #blkioDeviceReadIOps + */ + @CheckForNull + public List getBlkioDeviceReadIOps() { + return blkioDeviceReadIOps; + } + + public UpdateContainerCmd withBlkioDeviceReadIOps(List blkioDeviceReadIOps) { + this.blkioDeviceReadIOps = blkioDeviceReadIOps; + return this; + } + + /** + * @see #blkioDeviceWriteIOps + */ + @CheckForNull + public List getBlkioDeviceWriteIOps() { + return blkioDeviceWriteIOps; + } + + @Override + public UpdateContainerCmd withBlkioDeviceWriteIOps(List blkioDeviceWriteIOps) { + this.blkioDeviceWriteIOps = blkioDeviceWriteIOps; return this; } @@ -97,14 +221,14 @@ public UpdateContainerCmd withContainerId(@Nonnull String containerId) { * @see #cpuPeriod */ @CheckForNull - public Integer getCpuPeriod() { + public Long getCpuPeriod() { return cpuPeriod; } /** * @see #cpuPeriod */ - public UpdateContainerCmd withCpuPeriod(Integer cpuPeriod) { + public UpdateContainerCmd withCpuPeriod(Long cpuPeriod) { this.cpuPeriod = cpuPeriod; return this; } @@ -113,14 +237,14 @@ public UpdateContainerCmd withCpuPeriod(Integer cpuPeriod) { * @see #cpuQuota */ @CheckForNull - public Integer getCpuQuota() { + public Long getCpuQuota() { return cpuQuota; } /** * @see #cpuQuota */ - public UpdateContainerCmd withCpuQuota(Integer cpuQuota) { + public UpdateContainerCmd withCpuQuota(Long cpuQuota) { this.cpuQuota = cpuQuota; return this; } @@ -173,6 +297,71 @@ public UpdateContainerCmd withCpuShares(Integer cpuShares) { return this; } + /** + * @see #cpuRealtimePeriod + */ + @CheckForNull + public Long getCpuRealtimePeriod() { + return cpuRealtimePeriod; + } + + public UpdateContainerCmd withCpuRealtimePeriod(Long cpuRealtimePeriod) { + this.cpuRealtimePeriod = cpuRealtimePeriod; + return this; + } + + /** + * @see #cpuRealtimeRuntime + */ + @CheckForNull + public Long getCpuRealtimeRuntime() { + return cpuRealtimeRuntime; + } + + public UpdateContainerCmd withCpuRealtimeRuntime(Long cpuRealtimeRuntime) { + this.cpuRealtimeRuntime = cpuRealtimeRuntime; + return this; + } + + /** + * @see #devices + */ + @CheckForNull + public List getDevices() { + return devices; + } + + public UpdateContainerCmd withDevices(List devices) { + this.devices = devices; + return this; + } + + /** + * @see #deviceCgroupRules + */ + @CheckForNull + public List getDeviceCgroupRules() { + return deviceCgroupRules; + } + + public UpdateContainerCmd withDeviceCgroupRules(List deviceCgroupRules) { + this.deviceCgroupRules = deviceCgroupRules; + return this; + } + + /** + * @see #deviceRequests + */ + @CheckForNull + public List getDeviceRequests() { + return deviceRequests; + } + + public UpdateContainerCmd withDeviceRequests(List deviceRequests) { + this.deviceRequests = deviceRequests; + return this; + } + /** * @see #kernelMemory */ @@ -237,6 +426,84 @@ public UpdateContainerCmd withMemorySwap(Long memorySwap) { return this; } + /** + * @see #nanoCPUs + */ + @CheckForNull + public Long getNanoCPUs() { + return nanoCPUs; + } + + public UpdateContainerCmd withNanoCPUs(Long nanoCPUs) { + this.nanoCPUs = nanoCPUs; + return this; + } + + /** + * @see #oomKillDisable + */ + @CheckForNull + public Boolean getOomKillDisable() { + return oomKillDisable; + } + + public UpdateContainerCmd withOomKillDisable(Boolean oomKillDisable) { + this.oomKillDisable = oomKillDisable; + return this; + } + + /** + * @see #init + */ + @CheckForNull + public Boolean getInit() { + return init; + } + + public UpdateContainerCmd withInit(Boolean init) { + this.init = init; + return this; + } + + /** + * @see #pidsLimit + */ + @CheckForNull + public Long getPidsLimit() { + return pidsLimit; + } + + public UpdateContainerCmd withPidsLimit(Long pidsLimit) { + this.pidsLimit = pidsLimit; + return this; + } + + /** + * @see #ulimits + */ + @CheckForNull + public List getUlimits() { + return ulimits; + } + + public UpdateContainerCmd withUlimits(List ulimits) { + this.ulimits = ulimits; + return this; + } + + /** + * @see #restartPolicy + */ + @CheckForNull + public RestartPolicy getRestartPolicy() { + return restartPolicy; + } + + public UpdateContainerCmd withRestartPolicy(RestartPolicy restartPolicy) { + this.restartPolicy = restartPolicy; + return this; + } + /** * @throws NotFoundException No such container */ diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateServiceCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateServiceCmdImpl.java index 664ffd997..7ff9412a9 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateServiceCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateServiceCmdImpl.java @@ -4,10 +4,10 @@ import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.ServiceSpec; import com.github.dockerjava.core.RemoteApiVersion; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmCmdImpl.java index d1eefcae2..372cd34ce 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmCmdImpl.java @@ -1,11 +1,11 @@ package com.github.dockerjava.core.command; +import java.util.Objects; + import com.github.dockerjava.api.command.UpdateSwarmCmd; import com.github.dockerjava.api.model.SwarmSpec; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Update a swarm. */ @@ -62,8 +62,7 @@ public SwarmSpec getSwarmSpec() { @Override public UpdateSwarmCmd withSwarmSpec(SwarmSpec swarmSpec) { - checkNotNull(swarmSpec, "swarmSpec was not specified"); - this.swarmSpec = swarmSpec; + this.swarmSpec = Objects.requireNonNull(swarmSpec, "swarmSpec was not specified"); return this; } } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmNodeCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmNodeCmdImpl.java index 278599641..a2f22fa14 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmNodeCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/UpdateSwarmNodeCmdImpl.java @@ -4,10 +4,10 @@ import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.SwarmNodeSpec; import com.github.dockerjava.core.RemoteApiVersion; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/command/WaitContainerCmdImpl.java b/docker-java-core/src/main/java/com/github/dockerjava/core/command/WaitContainerCmdImpl.java index eeb05ff60..b627e2ccd 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/command/WaitContainerCmdImpl.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/command/WaitContainerCmdImpl.java @@ -1,8 +1,11 @@ package com.github.dockerjava.core.command; -import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Objects; + +import javax.annotation.Nullable; import com.github.dockerjava.api.command.WaitContainerCmd; +import com.github.dockerjava.api.model.WaitContainerCondition; import com.github.dockerjava.api.model.WaitResponse; /** @@ -15,6 +18,8 @@ public class WaitContainerCmdImpl extends AbstrAsyncDockerCmd { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java b/docker-java-core/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java index aefff137d..fb2447c2d 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java @@ -8,7 +8,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import com.github.dockerjava.api.exception.DockerClientException; import com.google.common.base.MoreObjects; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/AbstrDockerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/AbstrDockerCmdExec.java index d1d2adc3e..ad7f285f4 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/AbstrDockerCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/AbstrDockerCmdExec.java @@ -13,10 +13,10 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import java.io.IOException; +import java.util.Objects; import static com.github.dockerjava.core.RemoteApiVersion.UNKNOWN_VERSION; import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_19; -import static com.google.common.base.Preconditions.checkNotNull; public abstract class AbstrDockerCmdExec { @@ -25,10 +25,8 @@ public abstract class AbstrDockerCmdExec { private final transient WebTarget baseResource; public AbstrDockerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { - checkNotNull(baseResource, "baseResource was not specified"); - checkNotNull(dockerClientConfig, "dockerClientConfig was not specified"); - this.baseResource = baseResource; - this.dockerClientConfig = dockerClientConfig; + this.baseResource = Objects.requireNonNull(baseResource, "baseResource was not specified"); + this.dockerClientConfig = Objects.requireNonNull(dockerClientConfig, "dockerClientConfig was not specified"); } protected WebTarget getBaseResource() { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/BuildImageCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/BuildImageCmdExec.java index edf9b6bf9..aa65fff40 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/BuildImageCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/BuildImageCmdExec.java @@ -15,7 +15,7 @@ import javax.annotation.CheckForNull; import static com.github.dockerjava.core.util.CacheFromEncoder.jsonEncode; -import static org.apache.commons.lang.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; public class BuildImageCmdExec extends AbstrAsyncDockerCmdExec implements BuildImageCmd.Exec { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CopyArchiveToContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CopyArchiveToContainerCmdExec.java index d1effbb3e..ea4a527b1 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CopyArchiveToContainerCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CopyArchiveToContainerCmdExec.java @@ -28,7 +28,9 @@ protected Void execute(CopyArchiveToContainerCmd command) { InputStream streamToUpload = command.getTarInputStream(); webResource.queryParam("path", command.getRemotePath()) - .queryParam("noOverwriteDirNonDir", command.isNoOverwriteDirNonDir()).request() + .queryParam("noOverwriteDirNonDir", command.isNoOverwriteDirNonDir()) + .queryParam("copyUIDGID", command.isCopyUIDGID()) + .request() .put(streamToUpload, MediaType.APPLICATION_X_TAR); return null; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CreateConfigCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CreateConfigCmdExec.java new file mode 100644 index 000000000..4ead9cb48 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CreateConfigCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.core.exec; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.CreateConfigCmd; +import com.github.dockerjava.api.command.CreateConfigResponse; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CreateConfigCmdExec extends AbstrSyncDockerCmdExec + implements CreateConfigCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(CreateConfigCmdExec.class); + + public CreateConfigCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected CreateConfigResponse execute(CreateConfigCmd command) { + WebTarget webResource = getBaseResource().path("/configs/create"); + + LOGGER.trace("POST: {} ", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON) + .post(command, new TypeReference() { + }); + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CreateContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CreateContainerCmdExec.java index d04233f2a..87d2cca81 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CreateContainerCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/CreateContainerCmdExec.java @@ -27,6 +27,10 @@ protected CreateContainerResponse execute(CreateContainerCmd command) { webResource = webResource.queryParam("name", command.getName()); } + if (command.getPlatform() != null) { + webResource = webResource.queryParam("platform", command.getPlatform()); + } + LOGGER.trace("POST: {} ", webResource); return resourceWithOptionalAuthConfig(command.getAuthConfig(), webResource.request()) .accept(MediaType.APPLICATION_JSON) diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ImageHistoryCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ImageHistoryCmdExec.java new file mode 100644 index 000000000..8ba2a066d --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ImageHistoryCmdExec.java @@ -0,0 +1,35 @@ +package com.github.dockerjava.core.exec; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.ImageHistoryCmd; +import com.github.dockerjava.api.model.ImageHistory; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; + +public class ImageHistoryCmdExec extends AbstrSyncDockerCmdExec> implements + ImageHistoryCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ImageHistoryCmdExec.class); + + public ImageHistoryCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected List execute(ImageHistoryCmd command) { + WebTarget webResource = getBaseResource().path("/images/{id}/history").resolveTemplate("id", + command.getImageId()); + + LOGGER.trace("GET: {}", webResource); + + return webResource.request().accept(MediaType.APPLICATION_JSON).get(new TypeReference>() { + }); + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/InspectConfigCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/InspectConfigCmdExec.java new file mode 100644 index 000000000..b751c4655 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/InspectConfigCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.core.exec; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.InspectConfigCmd; +import com.github.dockerjava.api.model.Config; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class InspectConfigCmdExec extends AbstrSyncDockerCmdExec + implements InspectConfigCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(InspectConfigCmdExec.class); + + public InspectConfigCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Config execute(InspectConfigCmd command) { + WebTarget webResource = getBaseResource().path("/configs/{id}") + .resolveTemplate("id", command.getConfigId()); + + LOGGER.debug("GET: {}", webResource); + return webResource.request().accept(MediaType.APPLICATION_JSON).get(new TypeReference() { }); + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ListConfigsCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ListConfigsCmdExec.java new file mode 100644 index 000000000..89a1b83b1 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ListConfigsCmdExec.java @@ -0,0 +1,43 @@ +package com.github.dockerjava.core.exec; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.command.ListConfigsCmd; +import com.github.dockerjava.api.model.Config; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import com.github.dockerjava.core.util.FiltersEncoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class ListConfigsCmdExec extends AbstrSyncDockerCmdExec> implements ListConfigsCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ListConfigsCmdExec.class); + + public ListConfigsCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected List execute(ListConfigsCmd command) { + WebTarget webTarget = getBaseResource().path("/configs"); + + if (command.getFilters() != null && !command.getFilters().isEmpty()) { + webTarget = webTarget + .queryParam("filters", FiltersEncoder.jsonEncode(command.getFilters())); + } + + LOGGER.trace("GET: {}", webTarget); + + List configs = webTarget.request().accept(MediaType.APPLICATION_JSON) + .get(new TypeReference>() { + }); + + LOGGER.trace("Response: {}", configs); + + return configs; + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/LoadImageAsyncCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/LoadImageAsyncCmdExec.java new file mode 100644 index 000000000..47f1d52fc --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/LoadImageAsyncCmdExec.java @@ -0,0 +1,30 @@ +package com.github.dockerjava.core.exec; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.LoadImageAsyncCmd; +import com.github.dockerjava.api.model.LoadResponseItem; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LoadImageAsyncCmdExec extends AbstrAsyncDockerCmdExec implements LoadImageAsyncCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(LoadImageAsyncCmdExec.class); + + public LoadImageAsyncCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute0(LoadImageAsyncCmd command, ResultCallback resultCallback) { + WebTarget webTarget = getBaseResource().path("/images/load"); + + LOGGER.trace("POST: {}", webTarget); + + webTarget.request().post(new TypeReference() { }, resultCallback, command.getImageStream()); + + return null; + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/LogContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/LogContainerCmdExec.java index 54168bb5e..357af6d0e 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/LogContainerCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/LogContainerCmdExec.java @@ -32,6 +32,10 @@ protected Void execute0(LogContainerCmd command, ResultCallback resultCal webTarget = webTarget.queryParam("since", command.getSince()); } + if (command.getUntil() != null) { + webTarget = webTarget.queryParam("until", command.getUntil()); + } + webTarget = booleanQueryParam(webTarget, "timestamps", command.hasTimestampsEnabled()); webTarget = booleanQueryParam(webTarget, "stdout", command.hasStdoutEnabled()); webTarget = booleanQueryParam(webTarget, "stderr", command.hasStderrEnabled()); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/PushImageCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/PushImageCmdExec.java index 0f3705089..4f4540891 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/PushImageCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/PushImageCmdExec.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.PushImageCmd; -import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.PushResponseItem; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.InvocationBuilder; @@ -22,17 +21,11 @@ public PushImageCmdExec(WebTarget baseResource, DockerClientConfig dockerClientC super(baseResource, dockerClientConfig); } - private String name(PushImageCmd command) { - String name = command.getName(); - AuthConfig authConfig = command.getAuthConfig(); - return (name.contains("/") || authConfig == null) ? name : authConfig.getUsername(); - } - @Override protected Void execute0(PushImageCmd command, ResultCallback resultCallback) { - - WebTarget webResource = getBaseResource().path("/images/" + name(command) + "/push").queryParam("tag", - command.getTag()); + WebTarget webResource = getBaseResource().path("/images/{imageName}/push") + .resolveTemplate("imageName", command.getName()) + .queryParam("tag", command.getTag()); LOGGER.trace("POST: {}", webResource); diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/RemoveConfigCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/RemoveConfigCmdExec.java new file mode 100644 index 000000000..1b81ef644 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/RemoveConfigCmdExec.java @@ -0,0 +1,28 @@ +package com.github.dockerjava.core.exec; + +import com.github.dockerjava.api.command.RemoveConfigCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RemoveConfigCmdExec extends AbstrSyncDockerCmdExec implements RemoveConfigCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(RemoveConfigCmdExec.class); + + public RemoveConfigCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(RemoveConfigCmd command) { + WebTarget webTarget = getBaseResource().path("/configs/" + command.getConfigId()); + + LOGGER.trace("DELETE: {}", webTarget); + webTarget.request().accept(MediaType.APPLICATION_JSON).delete(); + + return null; + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeContainerCmdExec.java new file mode 100644 index 000000000..4913bde79 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeContainerCmdExec.java @@ -0,0 +1,36 @@ +package com.github.dockerjava.core.exec; + +import com.github.dockerjava.api.command.ResizeContainerCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class ResizeContainerCmdExec extends AbstrSyncDockerCmdExec implements ResizeContainerCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ResizeContainerCmdExec.class); + + public ResizeContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(ResizeContainerCmd command) { + WebTarget webResource = getBaseResource().path("/containers/{id}/resize") + .resolveTemplate("id", command.getContainerId()).queryParam("h", command.getHeight()) + .queryParam("w", command.getWidth()); + + LOGGER.trace("POST: {}", webResource); + + try { + webResource.request().accept(MediaType.APPLICATION_JSON).post(command).close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return null; + } +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeExecCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeExecCmdExec.java new file mode 100644 index 000000000..e799a95d5 --- /dev/null +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/ResizeExecCmdExec.java @@ -0,0 +1,37 @@ +package com.github.dockerjava.core.exec; + +import com.github.dockerjava.api.command.ResizeExecCmd; +import com.github.dockerjava.core.DockerClientConfig; +import com.github.dockerjava.core.MediaType; +import com.github.dockerjava.core.WebTarget; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + + +public class ResizeExecCmdExec extends AbstrSyncDockerCmdExec implements ResizeExecCmd.Exec { + + private static final Logger LOGGER = LoggerFactory.getLogger(ResizeExecCmdExec.class); + + public ResizeExecCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { + super(baseResource, dockerClientConfig); + } + + @Override + protected Void execute(ResizeExecCmd command) { + WebTarget webResource = getBaseResource().path("/exec/{id}/resize") + .resolveTemplate("id", command.getExecId()).queryParam("h", command.getHeight()).queryParam("w", command.getWidth()); + + LOGGER.trace("POST: {}", webResource); + + try { + webResource.request().accept(MediaType.APPLICATION_JSON).post(null).close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return null; + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/RestartContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/RestartContainerCmdExec.java index ecb317a34..42f2579e6 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/RestartContainerCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/RestartContainerCmdExec.java @@ -24,6 +24,10 @@ protected Void execute(RestartContainerCmd command) { WebTarget webResource = getBaseResource().path("/containers/{id}/restart").resolveTemplate("id", command.getContainerId()); + if (command.getSignal() != null) { + webResource = webResource.queryParam("signal", command.getSignal()); + } + if (command.getTimeout() != null) { webResource = webResource.queryParam("t", String.valueOf(command.getTimeout())); } diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/TopContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/TopContainerCmdExec.java index c6fff7044..f0ce0f71a 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/TopContainerCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/TopContainerCmdExec.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core.exec; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/WaitContainerCmdExec.java b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/WaitContainerCmdExec.java index 57cc727fe..3d2b2fa8e 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/exec/WaitContainerCmdExec.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/exec/WaitContainerCmdExec.java @@ -1,5 +1,6 @@ package com.github.dockerjava.core.exec; +import com.github.dockerjava.api.model.WaitContainerCondition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,6 +26,11 @@ protected Void execute0(WaitContainerCmd command, ResultCallback r WebTarget webTarget = getBaseResource().path("/containers/{id}/wait").resolveTemplate("id", command.getContainerId()); + WaitContainerCondition condition = command.getCondition(); + if (condition != null) { + webTarget = webTarget.queryParam("condition", condition.getValue()); + } + LOGGER.trace("POST: {}", webTarget); webTarget.request().accept(MediaType.APPLICATION_JSON).post((Object) null, new TypeReference() { diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java b/docker-java-core/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java index 82563962a..7cb1a19d4 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java @@ -89,11 +89,13 @@ public static List loadCertificates(final Reader reader) throws IOE JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter() .setProvider(BouncyCastleProvider.PROVIDER_NAME); - Object certObj = pemParser.readObject(); + Object certObj; - if (certObj instanceof X509CertificateHolder) { - X509CertificateHolder certificateHolder = (X509CertificateHolder) certObj; - certificates.add(certificateConverter.getCertificate(certificateHolder)); + while ((certObj = pemParser.readObject()) != null) { + if (certObj instanceof X509CertificateHolder) { + X509CertificateHolder certificateHolder = (X509CertificateHolder) certObj; + certificates.add(certificateConverter.getCertificate(certificateHolder)); + } } return certificates; diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/util/CompressArchiveUtil.java b/docker-java-core/src/main/java/com/github/dockerjava/core/util/CompressArchiveUtil.java index 4590abb13..eb7b90aca 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/util/CompressArchiveUtil.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/util/CompressArchiveUtil.java @@ -54,7 +54,8 @@ private static TarArchiveOutputStream buildTarStream(Path outputPath, boolean gZ outputStream = new GzipCompressorOutputStream(outputStream); } TarArchiveOutputStream tarArchiveOutputStream = new TarArchiveOutputStream(outputStream); - tarArchiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); + tarArchiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); + tarArchiveOutputStream.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); return tarArchiveOutputStream; } @@ -98,7 +99,8 @@ public static File archiveTARFiles(File base, Iterable files, String archi tarFile.deleteOnExit(); try (TarArchiveOutputStream tos = new TarArchiveOutputStream(new GZIPOutputStream(new BufferedOutputStream( new FileOutputStream(tarFile))))) { - tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); + tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); + tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); for (File file : files) { // relativize with method using Path otherwise method with File resolves the symlinks // and this is not want we want. If the file is a symlink, the relativized path should diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/util/FiltersBuilder.java b/docker-java-core/src/main/java/com/github/dockerjava/core/util/FiltersBuilder.java index 73b369ca7..0d6c1d268 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/util/FiltersBuilder.java +++ b/docker-java-core/src/main/java/com/github/dockerjava/core/util/FiltersBuilder.java @@ -10,6 +10,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Representation of Docker filters. @@ -64,6 +66,16 @@ public List getContainer() { return getFilter("container"); } + /** + * Filter by event types + * + * @param eventTypes an array of event types + */ + public FiltersBuilder withEventTypes(String... eventTypes) { + withFilter("type", Stream.of(eventTypes).collect(Collectors.toList())); + return this; + } + /** * Filter by labels * diff --git a/docker-java-transport-httpclient5/pom.xml b/docker-java-transport-httpclient5/pom.xml index 2ed959e83..52cf66de2 100644 --- a/docker-java-transport-httpclient5/pom.xml +++ b/docker-java-transport-httpclient5/pom.xml @@ -4,7 +4,7 @@ com.github.docker-java docker-java-parent - 3.2.2-SNAPSHOT + 0-SNAPSHOT ../pom.xml @@ -15,29 +15,34 @@ https://github.com/docker-java/docker-java Java API Client for Docker + + com.github.dockerjava.transport.httpclient5 + + ${project.groupId} - docker-java-core + docker-java-transport ${project.version} org.apache.httpcomponents.client5 httpclient5 - 5.0 - - - org.apache.httpcomponents.core5 - httpcore5-h2 - - + 5.5.1 net.java.dev.jna - jna-platform - 5.5.0 + jna + 5.18.1 + + + + ${project.groupId} + docker-java-transport-tck + ${project.version} + test diff --git a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/ApacheDockerHttpClient.java b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/ApacheDockerHttpClient.java index 997a7d57a..68e0eeddf 100644 --- a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/ApacheDockerHttpClient.java +++ b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/ApacheDockerHttpClient.java @@ -1,240 +1,58 @@ package com.github.dockerjava.httpclient5; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.core.DockerHttpClient; -import com.github.dockerjava.core.SSLConfig; -import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; -import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.core5.http.ConnectionClosedException; -import org.apache.hc.core5.http.ContentLengthStrategy; -import org.apache.hc.core5.http.Header; -import org.apache.hc.core5.http.HttpHeaders; -import org.apache.hc.core5.http.HttpHost; -import org.apache.hc.core5.http.NameValuePair; -import org.apache.hc.core5.http.config.Registry; -import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy; -import org.apache.hc.core5.http.impl.io.EmptyInputStream; -import org.apache.hc.core5.http.io.entity.InputStreamEntity; -import org.apache.hc.core5.http.protocol.BasicHttpContext; -import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.net.URIAuthority; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.net.ssl.SSLContext; -import java.io.IOException; -import java.io.InputStream; -import java.net.Socket; +import com.github.dockerjava.transport.SSLConfig; + import java.net.URI; -import java.util.List; -import java.util.Map; +import java.time.Duration; import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public final class ApacheDockerHttpClient implements DockerHttpClient { - - public static final class Factory { - private DockerClientConfig dockerClientConfig = null; +public final class ApacheDockerHttpClient extends ApacheDockerHttpClientImpl { - public Factory dockerClientConfig(DockerClientConfig value) { - this.dockerClientConfig = value; - return this; - } - - public ApacheDockerHttpClient build() { - Objects.requireNonNull(dockerClientConfig, "dockerClientConfig"); - return new ApacheDockerHttpClient(dockerClientConfig); - } - } - - private final CloseableHttpClient httpClient; - - private final HttpHost host; - - private ApacheDockerHttpClient(DockerClientConfig dockerClientConfig) { - Registry socketFactoryRegistry = createConnectionSocketFactoryRegistry(dockerClientConfig); - - URI dockerHost = dockerClientConfig.getDockerHost(); - - switch (dockerHost.getScheme()) { - case "unix": - case "npipe": - host = new HttpHost(dockerHost.getScheme(), "localhost", 2375); - break; - case "tcp": - host = new HttpHost( - socketFactoryRegistry.lookup("https") != null ? "https" : "http", - dockerHost.getHost(), - dockerHost.getPort() - ); - break; - default: - host = HttpHost.create(dockerHost); - } - - httpClient = HttpClients.custom() - .setRequestExecutor(new HijackingHttpRequestExecutor(null)) - .setConnectionManager(new PoolingHttpClientConnectionManager( - socketFactoryRegistry, - new ManagedHttpClientConnectionFactory( - null, - null, - null, - null, - message -> { - Header transferEncodingHeader = message.getFirstHeader(HttpHeaders.TRANSFER_ENCODING); - if (transferEncodingHeader != null) { - if ("identity".equalsIgnoreCase(transferEncodingHeader.getValue())) { - return ContentLengthStrategy.UNDEFINED; - } - } - return DefaultContentLengthStrategy.INSTANCE.determineLength(message); - }, - null - ) - )) - .build(); - } - - private Registry createConnectionSocketFactoryRegistry(DockerClientConfig dockerClientConfig) { - RegistryBuilder socketFactoryRegistryBuilder = RegistryBuilder.create(); - - SSLConfig sslConfig = dockerClientConfig.getSSLConfig(); - if (sslConfig != null) { - try { - SSLContext sslContext = sslConfig.getSSLContext(); - if (sslContext != null) { - socketFactoryRegistryBuilder.register("https", new SSLConnectionSocketFactory(sslContext)); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - return socketFactoryRegistryBuilder - .register("tcp", PlainConnectionSocketFactory.INSTANCE) - .register("http", PlainConnectionSocketFactory.INSTANCE) - .register("unix", new PlainConnectionSocketFactory() { - @Override - public Socket createSocket(HttpContext context) throws IOException { - URI dockerHost = dockerClientConfig.getDockerHost(); - - return new UnixDomainSocket(dockerHost.getPath()); - } - }) - .register("npipe", new PlainConnectionSocketFactory() { - @Override - public Socket createSocket(HttpContext context) { - URI dockerHost = dockerClientConfig.getDockerHost(); - - return new NamedPipeSocket(dockerHost.getPath()); - } - }) - .build(); - } + public static final class Builder { - @Override - public Response execute(Request request) { - HttpContext context = new BasicHttpContext(); - HttpUriRequestBase httpUriRequest = new HttpUriRequestBase(request.method(), URI.create(request.path())); - httpUriRequest.setScheme(host.getSchemeName()); - httpUriRequest.setAuthority(new URIAuthority(host.getHostName(), host.getPort())); + private URI dockerHost = null; - request.headers().forEach(httpUriRequest::addHeader); + private SSLConfig sslConfig = null; - InputStream body = request.body(); - if (body != null) { - httpUriRequest.setEntity(new InputStreamEntity(body, null)); - } + private int maxConnections = Integer.MAX_VALUE; - if (request.hijackedInput() != null) { - context.setAttribute(HijackingHttpRequestExecutor.HIJACKED_INPUT_ATTRIBUTE, request.hijackedInput()); - httpUriRequest.setHeader("Upgrade", "tcp"); - httpUriRequest.setHeader("Connection", "Upgrade"); - } + private Duration connectionTimeout; - try { - CloseableHttpResponse response = httpClient.execute(host, httpUriRequest, context); + private Duration responseTimeout; - return new ApacheResponse(httpUriRequest, response); - } catch (IOException e) { - throw new RuntimeException(e); + public Builder dockerHost(URI value) { + this.dockerHost = Objects.requireNonNull(value, "dockerHost"); + return this; } - } - - @Override - public void close() throws IOException { - httpClient.close(); - } - - static class ApacheResponse implements Response { - - private static final Logger LOGGER = LoggerFactory.getLogger(ApacheResponse.class); - - private final HttpUriRequestBase request; - private final CloseableHttpResponse response; - - ApacheResponse(HttpUriRequestBase httpUriRequest, CloseableHttpResponse response) { - this.request = httpUriRequest; - this.response = response; + public Builder sslConfig(SSLConfig value) { + this.sslConfig = value; + return this; } - @Override - public int getStatusCode() { - return response.getCode(); + public Builder maxConnections(int value) { + this.maxConnections = value; + return this; } - @Override - public Map> getHeaders() { - return Stream.of(response.getHeaders()).collect(Collectors.groupingBy( - NameValuePair::getName, - Collectors.mapping(NameValuePair::getValue, Collectors.toList()) - )); + public Builder connectionTimeout(Duration connectionTimeout) { + this.connectionTimeout = connectionTimeout; + return this; } - @Override - public String getHeader(String name) { - Header firstHeader = response.getFirstHeader(name); - return firstHeader != null ? firstHeader.getValue() : null; + public Builder responseTimeout(Duration responseTimeout) { + this.responseTimeout = responseTimeout; + return this; } - @Override - public InputStream getBody() { - try { - return response.getEntity() != null - ? response.getEntity().getContent() - : EmptyInputStream.INSTANCE; - } catch (IOException e) { - throw new RuntimeException(e); - } + public ApacheDockerHttpClient build() { + Objects.requireNonNull(dockerHost, "dockerHost"); + return new ApacheDockerHttpClient(dockerHost, sslConfig, maxConnections, connectionTimeout, responseTimeout); } + } - @Override - public void close() { - try { - request.abort(); - } catch (Exception e) { - LOGGER.debug("Failed to abort the request", e); - } - - try { - response.close(); - } catch (ConnectionClosedException e) { - LOGGER.trace("Failed to close the response", e); - } catch (Exception e) { - LOGGER.debug("Failed to close the response", e); - } - } + private ApacheDockerHttpClient(URI dockerHost, SSLConfig sslConfig, int maxConnections, Duration connectionTimeout, + Duration responseTimeout) { + super(dockerHost, sslConfig, maxConnections, connectionTimeout, responseTimeout); } } diff --git a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/ApacheDockerHttpClientImpl.java b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/ApacheDockerHttpClientImpl.java new file mode 100644 index 000000000..c97a2bc45 --- /dev/null +++ b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/ApacheDockerHttpClientImpl.java @@ -0,0 +1,262 @@ +package com.github.dockerjava.httpclient5; + +import com.github.dockerjava.transport.DockerHttpClient; +import com.github.dockerjava.transport.NamedPipeSocket; +import com.github.dockerjava.transport.SSLConfig; +import com.github.dockerjava.transport.UnixSocket; + +import org.apache.hc.client5.http.SystemDefaultDnsResolver; +import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.DefaultSchemePortResolver; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.DefaultHttpClientConnectionOperator; +import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.io.HttpClientConnectionOperator; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.http.ssl.TlsSocketStrategy; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ConnectionClosedException; +import org.apache.hc.core5.http.ContentLengthStrategy; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.http.io.entity.ByteArrayEntity; +import org.apache.hc.core5.http.io.entity.EmptyInputStream; +import org.apache.hc.core5.http.io.entity.InputStreamEntity; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.http.protocol.HttpCoreContext; +import org.apache.hc.core5.net.URIAuthority; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.net.URI; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class ApacheDockerHttpClientImpl implements DockerHttpClient { + + private final CloseableHttpClient httpClient; + private final HttpHost host; + private final String pathPrefix; + + protected ApacheDockerHttpClientImpl( + URI dockerHost, + SSLConfig sslConfig, + int maxConnections, + Duration connectionTimeout, + Duration responseTimeout + ) { + SSLContext sslContext; + try { + sslContext = sslConfig != null ? sslConfig.getSSLContext() : null; + } catch (Exception e) { + throw new RuntimeException(e); + } + HttpClientConnectionOperator connectionOperator = createConnectionOperator(dockerHost, sslContext); + + switch (dockerHost.getScheme()) { + case "unix": + case "npipe": + pathPrefix = ""; + host = new HttpHost(dockerHost.getScheme(), "localhost", 2375); + break; + case "tcp": + String rawPath = dockerHost.getRawPath(); + pathPrefix = rawPath.endsWith("/") + ? rawPath.substring(0, rawPath.length() - 1) + : rawPath; + host = new HttpHost( + sslContext != null ? "https" : "http", + dockerHost.getHost(), + dockerHost.getPort() + ); + break; + default: + throw new IllegalArgumentException("Unsupported protocol scheme: " + dockerHost); + } + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager( + connectionOperator, + null, + null, + null, + new ManagedHttpClientConnectionFactory( + null, + null, + null, + null, + message -> { + Header transferEncodingHeader = message.getFirstHeader(HttpHeaders.TRANSFER_ENCODING); + if (transferEncodingHeader != null) { + if ("identity".equalsIgnoreCase(transferEncodingHeader.getValue())) { + return ContentLengthStrategy.UNDEFINED; + } + } + return DefaultContentLengthStrategy.INSTANCE.determineLength(message); + }, + null + ) + ); + // See https://github.com/docker-java/docker-java/pull/1590#issuecomment-870581289 + connectionManager.setDefaultSocketConfig( + SocketConfig.copy(SocketConfig.DEFAULT) + .setSoTimeout(Timeout.ZERO_MILLISECONDS) + .build() + ); + connectionManager.setMaxTotal(maxConnections); + connectionManager.setDefaultMaxPerRoute(maxConnections); + connectionManager.setDefaultConnectionConfig(ConnectionConfig.custom() + .setValidateAfterInactivity(TimeValue.NEG_ONE_SECOND) + .setConnectTimeout(connectionTimeout != null ? Timeout.of(connectionTimeout.toNanos(), TimeUnit.NANOSECONDS) : null) + .build()); + + httpClient = HttpClients.custom() + .setRequestExecutor(new HijackingHttpRequestExecutor(null)) + .setConnectionManager(connectionManager) + .setDefaultRequestConfig(RequestConfig.custom() + .setResponseTimeout(responseTimeout != null ? Timeout.of(responseTimeout.toNanos(), TimeUnit.NANOSECONDS) : null) + .build()) + .disableConnectionState() + .build(); + } + + private HttpClientConnectionOperator createConnectionOperator( + URI dockerHost, + SSLContext sslContext + ) { + String dockerHostScheme = dockerHost.getScheme(); + String dockerHostPath = dockerHost.getPath(); + TlsSocketStrategy tlsSocketStrategy = sslContext != null ? + new DefaultClientTlsStrategy(sslContext) : DefaultClientTlsStrategy.createSystemDefault(); + return new DefaultHttpClientConnectionOperator( + socksProxy -> { + if ("unix".equalsIgnoreCase(dockerHostScheme)) { + return UnixSocket.get(dockerHostPath); + } else if ("npipe".equalsIgnoreCase(dockerHostScheme)) { + return new NamedPipeSocket(dockerHostPath); + } else { + return socksProxy == null ? new Socket() : new Socket(socksProxy); + } + }, + DefaultSchemePortResolver.INSTANCE, + SystemDefaultDnsResolver.INSTANCE, + name -> "https".equalsIgnoreCase(name) ? tlsSocketStrategy : null); + } + + @Override + public Response execute(Request request) { + HttpContext context = new HttpCoreContext(); + HttpUriRequestBase httpUriRequest = new HttpUriRequestBase(request.method(), URI.create(pathPrefix + request.path())); + httpUriRequest.setScheme(host.getSchemeName()); + httpUriRequest.setAuthority(new URIAuthority(host.getHostName(), host.getPort())); + + request.headers().forEach(httpUriRequest::addHeader); + + byte[] bodyBytes = request.bodyBytes(); + if (bodyBytes != null) { + httpUriRequest.setEntity(new ByteArrayEntity(bodyBytes, null)); + } else { + InputStream body = request.body(); + if (body != null) { + httpUriRequest.setEntity(new InputStreamEntity(body, null)); + } + } + + if (request.hijackedInput() != null) { + context.setAttribute(HijackingHttpRequestExecutor.HIJACKED_INPUT_ATTRIBUTE, request.hijackedInput()); + httpUriRequest.setHeader("Upgrade", "tcp"); + httpUriRequest.setHeader("Connection", "Upgrade"); + } + + try { + ClassicHttpResponse response = httpClient.executeOpen(host, httpUriRequest, context); + + return new ApacheResponse(httpUriRequest, response); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() throws IOException { + httpClient.close(); + } + + static class ApacheResponse implements Response { + + private static final Logger LOGGER = LoggerFactory.getLogger(ApacheResponse.class); + + private final HttpUriRequestBase request; + + private final ClassicHttpResponse response; + + ApacheResponse(HttpUriRequestBase httpUriRequest, ClassicHttpResponse response) { + this.request = httpUriRequest; + this.response = response; + } + + @Override + public int getStatusCode() { + return response.getCode(); + } + + @Override + public Map> getHeaders() { + return Stream.of(response.getHeaders()).collect(Collectors.groupingBy( + NameValuePair::getName, + Collectors.mapping(NameValuePair::getValue, Collectors.toList()) + )); + } + + @Override + public String getHeader(String name) { + Header firstHeader = response.getFirstHeader(name); + return firstHeader != null ? firstHeader.getValue() : null; + } + + @Override + public InputStream getBody() { + try { + return response.getEntity() != null + ? response.getEntity().getContent() + : EmptyInputStream.INSTANCE; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() { + try { + request.abort(); + } catch (Exception e) { + LOGGER.debug("Failed to abort the request", e); + } + + try { + response.close(); + } catch (ConnectionClosedException e) { + LOGGER.trace("Failed to close the response", e); + } catch (Exception e) { + LOGGER.debug("Failed to close the response", e); + } + } + } +} diff --git a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/HijackingHttpRequestExecutor.java b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/HijackingHttpRequestExecutor.java index 59888a5dd..df8fbd059 100644 --- a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/HijackingHttpRequestExecutor.java +++ b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/HijackingHttpRequestExecutor.java @@ -44,7 +44,7 @@ public ClassicHttpResponse execute( InputStream hijackedInput = (InputStream) context.getAttribute(HIJACKED_INPUT_ATTRIBUTE); if (hijackedInput != null) { - return executeHijacked(request, conn, context, hijackedInput); + return executeHijacked(request, conn, (HttpCoreContext) context, hijackedInput); } return super.execute(request, conn, informationCallback, context); @@ -53,12 +53,12 @@ public ClassicHttpResponse execute( private ClassicHttpResponse executeHijacked( ClassicHttpRequest request, HttpClientConnection conn, - HttpContext context, + HttpCoreContext context, InputStream hijackedInput ) throws HttpException, IOException { try { - context.setAttribute(HttpCoreContext.SSL_SESSION, conn.getSSLSession()); - context.setAttribute(HttpCoreContext.CONNECTION_ENDPOINT, conn.getEndpointDetails()); + context.setSSLSession(conn.getSSLSession()); + context.setEndpointDetails(conn.getEndpointDetails()); final ProtocolVersion transportVersion = request.getVersion(); if (transportVersion != null) { context.setProtocolVersion(transportVersion); diff --git a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/NamedPipeSocket.java b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/NamedPipeSocket.java deleted file mode 100644 index b016c03d2..000000000 --- a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/NamedPipeSocket.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.github.dockerjava.httpclient5; - -import com.sun.jna.platform.win32.Kernel32; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.RandomAccessFile; -import java.net.Socket; -import java.net.SocketAddress; - -class NamedPipeSocket extends Socket { - - private final String socketFileName; - - private RandomAccessFile file; - - private InputStream is; - - private OutputStream os; - - NamedPipeSocket(String socketFileName) { - this.socketFileName = socketFileName; - } - - @Override - public void close() throws IOException { - if (file != null) { - file.close(); - file = null; - } - } - - @Override - public void connect(SocketAddress endpoint) { - connect(endpoint, 0); - } - - @Override - public void connect(SocketAddress endpoint, int timeout) { - long startedAt = System.currentTimeMillis(); - timeout = Math.max(timeout, 10_000); - while (true) { - try { - file = new RandomAccessFile(socketFileName, "rw"); - break; - } catch (FileNotFoundException e) { - if (System.currentTimeMillis() - startedAt >= timeout) { - throw new RuntimeException(e); - } else { - Kernel32.INSTANCE.WaitNamedPipe(socketFileName, 100); - } - } - } - - is = new InputStream() { - @Override - public int read(byte[] bytes, int off, int len) throws IOException { - return file.read(bytes, off, len); - } - - @Override - public int read() throws IOException { - return file.read(); - } - - @Override - public int read(byte[] bytes) throws IOException { - return file.read(bytes); - } - }; - - os = new OutputStream() { - @Override - public void write(byte[] bytes, int off, int len) throws IOException { - file.write(bytes, off, len); - } - - @Override - public void write(int value) throws IOException { - file.write(value); - } - - @Override - public void write(byte[] bytes) throws IOException { - file.write(bytes); - } - }; - } - - @Override - public InputStream getInputStream() { - return is; - } - - @Override - public OutputStream getOutputStream() { - return os; - } -} diff --git a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/UnixDomainSocket.java b/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/UnixDomainSocket.java deleted file mode 100644 index cbbfd16a1..000000000 --- a/docker-java-transport-httpclient5/src/main/java/com/github/dockerjava/httpclient5/UnixDomainSocket.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * - * MariaDB Client for Java - * - * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2019 MariaDB Ab. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this library; if not, write to Monty Program Ab info@montyprogram.com. - * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -package com.github.dockerjava.httpclient5; - -import com.sun.jna.LastErrorException; -import com.sun.jna.Native; -import com.sun.jna.Platform; -import com.sun.jna.Structure; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicBoolean; - -class UnixDomainSocket extends Socket { - - private static final int AF_UNIX = 1; - private static final int SOCK_STREAM = Platform.isSolaris() ? 2 : 1; - private static final int PROTOCOL = 0; - - static { - if (Platform.isSolaris()) { - System.loadLibrary("nsl"); - System.loadLibrary("socket"); - } - if (!Platform.isWindows() && !Platform.isWindowsCE()) { - Native.register("c"); - } - } - - private final AtomicBoolean closeLock = new AtomicBoolean(); - private final SockAddr sockaddr; - private final int fd; - private InputStream is; - private OutputStream os; - private boolean connected; - - UnixDomainSocket(String path) throws IOException { - if (Platform.isWindows() || Platform.isWindowsCE()) { - throw new IOException("Unix domain sockets are not supported on Windows"); - } - sockaddr = new SockAddr(path); - closeLock.set(false); - try { - fd = socket(AF_UNIX, SOCK_STREAM, PROTOCOL); - } catch (LastErrorException lee) { - throw new IOException("native socket() failed : " + formatError(lee)); - } - } - - public static native int socket(int domain, int type, int protocol) throws LastErrorException; - - public static native int connect(int sockfd, SockAddr sockaddr, int addrlen) - throws LastErrorException; - - public static native int read(int fd, byte[] buffer, long size) - throws LastErrorException; - - public static native int send(int fd, byte[] buffer, int count, int flags) - throws LastErrorException; - - public static native int close(int fd) throws LastErrorException; - - public static native String strerror(int errno); - - private static String formatError(LastErrorException lee) { - try { - return strerror(lee.getErrorCode()); - } catch (Throwable t) { - return lee.getMessage(); - } - } - - @Override - public boolean isConnected() { - return connected; - } - - @Override - public void close() throws IOException { - if (!closeLock.getAndSet(true)) { - try { - close(fd); - } catch (LastErrorException lee) { - throw new IOException("native close() failed : " + formatError(lee)); - } - connected = false; - } - } - - @Override - public void connect(SocketAddress endpoint) throws IOException { - connect(endpoint, 0); - } - - public void connect(SocketAddress endpoint, int timeout) throws IOException { - try { - int ret = connect(fd, sockaddr, sockaddr.size()); - if (ret != 0) { - throw new IOException(strerror(Native.getLastError())); - } - connected = true; - } catch (LastErrorException lee) { - throw new IOException("native connect() failed : " + formatError(lee)); - } - is = new UnixSocketInputStream(); - os = new UnixSocketOutputStream(); - } - - public InputStream getInputStream() { - return is; - } - - public OutputStream getOutputStream() { - return os; - } - - public void setTcpNoDelay(boolean b) { - // do nothing - } - - public void setKeepAlive(boolean b) { - // do nothing - } - - public void setReceiveBufferSize(int size) { - // do nothing - } - - public void setSendBufferSize(int size) { - // do nothing - } - - public void setSoLinger(boolean b, int i) { - // do nothing - } - - public void setSoTimeout(int timeout) { - } - - public void shutdownInput() { - // do nothing - } - - public void shutdownOutput() { - // do nothing - } - - public static class SockAddr extends Structure { - - @SuppressWarnings("checkstyle:membername") - public short sun_family; - @SuppressWarnings("checkstyle:membername") - public byte[] sun_path; - - /** - * Contructor. - * - * @param sunPath path - */ - SockAddr(String sunPath) { - sun_family = AF_UNIX; - byte[] arr = sunPath.getBytes(); - sun_path = new byte[arr.length + 1]; - System.arraycopy(arr, 0, sun_path, 0, Math.min(sun_path.length - 1, arr.length)); - allocateMemory(); - } - - @Override - protected java.util.List getFieldOrder() { - return Arrays.asList("sun_family", "sun_path"); - } - } - - class UnixSocketInputStream extends InputStream { - - @Override - public int read(byte[] bytesEntry, int off, int len) throws IOException { - try { - if (off > 0) { - int bytes = 0; - int remainingLength = len; - int size; - byte[] data = new byte[(len < 10240) ? len : 10240]; - do { - if (!isConnected()) { - return -1; - } - size = UnixDomainSocket.read(fd, data, (remainingLength < 10240) ? remainingLength : 10240); - if (size <= 0) { - return -1; - } - System.arraycopy(data, 0, bytesEntry, off, size); - bytes += size; - off += size; - remainingLength -= size; - } while ((remainingLength > 0) && (size > 0)); - return bytes; - } else { - if (!isConnected()) { - return -1; - } - int size = UnixDomainSocket.read(fd, bytesEntry, len); - if (size <= 0) { - return -1; - } - return size; - } - } catch (LastErrorException lee) { - throw new IOException("native read() failed : " + formatError(lee)); - } - } - - @Override - public int read() throws IOException { - byte[] bytes = new byte[1]; - int bytesRead = read(bytes); - if (bytesRead == 0) { - return -1; - } - return bytes[0] & 0xff; - } - - @Override - public int read(byte[] bytes) throws IOException { - if (!isConnected()) { - return -1; - } - return read(bytes, 0, bytes.length); - } - } - - class UnixSocketOutputStream extends OutputStream { - - @Override - public void write(byte[] bytesEntry, int off, int len) throws IOException { - int bytes; - try { - if (off > 0) { - int size; - int remainingLength = len; - byte[] data = new byte[(len < 10240) ? len : 10240]; - do { - size = (remainingLength < 10240) ? remainingLength : 10240; - System.arraycopy(bytesEntry, off, data, 0, size); - if (!isConnected()) { - return; - } - bytes = UnixDomainSocket.send(fd, data, size, 0); - if (bytes > 0) { - off += bytes; - remainingLength -= bytes; - } - } while ((remainingLength > 0) && (bytes > 0)); - } else { - if (!isConnected()) { - return; - } - bytes = UnixDomainSocket.send(fd, bytesEntry, len, 0); - } - - if (bytes != len) { - throw new IOException("can't write " + len + "bytes"); - } - } catch (LastErrorException lee) { - throw new IOException("native write() failed : " + formatError(lee)); - } - } - - @Override - public void write(int value) throws IOException { - write(new byte[] {(byte) value}); - } - - @Override - public void write(byte[] bytes) throws IOException { - write(bytes, 0, bytes.length); - } - } -} diff --git a/docker-java-transport-httpclient5/src/test/java/com/github/dockerjava/transport/HttpClient5Tests.java b/docker-java-transport-httpclient5/src/test/java/com/github/dockerjava/transport/HttpClient5Tests.java new file mode 100644 index 000000000..d83621f78 --- /dev/null +++ b/docker-java-transport-httpclient5/src/test/java/com/github/dockerjava/transport/HttpClient5Tests.java @@ -0,0 +1,16 @@ +package com.github.dockerjava.transport; + +import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; + +import java.net.URI; + +public class HttpClient5Tests extends DockerHttpClientTCK { + + @Override + protected DockerHttpClient createDockerHttpClient(URI dockerHost, SSLConfig sslConfig) { + return new ApacheDockerHttpClient.Builder() + .dockerHost(dockerHost) + .sslConfig(sslConfig) + .build(); + } +} diff --git a/docker-java-transport-jersey/pom.xml b/docker-java-transport-jersey/pom.xml index 37de78f58..a600c208d 100644 --- a/docker-java-transport-jersey/pom.xml +++ b/docker-java-transport-jersey/pom.xml @@ -4,7 +4,7 @@ com.github.docker-java docker-java-parent - 3.2.2-SNAPSHOT + 0-SNAPSHOT ../pom.xml @@ -15,6 +15,10 @@ https://github.com/docker-java/docker-java Java API Client for Docker + + com.github.dockerjava.transport.jersey + + ${project.groupId} @@ -22,11 +26,6 @@ ${project.version} - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-json-provider - ${jackson-jaxrs.version} - org.glassfish.jersey.connectors jersey-apache-connector @@ -68,6 +67,20 @@ junixsocket-native-common ${junixsocket.version} + + + org.slf4j + jcl-over-slf4j + 1.7.30 + test + + + + ${project.groupId} + docker-java-transport-tck + ${project.version} + test + diff --git a/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerCmdExecFactory.java b/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerCmdExecFactory.java index 82d7b8324..6298cae3b 100644 --- a/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerCmdExecFactory.java +++ b/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerCmdExecFactory.java @@ -6,7 +6,7 @@ import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.DockerClientConfigAware; import com.github.dockerjava.core.DockerClientImpl; -import com.github.dockerjava.core.DockerHttpClient; +import com.github.dockerjava.transport.DockerHttpClient; import org.glassfish.jersey.client.RequestEntityProcessing; import javax.ws.rs.client.ClientRequestFilter; @@ -15,12 +15,12 @@ //import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; // see https://github.com/docker-java/docker-java/issues/196 /** - * @deprecated use {@link JerseyDockerHttpClient} with {@link DockerClientImpl#withHttpClient(DockerHttpClient)} + * @deprecated use {@link JerseyDockerHttpClient} with {@link DockerClientImpl#getInstance(DockerClientConfig, DockerHttpClient)} */ @Deprecated public class JerseyDockerCmdExecFactory extends DelegatingDockerCmdExecFactory implements DockerClientConfigAware { - private JerseyDockerHttpClient.Factory clientFactory = new JerseyDockerHttpClient.Factory(); + private JerseyDockerHttpClient.Builder clientBuilder = new JerseyDockerHttpClient.Builder(); @Deprecated protected Integer connectTimeout; @@ -37,9 +37,11 @@ public final DockerCmdExecFactory getDockerCmdExecFactory() { @Override public void init(DockerClientConfig dockerClientConfig) { - clientFactory = clientFactory.dockerClientConfig(dockerClientConfig); + clientBuilder = clientBuilder + .dockerHost(dockerClientConfig.getDockerHost()) + .sslConfig(dockerClientConfig.getSSLConfig()); dockerCmdExecFactory = new DefaultDockerCmdExecFactory( - clientFactory.build(), + clientBuilder.build(), dockerClientConfig.getObjectMapper() ); dockerCmdExecFactory.init(dockerClientConfig); @@ -49,7 +51,7 @@ public void init(DockerClientConfig dockerClientConfig) { * Configure connection timeout in milliseconds */ public JerseyDockerCmdExecFactory withConnectTimeout(Integer connectTimeout) { - clientFactory = clientFactory.connectTimeout(connectTimeout); + clientBuilder = clientBuilder.connectTimeout(connectTimeout); this.connectTimeout = connectTimeout; return this; } @@ -58,38 +60,38 @@ public JerseyDockerCmdExecFactory withConnectTimeout(Integer connectTimeout) { * Configure read timeout in milliseconds */ public JerseyDockerCmdExecFactory withReadTimeout(Integer readTimeout) { - clientFactory = clientFactory.readTimeout(readTimeout); + clientBuilder = clientBuilder.readTimeout(readTimeout); this.readTimeout = readTimeout; return this; } public JerseyDockerCmdExecFactory withMaxTotalConnections(Integer maxTotalConnections) { - clientFactory = clientFactory.maxTotalConnections(maxTotalConnections); + clientBuilder = clientBuilder.maxTotalConnections(maxTotalConnections); return this; } public JerseyDockerCmdExecFactory withMaxPerRouteConnections(Integer maxPerRouteConnections) { - clientFactory = clientFactory.maxPerRouteConnections(maxPerRouteConnections); + clientBuilder = clientBuilder.maxPerRouteConnections(maxPerRouteConnections); return this; } public JerseyDockerCmdExecFactory withConnectionRequestTimeout(Integer connectionRequestTimeout) { - clientFactory = clientFactory.connectionRequestTimeout(connectionRequestTimeout); + clientBuilder = clientBuilder.connectionRequestTimeout(connectionRequestTimeout); return this; } public JerseyDockerCmdExecFactory withClientResponseFilters(ClientResponseFilter... clientResponseFilter) { - clientFactory = clientFactory.clientResponseFilters(clientResponseFilter); + clientBuilder = clientBuilder.clientResponseFilters(clientResponseFilter); return this; } public JerseyDockerCmdExecFactory withClientRequestFilters(ClientRequestFilter... clientRequestFilters) { - clientFactory = clientFactory.clientRequestFilters(clientRequestFilters); + clientBuilder = clientBuilder.clientRequestFilters(clientRequestFilters); return this; } public JerseyDockerCmdExecFactory withRequestEntityProcessing(RequestEntityProcessing requestEntityProcessing) { - clientFactory = clientFactory.requestEntityProcessing(requestEntityProcessing); + clientBuilder = clientBuilder.requestEntityProcessing(requestEntityProcessing); return this; } } diff --git a/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerHttpClient.java b/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerHttpClient.java index c2f9f78da..78a65cf63 100644 --- a/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerHttpClient.java +++ b/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/JerseyDockerHttpClient.java @@ -1,11 +1,9 @@ package com.github.dockerjava.jaxrs; -import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.core.DockerHttpClient; -import com.github.dockerjava.core.SSLConfig; +import com.github.dockerjava.transport.DockerHttpClient; +import com.github.dockerjava.transport.SSLConfig; import com.github.dockerjava.jaxrs.filter.ResponseStatusExceptionFilter; import com.github.dockerjava.jaxrs.filter.SelectiveLoggingFilter; import org.apache.http.client.config.RequestConfig; @@ -42,20 +40,27 @@ import java.net.URISyntaxException; import java.util.List; import java.util.Map; +import java.util.Objects; +/** + * @deprecated use Apache HttpClient 5-based transport + */ +@Deprecated public final class JerseyDockerHttpClient implements DockerHttpClient { - public static final class Factory { + public static final class Builder { - private DockerClientConfig dockerClientConfig = null; + private URI dockerHost = null; + + private SSLConfig sslConfig = null; private Integer readTimeout = null; private Integer connectTimeout = null; - private Integer maxTotalConnections = null; + private Integer maxTotalConnections = Integer.MAX_VALUE; - private Integer maxPerRouteConnections = null; + private Integer maxPerRouteConnections = Integer.MAX_VALUE; private Integer connectionRequestTimeout = null; @@ -65,54 +70,60 @@ public static final class Factory { private RequestEntityProcessing requestEntityProcessing; - public Factory dockerClientConfig(DockerClientConfig value) { - this.dockerClientConfig = value; + public Builder dockerHost(URI value) { + this.dockerHost = Objects.requireNonNull(value, "dockerHost"); + return this; + } + + public Builder sslConfig(SSLConfig value) { + this.sslConfig = value; return this; } - public Factory readTimeout(Integer value) { + public Builder readTimeout(Integer value) { this.readTimeout = value; return this; } - public Factory connectTimeout(Integer value) { + public Builder connectTimeout(Integer value) { this.connectTimeout = value; return this; } - public Factory maxTotalConnections(Integer value) { + public Builder maxTotalConnections(Integer value) { this.maxTotalConnections = value; return this; } - public Factory maxPerRouteConnections(Integer value) { + public Builder maxPerRouteConnections(Integer value) { this.maxPerRouteConnections = value; return this; } - public Factory connectionRequestTimeout(Integer value) { + public Builder connectionRequestTimeout(Integer value) { this.connectionRequestTimeout = value; return this; } - public Factory clientResponseFilters(ClientResponseFilter[] value) { + public Builder clientResponseFilters(ClientResponseFilter[] value) { this.clientResponseFilters = value; return this; } - public Factory clientRequestFilters(ClientRequestFilter[] value) { + public Builder clientRequestFilters(ClientRequestFilter[] value) { this.clientRequestFilters = value; return this; } - public Factory requestEntityProcessing(RequestEntityProcessing value) { + public Builder requestEntityProcessing(RequestEntityProcessing value) { this.requestEntityProcessing = value; return this; } public JerseyDockerHttpClient build() { return new JerseyDockerHttpClient( - dockerClientConfig, + dockerHost, + sslConfig, maxTotalConnections, maxPerRouteConnections, connectionRequestTimeout, @@ -134,7 +145,8 @@ public JerseyDockerHttpClient build() { private final URI originalUri; private JerseyDockerHttpClient( - DockerClientConfig dockerClientConfig, + URI dockerHost, + SSLConfig sslConfig, Integer maxTotalConnections, Integer maxPerRouteConnections, Integer connectionRequestTimeout, @@ -152,14 +164,12 @@ private JerseyDockerHttpClient( clientConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING, requestEntityProcessing); } - clientConfig.register(new ResponseStatusExceptionFilter(dockerClientConfig.getObjectMapper())); + clientConfig.register(new ResponseStatusExceptionFilter()); // clientConfig.register(JsonClientFilter.class); RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); - clientConfig.register(new JacksonJsonProvider(dockerClientConfig.getObjectMapper())); - // logging may disabled via log level - clientConfig.register(new SelectiveLoggingFilter(LOGGER, true)); + clientConfig.register(new SelectiveLoggingFilter(LOGGER, false)); if (readTimeout != null) { requestConfigBuilder.setSocketTimeout(readTimeout); @@ -187,12 +197,9 @@ private JerseyDockerHttpClient( } } - URI dockerHost = dockerClientConfig.getDockerHost(); - SSLContext sslContext = null; try { - final SSLConfig sslConfig = dockerClientConfig.getSSLConfig(); if (sslConfig != null) { sslContext = sslConfig.getSSLContext(); } @@ -301,7 +308,11 @@ public Response execute(Request request) { } } - private Entity toEntity(Request request) { + private Entity toEntity(Request request) { + byte[] bodyBytes = request.bodyBytes(); + if (bodyBytes != null) { + return Entity.json(bodyBytes); + } InputStream body = request.body(); if (body != null) { return Entity.entity(body, MediaType.APPLICATION_JSON_TYPE); @@ -375,7 +386,11 @@ public InputStream getBody() { @Override public void close() { - response.close(); + try { + response.close(); + } catch (Exception e) { + LOGGER.debug("Failed to close the response", e); + } } } } diff --git a/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java b/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java index 0895dbfd9..8cc0a0746 100644 --- a/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java +++ b/docker-java-transport-jersey/src/main/java/com/github/dockerjava/jaxrs/filter/ResponseStatusExceptionFilter.java @@ -1,22 +1,7 @@ package com.github.dockerjava.jaxrs.filter; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; - -import javax.ws.rs.client.ClientRequestContext; -import javax.ws.rs.client.ClientResponseContext; -import javax.ws.rs.client.ClientResponseFilter; -import javax.ws.rs.core.MediaType; - -import com.github.dockerjava.core.DefaultDockerClientConfig; -import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; - import com.github.dockerjava.api.exception.BadRequestException; import com.github.dockerjava.api.exception.ConflictException; import com.github.dockerjava.api.exception.DockerException; @@ -25,6 +10,17 @@ import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.exception.UnauthorizedException; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; /** * This {@link ClientResponseFilter} implementation detects http status codes and throws {@link DockerException}s @@ -41,7 +37,7 @@ public class ResponseStatusExceptionFilter implements ClientResponseFilter { @Deprecated public ResponseStatusExceptionFilter() { - this(DefaultDockerClientConfig.createDefaultConfigBuilder().build().getObjectMapper()); + this(new ObjectMapper()); } public ResponseStatusExceptionFilter(ObjectMapper objectMapper) { diff --git a/docker-java-transport-jersey/src/test/java/com/github/dockerjava/transport/JerseyTests.java b/docker-java-transport-jersey/src/test/java/com/github/dockerjava/transport/JerseyTests.java new file mode 100644 index 000000000..64dfe3966 --- /dev/null +++ b/docker-java-transport-jersey/src/test/java/com/github/dockerjava/transport/JerseyTests.java @@ -0,0 +1,26 @@ +package com.github.dockerjava.transport; + +import com.github.dockerjava.jaxrs.JerseyDockerHttpClient; +import org.junit.Ignore; +import org.junit.Test; + +import java.net.URI; + +public class JerseyTests extends DockerHttpClientTCK { + + @Override + protected DockerHttpClient createDockerHttpClient(URI dockerHost, SSLConfig sslConfig) { + return new JerseyDockerHttpClient.Builder() + .dockerHost(dockerHost) + .sslConfig(sslConfig) + .connectTimeout(30 * 1000) + .build(); + } + + @Test + @Ignore("does not support hijacking") + @Override + public void testHijacking() throws Exception { + super.testHijacking(); + } +} diff --git a/docker-java-transport-netty/pom.xml b/docker-java-transport-netty/pom.xml index 7741aea95..42fdd34b7 100644 --- a/docker-java-transport-netty/pom.xml +++ b/docker-java-transport-netty/pom.xml @@ -4,7 +4,7 @@ com.github.docker-java docker-java-parent - 3.2.2-SNAPSHOT + 0-SNAPSHOT ../pom.xml @@ -15,6 +15,10 @@ https://github.com/docker-java/docker-java Java API Client for Docker + + com.github.dockerjava.transport.netty + + ${project.groupId} diff --git a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyDockerCmdExecFactory.java b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyDockerCmdExecFactory.java index cc1c4452b..ed66a6db8 100644 --- a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyDockerCmdExecFactory.java +++ b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyDockerCmdExecFactory.java @@ -1,6 +1,5 @@ package com.github.dockerjava.netty; -import static com.google.common.base.Preconditions.checkNotNull; import static java.util.Objects.nonNull; import java.io.IOException; @@ -9,6 +8,7 @@ import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.security.Security; +import java.util.Objects; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLEngine; @@ -16,7 +16,7 @@ import com.github.dockerjava.core.AbstractDockerCmdExecFactory; import com.github.dockerjava.core.WebTarget; -import org.apache.commons.lang.SystemUtils; +import org.apache.commons.lang3.SystemUtils; import com.github.dockerjava.api.command.DockerCmdExecFactory; import com.github.dockerjava.core.DockerClientConfig; @@ -284,7 +284,7 @@ public SSLParameters enableHostNameVerification(SSLParameters sslParameters) { @Override public void close() throws IOException { - checkNotNull(eventLoopGroup, "Factory not initialized. You probably forgot to call init()!"); + Objects.requireNonNull(eventLoopGroup, "Factory not initialized. You probably forgot to call init()!"); eventLoopGroup.shutdownGracefully(); } @@ -331,7 +331,7 @@ protected synchronized void channelIdle(ChannelHandlerContext ctx, IdleStateEven } protected WebTarget getBaseResource() { - checkNotNull(baseResource, "Factory not initialized, baseResource not set. You probably forgot to call init()!"); + Objects.requireNonNull(baseResource, "Factory not initialized, baseResource not set. You probably forgot to call init()!"); return baseResource; } } diff --git a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyInvocationBuilder.java b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyInvocationBuilder.java index 8830edb77..ab13dc7b7 100644 --- a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyInvocationBuilder.java +++ b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyInvocationBuilder.java @@ -6,7 +6,7 @@ import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.model.Frame; -import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.InvocationBuilder; import com.github.dockerjava.core.async.ResultCallbackTemplate; import com.github.dockerjava.netty.handler.FramedResponseStreamHandler; @@ -85,7 +85,7 @@ public void onNext(Void object) { @Deprecated public NettyInvocationBuilder(ChannelProvider channelProvider, String resource) { this( - DefaultDockerClientConfig.createDefaultConfigBuilder().build().getObjectMapper(), + DockerClientConfig.getDefaultObjectMapper(), channelProvider, resource ); @@ -111,17 +111,20 @@ public void delete() { HttpRequestProvider requestProvider = httpDeleteRequestProvider(); - ResponseCallback callback = new ResponseCallback<>(); + try (ResponseCallback callback = new ResponseCallback<>()) { - HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, callback); + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, callback); - Channel channel = getChannel(); + Channel channel = getChannel(); - channel.pipeline().addLast(responseHandler); + channel.pipeline().addLast(responseHandler); - sendRequest(requestProvider, channel); + sendRequest(requestProvider, channel); - callback.awaitResult(); + callback.awaitResult(); + } catch (IOException e) { + throw new RuntimeException(e); + } } public void get(ResultCallback resultCallback) { @@ -141,12 +144,13 @@ public void get(ResultCallback resultCallback) { } public T get(TypeReference typeReference) { + try (ResponseCallback callback = new ResponseCallback<>()) { + get(typeReference, callback); - ResponseCallback callback = new ResponseCallback<>(); - - get(typeReference, callback); - - return callback.awaitResult(); + return callback.awaitResult(); + } catch (IOException e) { + throw new RuntimeException(e); + } } public void get(TypeReference typeReference, ResultCallback resultCallback) { @@ -267,12 +271,13 @@ public void run() { } public T post(final Object entity, TypeReference typeReference) { + try (ResponseCallback callback = new ResponseCallback<>()) { + post(entity, typeReference, callback); - ResponseCallback callback = new ResponseCallback<>(); - - post(entity, typeReference, callback); - - return callback.awaitResult(); + return callback.awaitResult(); + } catch (IOException e) { + throw new RuntimeException(e); + } } public void post(final Object entity, TypeReference typeReference, final ResultCallback resultCallback) { @@ -372,12 +377,13 @@ private void setDefaultHeaders(HttpRequest request) { } public T post(TypeReference typeReference, InputStream body) { + try (ResponseCallback callback = new ResponseCallback<>()) { + post(typeReference, callback, body); - ResponseCallback callback = new ResponseCallback<>(); - - post(typeReference, callback, body); - - return callback.awaitResult(); + return callback.awaitResult(); + } catch (IOException e) { + throw new RuntimeException(e); + } } public void post(TypeReference typeReference, ResultCallback resultCallback, InputStream body) { @@ -464,28 +470,30 @@ public void put(InputStream body, com.github.dockerjava.core.MediaType mediaType Channel channel = getChannel(); - ResponseCallback resultCallback = new ResponseCallback<>(); + try (ResponseCallback resultCallback = new ResponseCallback<>()) { + HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); - HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback); + channel.pipeline().addLast(new ChunkedWriteHandler()); + channel.pipeline().addLast(responseHandler); - channel.pipeline().addLast(new ChunkedWriteHandler()); - channel.pipeline().addLast(responseHandler); - - HttpRequest request = requestProvider.getHttpRequest(resource); + HttpRequest request = requestProvider.getHttpRequest(resource); - // don't accept FullHttpRequest here - if (request instanceof FullHttpRequest) { - throw new DockerClientException("fatal: request is instance of FullHttpRequest"); - } + // don't accept FullHttpRequest here + if (request instanceof FullHttpRequest) { + throw new DockerClientException("fatal: request is instance of FullHttpRequest"); + } - request.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); - request.headers().remove(HttpHeaderNames.CONTENT_LENGTH); - request.headers().set(HttpHeaderNames.CONTENT_TYPE, mediaType.getMediaType()); + request.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); + request.headers().remove(HttpHeaderNames.CONTENT_LENGTH); + request.headers().set(HttpHeaderNames.CONTENT_TYPE, mediaType.getMediaType()); - channel.write(request); - channel.write(new ChunkedStream(new BufferedInputStream(body, 1024 * 1024))); - channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); + channel.write(request); + channel.write(new ChunkedStream(new BufferedInputStream(body, 1024 * 1024))); + channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); - resultCallback.awaitResult(); + resultCallback.awaitResult(); + } catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyWebTarget.java b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyWebTarget.java index 492308ad6..8f2ffce27 100644 --- a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyWebTarget.java +++ b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/NettyWebTarget.java @@ -13,11 +13,11 @@ import java.util.Set; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.WebTarget; import com.google.common.collect.ImmutableSet; import io.netty.handler.codec.http.HttpConstants; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -50,7 +50,7 @@ public class NettyWebTarget implements WebTarget { @Deprecated public NettyWebTarget(ChannelProvider channelProvider, String host) { this( - DefaultDockerClientConfig.createDefaultConfigBuilder().build().getObjectMapper(), + DockerClientConfig.getDefaultObjectMapper(), channelProvider, host, ImmutableList.of(), diff --git a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonRequestHandler.java b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonRequestHandler.java index 30e1831f8..b122c5090 100644 --- a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonRequestHandler.java +++ b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonRequestHandler.java @@ -1,12 +1,11 @@ package com.github.dockerjava.netty.handler; -import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.core.DockerClientConfig; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; -import com.fasterxml.jackson.databind.ObjectMapper; - /** * Handler that encodes an outgoing object to JSON. * @@ -17,7 +16,7 @@ @Deprecated public class JsonRequestHandler extends MessageToByteEncoder { - private ObjectMapper mapper = DefaultDockerClientConfig.createDefaultConfigBuilder().build().getObjectMapper(); + private ObjectMapper mapper = DockerClientConfig.getDefaultObjectMapper(); @Override protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { diff --git a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonResponseCallbackHandler.java b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonResponseCallbackHandler.java index 0d13bd306..f6e8af3c3 100644 --- a/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonResponseCallbackHandler.java +++ b/docker-java-transport-netty/src/main/java/com/github/dockerjava/netty/handler/JsonResponseCallbackHandler.java @@ -1,6 +1,6 @@ package com.github.dockerjava.netty.handler; -import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientConfig; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; @@ -25,7 +25,7 @@ public class JsonResponseCallbackHandler extends SimpleChannelInboundHandler< @Deprecated public JsonResponseCallbackHandler(TypeReference typeReference, ResultCallback callback) { this( - DefaultDockerClientConfig.createDefaultConfigBuilder().build().getObjectMapper(), + DockerClientConfig.getDefaultObjectMapper(), typeReference, callback ); diff --git a/docker-java-transport-okhttp/pom.xml b/docker-java-transport-okhttp/pom.xml index 3e6de70c2..2a0ae4227 100644 --- a/docker-java-transport-okhttp/pom.xml +++ b/docker-java-transport-okhttp/pom.xml @@ -4,7 +4,7 @@ com.github.docker-java docker-java-parent - 3.2.2-SNAPSHOT + 0-SNAPSHOT ../pom.xml @@ -15,6 +15,10 @@ https://github.com/docker-java/docker-java Java API Client for Docker + + com.github.dockerjava.transport.okhttp + + ${project.groupId} @@ -25,13 +29,20 @@ com.squareup.okhttp3 okhttp - 3.14.4 + 3.14.9 net.java.dev.jna - jna-platform - 5.5.0 + jna + 5.18.1 + + + + ${project.groupId} + docker-java-transport-tck + ${project.version} + test @@ -49,6 +60,9 @@ true + + com.github.dockerjava.okhttp.UnixDomainSocket$SockAddr + diff --git a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/HijackingInterceptor.java b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/HijackingInterceptor.java index 29aa524e7..275d8290b 100644 --- a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/HijackingInterceptor.java +++ b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/HijackingInterceptor.java @@ -1,6 +1,6 @@ package com.github.dockerjava.okhttp; -import com.github.dockerjava.core.DockerHttpClient; +import com.github.dockerjava.transport.DockerHttpClient; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; diff --git a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/NamedPipeSocketFactory.java b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/NamedPipeSocketFactory.java index d993a9c52..066ae7ce8 100644 --- a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/NamedPipeSocketFactory.java +++ b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/NamedPipeSocketFactory.java @@ -1,17 +1,10 @@ package com.github.dockerjava.okhttp; -import com.github.dockerjava.okhttp.OkDockerHttpClient.OkResponse; -import com.sun.jna.platform.win32.Kernel32; +import com.github.dockerjava.transport.NamedPipeSocket; import javax.net.SocketFactory; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.RandomAccessFile; import java.net.InetAddress; import java.net.Socket; -import java.net.SocketAddress; class NamedPipeSocketFactory extends SocketFactory { @@ -23,96 +16,7 @@ class NamedPipeSocketFactory extends SocketFactory { @Override public Socket createSocket() { - return new Socket() { - - RandomAccessFile file; - InputStream is; - OutputStream os; - - @Override - public void close() throws IOException { - if (file != null) { - file.close(); - file = null; - } - } - - @Override - public void connect(SocketAddress endpoint) { - connect(endpoint, 0); - } - - @Override - public void connect(SocketAddress endpoint, int timeout) { - long startedAt = System.currentTimeMillis(); - timeout = Math.max(timeout, 10_000); - while (true) { - try { - file = new RandomAccessFile(socketFileName, "rw"); - break; - } catch (FileNotFoundException e) { - if (System.currentTimeMillis() - startedAt >= timeout) { - throw new RuntimeException(e); - } else { - Kernel32.INSTANCE.WaitNamedPipe(socketFileName, 100); - } - } - } - - is = new InputStream() { - @Override - public int read(byte[] bytes, int off, int len) throws IOException { - if (OkResponse.CLOSING.get()) { - return 0; - } - return file.read(bytes, off, len); - } - - @Override - public int read() throws IOException { - if (OkResponse.CLOSING.get()) { - return 0; - } - return file.read(); - } - - @Override - public int read(byte[] bytes) throws IOException { - if (OkResponse.CLOSING.get()) { - return 0; - } - return file.read(bytes); - } - }; - - os = new OutputStream() { - @Override - public void write(byte[] bytes, int off, int len) throws IOException { - file.write(bytes, off, len); - } - - @Override - public void write(int value) throws IOException { - file.write(value); - } - - @Override - public void write(byte[] bytes) throws IOException { - file.write(bytes); - } - }; - } - - @Override - public InputStream getInputStream() { - return is; - } - - @Override - public OutputStream getOutputStream() { - return os; - } - }; + return new NamedPipeSocket(socketFileName); } @Override diff --git a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkDockerHttpClient.java b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkDockerHttpClient.java index 8853dd815..ee58acb09 100644 --- a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkDockerHttpClient.java +++ b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkDockerHttpClient.java @@ -1,8 +1,8 @@ package com.github.dockerjava.okhttp; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.core.DockerHttpClient; -import com.github.dockerjava.core.SSLConfig; +import com.github.dockerjava.transport.DockerHttpClient; +import com.github.dockerjava.transport.SSLConfig; +import okhttp3.Call; import okhttp3.ConnectionPool; import okhttp3.Dns; import okhttp3.HttpUrl; @@ -12,6 +12,8 @@ import okhttp3.ResponseBody; import okio.BufferedSink; import okio.Okio; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; @@ -24,13 +26,18 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; public final class OkDockerHttpClient implements DockerHttpClient { - public static final class Factory { + private static final Logger LOGGER = LoggerFactory.getLogger(OkDockerHttpClient.class); - private DockerClientConfig dockerClientConfig = null; + public static final class Builder { + + private URI dockerHost = null; + + private SSLConfig sslConfig = null; private Integer readTimeout = null; @@ -38,29 +45,36 @@ public static final class Factory { private Boolean retryOnConnectionFailure = null; - public Factory dockerClientConfig(DockerClientConfig value) { - this.dockerClientConfig = value; + public Builder dockerHost(URI value) { + this.dockerHost = Objects.requireNonNull(value, "dockerHost"); + return this; + } + + public Builder sslConfig(SSLConfig value) { + this.sslConfig = value; return this; } - public Factory readTimeout(Integer value) { + public Builder readTimeout(Integer value) { this.readTimeout = value; return this; } - public Factory connectTimeout(Integer value) { + public Builder connectTimeout(Integer value) { this.connectTimeout = value; return this; } - Factory retryOnConnectionFailure(Boolean value) { + Builder retryOnConnectionFailure(Boolean value) { this.retryOnConnectionFailure = value; return this; } public OkDockerHttpClient build() { + Objects.requireNonNull(dockerHost, "dockerHost"); return new OkDockerHttpClient( - dockerClientConfig, + dockerHost, + sslConfig, readTimeout, connectTimeout, retryOnConnectionFailure @@ -77,7 +91,8 @@ public OkDockerHttpClient build() { private final HttpUrl baseUrl; private OkDockerHttpClient( - DockerClientConfig dockerClientConfig, + URI dockerHost, + SSLConfig sslConfig, Integer readTimeout, Integer connectTimeout, Boolean retryOnConnectionFailure @@ -99,7 +114,6 @@ private OkDockerHttpClient( clientBuilder.retryOnConnectionFailure(retryOnConnectionFailure); } - URI dockerHost = dockerClientConfig.getDockerHost(); switch (dockerHost.getScheme()) { case "unix": case "npipe": @@ -125,7 +139,6 @@ private OkDockerHttpClient( } boolean isSSL = false; - SSLConfig sslConfig = dockerClientConfig.getSSLConfig(); if (sslConfig != null) { try { SSLContext sslContext = sslConfig.getSSLContext(); @@ -156,14 +169,23 @@ private OkDockerHttpClient( .scheme(isSSL ? "https" : "http") .host(dockerHost.getHost()) .port(dockerHost.getPort()); + + if (dockerHost.getPath().length() > 0) { + baseUrlBuilder = baseUrlBuilder.encodedPath(dockerHost.getPath()); + } break; default: - baseUrlBuilder = HttpUrl.get(dockerHost.toString()).newBuilder(); + throw new IllegalArgumentException("Unsupported protocol scheme: " + dockerHost); } baseUrl = baseUrlBuilder.build(); } private RequestBody toRequestBody(Request request) { + byte[] bodyBytes = request.bodyBytes(); + if (bodyBytes != null) { + return RequestBody.create(null, bodyBytes); + } + InputStream body = request.body(); if (body != null) { return new RequestBody() { @@ -207,9 +229,11 @@ public Response execute(Request request) { clientToUse = streamingClient; } + Call call = clientToUse.newCall(requestBuilder.build()); try { - return new OkResponse(clientToUse.newCall(requestBuilder.build()).execute()); + return new OkResponse(call); } catch (IOException e) { + call.cancel(); throw new UncheckedIOException("Error while executing " + request, e); } } @@ -227,10 +251,13 @@ static class OkResponse implements Response { static final ThreadLocal CLOSING = ThreadLocal.withInitial(() -> false); + private final Call call; + private final okhttp3.Response response; - OkResponse(okhttp3.Response response) { - this.response = response; + OkResponse(Call call) throws IOException { + this.call = call; + this.response = call.execute(); } @Override @@ -258,7 +285,10 @@ public void close() { boolean previous = CLOSING.get(); CLOSING.set(true); try { + call.cancel(); response.close(); + } catch (Exception | AssertionError e) { + LOGGER.debug("Failed to close the response", e); } finally { CLOSING.set(previous); } diff --git a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkHttpDockerCmdExecFactory.java b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkHttpDockerCmdExecFactory.java index 90f37b7d8..a824e9954 100644 --- a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkHttpDockerCmdExecFactory.java +++ b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/OkHttpDockerCmdExecFactory.java @@ -6,15 +6,15 @@ import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.DockerClientConfigAware; import com.github.dockerjava.core.DockerClientImpl; -import com.github.dockerjava.core.DockerHttpClient; +import com.github.dockerjava.transport.DockerHttpClient; /** - * @deprecated use {@link OkDockerHttpClient} with {@link DockerClientImpl#withHttpClient(DockerHttpClient)} + * @deprecated use {@link OkDockerHttpClient} with {@link DockerClientImpl#getInstance(DockerClientConfig, DockerHttpClient)} */ @Deprecated public class OkHttpDockerCmdExecFactory extends DelegatingDockerCmdExecFactory implements DockerClientConfigAware { - private OkDockerHttpClient.Factory clientFactory = new OkDockerHttpClient.Factory(); + private OkDockerHttpClient.Builder clientBuilder = new OkDockerHttpClient.Builder(); @Deprecated protected Integer connectTimeout; @@ -28,7 +28,7 @@ public class OkHttpDockerCmdExecFactory extends DelegatingDockerCmdExecFactory i * Configure connection timeout in milliseconds */ public OkHttpDockerCmdExecFactory withConnectTimeout(Integer connectTimeout) { - clientFactory = clientFactory.connectTimeout(connectTimeout); + clientBuilder = clientBuilder.connectTimeout(connectTimeout); this.connectTimeout = connectTimeout; return this; } @@ -37,13 +37,13 @@ public OkHttpDockerCmdExecFactory withConnectTimeout(Integer connectTimeout) { * Configure read timeout in milliseconds */ public OkHttpDockerCmdExecFactory withReadTimeout(Integer readTimeout) { - clientFactory = clientFactory.readTimeout(readTimeout); + clientBuilder = clientBuilder.readTimeout(readTimeout); this.readTimeout = readTimeout; return this; } public OkHttpDockerCmdExecFactory setRetryOnConnectionFailure(Boolean retryOnConnectionFailure) { - this.clientFactory = clientFactory.retryOnConnectionFailure(retryOnConnectionFailure); + this.clientBuilder = clientBuilder.retryOnConnectionFailure(retryOnConnectionFailure); return this; } @@ -54,9 +54,11 @@ public final DockerCmdExecFactory getDockerCmdExecFactory() { @Override public void init(DockerClientConfig dockerClientConfig) { - clientFactory = clientFactory.dockerClientConfig(dockerClientConfig); + clientBuilder = clientBuilder + .dockerHost(dockerClientConfig.getDockerHost()) + .sslConfig(dockerClientConfig.getSSLConfig()); dockerCmdExecFactory = new DefaultDockerCmdExecFactory( - clientFactory.build(), + clientBuilder.build(), dockerClientConfig.getObjectMapper() ); dockerCmdExecFactory.init(dockerClientConfig); diff --git a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/UnixDomainSocket.java b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/UnixDomainSocket.java deleted file mode 100644 index e2f1002d7..000000000 --- a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/UnixDomainSocket.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * - * MariaDB Client for Java - * - * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2019 MariaDB Ab. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with this library; if not, write to Monty Program Ab info@montyprogram.com. - * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - */ - -package com.github.dockerjava.okhttp; - -import com.sun.jna.LastErrorException; -import com.sun.jna.Native; -import com.sun.jna.Platform; -import com.sun.jna.Structure; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicBoolean; - -class UnixDomainSocket extends Socket { - - private static final int AF_UNIX = 1; - private static final int SOCK_STREAM = Platform.isSolaris() ? 2 : 1; - private static final int PROTOCOL = 0; - - static { - if (Platform.isSolaris()) { - System.loadLibrary("nsl"); - System.loadLibrary("socket"); - } - if (!Platform.isWindows() && !Platform.isWindowsCE()) { - Native.register("c"); - } - } - - private final AtomicBoolean closeLock = new AtomicBoolean(); - private final SockAddr sockaddr; - private final int fd; - private InputStream is; - private OutputStream os; - private boolean connected; - - UnixDomainSocket(String path) throws IOException { - if (Platform.isWindows() || Platform.isWindowsCE()) { - throw new IOException("Unix domain sockets are not supported on Windows"); - } - sockaddr = new SockAddr(path); - closeLock.set(false); - try { - fd = socket(AF_UNIX, SOCK_STREAM, PROTOCOL); - } catch (LastErrorException lee) { - throw new IOException("native socket() failed : " + formatError(lee)); - } - } - - public static native int socket(int domain, int type, int protocol) throws LastErrorException; - - public static native int connect(int sockfd, SockAddr sockaddr, int addrlen) - throws LastErrorException; - - public static native int recv(int fd, byte[] buffer, int count, int flags) - throws LastErrorException; - - public static native int send(int fd, byte[] buffer, int count, int flags) - throws LastErrorException; - - public static native int close(int fd) throws LastErrorException; - - public static native String strerror(int errno); - - private static String formatError(LastErrorException lee) { - try { - return strerror(lee.getErrorCode()); - } catch (Throwable t) { - return lee.getMessage(); - } - } - - @Override - public boolean isConnected() { - return connected; - } - - @Override - public void close() throws IOException { - if (!closeLock.getAndSet(true)) { - try { - close(fd); - } catch (LastErrorException lee) { - throw new IOException("native close() failed : " + formatError(lee)); - } - connected = false; - } - } - - @Override - public void connect(SocketAddress endpoint) throws IOException { - connect(endpoint, 0); - } - - public void connect(SocketAddress endpoint, int timeout) throws IOException { - try { - int ret = connect(fd, sockaddr, sockaddr.size()); - if (ret != 0) { - throw new IOException(strerror(Native.getLastError())); - } - connected = true; - } catch (LastErrorException lee) { - throw new IOException("native connect() failed : " + formatError(lee)); - } - is = new UnixSocketInputStream(); - os = new UnixSocketOutputStream(); - } - - public InputStream getInputStream() { - return is; - } - - public OutputStream getOutputStream() { - return os; - } - - public void setTcpNoDelay(boolean b) { - // do nothing - } - - public void setKeepAlive(boolean b) { - // do nothing - } - - public void setReceiveBufferSize(int size) { - // do nothing - } - - public void setSendBufferSize(int size) { - // do nothing - } - - public void setSoLinger(boolean b, int i) { - // do nothing - } - - public void setSoTimeout(int timeout) { - // do nothing - } - - public void shutdownInput() { - // do nothing - } - - public void shutdownOutput() { - // do nothing - } - - public static class SockAddr extends Structure { - - @SuppressWarnings("checkstyle:membername") - public short sun_family; - @SuppressWarnings("checkstyle:membername") - public byte[] sun_path; - - /** - * Contructor. - * - * @param sunPath path - */ - SockAddr(String sunPath) { - sun_family = AF_UNIX; - byte[] arr = sunPath.getBytes(); - sun_path = new byte[arr.length + 1]; - System.arraycopy(arr, 0, sun_path, 0, Math.min(sun_path.length - 1, arr.length)); - allocateMemory(); - } - - @Override - protected java.util.List getFieldOrder() { - return Arrays.asList("sun_family", "sun_path"); - } - } - - class UnixSocketInputStream extends InputStream { - - @Override - public int read(byte[] bytesEntry, int off, int len) throws IOException { - try { - if (off > 0) { - int bytes = 0; - int remainingLength = len; - int size; - byte[] data = new byte[(len < 10240) ? len : 10240]; - do { - size = recv(fd, data, (remainingLength < 10240) ? remainingLength : 10240, 0); - if (size > 0) { - System.arraycopy(data, 0, bytesEntry, off, size); - bytes += size; - off += size; - remainingLength -= size; - } - } while ((remainingLength > 0) && (size > 0)); - return bytes; - } else { - return recv(fd, bytesEntry, len, 0); - } - } catch (LastErrorException lee) { - throw new IOException("native read() failed : " + formatError(lee)); - } - } - - @Override - public int read() throws IOException { - byte[] bytes = new byte[1]; - int bytesRead = read(bytes); - if (bytesRead == 0) { - return -1; - } - return bytes[0] & 0xff; - } - - @Override - public int read(byte[] bytes) throws IOException { - return read(bytes, 0, bytes.length); - } - } - - class UnixSocketOutputStream extends OutputStream { - - @Override - public void write(byte[] bytesEntry, int off, int len) throws IOException { - int bytes; - try { - if (off > 0) { - int size; - int remainingLength = len; - byte[] data = new byte[(len < 10240) ? len : 10240]; - do { - size = (remainingLength < 10240) ? remainingLength : 10240; - System.arraycopy(bytesEntry, off, data, 0, size); - bytes = send(fd, data, size, 0); - if (bytes > 0) { - off += bytes; - remainingLength -= bytes; - } - } while ((remainingLength > 0) && (bytes > 0)); - } else { - bytes = send(fd, bytesEntry, len, 0); - } - - if (bytes != len) { - throw new IOException("can't write " + len + "bytes"); - } - } catch (LastErrorException lee) { - throw new IOException("native write() failed : " + formatError(lee)); - } - } - - @Override - public void write(int value) throws IOException { - write(new byte[] {(byte) value}); - } - - @Override - public void write(byte[] bytes) throws IOException { - write(bytes, 0, bytes.length); - } - } -} diff --git a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/UnixSocketFactory.java b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/UnixSocketFactory.java index 6c9dbe10b..d25bcb3d3 100644 --- a/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/UnixSocketFactory.java +++ b/docker-java-transport-okhttp/src/main/java/com/github/dockerjava/okhttp/UnixSocketFactory.java @@ -1,16 +1,11 @@ package com.github.dockerjava.okhttp; -import com.github.dockerjava.okhttp.OkDockerHttpClient.OkResponse; +import com.github.dockerjava.transport.UnixSocket; import javax.net.SocketFactory; -import java.io.FilterInputStream; -import java.io.FilterOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; -import java.net.SocketAddress; class UnixSocketFactory extends SocketFactory { @@ -23,48 +18,9 @@ class UnixSocketFactory extends SocketFactory { @Override public Socket createSocket() { try { - return new UnixDomainSocket(socketPath) { - @Override - public void connect(SocketAddress endpoint, int timeout) throws IOException { - super.connect(endpoint, timeout); - } - - @Override - public InputStream getInputStream() { - return new FilterInputStream(super.getInputStream()) { - @Override - public void close() throws IOException { - shutdownInput(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - if (OkResponse.CLOSING.get()) { - return 0; - } - return super.read(b, off, len); - } - }; - } - - @Override - public OutputStream getOutputStream() { - return new FilterOutputStream(super.getOutputStream()) { - - @Override - public void write(byte[] b, int off, int len) throws IOException { - out.write(b, off, len); - } - - @Override - public void close() throws IOException { - shutdownOutput(); - } - }; - } - }; + return UnixSocket.get(socketPath); } catch (IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("Failed create socket with path " + socketPath, e); } } diff --git a/docker-java-transport-okhttp/src/test/java/com/github/dockerjava/transport/OkHttpClientTests.java b/docker-java-transport-okhttp/src/test/java/com/github/dockerjava/transport/OkHttpClientTests.java new file mode 100644 index 000000000..9a5b77ff3 --- /dev/null +++ b/docker-java-transport-okhttp/src/test/java/com/github/dockerjava/transport/OkHttpClientTests.java @@ -0,0 +1,17 @@ +package com.github.dockerjava.transport; + +import com.github.dockerjava.okhttp.OkDockerHttpClient; + +import java.net.URI; + +public class OkHttpClientTests extends DockerHttpClientTCK { + + @Override + protected DockerHttpClient createDockerHttpClient(URI dockerHost, SSLConfig sslConfig) { + return new OkDockerHttpClient.Builder() + .dockerHost(dockerHost) + .sslConfig(sslConfig) + .connectTimeout(30 * 100) + .build(); + } +} diff --git a/docker-java-transport-tck/pom.xml b/docker-java-transport-tck/pom.xml new file mode 100644 index 000000000..d7253c786 --- /dev/null +++ b/docker-java-transport-tck/pom.xml @@ -0,0 +1,70 @@ + + 4.0.0 + + + com.github.docker-java + docker-java-parent + 0-SNAPSHOT + ../pom.xml + + + docker-java-transport-tck + jar + + docker-java-transport-tck + https://github.com/docker-java/docker-java + Java API Client for Docker + + + com.github.dockerjava.transport.tck + + + + + ${project.groupId} + docker-java-core + ${project.version} + + + ${project.groupId} + docker-java-transport + ${project.version} + + + + org.assertj + assertj-core + 3.27.6 + + + + com.squareup.okhttp3 + mockwebserver + 3.14.9 + + + + org.testcontainers + testcontainers + 2.0.2 + + + + org.slf4j + slf4j-jdk14 + 1.7.35 + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + diff --git a/docker-java-transport-tck/src/main/java/com/github/dockerjava/transport/DockerHttpClientTCK.java b/docker-java-transport-tck/src/main/java/com/github/dockerjava/transport/DockerHttpClientTCK.java new file mode 100644 index 000000000..f90973be6 --- /dev/null +++ b/docker-java-transport-tck/src/main/java/com/github/dockerjava/transport/DockerHttpClientTCK.java @@ -0,0 +1,148 @@ +package com.github.dockerjava.transport; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.transport.DockerHttpClient.Request; +import com.github.dockerjava.transport.DockerHttpClient.Request.Method; +import com.github.dockerjava.transport.DockerHttpClient.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.Test; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.dockerclient.TransportConfig; + +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.net.URI; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class DockerHttpClientTCK { + + protected abstract DockerHttpClient createDockerHttpClient(URI dockerHost, SSLConfig sslConfig); + + @Test + public void testHijacking() throws Exception { + try ( + DockerClient client = createDockerClient(); + + PipedOutputStream out = new PipedOutputStream(); + PipedInputStream in = new PipedInputStream(out); + + AttachContainerTestCallback callback = new AttachContainerTestCallback(); + + AttacheableContainer container = new AttacheableContainer() { + @Override + protected void containerIsCreated(String containerId) { + client.attachContainerCmd(containerId) + .withStdOut(true) + .withFollowStream(true) + .withStdIn(in) + .exec(callback); + } + }; + ) { + container.start(); + assertThat(callback.awaitStarted(5, SECONDS)).as("attached").isTrue(); + + String snippet = "hello world"; + out.write((snippet + "\n").getBytes()); + out.flush(); + + assertThat(callback.awaitCompletion(15, SECONDS)).as("completed").isTrue(); + assertThat(callback.toString()).contains("STDOUT: " + snippet); + } + } + + /** + * Test that docker-java supports path in DOCKER_HOST + * + * @see valid values + */ + @Test + public final void testPath() throws Exception { + try (MockWebServer server = new MockWebServer()) { + String dockerHost = server.url("/%20some/path/").toString() + .replace("http://", "tcp://"); + + try (DockerHttpClient client = createDockerHttpClient(dockerHost)) { + server.enqueue(new MockResponse().setResponseCode(200)); + ping(client); + assertThat(server.takeRequest().getPath()) + .as("recorded path") + .isEqualTo("/%20some/path/_ping"); + } + } + } + + private DockerHttpClient createDockerHttpClient() { + // Use Testcontainers to detect Docker environment + TransportConfig transportConfig = DockerClientFactory.instance().getTransportConfig(); + return createDockerHttpClient(transportConfig.getDockerHost(), transportConfig.getSslConfig()); + } + + private DockerHttpClient createDockerHttpClient(String dockerHost) { + return createDockerHttpClient(URI.create(dockerHost), null); + } + + private DockerClient createDockerClient() { + return createDockerClient(createDockerHttpClient()); + } + + private DockerClient createDockerClient(DockerHttpClient dockerHttpClient) { + return DockerClientImpl.getInstance( + DefaultDockerClientConfig.createDefaultConfigBuilder().build(), + dockerHttpClient + ); + } + + private void ping(DockerHttpClient client) { + Request pingRequest = Request.builder() + .method(Method.GET) + .path("/_ping") + .build(); + + try (Response response = client.execute(pingRequest)) { + assertThat(response.getStatusCode()) + .as("status code") + .isEqualTo(200); + } + } + + private static class AttachContainerTestCallback extends ResultCallback.Adapter { + + private final StringBuffer log = new StringBuffer(); + + @Override + public void onNext(Frame item) { + log.append(item.toString()); + super.onNext(item); + } + + @Override + public String toString() { + return log.toString(); + } + } + + private static class AttacheableContainer extends GenericContainer { + + private AttacheableContainer() { + super("busybox:1.35.0"); + + withCommand("/bin/sh", "-c", "read line && echo $line"); + withCreateContainerCmdModifier(it -> { + it.withTty(false); + it.withAttachStdin(true); + it.withAttachStdout(true); + it.withAttachStderr(true); + it.withStdinOpen(true); + }); + } + } +} diff --git a/docker-java-transport-zerodep/pom.xml b/docker-java-transport-zerodep/pom.xml new file mode 100644 index 000000000..3cccafa33 --- /dev/null +++ b/docker-java-transport-zerodep/pom.xml @@ -0,0 +1,108 @@ + + 4.0.0 + + + com.github.docker-java + docker-java-parent + 0-SNAPSHOT + ../pom.xml + + + docker-java-transport-zerodep + jar + + docker-java-transport-zerodep + https://github.com/docker-java/docker-java + Java API Client for Docker + + + com.github.dockerjava.transport.zerodep + + + + + ${project.groupId} + docker-java-transport-httpclient5 + ${project.version} + + + + + + + com.github.siom79.japicmp + japicmp-maven-plugin + + + true + + + + + org.apache.felix + maven-bundle-plugin + true + + + com.github.dockerjava.zerodep.* + + + + + + org.apache.maven.plugins + maven-shade-plugin + + true + true + true + + + + com.github.docker-java:docker-java-transport + net.java.dev.jna:jna-platform + net.java.dev.jna:* + org.slf4j:slf4j-api + + + + + com.github.docker-java:docker-java-transport-httpclient5 + + com/github/dockerjava/httpclient5/ApacheDockerHttpClient.class + com/github/dockerjava/httpclient5/ApacheDockerHttpClient$* + + + + org.apache.httpcomponents.client5:httpclient5 + + mozilla/* + + + + + + org.apache + com.github.dockerjava.zerodep.shaded.org.apache + + + com.github.dockerjava.httpclient5 + com.github.dockerjava.zerodep + + + + + + + + + package + + shade + + + + + + + diff --git a/docker-java-transport-zerodep/src/main/java/com/github/dockerjava/httpclient5/ZerodepDockerHttpClient.java b/docker-java-transport-zerodep/src/main/java/com/github/dockerjava/httpclient5/ZerodepDockerHttpClient.java new file mode 100644 index 000000000..fcacc6d1b --- /dev/null +++ b/docker-java-transport-zerodep/src/main/java/com/github/dockerjava/httpclient5/ZerodepDockerHttpClient.java @@ -0,0 +1,58 @@ +package com.github.dockerjava.httpclient5; + +import java.net.URI; +import java.time.Duration; +import java.util.Objects; +import com.github.dockerjava.transport.SSLConfig; + +@SuppressWarnings("unused") +public final class ZerodepDockerHttpClient extends ApacheDockerHttpClientImpl { + + public static final class Builder { + + private URI dockerHost = null; + + private SSLConfig sslConfig = null; + + private int maxConnections = Integer.MAX_VALUE; + + private Duration connectionTimeout; + + private Duration responseTimeout; + + public Builder dockerHost(URI value) { + this.dockerHost = Objects.requireNonNull(value, "dockerHost"); + return this; + } + + public Builder sslConfig(SSLConfig value) { + this.sslConfig = value; + return this; + } + + public Builder maxConnections(int value) { + this.maxConnections = value; + return this; + } + + public Builder connectionTimeout(Duration connectionTimeout) { + this.connectionTimeout = connectionTimeout; + return this; + } + + public Builder responseTimeout(Duration responseTimeout) { + this.responseTimeout = responseTimeout; + return this; + } + + public ZerodepDockerHttpClient build() { + Objects.requireNonNull(dockerHost, "dockerHost"); + return new ZerodepDockerHttpClient(dockerHost, sslConfig, maxConnections, connectionTimeout, responseTimeout); + } + } + + private ZerodepDockerHttpClient(URI dockerHost, SSLConfig sslConfig, int maxConnections, Duration connectionTimeout, + Duration responseTimeout) { + super(dockerHost, sslConfig, maxConnections, connectionTimeout, responseTimeout); + } +} diff --git a/docker-java-transport/pom.xml b/docker-java-transport/pom.xml new file mode 100644 index 000000000..8be456dd1 --- /dev/null +++ b/docker-java-transport/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + + + com.github.docker-java + docker-java-parent + 0-SNAPSHOT + ../pom.xml + + + docker-java-transport + jar + + docker-java-transport + https://github.com/docker-java/docker-java + Java API Client for Docker + + + com.github.dockerjava.transport + + + + + com.google.code.findbugs + annotations + 3.0.1u2 + provided + + + + org.immutables + value + 2.10.1 + provided + + + + net.java.dev.jna + jna + 5.18.1 + provided + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + com.github.dockerjava.transport.* + + + + + + diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/AbstractSocket.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/AbstractSocket.java new file mode 100644 index 000000000..37a538bc9 --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/AbstractSocket.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.dockerjava.transport; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; + +/** + * Abstract base class for custom socket implementation. + * + * @author Phillip Webb + */ +class AbstractSocket extends Socket { + + @Override + public void connect(SocketAddress endpoint) throws IOException { + } + + @Override + public void connect(SocketAddress endpoint, int timeout) throws IOException { + } + + @Override + public boolean isConnected() { + return true; + } + + @Override + public boolean isBound() { + return true; + } + + @Override + public void shutdownInput() throws IOException { + throw new UnsupportedSocketOperationException(); + } + + @Override + public void shutdownOutput() throws IOException { + throw new UnsupportedSocketOperationException(); + } + + @Override + public InetAddress getInetAddress() { + return null; + } + + @Override + public InetAddress getLocalAddress() { + return null; + } + + @Override + public SocketAddress getLocalSocketAddress() { + return null; + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return null; + } + + private static class UnsupportedSocketOperationException extends UnsupportedOperationException { + + UnsupportedSocketOperationException() { + super("Unsupported socket operation"); + } + + } + +} diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/BsdDomainSocket.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/BsdDomainSocket.java new file mode 100644 index 000000000..12d2004e6 --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/BsdDomainSocket.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.dockerjava.transport; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; + +import com.sun.jna.LastErrorException; +import com.sun.jna.Native; +import com.sun.jna.Platform; +import com.sun.jna.Structure; + +/** + * {@link DomainSocket} implementation for BSD based platforms. + * + * @author Phillip Webb + */ +class BsdDomainSocket extends DomainSocket { + + private static final int MAX_PATH_LENGTH = 104; + + static { + Native.register(Platform.C_LIBRARY_NAME); + } + + BsdDomainSocket(String path) throws IOException { + super(path); + } + + @Override + protected void connect(String path, int handle) { + SockaddrUn address = new SockaddrUn(AF_LOCAL, path.getBytes(StandardCharsets.UTF_8)); + connect(handle, address, address.size()); + } + + private native int connect(int fd, SockaddrUn address, int addressLen) throws LastErrorException; + + /** + * Native {@code sockaddr_un} structure as defined in {@code sys/un.h}. + */ + public static class SockaddrUn extends Structure implements Structure.ByReference { + + public byte sunLen; + + public byte sunFamily; + + public byte[] sunPath = new byte[MAX_PATH_LENGTH]; + + private SockaddrUn(byte sunFamily, byte[] path) { + if (path.length > MAX_PATH_LENGTH) { + throw new IllegalArgumentException("Path cannot exceed " + MAX_PATH_LENGTH + " bytes"); + } + System.arraycopy(path, 0, this.sunPath, 0, path.length); + this.sunPath[path.length] = 0; + this.sunLen = (byte) (fieldOffset("sunPath") + path.length); + this.sunFamily = sunFamily; + allocateMemory(); + } + + @Override + protected List getFieldOrder() { + return Arrays.asList("sunLen", "sunFamily", "sunPath"); + } + + } + +} diff --git a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerHttpClient.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/DockerHttpClient.java similarity index 82% rename from docker-java-core/src/main/java/com/github/dockerjava/core/DockerHttpClient.java rename to docker-java-transport/src/main/java/com/github/dockerjava/transport/DockerHttpClient.java index 6b56fd07f..7b780cb06 100644 --- a/docker-java-core/src/main/java/com/github/dockerjava/core/DockerHttpClient.java +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/DockerHttpClient.java @@ -1,9 +1,10 @@ -package com.github.dockerjava.core; +package com.github.dockerjava.transport; import org.immutables.value.Value; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.InputStream; import java.util.List; @@ -70,7 +71,16 @@ public static Builder builder() { public abstract String path(); @Nullable - public abstract InputStream body(); + @Value.Default + public InputStream body() { + byte[] bodyBytes = bodyBytes(); + return bodyBytes != null + ? new ByteArrayInputStream(bodyBytes) + : null; + } + + @Nullable + public abstract byte[] bodyBytes(); @Nullable public abstract InputStream hijackedInput(); diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/DomainSocket.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/DomainSocket.java new file mode 100644 index 000000000..a2a3503f5 --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/DomainSocket.java @@ -0,0 +1,191 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.dockerjava.transport; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.ByteBuffer; + +import com.github.dockerjava.transport.FileDescriptor.Handle; +import com.sun.jna.LastErrorException; +import com.sun.jna.Native; +import com.sun.jna.Platform; + +/** + * A {@link Socket} implementation for Linux of BSD domain sockets. + * + * @author Phillip Webb + */ +public abstract class DomainSocket extends AbstractSocket { + + private static final int SHUT_RD = 0; + + private static final int SHUT_WR = 1; + + protected static final int PF_LOCAL = 1; + + protected static final byte AF_LOCAL = 1; + + protected static final int SOCK_STREAM = 1; + + private final FileDescriptor fileDescriptor; + + private final InputStream inputStream; + + private final OutputStream outputStream; + + static { + Native.register(Platform.C_LIBRARY_NAME); + } + + DomainSocket(String path) throws IOException { + try { + this.fileDescriptor = open(path); + this.inputStream = new DomainSocketInputStream(); + this.outputStream = new DomainSocketOutputStream(); + } catch (LastErrorException ex) { + throw new IOException(ex); + } + } + + private FileDescriptor open(String path) { + int handle = socket(PF_LOCAL, SOCK_STREAM, 0); + connect(path, handle); + return new FileDescriptor(handle, this::close); + } + + private int read(ByteBuffer buffer) throws IOException { + try (Handle handle = this.fileDescriptor.acquire()) { + if (handle.isClosed()) { + return -1; + } + try { + return read(handle.intValue(), buffer, buffer.remaining()); + } catch (LastErrorException ex) { + throw new IOException(ex); + } + } + } + + public void write(ByteBuffer buffer) throws IOException { + try (Handle handle = this.fileDescriptor.acquire()) { + if (!handle.isClosed()) { + try { + write(handle.intValue(), buffer, buffer.remaining()); + } catch (LastErrorException ex) { + throw new IOException(ex); + } + } + } + } + + @Override + public InputStream getInputStream() { + return this.inputStream; + } + + @Override + public OutputStream getOutputStream() { + return this.outputStream; + } + + @Override + public void close() throws IOException { + super.close(); + try { + this.fileDescriptor.close(); + } catch (LastErrorException ex) { + throw new IOException(ex); + } + } + + protected abstract void connect(String path, int handle); + + private native int socket(int domain, int type, int protocol) throws LastErrorException; + + private native int read(int fd, ByteBuffer buffer, int count) throws LastErrorException; + + private native int write(int fd, ByteBuffer buffer, int count) throws LastErrorException; + + private native int close(int fd) throws LastErrorException; + + /** + * Return a new {@link DomainSocket} for the given path. + * @param path the path to the domain socket + * @return a {@link DomainSocket} instance + * @throws IOException if the socket cannot be opened + * @deprecated use {@link UnixSocket#get(String)} + */ + @Deprecated + public static DomainSocket get(String path) throws IOException { + if (Platform.isMac() || isBsdPlatform()) { + return new BsdDomainSocket(path); + } + return new LinuxDomainSocket(path); + } + + private static boolean isBsdPlatform() { + return Platform.isFreeBSD() || Platform.iskFreeBSD() || Platform.isNetBSD() || Platform.isOpenBSD(); + } + + /** + * {@link InputStream} returned from the {@link DomainSocket}. + */ + private class DomainSocketInputStream extends InputStream { + + @Override + public int read() throws IOException { + ByteBuffer buffer = ByteBuffer.allocate(1); + int amountRead = DomainSocket.this.read(buffer); + return (amountRead != 1) ? -1 : buffer.get() & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (len == 0) { + return 0; + } + int amountRead = DomainSocket.this.read(ByteBuffer.wrap(b, off, len)); + return (amountRead > 0) ? amountRead : -1; + } + + } + + /** + * {@link OutputStream} returned from the {@link DomainSocket}. + */ + private class DomainSocketOutputStream extends OutputStream { + + @Override + public void write(int b) throws IOException { + ByteBuffer buffer = ByteBuffer.allocate(1); + buffer.put(0, (byte) (b & 0xFF)); + DomainSocket.this.write(buffer); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (len != 0) { + DomainSocket.this.write(ByteBuffer.wrap(b, off, len)); + } + } + + } + +} diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/FileDescriptor.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/FileDescriptor.java new file mode 100644 index 000000000..31960f949 --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/FileDescriptor.java @@ -0,0 +1,121 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.dockerjava.transport; + +import java.io.Closeable; +import java.io.IOException; +import java.util.function.IntConsumer; + +/** + * Provides access to the underlying file system representation of an open file. + * + * @author Phillip Webb + * @see #acquire() + */ +class FileDescriptor { + + private final Handle openHandle; + + private final Handle closedHandler; + + private final IntConsumer closer; + + private Status status = Status.OPEN; + + private int referenceCount; + + FileDescriptor(int handle, IntConsumer closer) { + this.openHandle = new Handle(handle); + this.closedHandler = new Handle(-1); + this.closer = closer; + } + + @Override + protected void finalize() throws Throwable { + close(); + } + + /** + * Acquire an instance of the actual {@link Handle}. The caller must + * {@link Handle#close() close} the resulting handle when done. + * @return the handle + */ + synchronized Handle acquire() { + this.referenceCount++; + return (this.status != Status.OPEN) ? this.closedHandler : this.openHandle; + } + + private synchronized void release() { + this.referenceCount--; + if (this.referenceCount == 0 && this.status == Status.CLOSE_PENDING) { + this.closer.accept(this.openHandle.value); + this.status = Status.CLOSED; + } + } + + /** + * Close the underlying file when all handles have been released. + */ + synchronized void close() { + if (this.status == Status.OPEN) { + if (this.referenceCount == 0) { + this.closer.accept(this.openHandle.value); + this.status = Status.CLOSED; + } else { + this.status = Status.CLOSE_PENDING; + } + } + } + + /** + * The status of the file descriptor. + */ + private enum Status { + + OPEN, CLOSE_PENDING, CLOSED + + } + + /** + * Provides access to the actual file descriptor handle. + */ + final class Handle implements Closeable { + + private final int value; + + private Handle(int value) { + this.value = value; + } + + boolean isClosed() { + return this.value == -1; + } + + int intValue() { + return this.value; + } + + @Override + public void close() throws IOException { + if (!isClosed()) { + release(); + } + } + + } + +} diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/LinuxDomainSocket.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/LinuxDomainSocket.java new file mode 100644 index 000000000..e1467858a --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/LinuxDomainSocket.java @@ -0,0 +1,80 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.dockerjava.transport; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; + +import com.sun.jna.LastErrorException; +import com.sun.jna.Native; +import com.sun.jna.Platform; +import com.sun.jna.Structure; + +/** + * {@link DomainSocket} implementation for Linux based platforms. + * + * @author Phillip Webb + */ +class LinuxDomainSocket extends DomainSocket { + + static { + Native.register(Platform.C_LIBRARY_NAME); + } + + LinuxDomainSocket(String path) throws IOException { + super(path); + } + + private static final int MAX_PATH_LENGTH = 108; + + @Override + protected void connect(String path, int handle) { + SockaddrUn address = new SockaddrUn(AF_LOCAL, path.getBytes(StandardCharsets.UTF_8)); + connect(handle, address, address.size()); + } + + private native int connect(int fd, SockaddrUn address, int addressLen) throws LastErrorException; + + /** + * Native {@code sockaddr_un} structure as defined in {@code sys/un.h}. + */ + public static class SockaddrUn extends Structure implements Structure.ByReference { + + public short sunFamily; + + public byte[] sunPath = new byte[MAX_PATH_LENGTH]; + + private SockaddrUn(byte sunFamily, byte[] path) { + if (path.length > MAX_PATH_LENGTH) { + throw new IllegalArgumentException("Path cannot exceed " + MAX_PATH_LENGTH + " bytes"); + } + System.arraycopy(path, 0, this.sunPath, 0, path.length); + this.sunPath[path.length] = 0; + this.sunFamily = sunFamily; + allocateMemory(); + } + + @Override + protected List getFieldOrder() { + return Arrays.asList("sunFamily", "sunPath"); + } + + } + +} diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/NamedPipeSocket.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/NamedPipeSocket.java new file mode 100644 index 000000000..e4aa315eb --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/NamedPipeSocket.java @@ -0,0 +1,158 @@ +package com.github.dockerjava.transport; + +import com.sun.jna.Native; +import com.sun.jna.win32.StdCallLibrary; +import com.sun.jna.win32.W32APIOptions; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousByteChannel; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.channels.Channels; +import java.nio.channels.CompletionHandler; +import java.nio.file.FileSystemException; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +public class NamedPipeSocket extends Socket { + + private final String socketFileName; + + private AsynchronousFileByteChannel channel; + + public NamedPipeSocket(String socketFileName) { + this.socketFileName = socketFileName; + } + + @Override + public void close() throws IOException { + if (channel != null) { + channel.close(); + } + } + + @Override + public void connect(SocketAddress endpoint) throws IOException { + connect(endpoint, 0); + } + + @Override + public void connect(SocketAddress endpoint, int timeout) throws IOException { + long startedAt = System.currentTimeMillis(); + timeout = Math.max(timeout, 10_000); + while (true) { + try { + channel = new AsynchronousFileByteChannel( + AsynchronousFileChannel.open( + Paths.get(socketFileName), + StandardOpenOption.READ, + StandardOpenOption.WRITE + ) + ); + break; + } catch (FileSystemException e) { + if (System.currentTimeMillis() - startedAt >= timeout) { + throw new RuntimeException(e); + } else { + Kernel32.INSTANCE.WaitNamedPipe(socketFileName, 100); + } + } + } + } + + @Override + public InputStream getInputStream() { + return Channels.newInputStream(channel); + } + + @Override + public OutputStream getOutputStream() { + return Channels.newOutputStream(channel); + } + + interface Kernel32 extends StdCallLibrary { + + Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class, W32APIOptions.DEFAULT_OPTIONS); + + @SuppressWarnings("checkstyle:methodname") + boolean WaitNamedPipe(String lpNamedPipeName, int nTimeOut); + } + + private static class AsynchronousFileByteChannel implements AsynchronousByteChannel { + private final AsynchronousFileChannel fileChannel; + + AsynchronousFileByteChannel(AsynchronousFileChannel fileChannel) { + this.fileChannel = fileChannel; + } + + @Override + public void read(ByteBuffer dst, A attachment, CompletionHandler handler) { + fileChannel.read(dst, 0, attachment, new CompletionHandler() { + @Override + public void completed(Integer read, A attachment) { + handler.completed(read > 0 ? read : -1, attachment); + } + + @Override + public void failed(Throwable exc, A attachment) { + if (exc instanceof AsynchronousCloseException) { + handler.completed(-1, attachment); + return; + } + handler.failed(exc, attachment); + } + }); + } + + @Override + public Future read(ByteBuffer dst) { + CompletableFutureHandler future = new CompletableFutureHandler(); + fileChannel.read(dst, 0, null, future); + return future; + } + + @Override + public void write(ByteBuffer src, A attachment, CompletionHandler handler) { + fileChannel.write(src, 0, attachment, handler); + } + + @Override + public Future write(ByteBuffer src) { + return fileChannel.write(src, 0); + } + + @Override + public void close() throws IOException { + fileChannel.close(); + } + + @Override + public boolean isOpen() { + return fileChannel.isOpen(); + } + + private static class CompletableFutureHandler extends CompletableFuture implements CompletionHandler { + + @Override + public void completed(Integer read, Object attachment) { + complete(read > 0 ? read : -1); + } + + @Override + public void failed(Throwable exc, Object attachment) { + if (exc instanceof AsynchronousCloseException) { + complete(-1); + return; + } + completeExceptionally(exc); + } + } + } +} diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/SSLConfig.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/SSLConfig.java new file mode 100644 index 000000000..a2840cb5f --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/SSLConfig.java @@ -0,0 +1,21 @@ +package com.github.dockerjava.transport; + +import javax.net.ssl.SSLContext; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; + +/** + * Get an SSL Config. Allows for various different implementations. + */ +public interface SSLConfig { + + /** + * Get the SSL Context, from wherever it comes (file, keystore). + * + * @return an SSL context. + */ + SSLContext getSSLContext() throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, + KeyStoreException; +} diff --git a/docker-java-transport/src/main/java/com/github/dockerjava/transport/UnixSocket.java b/docker-java-transport/src/main/java/com/github/dockerjava/transport/UnixSocket.java new file mode 100644 index 000000000..eb7a49b51 --- /dev/null +++ b/docker-java-transport/src/main/java/com/github/dockerjava/transport/UnixSocket.java @@ -0,0 +1,111 @@ +package com.github.dockerjava.transport; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; + +public class UnixSocket extends AbstractSocket { + + /** + * Return a new {@link Socket} for the given path. Will use JDK's {@link java.net.UnixDomainSocketAddress} + * if available and fallback to {@link DomainSocket} otherwise. + * + * @param path the path to the domain socket + * @return a {@link Socket} instance + * @throws IOException if the socket cannot be opened + */ + public static Socket get(String path) throws IOException { + try { + return new UnixSocket(path); + } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | + IllegalAccessException e) { + //noinspection deprecation + return DomainSocket.get(path); + } + } + + private final SocketAddress socketAddress; + + private final SocketChannel socketChannel; + + private UnixSocket(String path) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + IllegalAccessException, IOException { + Class unixDomainSocketAddress = Class.forName("java.net.UnixDomainSocketAddress"); + this.socketAddress = + (SocketAddress) unixDomainSocketAddress.getMethod("of", String.class) + .invoke(null, path); + this.socketChannel = SocketChannel.open(this.socketAddress); + } + + @Override + public InputStream getInputStream() throws IOException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + if (!isConnected()) { + throw new SocketException("Socket is not connected"); + } + if (isInputShutdown()) { + throw new SocketException("Socket input is shutdown"); + } + + return Channels.newInputStream(socketChannel); + } + + @Override + public OutputStream getOutputStream() throws IOException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } + if (!isConnected()) { + throw new SocketException("Socket is not connected"); + } + if (isOutputShutdown()) { + throw new SocketException("Socket output is shutdown"); + } + + return Channels.newOutputStream(new WrappedWritableByteChannel()); + } + + @Override + public SocketAddress getLocalSocketAddress() { + return socketAddress; + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return socketAddress; + } + + @Override + public void close() throws IOException { + super.close(); + this.socketChannel.close(); + } + + private class WrappedWritableByteChannel implements WritableByteChannel { + + @Override + public int write(ByteBuffer src) throws IOException { + return UnixSocket.this.socketChannel.write(src); + } + + @Override + public boolean isOpen() { + return UnixSocket.this.socketChannel.isOpen(); + } + + @Override + public void close() throws IOException { + UnixSocket.this.socketChannel.close(); + } + } +} diff --git a/docker-java/pom.xml b/docker-java/pom.xml index 6952d7751..3cfd7f255 100644 --- a/docker-java/pom.xml +++ b/docker-java/pom.xml @@ -4,7 +4,7 @@ com.github.docker-java docker-java-parent - 3.2.2-SNAPSHOT + 0-SNAPSHOT ../pom.xml @@ -15,6 +15,10 @@ https://github.com/docker-java/docker-java Java API Client for Docker + + com.github.dockerjava + + ${project.groupId} @@ -111,6 +115,35 @@ 4.13 test + + org.awaitility + awaitility + 4.3.0 + test + + + + com.fasterxml.jackson.core + jackson-databind + + 2.20.1 + test + + + + com.fasterxml.jackson.core + jackson-annotations + + 2.20 + test + + + + org.projectlombok + lombok + 1.18.38 + provided + @@ -142,7 +175,6 @@ false 5 com.github.dockerjava.junit.category.Integration - com.github.dockerjava.junit.category.AuthIntegration,com.github.dockerjava.junit.category.SwarmModeIntegration diff --git a/docker-java/src/main/java/com/github/dockerjava/core/DockerClientBuilder.java b/docker-java/src/main/java/com/github/dockerjava/core/DockerClientBuilder.java index 991bdbb86..8100f285e 100644 --- a/docker-java/src/main/java/com/github/dockerjava/core/DockerClientBuilder.java +++ b/docker-java/src/main/java/com/github/dockerjava/core/DockerClientBuilder.java @@ -2,51 +2,109 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.DockerCmdExecFactory; -import com.github.dockerjava.core.DefaultDockerClientConfig.Builder; import com.github.dockerjava.jaxrs.JerseyDockerCmdExecFactory; +import com.github.dockerjava.jaxrs.JerseyDockerHttpClient; +import com.github.dockerjava.transport.DockerHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DockerClientBuilder { - private DockerClientImpl dockerClient = null; + private final DockerClientConfig dockerClientConfig; private DockerCmdExecFactory dockerCmdExecFactory = null; - private DockerClientBuilder(DockerClientImpl dockerClient) { - this.dockerClient = dockerClient; + private DockerHttpClient dockerHttpClient = null; + + private DockerClientBuilder(DockerClientConfig dockerClientConfig) { + this.dockerClientConfig = dockerClientConfig; } public static DockerClientBuilder getInstance() { - return new DockerClientBuilder(DockerClientImpl.getInstance()); + return new DockerClientBuilder( + DefaultDockerClientConfig.createDefaultConfigBuilder().build() + ); } - public static DockerClientBuilder getInstance(Builder dockerClientConfigBuilder) { + /** + * + * @deprecated use {@link #getInstance(DockerClientConfig)} + */ + @Deprecated + public static DockerClientBuilder getInstance(DefaultDockerClientConfig.Builder dockerClientConfigBuilder) { return getInstance(dockerClientConfigBuilder.build()); } public static DockerClientBuilder getInstance(DockerClientConfig dockerClientConfig) { - return new DockerClientBuilder(DockerClientImpl.getInstance(dockerClientConfig)); + return new DockerClientBuilder(dockerClientConfig); } + /** + * + * @deprecated use {@link DefaultDockerClientConfig.Builder#withDockerHost(String)} + */ + @Deprecated public static DockerClientBuilder getInstance(String serverUrl) { - return new DockerClientBuilder(DockerClientImpl.getInstance(serverUrl)); + return new DockerClientBuilder( + DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerHost(serverUrl) + .build() + ); } + /** + * + * @deprecated no replacement, use one of {@link DockerHttpClient} + */ + @Deprecated public static DockerCmdExecFactory getDefaultDockerCmdExecFactory() { return new JerseyDockerCmdExecFactory(); } + /** + * Note that this method overrides {@link DockerHttpClient} if it was previously set + * + * @deprecated use {@link #withDockerHttpClient(DockerHttpClient)} + */ + @Deprecated public DockerClientBuilder withDockerCmdExecFactory(DockerCmdExecFactory dockerCmdExecFactory) { this.dockerCmdExecFactory = dockerCmdExecFactory; + this.dockerHttpClient = null; + return this; + } + + /** + * Note that this method overrides {@link DockerCmdExecFactory} if it was previously set + */ + public DockerClientBuilder withDockerHttpClient(DockerHttpClient dockerHttpClient) { + this.dockerCmdExecFactory = null; + this.dockerHttpClient = dockerHttpClient; return this; } public DockerClient build() { - if (dockerCmdExecFactory != null) { - dockerClient.withDockerCmdExecFactory(dockerCmdExecFactory); + if (dockerHttpClient != null) { + return DockerClientImpl.getInstance( + dockerClientConfig, + dockerHttpClient + ); + } else if (dockerCmdExecFactory != null) { + return DockerClientImpl.getInstance(dockerClientConfig) + .withDockerCmdExecFactory(dockerCmdExecFactory); } else { - dockerClient.withDockerCmdExecFactory(getDefaultDockerCmdExecFactory()); - } + Logger log = LoggerFactory.getLogger(DockerClientBuilder.class); + log.warn( + "'dockerHttpClient' should be set. " + + "Falling back to Jersey, will be an error in future releases." + ); - return dockerClient; + return DockerClientImpl.getInstance( + dockerClientConfig, + new JerseyDockerHttpClient.Builder() + .dockerHost(dockerClientConfig.getDockerHost()) + .sslConfig(dockerClientConfig.getSSLConfig()) + .build() + ); + } } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/ModelsSerializableTest.java b/docker-java/src/test/java/com/github/dockerjava/api/ModelsSerializableTest.java index 183121a3d..1c7c1de6c 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/ModelsSerializableTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/ModelsSerializableTest.java @@ -2,12 +2,13 @@ import com.github.dockerjava.api.model.Binds; import com.github.dockerjava.api.model.BuildResponseItem; +import com.github.dockerjava.api.model.DockerObject; +import com.github.dockerjava.api.model.DockerObjectAccessor; import com.github.dockerjava.api.model.PullResponseItem; import com.github.dockerjava.api.model.PushResponseItem; import com.github.dockerjava.api.model.ResponseItem; import com.google.common.reflect.ClassPath.ClassInfo; -import org.apache.commons.lang.reflect.FieldUtils; -import org.hamcrest.MatcherAssert; +import org.apache.commons.lang3.reflect.FieldUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,6 +25,8 @@ import static org.hamcrest.object.IsCompatibleType.typeCompatibleWith; /** + * TODO use ArchUnit + * * @author Kanstantsin Shautsou */ public class ModelsSerializableTest { @@ -47,7 +50,11 @@ public void allModelsSerializable() throws IOException, NoSuchFieldException, Il continue; } - if (classInfo.getName().endsWith("Test")) { + if ( + classInfo.getName().endsWith("Test") + || DockerObject.class.getName().equals(classInfo.getName()) + || DockerObjectAccessor.class.getName().equals(classInfo.getName()) + ) { continue; } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/command/CommandJSONSamples.java b/docker-java/src/test/java/com/github/dockerjava/api/command/CommandJSONSamples.java index 0cf5141d4..23ef4b7f2 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/command/CommandJSONSamples.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/command/CommandJSONSamples.java @@ -28,7 +28,9 @@ public enum CommandJSONSamples implements JSONResourceRef { inspectContainerResponse_full_1_21, inspectContainerResponse_full_1_26a, inspectContainerResponse_full_1_26b, - inspectContainerResponse_empty; + inspectContainerResponse_empty, + updateContainerResponse_empty, + updateContainerResponse_warnings; @Override public String getFileName() { diff --git a/docker-java/src/test/java/com/github/dockerjava/api/command/InspectContainerResponseTest.java b/docker-java/src/test/java/com/github/dockerjava/api/command/InspectContainerResponseTest.java index 062088316..12105e8a1 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/command/InspectContainerResponseTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/command/InspectContainerResponseTest.java @@ -56,11 +56,11 @@ public void roundTrip_full() throws IOException { final InspectContainerResponse response = responses[0]; // Check volumes: https://github.com/docker-java/docker-java/issues/211 - assertEquals(response.getVolumes().length, 2); - assertEquals(response.getVolumesRW().length, 2); - assertEquals(response.getVolumes()[1].getContainerPath(), "/bar/foo/myvol2"); - assertEquals(response.getVolumes()[1].getHostPath(), "/path2"); - assertEquals(response.getVolumesRW()[1].getVolume().getPath(), "/bar/foo/myvol2"); + assertEquals(2, response.getVolumes().length); + assertEquals(2, response.getVolumesRW().length); + assertEquals("/bar/foo/myvol2" ,response.getVolumes()[1].getContainerPath()); + assertEquals("/path2", response.getVolumes()[1].getHostPath()); + assertEquals("/bar/foo/myvol2", response.getVolumesRW()[1].getVolume().getPath()); assertFalse(response.getVolumesRW()[1].getAccessMode().toBoolean()); assertTrue(response.getVolumesRW()[0].getAccessMode().toBoolean()); assertThat(response.getLogPath(), is("/mnt/sda1/var/lib/docker/containers/469e5edd8d5b33e3c905a7ffc97360ec6ee211d6782815fbcd144568045819e1/469e5edd8d5b33e3c905a7ffc97360ec6ee211d6782815fbcd144568045819e1-json.log")); @@ -76,11 +76,11 @@ public void roundTrip_full_healthcheck() throws IOException { type ); - assertEquals(response.getState().getHealth().getStatus(), "healthy"); - assertEquals(response.getState().getHealth().getFailingStreak(), new Integer(0)); - assertEquals(response.getState().getHealth().getLog().size(), 2); - assertEquals(response.getState().getHealth().getLog().get(0).getOutput(), "Hello"); - assertEquals(response.getState().getHealth().getLog().get(1).getOutput(), "World"); + assertEquals("healthy", response.getState().getHealth().getStatus()); + assertEquals(new Integer(0), response.getState().getHealth().getFailingStreak()); + assertEquals(2, response.getState().getHealth().getLog().size()); + assertEquals("Hello", response.getState().getHealth().getLog().get(0).getOutput()); + assertEquals("World", response.getState().getHealth().getLog().get(1).getOutput()); } @Test @@ -108,11 +108,11 @@ public void roundTrip_1_26a_full() throws IOException { final InspectContainerResponse response = responses[0]; final List mounts = response.getMounts(); - assertEquals(mounts.size(), 1); + assertEquals(1, mounts.size()); final InspectContainerResponse.Mount mount = mounts.get(0); final Volume volume = mount.getDestination(); - assertEquals(volume.getPath(), "/var/lib/postgresql/data"); + assertEquals("/var/lib/postgresql/data", volume.getPath()); } @Test @@ -124,11 +124,11 @@ public void roundTrip_1_26b_full() throws IOException { final InspectContainerResponse response = responses[0]; final List mounts = response.getMounts(); - assertEquals(mounts.size(), 1); + assertEquals(1, mounts.size()); final InspectContainerResponse.Mount mount = mounts.get(0); final Volume volume = mount.getDestination(); - assertEquals(volume.getPath(), "/srv/test"); + assertEquals("/srv/test", volume.getPath()); } @Test diff --git a/docker-java/src/test/java/com/github/dockerjava/api/command/UpdateContainerResponseTest.java b/docker-java/src/test/java/com/github/dockerjava/api/command/UpdateContainerResponseTest.java new file mode 100644 index 000000000..300a5c324 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/api/command/UpdateContainerResponseTest.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.api.command; + +import com.github.dockerjava.api.model.UpdateContainerResponse; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +import static com.github.dockerjava.test.serdes.JSONTestHelper.testRoundTrip; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class UpdateContainerResponseTest { + @Test + public void roundTrip_empty() throws IOException { + UpdateContainerResponse response = testRoundTrip(CommandJSONSamples.updateContainerResponse_empty, UpdateContainerResponse.class); + assertNull(response.getWarnings()); + } + + @Test + public void roundTrip_warnings() throws IOException { + UpdateContainerResponse response = testRoundTrip(CommandJSONSamples.updateContainerResponse_warnings, + UpdateContainerResponse.class); + + List warnings = response.getWarnings(); + assertNotNull(warnings); + assertEquals(1, warnings.size()); + + final String warning = warnings.get(0); + assertEquals("Published ports are discarded when using host network mode", warning); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/AccessModeTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/AccessModeTest.java index 9d08843dc..d5ff7044a 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/AccessModeTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/AccessModeTest.java @@ -15,17 +15,17 @@ public class AccessModeTest { @Test public void defaultAccessMode() { - assertEquals(AccessMode.DEFAULT, rw); + assertEquals(rw, AccessMode.DEFAULT); } @Test public void stringify() { - assertEquals(AccessMode.rw.toString(), "rw"); + assertEquals("rw", AccessMode.rw.toString()); } @Test public void fromString() { - assertEquals(AccessMode.valueOf("rw"), rw); + assertEquals(rw, AccessMode.valueOf("rw")); } @Test diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/AuthConfigTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/AuthConfigTest.java index f77ac56c9..ae3e4a91b 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/AuthConfigTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/AuthConfigTest.java @@ -8,17 +8,16 @@ import java.io.IOException; import static com.github.dockerjava.test.serdes.JSONSamples.testRoundTrip; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertEquals; public class AuthConfigTest { @Test - public void defaultServerAddress() throws Exception { + public void defaultServerAddress() { assertEquals(new AuthConfig().getRegistryAddress(), "https://index.docker.io/v1/"); } @@ -89,4 +88,23 @@ public void shouldNotFailWithStackOrchestratorInConfig() throws IOException { assertThat(authConfig.getStackOrchestrator(), is("kubernetes")); } + @Test + public void toStringDoesNotContainSensitiveStrings() { + AuthConfig authConfig = new AuthConfig() + .withAuth("authValue") + .withEmail("emailValue") + .withPassword("passwordValue") + .withIdentityToken("identityTokenValue") + .withRegistrytoken("registryTokenValue") + .withRegistryAddress("registryAddressValue"); + String toStringValue = authConfig.toString(); + + assertThat(toStringValue, not(containsString("authValue"))); + assertThat(toStringValue, not(containsString("passwordValue"))); + assertThat(toStringValue, not(containsString("identityTokenValue"))); + assertThat(toStringValue, not(containsString("registryTokenValue"))); + + assertThat(toStringValue, containsString("emailValue")); + assertThat(toStringValue, containsString("registryAddressValue")); + } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/BindTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/BindTest.java index 3343bf6bd..d31a66dde 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/BindTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/BindTest.java @@ -26,6 +26,113 @@ public void parseUsingDefaultAccessMode() { assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); } + @Test + public void parseReadWriteWindows() { + Bind bind = Bind.parse("C:\\host:/container:rw"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); + } + + @Test + public void parseReadWriteNoCopyWindows() { + Bind bind = Bind.parse("C:\\host:/container:rw,nocopy"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), is(true)); + assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); + } + + @Test + public void parseReadWriteSharedWindows() { + Bind bind = Bind.parse("C:\\host:/container:rw,shared"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.SHARED)); + } + + @Test + public void parseReadWriteSlaveWindows() { + Bind bind = Bind.parse("C:\\host:/container:rw,slave"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.SLAVE)); + } + + @Test + public void parseReadWritePrivateWindows() { + Bind bind = Bind.parse("C:\\host:/container:rw,private"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.PRIVATE)); + } + + @Test + public void parseReadOnlyWindows() { + Bind bind = Bind.parse("C:\\host:/container:ro"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(ro)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); + } + + @Test + public void parseSELOnlyWindows() { + Bind bind = Bind.parse("C:\\host:/container:Z"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(AccessMode.DEFAULT)); + assertThat(bind.getSecMode(), is(SELContext.single)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); + + bind = Bind.parse("C:\\host:/container:z"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(AccessMode.DEFAULT)); + assertThat(bind.getSecMode(), is(SELContext.shared)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); + } + + @Test + public void parseReadWriteSELWindows() { + Bind bind = Bind.parse("C:\\host:/container:rw,Z"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.single)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); + } + + @Test + public void parseReadOnlySELWindows() { + Bind bind = Bind.parse("C:\\host:/container:ro,z"); + assertThat(bind.getPath(), is("C:\\host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(ro)); + assertThat(bind.getSecMode(), is(SELContext.shared)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.DEFAULT_MODE)); + } + @Test public void parseReadWrite() { Bind bind = Bind.parse("/host:/container:rw"); @@ -59,6 +166,17 @@ public void parseReadWriteShared() { assertThat(bind.getPropagationMode(), is(PropagationMode.SHARED)); } + @Test + public void parseReadWriteRshared() { + Bind bind = Bind.parse("/host:/container:rw,rshared"); + assertThat(bind.getPath(), is("/host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.RSHARED)); + } + @Test public void parseReadWriteSlave() { Bind bind = Bind.parse("/host:/container:rw,slave"); @@ -70,6 +188,17 @@ public void parseReadWriteSlave() { assertThat(bind.getPropagationMode(), is(PropagationMode.SLAVE)); } + @Test + public void parseReadWriteRslave() { + Bind bind = Bind.parse("/host:/container:rw,rslave"); + assertThat(bind.getPath(), is("/host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.RSLAVE)); + } + @Test public void parseReadWritePrivate() { Bind bind = Bind.parse("/host:/container:rw,private"); @@ -81,6 +210,17 @@ public void parseReadWritePrivate() { assertThat(bind.getPropagationMode(), is(PropagationMode.PRIVATE)); } + @Test + public void parseReadWriteRprivate() { + Bind bind = Bind.parse("/host:/container:rw,rprivate"); + assertThat(bind.getPath(), is("/host")); + assertThat(bind.getVolume().getPath(), is("/container")); + assertThat(bind.getAccessMode(), is(rw)); + assertThat(bind.getSecMode(), is(SELContext.none)); + assertThat(bind.getNoCopy(), nullValue()); + assertThat(bind.getPropagationMode(), is(PropagationMode.RPRIVATE)); + } + @Test public void parseReadOnly() { Bind bind = Bind.parse("/host:/container:ro"); @@ -177,16 +317,31 @@ public void toStringReadWriteShared() { assertThat(Bind.parse("/host:/container:rw,shared").toString(), is("/host:/container:rw,shared")); } + @Test + public void toStringReadWriteRshared() { + assertThat(Bind.parse("/host:/container:rw,rshared").toString(), is("/host:/container:rw,rshared")); + } + @Test public void toStringReadWriteSlave() { assertThat(Bind.parse("/host:/container:rw,slave").toString(), is("/host:/container:rw,slave")); } + @Test + public void toStringReadWriteRslave() { + assertThat(Bind.parse("/host:/container:rw,rslave").toString(), is("/host:/container:rw,rslave")); + } + @Test public void toStringReadWritePrivate() { assertThat(Bind.parse("/host:/container:rw,private").toString(), is("/host:/container:rw,private")); } + @Test + public void toStringReadWriteRprivate() { + assertThat(Bind.parse("/host:/container:rw,rprivate").toString(), is("/host:/container:rw,rprivate")); + } + @Test public void toStringDefaultAccessMode() { assertThat(Bind.parse("/host:/container").toString(), is("/host:/container:rw")); diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/CapabilityTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/CapabilityTest.java index e76d2437c..b0652d945 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/CapabilityTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/CapabilityTest.java @@ -11,13 +11,16 @@ public class CapabilityTest { @Test public void serializeCapability() throws Exception { String json = JSONTestHelper.getMapper().writeValueAsString(Capability.ALL); - assertEquals(json, "\"ALL\""); + assertEquals("\"ALL\"", json); } @Test public void deserializeCapability() throws Exception { Capability capability = JSONTestHelper.getMapper().readValue("\"ALL\"", Capability.class); - assertEquals(capability, Capability.ALL); + assertEquals(Capability.ALL, capability); + + Capability compatibleCapability = JSONTestHelper.getMapper().readValue("\"CAP_ALL\"", Capability.class); + assertEquals(Capability.ALL, compatibleCapability); } @Test(expected = JsonMappingException.class) diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/DeviceTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/DeviceTest.java index 18c6fbbc8..9d191fe52 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/DeviceTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/DeviceTest.java @@ -54,7 +54,7 @@ public class DeviceTest { }}; @Test - public void testParse() throws Exception { + public void testParse() { assertThat(Device.parse("/dev/sda:/dev/xvdc:r"), equalTo(new Device("r", "/dev/xvdc", "/dev/sda"))); diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortTest.java index 20999a92f..fce761380 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortTest.java @@ -16,13 +16,13 @@ public class ExposedPortTest { @Test public void parsePortAndProtocol() { ExposedPort exposedPort = ExposedPort.parse("80/tcp"); - assertEquals(exposedPort, new ExposedPort(80, TCP)); + assertEquals(new ExposedPort(80, TCP), exposedPort); } @Test public void parsePortOnly() { ExposedPort exposedPort = ExposedPort.parse("80"); - assertEquals(exposedPort, new ExposedPort(80, DEFAULT)); + assertEquals(new ExposedPort(80, DEFAULT), exposedPort); } @Test @@ -43,7 +43,7 @@ public void parseNull() { @Test public void stringify() { - assertEquals(ExposedPort.parse("80/tcp").toString(), "80/tcp"); + assertEquals("80/tcp", ExposedPort.parse("80/tcp").toString()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortsTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortsTest.java index c64d5ace2..f46dddc68 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortsTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/ExposedPortsTest.java @@ -6,10 +6,13 @@ import org.junit.Test; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.aMapWithSize; import static org.hamcrest.Matchers.arrayContainingInAnyOrder; +import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.notNullValue; public class ExposedPortsTest { @@ -46,4 +49,19 @@ public void usesFromJson() throws Exception { new ExposedPort(3868, InternetProtocol.SCTP) )); } + + @Test + public void usesFromJsonWithDuplicate() { + ExposedPorts ports = new ExposedPorts( + new ExposedPort(80, InternetProtocol.UDP), + new ExposedPort(80), + new ExposedPort(80) + ); + + assertThat(ports, notNullValue()); + assertThat(ports.getExposedPorts(), arrayWithSize(3)); + + Map map = ports.toPrimitive(); + assertThat(map, aMapWithSize(2)); + } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/HostConfigTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/HostConfigTest.java new file mode 100644 index 000000000..5e13103dd --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/HostConfigTest.java @@ -0,0 +1,15 @@ +package com.github.dockerjava.api.model; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class HostConfigTest { + + @Test + public void testNewObjectsEqual() { + assertThat(HostConfig.newHostConfig(), + equalTo(HostConfig.newHostConfig())); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/IdentifierTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/IdentifierTest.java index c39706e51..3b8efa2c5 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/IdentifierTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/IdentifierTest.java @@ -17,26 +17,26 @@ public void testFromCompoundString() throws Exception { Identifier i3A = Identifier.fromCompoundString("10.0.0.1:123/jim:latest"); assertTrue(!i1.tag.isPresent()); - assertEquals(i1.repository.name, "10.0.0.1/jim"); + assertEquals("10.0.0.1/jim", i1.repository.name); assertTrue(i2.tag.isPresent()); - assertEquals(i2.tag.get(), "123"); - assertEquals(i2.repository.name, "10.0.0.1/jim"); + assertEquals("123", i2.tag.get()); + assertEquals("10.0.0.1/jim", i2.repository.name); assertTrue(i3.tag.isPresent()); - assertEquals(i3.tag.get(), "124"); - assertEquals(i3.repository.name, "10.0.0.1:123/jim"); - assertEquals(i3.repository.getURL().getPort(), 123); - assertEquals(i3A.tag.get(), "latest"); + assertEquals("124", i3.tag.get()); + assertEquals("10.0.0.1:123/jim", i3.repository.name); + assertEquals(123, i3.repository.getURL().getPort()); + assertEquals("latest", i3A.tag.get()); Identifier i4 = Identifier.fromCompoundString("centos:latest"); assertTrue(i4.tag.isPresent()); - assertEquals(i4.tag.get(), "latest"); + assertEquals("latest", i4.tag.get()); Identifier i5 = Identifier.fromCompoundString("busybox"); assertTrue(!i5.tag.isPresent()); Identifier i6 = Identifier.fromCompoundString("10.0.0.1:5000/my-test-image:1234"); - assertEquals(i6.repository.getPath(), "my-test-image"); + assertEquals("my-test-image", i6.repository.getPath()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/ImageHistoryTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/ImageHistoryTest.java new file mode 100644 index 000000000..8f18facf0 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/ImageHistoryTest.java @@ -0,0 +1,90 @@ +package com.github.dockerjava.api.model; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.github.dockerjava.test.serdes.JSONSamples; +import com.github.dockerjava.test.serdes.JSONTestHelper; +import org.junit.Test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_22; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +public class ImageHistoryTest { + + @Test + public void serderJson() throws IOException { + final List history = JSONTestHelper.getMapper().readValue( + JSONSamples.getSampleContent(VERSION_1_22, "images/history/history.json"), + new TypeReference>() { + } + ); + + assertThat(history, notNullValue()); + assertThat(history, hasSize(3)); + + final ImageHistory first = history.get(0); + assertThat(first.getId(), is("3db9c44f45209632d6050b35958829c3a2aa256d81b9a7be45b362ff85c54710")); + assertThat(first.getCreated(), is(1398108230L)); + assertThat(first.getCreatedBy(), is("/bin/sh -c #(nop) ADD file:eb15dbd63394e063b805a3c32ca7bf0266ef64676d5a6fab4801f2e81e2a5148 in /")); + assertThat(first.getTags(), hasSize(2)); + assertThat(first.getTags(), contains("ubuntu:lucid", "ubuntu:10.04")); + assertThat(first.getSize(), is(182964289L)); + assertThat(first.getComment(), is("")); + + final ImageHistory second = history.get(1); + assertThat(second.getId(), is("6cfa4d1f33fb861d4d114f43b25abd0ac737509268065cdfd69d544a59c85ab8")); + assertThat(second.getCreated(), is(1398108222L)); + assertThat(second.getTags(), empty()); + assertThat(second.getSize(), is(0L)); + + final ImageHistory third = history.get(2); + assertThat(third.getId(), is("511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158")); + assertThat(third.getCreated(), is(1371157430L)); + assertThat(third.getCreatedBy(), is("")); + assertThat(third.getTags(), contains("scratch12:latest", "scratch:latest")); + assertThat(third.getSize(), is(0L)); + assertThat(third.getComment(), is("Imported from -")); + + // Test round-trip serialization + final String serialized = JSONTestHelper.getMapper().writeValueAsString(history); + final List deserialized = JSONTestHelper.getMapper().readValue( + serialized, + new TypeReference>() { + } + ); + assertThat(deserialized, hasSize(3)); + assertThat(deserialized.get(0).getId(), is(first.getId())); + assertThat(deserialized.get(0).getCreated(), is(first.getCreated())); + assertThat(deserialized.get(0).getCreatedBy(), is(first.getCreatedBy())); + assertThat(deserialized.get(0).getTags(), is(first.getTags())); + assertThat(deserialized.get(0).getSize(), is(first.getSize())); + assertThat(deserialized.get(0).getComment(), is(first.getComment())); + } + + @Test + public void builderPattern() { + final ImageHistory history = new ImageHistory() + .withId("abc123") + .withCreated(1234567890L) + .withCreatedBy("/bin/sh -c echo hello") + .withTags(Arrays.asList("myimage:latest")) + .withSize(1024L) + .withComment("test comment"); + + assertThat(history.getId(), is("abc123")); + assertThat(history.getCreated(), is(1234567890L)); + assertThat(history.getCreatedBy(), is("/bin/sh -c echo hello")); + assertThat(history.getTags(), contains("myimage:latest")); + assertThat(history.getSize(), is(1024L)); + assertThat(history.getComment(), is("test comment")); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/InternetProtocolTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/InternetProtocolTest.java index 5efb8d2c3..0421e1411 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/InternetProtocolTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/InternetProtocolTest.java @@ -13,22 +13,22 @@ public class InternetProtocolTest { @Test public void defaultProtocol() { - assertEquals(InternetProtocol.DEFAULT, TCP); + assertEquals(TCP, InternetProtocol.DEFAULT); } @Test public void stringify() { - assertEquals(TCP.toString(), "tcp"); + assertEquals("tcp", TCP.toString()); } @Test public void parseUpperCase() { - assertEquals(InternetProtocol.parse("TCP"), TCP); + assertEquals(TCP, InternetProtocol.parse("TCP")); } @Test public void parseLowerCase() { - assertEquals(InternetProtocol.parse("tcp"), TCP); + assertEquals(TCP, InternetProtocol.parse("tcp")); } @Test diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/LinkTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/LinkTest.java index 18363a9ee..b780eb22f 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/LinkTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/LinkTest.java @@ -14,15 +14,15 @@ public class LinkTest { @Test public void parse() { Link link = Link.parse("name:alias"); - assertEquals(link.getName(), "name"); - assertEquals(link.getAlias(), "alias"); + assertEquals("name", link.getName()); + assertEquals("alias", link.getAlias()); } @Test public void parseWithContainerNames() { Link link = Link.parse("/name:/conatiner/alias"); - assertEquals(link.getName(), "name"); - assertEquals(link.getAlias(), "alias"); + assertEquals("name", link.getName()); + assertEquals("alias", link.getAlias()); } @Test @@ -43,7 +43,7 @@ public void parseNull() { @Test public void stringify() { - assertEquals(Link.parse("name:alias").toString(), "name:alias"); + assertEquals("name:alias", Link.parse("name:alias").toString()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/PortBindingTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/PortBindingTest.java index 3849a6094..9190cfda4 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/PortBindingTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/PortBindingTest.java @@ -23,27 +23,27 @@ public void fullDefinition() { @Test public void noProtocol() { - assertEquals(PortBinding.parse("127.0.0.1:80:8080"), new PortBinding(Binding.bindIpAndPort("127.0.0.1", 80), TCP_8080)); + assertEquals(new PortBinding(Binding.bindIpAndPort("127.0.0.1", 80), TCP_8080), PortBinding.parse("127.0.0.1:80:8080")); } @Test public void noHostIp() { - assertEquals(PortBinding.parse("80:8080/tcp"), new PortBinding(Binding.bindPort(80), TCP_8080)); + assertEquals(new PortBinding(Binding.bindPort(80), TCP_8080), PortBinding.parse("80:8080/tcp")); } @Test public void portsOnly() { - assertEquals(PortBinding.parse("80:8080"), new PortBinding(Binding.bindPort(80), TCP_8080)); + assertEquals(new PortBinding(Binding.bindPort(80), TCP_8080), PortBinding.parse("80:8080")); } @Test public void exposedPortOnly() { - assertEquals(PortBinding.parse("8080"), new PortBinding(Binding.empty(), TCP_8080)); + assertEquals(new PortBinding(Binding.empty(), TCP_8080), PortBinding.parse("8080")); } @Test public void dynamicHostPort() { - assertEquals(PortBinding.parse("127.0.0.1::8080"), new PortBinding(Binding.bindIp("127.0.0.1"), TCP_8080)); + assertEquals(new PortBinding(Binding.bindIp("127.0.0.1"), TCP_8080), PortBinding.parse("127.0.0.1::8080")); } @Test diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/PortsAddBindingsTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/PortsAddBindingsTest.java index 02b3047e7..484e5897f 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/PortsAddBindingsTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/PortsAddBindingsTest.java @@ -36,9 +36,9 @@ public void addTwoBindingsForDifferentExposedPorts() { Map bindings = ports.getBindings(); // two keys with one value each - assertEquals(bindings.size(), 2); - assertArrayEquals(bindings.get(TCP_80), new Binding[] {BINDING_8080}); - assertArrayEquals(bindings.get(TCP_90), new Binding[] {BINDING_9090}); + assertEquals(2, bindings.size()); + assertArrayEquals(new Binding[] {BINDING_8080}, bindings.get(TCP_80)); + assertArrayEquals(new Binding[] {BINDING_9090}, bindings.get(TCP_90)); } @Test @@ -47,8 +47,8 @@ public void addTwoBindingsForSameExposedPort() { Map bindings = ports.getBindings(); // one key with two values - assertEquals(bindings.size(), 1); - assertArrayEquals(bindings.get(TCP_80), new Binding[] {BINDING_8080, BINDING_9090}); + assertEquals(1, bindings.size()); + assertArrayEquals(new Binding[] {BINDING_8080, BINDING_9090}, bindings.get(TCP_80)); } @Test @@ -56,7 +56,7 @@ public void addNullBindings() { ports.add(new PortBinding(null, TCP_80)); Map bindings = ports.getBindings(); // one key with two values - assertEquals(bindings.size(), 1); + assertEquals(1, bindings.size()); assertNull(bindings.get(TCP_80)); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/PortsSerializingTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/PortsSerializingTest.java index ecbdd9a49..2f528556f 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/PortsSerializingTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/PortsSerializingTest.java @@ -19,12 +19,12 @@ public class PortsSerializingTest { public void deserializingPortWithMultipleBindings() throws Exception { Ports ports = JSONTestHelper.getMapper().readValue(jsonWithDoubleBindingForOnePort, Ports.class); Map map = ports.getBindings(); - assertEquals(map.size(), 1); + assertEquals(1, map.size()); Binding[] bindings = map.get(ExposedPort.tcp(80)); - assertEquals(bindings.length, 2); - assertEquals(bindings[0], new Binding("10.0.0.1", "80")); - assertEquals(bindings[1], new Binding("10.0.0.2", "80")); + assertEquals(2, bindings.length); + assertEquals(new Binding("10.0.0.1", "80"), bindings[0]); + assertEquals(new Binding("10.0.0.2", "80"), bindings[1]); } @Test @@ -32,20 +32,20 @@ public void serializingPortWithMultipleBindings() throws Exception { Ports ports = new Ports(); ports.bind(ExposedPort.tcp(80), new Binding("10.0.0.1", "80")); ports.bind(ExposedPort.tcp(80), new Binding("10.0.0.2", "80")); - assertEquals(JSONTestHelper.getMapper().writeValueAsString(ports), jsonWithDoubleBindingForOnePort); + assertEquals(jsonWithDoubleBindingForOnePort, JSONTestHelper.getMapper().writeValueAsString(ports)); } @Test public void serializingEmptyBinding() throws Exception { Ports ports = new Ports(ExposedPort.tcp(80), new Binding(null, null)); - assertEquals(JSONTestHelper.getMapper().writeValueAsString(ports), "{\"80/tcp\":[{\"HostIp\":\"\",\"HostPort\":\"\"}]}"); + assertEquals("{\"80/tcp\":[{\"HostIp\":\"\",\"HostPort\":\"\"}]}", JSONTestHelper.getMapper().writeValueAsString(ports)); } @Test public void deserializingPortWithNullBindings() throws Exception { Ports ports = JSONTestHelper.getMapper().readValue(jsonWithNullBindingForOnePort, Ports.class); Map map = ports.getBindings(); - assertEquals(map.size(), 1); + assertEquals(1, map.size()); assertNull(map.get(ExposedPort.tcp(80))); } @@ -54,6 +54,6 @@ public void deserializingPortWithNullBindings() throws Exception { public void serializingWithNullBindings() throws Exception { Ports ports = new Ports(); ports.bind(ExposedPort.tcp(80), null); - assertEquals(JSONTestHelper.getMapper().writeValueAsString(ports), jsonWithNullBindingForOnePort); + assertEquals(jsonWithNullBindingForOnePort, JSONTestHelper.getMapper().writeValueAsString(ports)); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseItemTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseItemTest.java index 486badd55..f73036864 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseItemTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseItemTest.java @@ -29,6 +29,14 @@ * @author Zach Marshall */ public class PullResponseItemTest { + @Test + public void imageAlreadyExists() throws IOException { + PullResponseItem response = testRoundTrip(PullResponseJSONSamples.pullImageResponse_alreadyExists, + PullResponseItem.class); + assertTrue(response.isPullSuccessIndicated()); + assertFalse(response.isErrorIndicated()); + } + @Test public void pullNewerImage() throws IOException { PullResponseItem response = testRoundTrip(PullResponseJSONSamples.pullImageResponse_newerImage, diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseJSONSamples.java b/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseJSONSamples.java index 31cdf0f3b..4997a390a 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseJSONSamples.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/PullResponseJSONSamples.java @@ -23,7 +23,9 @@ * @author Zach Marshall */ public enum PullResponseJSONSamples implements JSONResourceRef { - pullImageResponse_legacy, pullImageResponse_error, pullImageResponse_newerImage, pullImageResponse_upToDate; + pullImageResponse_legacy, pullImageResponse_error, + pullImageResponse_newerImage, pullImageResponse_upToDate, + pullImageResponse_alreadyExists; @Override public String getFileName() { diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyParsingTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyParsingTest.java index fb79c0ca9..57dbc1b9f 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyParsingTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyParsingTest.java @@ -13,32 +13,32 @@ public class RestartPolicyParsingTest { @Test - public void noRestart() throws Exception { - assertEquals(RestartPolicy.parse("no"), RestartPolicy.noRestart()); + public void noRestart() { + assertEquals(RestartPolicy.noRestart(), RestartPolicy.parse("no")); } @Test - public void alwaysRestart() throws Exception { - assertEquals(RestartPolicy.parse("always"), RestartPolicy.alwaysRestart()); + public void alwaysRestart() { + assertEquals(RestartPolicy.alwaysRestart(), RestartPolicy.parse("always")); } @Test - public void unlessStoppedRestart() throws Exception { - assertEquals(RestartPolicy.parse("unless-stopped"), RestartPolicy.unlessStoppedRestart()); + public void unlessStoppedRestart() { + assertEquals(RestartPolicy.unlessStoppedRestart(), RestartPolicy.parse("unless-stopped")); } @Test - public void onFailureRestart() throws Exception { - assertEquals(RestartPolicy.parse("on-failure"), RestartPolicy.onFailureRestart(0)); + public void onFailureRestart() { + assertEquals(RestartPolicy.onFailureRestart(0), RestartPolicy.parse("on-failure")); } @Test - public void onFailureRestartWithCount() throws Exception { - assertEquals(RestartPolicy.parse("on-failure:2"), RestartPolicy.onFailureRestart(2)); + public void onFailureRestartWithCount() { + assertEquals(RestartPolicy.onFailureRestart(2), RestartPolicy.parse("on-failure:2")); } @Test - public void illegalSyntax() throws Exception { + public void illegalSyntax() { expectedEx.expect(IllegalArgumentException.class); expectedEx.expectMessage("Error parsing RestartPolicy 'nonsense'"); @@ -46,7 +46,7 @@ public void illegalSyntax() throws Exception { } @Test - public void illegalRetryCount() throws Exception { + public void illegalRetryCount() { expectedEx.expect(IllegalArgumentException.class); expectedEx.expectMessage("Error parsing RestartPolicy 'on-failure:X'"); diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicySerializingTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicySerializingTest.java index 6e4524fd5..c9c6a897d 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicySerializingTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicySerializingTest.java @@ -15,35 +15,35 @@ public class RestartPolicySerializingTest { // --restart no public void noRestart() throws Exception { String json = JSONTestHelper.getMapper().writeValueAsString(RestartPolicy.noRestart()); - assertEquals(json, "{\"MaximumRetryCount\":0,\"Name\":\"\"}"); + assertEquals("{\"MaximumRetryCount\":0,\"Name\":\"\"}", json); } @Test // --restart always public void alwaysRestart() throws Exception { String json = JSONTestHelper.getMapper().writeValueAsString(RestartPolicy.alwaysRestart()); - assertEquals(json, "{\"MaximumRetryCount\":0,\"Name\":\"always\"}"); + assertEquals("{\"MaximumRetryCount\":0,\"Name\":\"always\"}", json); } @Test // --restart unless-stopped public void unlessStoppedRestart() throws Exception { String json = JSONTestHelper.getMapper().writeValueAsString(RestartPolicy.unlessStoppedRestart()); - assertEquals(json, "{\"MaximumRetryCount\":0,\"Name\":\"unless-stopped\"}"); + assertEquals("{\"MaximumRetryCount\":0,\"Name\":\"unless-stopped\"}", json); } @Test // --restart on-failure public void onFailureRestart() throws Exception { String json = JSONTestHelper.getMapper().writeValueAsString(RestartPolicy.onFailureRestart(0)); - assertEquals(json, "{\"MaximumRetryCount\":0,\"Name\":\"on-failure\"}"); + assertEquals("{\"MaximumRetryCount\":0,\"Name\":\"on-failure\"}", json); } @Test // --restart on-failure:2 public void onFailureRestartWithCount() throws Exception { String json = JSONTestHelper.getMapper().writeValueAsString(RestartPolicy.onFailureRestart(2)); - assertEquals(json, "{\"MaximumRetryCount\":2,\"Name\":\"on-failure\"}"); + assertEquals("{\"MaximumRetryCount\":2,\"Name\":\"on-failure\"}", json); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyToStringTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyToStringTest.java index 4d9fa8cbc..e32f97341 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyToStringTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/RestartPolicyToStringTest.java @@ -18,8 +18,8 @@ public static Object[][] restartPolicies() { public String policy; @Test - public void serializationWithoutCount() throws Exception { - assertEquals(RestartPolicy.parse(policy).toString(), policy); + public void serializationWithoutCount() { + assertEquals(policy, RestartPolicy.parse(policy).toString()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeBindsTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeBindsTest.java index b413cf029..7f38eb0f0 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeBindsTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeBindsTest.java @@ -28,9 +28,9 @@ public void t() throws IOException { String s = "{\"/data\":\"/some/path\"}"; VolumeBinds volumeBinds = JSONTestHelper.getMapper().readValue(s, VolumeBinds.class); VolumeBind[] binds = volumeBinds.getBinds(); - assertEquals(binds.length, 1); - assertEquals(binds[0].getHostPath(), "/some/path"); - assertEquals(binds[0].getContainerPath(), "/data"); + assertEquals(1, binds.length); + assertEquals("/some/path", binds[0].getHostPath()); + assertEquals("/data", binds[0].getContainerPath()); } @Test(expected = JsonMappingException.class) diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeFromSerializingTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeFromSerializingTest.java index ae343047c..6155f88e3 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeFromSerializingTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeFromSerializingTest.java @@ -18,7 +18,7 @@ public void deserializing() throws Exception { @Test public void serializing() throws Exception { VolumesFrom volumeFrom = new VolumesFrom("container1", AccessMode.ro); - assertEquals(JSONTestHelper.getMapper().writeValueAsString(volumeFrom), json); + assertEquals(json, JSONTestHelper.getMapper().writeValueAsString(volumeFrom)); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeTest.java b/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeTest.java index cb1c4befd..20e28a55d 100644 --- a/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/api/model/VolumeTest.java @@ -7,6 +7,6 @@ public class VolumeTest { @Test public void getPath() { - assertEquals(new Volume("/path").getPath(), "/path"); + assertEquals("/path", new Volume("/path").getPath()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/AttachContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/AttachContainerCmdIT.java index 299213216..dde47e2d8 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/AttachContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/AttachContainerCmdIT.java @@ -3,34 +3,29 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerResponse; -import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.StreamType; -import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; import java.io.File; -import java.io.InputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static java.util.concurrent.TimeUnit.SECONDS; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * @author Kanstantsin Shautsou @@ -46,36 +41,31 @@ public class AttachContainerCmdIT extends CmdIT { public void attachContainerWithStdin() throws Exception { DockerClient dockerClient = dockerRule.getClient(); - Assume.assumeTrue("supports stdin attach", getFactoryType().supportsStdinAttach()); - String snippet = "hello world"; CreateContainerResponse container = dockerClient.createContainerCmd("busybox") - .withCmd("/bin/sh", "-c", "sleep 1 && read line && echo $line") - .withTty(false) - .withStdinOpen(true) - .exec(); + .withCmd("/bin/sh", "-c", "read line && echo $line") + .withTty(false) + .withAttachStdin(true) + .withAttachStdout(true) + .withAttachStderr(true) + .withStdinOpen(true) + .exec(); LOG.info("Created container: {}", container.toString()); assertThat(container.getId(), not(is(emptyString()))); - dockerClient.startContainerCmd(container.getId()).exec(); - - InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec(); - - assertThat(inspectContainerResponse.getState().getRunning(), is(true)); - AttachContainerTestCallback callback = new AttachContainerTestCallback() { @Override public void onNext(Frame frame) { - assertEquals(frame.getStreamType(), StreamType.STDOUT); + assertEquals(StreamType.STDOUT, frame.getStreamType()); super.onNext(frame); } }; try ( PipedOutputStream out = new PipedOutputStream(); - PipedInputStream in = new PipedInputStream(out); + PipedInputStream in = new PipedInputStream(out) ) { dockerClient.attachContainerCmd(container.getId()) .withStdErr(true) @@ -84,6 +74,11 @@ public void onNext(Frame frame) { .withStdIn(in) .exec(callback); + assertTrue("Processing of the response should start shortly after executing `attachContainerCmd`", + callback.awaitStarted(5, SECONDS)); + + dockerClient.startContainerCmd(container.getId()).exec(); + out.write((snippet + "\n").getBytes()); out.flush(); @@ -101,30 +96,36 @@ public void attachContainerWithoutTTY() throws Exception { String snippet = "hello world"; CreateContainerResponse container = dockerClient.createContainerCmd(DEFAULT_IMAGE) - .withCmd("echo", snippet) - .withTty(false) - .exec(); + .withCmd("echo", snippet) + .withTty(false) + .withAttachStdout(true) + .withAttachStderr(true) + .exec(); LOG.info("Created container: {}", container.toString()); assertThat(container.getId(), not(is(emptyString()))); - dockerClient.startContainerCmd(container.getId()).exec(); - AttachContainerTestCallback callback = new AttachContainerTestCallback() { @Override public void onNext(Frame frame) { assertThat(frame.getStreamType(), equalTo(StreamType.STDOUT)); super.onNext(frame); - }; + } }; dockerClient.attachContainerCmd(container.getId()) - .withStdErr(true) - .withStdOut(true) - .withFollowStream(true) - .withLogs(true) - .exec(callback) - .awaitCompletion(30, TimeUnit.SECONDS); + .withStdErr(true) + .withStdOut(true) + .withFollowStream(true) + .withLogs(true) + .exec(callback); + + assertTrue("Processing of the response should start shortly after executing `attachContainerCmd`", + callback.awaitStarted(5, SECONDS)); + + dockerClient.startContainerCmd(container.getId()).exec(); + + callback.awaitCompletion(30, TimeUnit.SECONDS); callback.close(); assertThat(callback.toString(), containsString(snippet)); @@ -135,77 +136,46 @@ public void attachContainerWithTTY() throws Exception { DockerClient dockerClient = dockerRule.getClient(); File baseDir = new File(Thread.currentThread().getContextClassLoader() - .getResource("attachContainerTestDockerfile").getFile()); + .getResource("attachContainerTestDockerfile").getFile()); String imageId = dockerRule.buildImage(baseDir); - CreateContainerResponse container = dockerClient.createContainerCmd(imageId).withTty(true).exec(); + CreateContainerResponse container = dockerClient.createContainerCmd(imageId) + .withTty(true) + .withAttachStdout(true) + .withAttachStderr(true) + .exec(); LOG.info("Created container: {}", container.toString()); assertThat(container.getId(), not(is(emptyString()))); - dockerClient.startContainerCmd(container.getId()).exec(); AttachContainerTestCallback callback = new AttachContainerTestCallback() { @Override public void onNext(Frame frame) { assertThat(frame.getStreamType(), equalTo(StreamType.RAW)); super.onNext(frame); - }; + } }; dockerClient.attachContainerCmd(container.getId()) - .withStdErr(true) - .withStdOut(true) - .withFollowStream(true) - .exec(callback) - .awaitCompletion(15, TimeUnit.SECONDS); - callback.close(); - - LOG.debug("log: {}", callback.toString()); - - // HexDump.dump(collectFramesCallback.toString().getBytes(), 0, System.out, 0); - assertThat(callback.toString(), containsString("stdout\r\nstderr")); - } - - @Test - public void attachContainerStdinUnsupported() throws Exception { + .withStdErr(true) + .withStdOut(true) + .withFollowStream(true) + .exec(callback); - DockerClient dockerClient = dockerRule.getClient(); - Assume.assumeFalse("does not support stdin attach", getFactoryType().supportsStdinAttach()); - expectedException.expect(UnsupportedOperationException.class); - - String snippet = "hello world"; - - CreateContainerResponse container = dockerClient.createContainerCmd(DEFAULT_IMAGE) - .withCmd("echo", snippet) - .withTty(false) - .exec(); - - LOG.info("Created container: {}", container.toString()); - assertThat(container.getId(), not(is(emptyString()))); + assertTrue("Processing of the response should start shortly after executing `attachContainerCmd`", + callback.awaitStarted(5, SECONDS)); dockerClient.startContainerCmd(container.getId()).exec(); - AttachContainerTestCallback callback = new AttachContainerTestCallback() { - @Override - public void onNext(Frame frame) { - assertThat(frame.getStreamType(), equalTo(StreamType.STDOUT)); - super.onNext(frame); - }; - }; + callback.awaitCompletion(15, TimeUnit.SECONDS); + callback.close(); - InputStream stdin = new ByteArrayInputStream("".getBytes()); + LOG.debug("log: {}", callback.toString()); - dockerClient.attachContainerCmd(container.getId()) - .withStdErr(true) - .withStdOut(true) - .withFollowStream(true) - .withLogs(true) - .withStdIn(stdin) - .exec(callback) - .awaitCompletion(30, TimeUnit.SECONDS); - callback.close(); + // HexDump.dump(collectFramesCallback.toString().getBytes(), 0, System.out, 0); + assertThat(callback.toString(), containsString("stdout\r\nstderr")); } /** @@ -217,33 +187,35 @@ public void attachContainerClosesStdoutWhenContainerExits() throws Exception { DockerClient dockerClient = dockerRule.getClient(); CreateContainerResponse container = dockerClient.createContainerCmd(DEFAULT_IMAGE) - .withCmd("echo", "hello") - .withTty(false) - .exec(); + .withCmd("echo", "hello") + .withTty(false) + .withAttachStdout(true) + .withAttachStderr(true) + .exec(); LOG.info("Created container: {}", container.toString()); CountDownLatch gotLine = new CountDownLatch(1); try ( - ResultCallback.Adapter resultCallback = dockerClient.attachContainerCmd(container.getId()) - .withStdOut(true) - .withStdErr(true) - .withFollowStream(true) - .exec(new ResultCallback.Adapter() { - @Override - public void onNext(Frame item) { - LOG.info("Got frame: {}", item); - if (item.getStreamType() == StreamType.STDOUT) { - gotLine.countDown(); - } - super.onNext(item); - } - - @Override - public void onComplete() { - LOG.info("On complete"); - super.onComplete(); - } - }) + ResultCallback.Adapter resultCallback = dockerClient.attachContainerCmd(container.getId()) + .withStdOut(true) + .withStdErr(true) + .withFollowStream(true) + .exec(new ResultCallback.Adapter() { + @Override + public void onNext(Frame item) { + LOG.info("Got frame: {}", item); + if (item.getStreamType() == StreamType.STDOUT) { + gotLine.countDown(); + } + super.onNext(item); + } + + @Override + public void onComplete() { + LOG.info("On complete"); + super.onComplete(); + } + }) ) { resultCallback.awaitStarted(5, SECONDS); LOG.info("Attach started"); @@ -258,7 +230,7 @@ public void onComplete() { } public static class AttachContainerTestCallback extends ResultCallback.Adapter { - private StringBuffer log = new StringBuffer(); + private final StringBuffer log = new StringBuffer(); @Override public void onNext(Frame item) { diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/AuthCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/AuthCmdIT.java index 887f97334..d37bea819 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/AuthCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/AuthCmdIT.java @@ -19,7 +19,7 @@ public class AuthCmdIT extends CmdIT { @Test - public void testAuth() throws Exception { + public void testAuth() { assumeThat("Fails on 1.22. Temporary disabled.", dockerRule, apiVersionGreater(VERSION_1_22)); AuthResponse response = dockerRule.getClient().authCmd().exec(); @@ -30,7 +30,7 @@ public void testAuth() throws Exception { @Ignore("Disabled because of 500/InternalServerException") @Test - public void testAuthInvalid() throws Exception { + public void testAuthInvalid() { assertThrows("Wrong login/password, please try again", UnauthorizedException.class, () -> { DockerClientBuilder.getInstance(dockerRule.config("garbage")) .build() diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/BuildImageCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/BuildImageCmdIT.java index cd9b1ef9c..d514ed59c 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/BuildImageCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/BuildImageCmdIT.java @@ -163,21 +163,21 @@ private String execBuild(BuildImageCmd buildImageCmd) throws Exception { } @Test(expected = DockerClientException.class) - public void dockerignoreDockerfileIgnored() throws Exception { + public void dockerignoreDockerfileIgnored() { File baseDir = fileFromBuildTestResource("dockerignore/DockerfileIgnored"); dockerRule.getClient().buildImageCmd(baseDir).withNoCache(true).start().awaitImageId(); } @Test - public void dockerignoreDockerfileNotIgnored() throws Exception { + public void dockerignoreDockerfileNotIgnored() { File baseDir = fileFromBuildTestResource("dockerignore/DockerfileNotIgnored"); dockerRule.getClient().buildImageCmd(baseDir).withNoCache(true).start().awaitImageId(); } @Test(expected = DockerClientException.class) - public void dockerignoreInvalidDockerIgnorePattern() throws Exception { + public void dockerignoreInvalidDockerIgnorePattern() { File baseDir = fileFromBuildTestResource("dockerignore/InvalidDockerignorePattern"); dockerRule.getClient().buildImageCmd(baseDir).withNoCache(true).start().awaitImageId(); @@ -241,7 +241,7 @@ public void fromPrivateRegistry() throws Exception { } @Test - public void buildArgs() throws Exception { + public void buildArgs() { File baseDir = fileFromBuildTestResource("buildArgs"); String imageId = dockerRule.getClient().buildImageCmd(baseDir).withNoCache(true).withBuildArg("testArg", "abc !@#$%^&*()_+") @@ -256,7 +256,7 @@ public void buildArgs() throws Exception { } @Test - public void labels() throws Exception { + public void labels() { assumeThat("API version should be >= 1.23", dockerRule, isGreaterOrEqual(VERSION_1_23)); File baseDir = fileFromBuildTestResource("labels"); @@ -274,7 +274,7 @@ public void labels() throws Exception { } @Test - public void multipleTags() throws Exception { + public void multipleTags() { assumeThat("API version should be >= 1.23", dockerRule, isGreaterOrEqual(VERSION_1_21)); @@ -295,7 +295,7 @@ public void multipleTags() throws Exception { } @Test - public void cacheFrom() throws Exception { + public void cacheFrom() { assumeThat(dockerRule, isGreaterOrEqual(VERSION_1_27)); File baseDir1 = fileFromBuildTestResource("CacheFrom/test1"); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CmdIT.java index ecb66d089..b01cb1e90 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CmdIT.java @@ -1,107 +1,39 @@ package com.github.dockerjava.cmd; -import com.github.dockerjava.api.command.DelegatingDockerCmdExecFactory; -import com.github.dockerjava.api.command.DockerCmdExecFactory; -import com.github.dockerjava.core.DefaultDockerCmdExecFactory; +import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.core.DockerClientConfigAware; +import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.core.DockerRule; import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; -import com.github.dockerjava.jaxrs.JerseyDockerCmdExecFactory; -import com.github.dockerjava.junit.DockerRule; import com.github.dockerjava.junit.category.Integration; -import com.github.dockerjava.netty.NettyDockerCmdExecFactory; -import com.github.dockerjava.okhttp.OkHttpDockerCmdExecFactory; +import com.github.dockerjava.transport.DockerHttpClient; import org.junit.Rule; import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.Arrays; /** * @author Kanstantsin Shautsou */ @Category(Integration.class) -@RunWith(Parameterized.class) public abstract class CmdIT { - public enum FactoryType { - NETTY(true) { - @Override - public DockerCmdExecFactory createExecFactory() { - return new NettyDockerCmdExecFactory().withConnectTimeout(30 * 1000); - } - }, - JERSEY(false) { - @Override - public DockerCmdExecFactory createExecFactory() { - return new JerseyDockerCmdExecFactory().withConnectTimeout(30 * 1000); - } - }, - OKHTTP(true) { - @Override - public DockerCmdExecFactory createExecFactory() { - return new OkHttpDockerCmdExecFactory().withConnectTimeout(30 * 1000); - } - }, - HTTPCLIENT5(true) { - @Override - public DockerCmdExecFactory createExecFactory() { - class FakeFactory extends DelegatingDockerCmdExecFactory implements DockerClientConfigAware { - - private DefaultDockerCmdExecFactory dockerCmdExecFactory; - - @Override - public final DockerCmdExecFactory getDockerCmdExecFactory() { - return dockerCmdExecFactory; - } - - @Override - public void init(DockerClientConfig dockerClientConfig) { - dockerCmdExecFactory = new DefaultDockerCmdExecFactory( - new ApacheDockerHttpClient.Factory() - .dockerClientConfig(dockerClientConfig) - .build(), - dockerClientConfig.getObjectMapper() - ); - dockerCmdExecFactory.init(dockerClientConfig); - } - } - return new FakeFactory(); - } - }; - - private final String subnetPrefix; - private final boolean supportsStdinAttach; - - FactoryType(boolean supportsStdinAttach) { - this.subnetPrefix = "10." + (100 + ordinal()) + "."; - this.supportsStdinAttach = supportsStdinAttach; - } - public String getSubnetPrefix() { - return subnetPrefix; - } - - public boolean supportsStdinAttach() { - return supportsStdinAttach; - } - - public abstract DockerCmdExecFactory createExecFactory(); - } - - @Parameterized.Parameters(name = "{index}:{0}") - public static Iterable data() { - return Arrays.asList(FactoryType.values()); + public static DockerHttpClient createDockerHttpClient(DockerClientConfig config) { + return new TrackingDockerHttpClient( + new ApacheDockerHttpClient.Builder() + .dockerHost(config.getDockerHost()) + .sslConfig(config.getSSLConfig()) + .build() + ); } - @Parameterized.Parameter - public FactoryType factoryType; - - public FactoryType getFactoryType() { - return factoryType; + public static DockerClientImpl createDockerClient(DockerClientConfig config) { + return (DockerClientImpl) DockerClientBuilder.getInstance(config) + .withDockerHttpClient(createDockerHttpClient(config)) + .build(); } @Rule - public DockerRule dockerRule = new DockerRule( this); + public DockerRule dockerRule = new DockerRule(); + @Rule + public DockerHttpClientLeakDetector leakDetector = new DockerHttpClientLeakDetector(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CommitCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CommitCmdIT.java index 4bba98a5f..bd87d4aab 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CommitCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CommitCmdIT.java @@ -11,7 +11,7 @@ import java.util.Map; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -46,9 +46,6 @@ public void commit() throws DockerException, InterruptedException { InspectImageResponse inspectImageResponse = dockerRule.getClient().inspectImageCmd(imageId).exec(); LOG.info("Image Inspect: {}", inspectImageResponse.toString()); - assertThat(inspectImageResponse, hasField("container", startsWith(container.getId()))); - assertThat(inspectImageResponse.getContainerConfig().getImage(), equalTo(DEFAULT_IMAGE)); - InspectImageResponse busyboxImg = dockerRule.getClient().inspectImageCmd("busybox").exec(); assertThat(inspectImageResponse.getParent(), equalTo(busyboxImg.getId())); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ConnectToNetworkCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ConnectToNetworkCmdIT.java index 42934c03e..40b552611 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/ConnectToNetworkCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ConnectToNetworkCmdIT.java @@ -10,7 +10,7 @@ import org.junit.Test; import static com.github.dockerjava.junit.DockerAssume.assumeNotSwarm; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.core.Is.is; @@ -26,7 +26,7 @@ public class ConnectToNetworkCmdIT extends CmdIT { @Test public void connectToNetwork() throws InterruptedException { assumeNotSwarm("no network in swarm", dockerRule); - String networkName = "connectToNetwork" + dockerRule.getKind(); + String networkName = "connectToNetwork"; CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE).withCmd("sleep", "9999").exec(); dockerRule.getClient().startContainerCmd(container.getId()).exec(); @@ -48,8 +48,8 @@ public void connectToNetwork() throws InterruptedException { public void connectToNetworkWithContainerNetwork() throws InterruptedException { assumeNotSwarm("no network in swarm", dockerRule); - final String subnetPrefix = getFactoryType().getSubnetPrefix() + "100"; - final String networkName = "ContainerWithNetwork" + dockerRule.getKind(); + final String subnetPrefix = "10.100.100"; + final String networkName = "ContainerWithNetwork"; final String containerIp = subnetPrefix + ".100"; CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) @@ -74,7 +74,7 @@ public void connectToNetworkWithContainerNetwork() throws InterruptedException { .withNetworkId(network.getId()) .withContainerId(container.getId()) .withContainerNetwork(new ContainerNetwork() - .withAliases("aliasName" + dockerRule.getKind()) + .withAliases("aliasName") .withIpamConfig(new ContainerNetwork.Ipam() .withIpv4Address(containerIp))) .exec(); @@ -89,7 +89,7 @@ public void connectToNetworkWithContainerNetwork() throws InterruptedException { ContainerNetwork testNetwork = inspectContainerResponse.getNetworkSettings().getNetworks().get(networkName); assertNotNull(testNetwork); - assertThat(testNetwork.getAliases(), hasItem("aliasName" + dockerRule.getKind())); + assertThat(testNetwork.getAliases(), hasItem("aliasName")); assertThat(testNetwork.getGateway(), is(subnetPrefix + ".1")); assertThat(testNetwork.getIpAddress(), is(containerIp)); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ContainerDiffCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ContainerDiffCmdIT.java index bc8bd67f1..7ff39f3fa 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/ContainerDiffCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ContainerDiffCmdIT.java @@ -11,7 +11,7 @@ import java.util.List; import static ch.lambdaj.Lambda.selectUnique; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveFromContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveFromContainerCmdIT.java index f04823ec0..e0c2ca03e 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveFromContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveFromContainerCmdIT.java @@ -17,7 +17,7 @@ import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.isEmptyOrNullString; import static org.hamcrest.Matchers.not; @@ -30,10 +30,10 @@ public class CopyArchiveFromContainerCmdIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(CopyArchiveFromContainerCmdIT.class); @Test - public void copyFromContainer() throws Exception { + public void copyFromContainer() { // TODO extract this into a shared method CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) - .withName("copyFromContainer" + dockerRule.getKind()) + .withName("copyFromContainer") .withCmd("touch", "/copyFromContainer") .exec(); @@ -51,7 +51,7 @@ public void copyFromContainer() throws Exception { } @Test(expected = NotFoundException.class) - public void copyFromNonExistingContainer() throws Exception { + public void copyFromNonExistingContainer() { dockerRule.getClient().copyArchiveFromContainerCmd("non-existing", "/test").exec(); } @@ -59,14 +59,14 @@ public void copyFromNonExistingContainer() throws Exception { @Test public void copyFromContainerBinaryFile() throws Exception { CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) - .withName("copyFromContainerBinaryFile" + dockerRule.getKind()) + .withName("copyFromContainerBinaryFile") .exec(); LOG.info("Created container: {}", container); assertThat(container.getId(), not(isEmptyOrNullString())); Path temp = Files.createTempFile("", ".tar.gz"); - Path binaryFile = Paths.get("src/test/resources/testCopyFromArchive/binary.dat"); + Path binaryFile = Paths.get(ClassLoader.getSystemResource("testCopyFromArchive/binary.dat").toURI()); CompressArchiveUtil.tar(binaryFile, temp, true, false); try (InputStream uploadStream = Files.newInputStream(temp)) { @@ -78,7 +78,7 @@ public void copyFromContainerBinaryFile() throws Exception { try (TarArchiveInputStream tarInputStream = new TarArchiveInputStream(response)) { TarArchiveEntry nextTarEntry = tarInputStream.getNextTarEntry(); - assertEquals(nextTarEntry.getName(), "binary.dat"); + assertEquals("binary.dat", nextTarEntry.getName()); try (InputStream binaryFileInputStream = Files.newInputStream(binaryFile, StandardOpenOption.READ)) { assertTrue(IOUtils.contentEquals(binaryFileInputStream, tarInputStream)); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java index 307c1e17c..efce65c29 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyArchiveToContainerCmdIT.java @@ -4,7 +4,9 @@ import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.core.util.CompressArchiveUtil; +import com.github.dockerjava.utils.LogContainerTestCallback; import org.apache.commons.io.FileUtils; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,12 +16,16 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.isEmptyOrNullString; import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeThat; public class CopyArchiveToContainerCmdIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(CopyArchiveToContainerCmdIT.class); @@ -28,7 +34,7 @@ public class CopyArchiveToContainerCmdIT extends CmdIT { public void copyFileToContainer() throws Exception { CreateContainerResponse container = prepareContainerForCopy("1"); Path temp = Files.createTempFile("", ".tar.gz"); - CompressArchiveUtil.tar(Paths.get("src/test/resources/testReadFile"), temp, true, false); + CompressArchiveUtil.tar(Paths.get(ClassLoader.getSystemResource("testReadFile").toURI()), temp, true, false); try (InputStream uploadStream = Files.newInputStream(temp)) { dockerRule.getClient() .copyArchiveToContainerCmd(container.getId()) @@ -42,7 +48,7 @@ public void copyFileToContainer() throws Exception { public void copyStreamToContainer() throws Exception { CreateContainerResponse container = prepareContainerForCopy("2"); dockerRule.getClient().copyArchiveToContainerCmd(container.getId()) - .withHostResource("src/test/resources/testReadFile") + .withHostResource(Paths.get(ClassLoader.getSystemResource("testReadFile").toURI()).toString()) .exec(); assertFileCopied(container); } @@ -50,8 +56,8 @@ public void copyStreamToContainer() throws Exception { @Test public void copyStreamToContainerTwice() throws Exception { CreateContainerResponse container = prepareContainerForCopy("rerun"); - CopyArchiveToContainerCmd copyArchiveToContainerCmd=dockerRule.getClient().copyArchiveToContainerCmd(container.getId()) - .withHostResource("src/test/resources/testReadFile"); + CopyArchiveToContainerCmd copyArchiveToContainerCmd = dockerRule.getClient().copyArchiveToContainerCmd(container.getId()) + .withHostResource(Paths.get(ClassLoader.getSystemResource("testReadFile").toURI()).toString()); copyArchiveToContainerCmd.exec(); assertFileCopied(container); //run again to make sure no DockerClientException @@ -60,7 +66,7 @@ public void copyStreamToContainerTwice() throws Exception { private CreateContainerResponse prepareContainerForCopy(String method) { CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") - .withName("docker-java-itest-copyToContainer" + method + dockerRule.getKind()) + .withName("docker-java-itest-copyToContainer" + method) .exec(); LOG.info("Created container: {}", container); assertThat(container.getId(), not(isEmptyOrNullString())); @@ -78,8 +84,8 @@ private void assertFileCopied(CreateContainerResponse container) throws IOExcept @Test(expected = NotFoundException.class) public void copyToNonExistingContainer() throws Exception { - - dockerRule.getClient().copyArchiveToContainerCmd("non-existing").withHostResource("src/test/resources/testReadFile").exec(); + dockerRule.getClient().copyArchiveToContainerCmd("non-existing") + .withHostResource(Paths.get(ClassLoader.getSystemResource("testReadFile").toURI()).toString()).exec(); } @Test @@ -108,7 +114,7 @@ public void copyDirWithLastAddedTarEntryEmptyDir() throws Exception{ // cleanup dir FileUtils.deleteDirectory(localDir.toFile()); } - + @Test public void copyFileWithExecutePermission() throws Exception { // create script file, add permission to execute @@ -125,7 +131,7 @@ public void copyFileWithExecutePermission() throws Exception { // script to be copied to the container's home dir and then executes it String containerCmd = "sleep 3; /home/" + scriptPath.getFileName().toString(); CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") - .withName("copyFileWithExecutivePerm" + dockerRule.getKind()) + .withName("copyFileWithExecutivePerm") .withCmd("/bin/sh", "-c", containerCmd) .exec(); // start the container @@ -143,4 +149,72 @@ public void copyFileWithExecutePermission() throws Exception { assertThat(exitCode, equalTo(0)); } + @Ignore("Docker issue https://github.com/moby/moby/issues/46388") + @Test + public void copyFileWithUIDGID() throws Exception { + Path with = Files.createFile(Files.createTempDirectory("copyFileWithUIDGID").resolve("uidgid.with")); + Files.write(with, "with".getBytes()); + + Path without = Files.createFile(Files.createTempDirectory("copyFileWithUIDGID").resolve("uidgid.without")); + Files.write(without, "without".getBytes()); + + String containerCmd = "while [ ! -f /home/uidgid.with ]; do true; done && stat -c %n:%u /home/uidgid.with /home/uidgid.without"; + Long syncUserUid = 4L; // sync user in busybox uses uid=4 + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") + .withName("copyFileWithUIDGID") + .withCmd("/bin/sh", "-c", containerCmd) + .withUser(syncUserUid.toString()) + .exec(); + // start the container + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + dockerRule.getClient().copyArchiveToContainerCmd(container.getId()) + .withRemotePath("/home/") + .withHostResource(without.toString()) + .withCopyUIDGID(false) + .exec(); + dockerRule.getClient().copyArchiveToContainerCmd(container.getId()) + .withRemotePath("/home/") + .withHostResource(with.toString()) + .withCopyUIDGID(true) + .exec(); + + // await exit code + int exitCode = dockerRule.getClient().waitContainerCmd(container.getId()) + .start() + .awaitStatusCode(); + // check result + assertThat(exitCode, equalTo(0)); + + LogContainerTestCallback loggingCallback = new LogContainerTestCallback(true); + + dockerRule.getClient().logContainerCmd(container.getId()) + .withStdOut(true) + .withTailAll() + .exec(loggingCallback); + + loggingCallback.awaitCompletion(3, TimeUnit.SECONDS); + String containerOutput = loggingCallback.toString(); + + assertThat(containerOutput, containsString(String.format("/home/uidgid.with:%d", syncUserUid))); + + Long hostUid = getHostUidIfPossible(); + assumeThat("could not get the uid on host platform", hostUid, notNullValue(Long.class)); + assertThat(containerOutput, containsString(String.format("/home/uidgid.without:%d", hostUid))); + } + + private static Long getHostUidIfPossible() { + try { + Class unixSystemClazz = Class.forName("com.sun.security.auth.module.UnixSystem"); + Object unixSystem = unixSystemClazz.newInstance(); + Object uid = unixSystemClazz.getMethod("getUid").invoke(unixSystem); + if (uid == null) { + return null; + } + + return uid instanceof Long ? (Long) uid : Long.parseLong(uid.toString()); + } catch (Exception e) { + return null; + } + } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyFileFromContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyFileFromContainerCmdIT.java index ffef0d38a..3864aa9e4 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CopyFileFromContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CopyFileFromContainerCmdIT.java @@ -23,12 +23,12 @@ public class CopyFileFromContainerCmdIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(CopyFileFromContainerCmdIT.class); @Test - public void copyFromContainer() throws Exception { + public void copyFromContainer() { assumeThat("Doesn't work since 1.24", dockerRule, not(isGreaterOrEqual(VERSION_1_24))); assumeNotSwarm("", dockerRule); - String containerName = "copyFileFromContainer" + dockerRule.getKind(); + String containerName = "copyFileFromContainer"; dockerRule.ensureContainerRemoved(containerName); // TODO extract this into a shared method @@ -51,7 +51,7 @@ public void copyFromContainer() throws Exception { } @Test(expected = NotFoundException.class) - public void copyFromNonExistingContainer() throws Exception { + public void copyFromNonExistingContainer() { dockerRule.getClient().copyFileFromContainerCmd("non-existing", "/test").exec(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CreateContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CreateContainerCmdIT.java index 227c0acc9..99d5dd997 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CreateContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CreateContainerCmdIT.java @@ -1,18 +1,24 @@ package com.github.dockerjava.cmd; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.CreateNetworkResponse; import com.github.dockerjava.api.command.CreateVolumeResponse; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.ConflictException; import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.ContainerNetwork; import com.github.dockerjava.api.model.Device; +import com.github.dockerjava.api.model.DockerObjectAccessor; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.HostConfig; @@ -30,7 +36,9 @@ import com.github.dockerjava.utils.TestUtils; import net.jcip.annotations.NotThreadSafe; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.SystemUtils; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -52,9 +60,10 @@ import static com.github.dockerjava.api.model.HostConfig.newHostConfig; import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_23; import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_24; +import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_44; import static com.github.dockerjava.junit.DockerMatchers.isGreaterOrEqual; import static com.github.dockerjava.junit.DockerMatchers.mountedVolumes; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.contains; @@ -69,6 +78,7 @@ import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; @@ -363,7 +373,7 @@ public void createContainerWithHostname() throws Exception { @Test(expected = ConflictException.class) public void createContainerWithName() throws DockerException { - String containerName = "container_" + dockerRule.getKind(); + String containerName = "container_"; CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) .withName(containerName) @@ -385,8 +395,8 @@ public void createContainerWithName() throws DockerException { @Test public void createContainerWithLink() throws DockerException { - String containerName1 = "containerWithlink_" + dockerRule.getKind(); - String containerName2 = "container2Withlink_" + dockerRule.getKind(); + String containerName1 = "containerWithlink_"; + String containerName2 = "container2Withlink_"; CreateContainerResponse container1 = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE).withCmd("sleep", "9999") .withName(containerName1).exec(); @@ -415,6 +425,7 @@ public void createContainerWithLink() throws DockerException { } @Test + @Ignore public void createContainerWithMemorySwappiness() throws DockerException { CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) .withCmd("sleep", "9999") @@ -436,9 +447,9 @@ public void createContainerWithMemorySwappiness() throws DockerException { @Test public void createContainerWithLinkInCustomNetwork() throws DockerException { - String containerName1 = "containerCustomlink_" + dockerRule.getKind(); - String containerName2 = "containerCustom2link_" + dockerRule.getKind(); - String networkName = "linkNetcustom" + dockerRule.getKind(); + String containerName1 = "containerCustomlink_"; + String containerName2 = "containerCustom2link_"; + String networkName = "linkNetcustom"; CreateNetworkResponse createNetworkResponse = dockerRule.getClient().createNetworkCmd() .withName(networkName) @@ -484,9 +495,9 @@ public void createContainerWithLinkInCustomNetwork() throws DockerException { @Test public void createContainerWithCustomIp() throws DockerException { - String containerName1 = "containerCustomIplink_" + dockerRule.getKind(); - String networkName = "customIpNet" + dockerRule.getKind(); - String subnetPrefix = getFactoryType().getSubnetPrefix() + "101"; + String containerName1 = "containerCustomIplink_"; + String networkName = "customIpNet"; + String subnetPrefix = "10.100.101"; CreateNetworkResponse createNetworkResponse = dockerRule.getClient().createNetworkCmd() .withIpam(new Network.Ipam() @@ -522,8 +533,8 @@ public void createContainerWithCustomIp() throws DockerException { @Test public void createContainerWithAlias() throws DockerException { - String containerName1 = "containerAlias_" + dockerRule.getKind(); - String networkName = "aliasNet" + dockerRule.getKind(); + String containerName1 = "containerAlias_"; + String networkName = "aliasNet"; CreateNetworkResponse createNetworkResponse = dockerRule.getClient().createNetworkCmd() .withName(networkName) @@ -537,7 +548,7 @@ public void createContainerWithAlias() throws DockerException { .withNetworkMode(networkName)) .withCmd("sleep", "9999") .withName(containerName1) - .withAliases("server" + dockerRule.getKind()) + .withAliases("server") .exec(); assertThat(container.getId(), not(is(emptyString()))); @@ -548,7 +559,7 @@ public void createContainerWithAlias() throws DockerException { .exec(); ContainerNetwork aliasNet = inspectContainerResponse.getNetworkSettings().getNetworks().get(networkName); - assertThat(aliasNet.getAliases(), hasItem("server" + dockerRule.getKind())); + assertThat(aliasNet.getAliases(), hasItem("server")); } @Test @@ -596,7 +607,7 @@ public void createContainerWithDns() throws DockerException { public void createContainerWithEntrypoint() throws DockerException { CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) - .withName("containerEntrypoint" + dockerRule.getKind()) + .withName("containerEntrypoint") .withEntrypoint("sleep", "9999").exec(); LOG.info("Created container {}", container.toString()); @@ -615,7 +626,7 @@ public void createContainerWithExtraHosts() throws DockerException { String[] extraHosts = {"dockerhost:127.0.0.1", "otherhost:10.0.0.1"}; CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) - .withName("containerextrahosts" + dockerRule.getKind()) + .withName("containerextrahosts") .withHostConfig(newHostConfig() .withExtraHosts(extraHosts)).exec(); @@ -649,7 +660,7 @@ public void createContainerWithDevices() throws DockerException { @Test public void createContainerWithPortBindings() throws DockerException { - int baseport = 10_000 + (getFactoryType().ordinal() * 1000); + int baseport = 10_000; ExposedPort tcp22 = ExposedPort.tcp(22); ExposedPort tcp23 = ExposedPort.tcp(23); @@ -686,8 +697,8 @@ public void createContainerWithPortBindings() throws DockerException { @Test public void createContainerWithLinking() throws DockerException { - String containerName1 = "containerWithlinking_" + dockerRule.getKind(); - String containerName2 = "container2Withlinking_" + dockerRule.getKind(); + String containerName1 = "containerWithlinking_"; + String containerName2 = "container2Withlinking_"; CreateContainerResponse container1 = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) .withCmd("sleep", "9999") @@ -811,7 +822,7 @@ public void createContainerWithMacAddress() throws DockerException { @Test public void createContainerWithULimits() throws DockerException { - String containerName = "containerulimit" + dockerRule.getKind(); + String containerName = "containerulimit"; Ulimit[] ulimits = {new Ulimit("nproc", 709, 1026), new Ulimit("nofile", 1024, 4096)}; CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) @@ -833,7 +844,7 @@ public void createContainerWithULimits() throws DockerException { @Test public void createContainerWithIntegerBoundsExceedingULimit() throws DockerException { - String containerName = "containercoreulimit" + dockerRule.getKind(); + String containerName = "containercoreulimit"; Ulimit[] ulimits = {new Ulimit("core", 99999999998L, 99999999999L)}; CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) @@ -954,6 +965,8 @@ public void onNext(Frame item) { @Test public void createContainerWithCgroupParent() throws DockerException { + assumeThat(!SystemUtils.IS_OS_LINUX, is(true)); + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") .withHostConfig(newHostConfig() .withCgroupParent("/parent")) @@ -1065,4 +1078,99 @@ public void createContainerWithTmpFs() throws DockerException { InspectContainerResponse inspectContainerResponse = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); assertThat(inspectContainerResponse.getHostConfig().getTmpFs().get("/tmp"), equalTo("rw,noexec,nosuid,size=50m")); } + + @Test + public void createContainerWithNanoCPUs() throws DockerException { + Long nanoCPUs = 1000000000L; + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) + .withCmd("sleep", "9999") + .withHostConfig(newHostConfig() + .withNanoCPUs(nanoCPUs)) + .exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(is(emptyString()))); + + InspectContainerResponse inspectContainerResponse = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getNanoCPUs(), is(nanoCPUs)); + } + + @Test + public void overrideHostConfigWithRawValues() { + HostConfig hostConfig = new HostConfig() + .withNanoCPUs(1_000_000_000L); + + DockerObjectAccessor.overrideRawValue( + hostConfig, + "NanoCPUs", + 500_000_000L + ); + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) + .withCmd("sleep", "9999") + .withHostConfig(hostConfig) + .exec(); + + LOG.info("Created container {}", container.toString()); + + InspectContainerResponse inspectContainerResponse = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getNanoCPUs(), is(500_000_000L)); + } + + @Test + public void shouldNotEncodeAuth() { + CreateContainerCmd cmd = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) + .withAuthConfig(new AuthConfig().withEmail("test@test.com")) + .withCmd("sleep", "9999"); + + ObjectMapper objectMapper = dockerRule.getConfig().getObjectMapper(); + + ObjectNode jsonNode = objectMapper.valueToTree(cmd); + + assertThat(jsonNode.get("authConfig"), nullValue()); + } + + @Test + public void shouldHandleANetworkAliasWithoutACustomNetworkGracefully() { + // Should not throw + dockerRule.getClient() + .createContainerCmd(DEFAULT_IMAGE) + .withAliases("hello-world") + .withHostConfig(newHostConfig()) + .withCmd("sleep", "9999") + .exec(); + } + + @Test + public void createContainerWithAnnotations() throws DockerException { + DefaultDockerClientConfig forcedConfig = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withApiVersion(VERSION_1_44) + .withRegistryUrl("https://index.docker.io/v1/") + .build(); + + DockerClient forcedClient = CmdIT.createDockerClient(forcedConfig); + Map annotations = new HashMap<>(); + annotations.put("com.example.key1", "value1"); + annotations.put("com.example.key2", "value2"); + + CreateContainerResponse container = forcedClient.createContainerCmd(DEFAULT_IMAGE) + .withCmd("sleep", "9999") + .withHostConfig(newHostConfig() + .withAnnotations(annotations)) + .exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(is(emptyString()))); + + InspectContainerResponse inspectContainerResponse = forcedClient.inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getAnnotations(), equalTo(annotations)); + assertThat(inspectContainerResponse.getHostConfig().getAnnotations().get("com.example.key1"), equalTo("value1")); + assertThat(inspectContainerResponse.getHostConfig().getAnnotations().get("com.example.key2"), equalTo("value2")); + } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CreateNetworkCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CreateNetworkCmdIT.java index 36776bdb1..d60425a2a 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/CreateNetworkCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CreateNetworkCmdIT.java @@ -15,9 +15,11 @@ import static com.github.dockerjava.junit.DockerMatchers.isGreaterOrEqual; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeThat; @@ -28,7 +30,7 @@ public class CreateNetworkCmdIT extends CmdIT { public void createNetwork() throws DockerException { assumeNotSwarm("no network in swarm", dockerRule); - String networkName = "createNetwork" + dockerRule.getKind(); + String networkName = "createNetwork"; CreateNetworkResponse createNetworkResponse = dockerRule.getClient().createNetworkCmd().withName(networkName).exec(); @@ -37,14 +39,15 @@ public void createNetwork() throws DockerException { Network network = dockerRule.getClient().inspectNetworkCmd().withNetworkId(createNetworkResponse.getId()).exec(); assertThat(network.getName(), is(networkName)); assertThat(network.getDriver(), is("bridge")); + assertThat(network.getCreated().getTime(), greaterThan(0L)); } @Test public void createNetworkWithIpamConfig() throws DockerException { assumeNotSwarm("no network in swarm", dockerRule); - String networkName = "networkIpam" + dockerRule.getKind(); - String subnet = "10.67." + (79 + getFactoryType().ordinal()) + ".0/24"; + String networkName = "networkIpam"; + String subnet = "10.67.79.0/24"; Network.Ipam ipam = new Network.Ipam().withConfig(new Network.Ipam.Config().withSubnet(subnet)); CreateNetworkResponse createNetworkResponse = dockerRule.getClient().createNetworkCmd().withName(networkName).withIpam(ipam).exec(); @@ -52,7 +55,7 @@ public void createNetworkWithIpamConfig() throws DockerException { assertNotNull(createNetworkResponse.getId()); Network network = dockerRule.getClient().inspectNetworkCmd().withNetworkId(createNetworkResponse.getId()).exec(); - assertEquals(network.getName(), networkName); + assertEquals(networkName, network.getName()); assertEquals("bridge", network.getDriver()); assertEquals(subnet, network.getIpam().getConfig().iterator().next().getSubnet()); } @@ -61,7 +64,7 @@ public void createNetworkWithIpamConfig() throws DockerException { public void createAttachableNetwork() throws DockerException { assumeThat("API version should be > 1.24", dockerRule, isGreaterOrEqual(VERSION_1_25)); - String networkName = "createAttachableNetwork" + dockerRule.getKind(); + String networkName = "createAttachableNetwork"; CreateNetworkResponse createNetworkResponse = dockerRule.getClient().createNetworkCmd() .withName(networkName) .withAttachable(true) @@ -77,12 +80,12 @@ public void createNetworkWithLabel() throws DockerException { assumeNotSwarm("no network in swarm?", dockerRule); assumeThat("API version should be >= 1.21", dockerRule, isGreaterOrEqual(VERSION_1_21)); - String networkName = "createNetworkWithLabel" + dockerRule.getKind(); + String networkName = "createNetworkWithLabel"; Map labels = new HashMap<>(); - labels.put("com.example.usage" + dockerRule.getKind(), "test"); + labels.put("com.example.usage", "test"); CreateNetworkResponse createNetworkResponse = dockerRule.getClient().createNetworkCmd().withName(networkName).withLabels(labels).exec(); assertNotNull(createNetworkResponse.getId()); Network network = dockerRule.getClient().inspectNetworkCmd().withNetworkId(createNetworkResponse.getId()).exec(); - assertEquals(network.getLabels(), labels); + assertEquals(labels, network.getLabels()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/CustomCommandIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/CustomCommandIT.java new file mode 100644 index 000000000..bf273a98c --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/CustomCommandIT.java @@ -0,0 +1,34 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.core.DockerRule; +import com.github.dockerjava.transport.DockerHttpClient; +import com.github.dockerjava.transport.DockerHttpClient.Request; +import com.github.dockerjava.transport.DockerHttpClient.Response; +import org.apache.commons.io.IOUtils; +import org.junit.Assume; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class CustomCommandIT extends CmdIT { + + @Test + public void testCustomCommand() throws Exception { + DockerHttpClient httpClient = CmdIT.createDockerHttpClient(DockerRule.config(null)); + + Assume.assumeNotNull(httpClient); + + Request request = Request.builder() + .method(Request.Method.GET) + .path("/_ping") + .build(); + + try (Response response = httpClient.execute(request)) { + assertThat(response.getStatusCode(), equalTo(200)); + assertThat(IOUtils.toString(response.getBody(), StandardCharsets.UTF_8), equalTo("OK")); + } + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/DisconnectFromNetworkCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/DisconnectFromNetworkCmdIT.java index 3c9451545..2d932cc24 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/DisconnectFromNetworkCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/DisconnectFromNetworkCmdIT.java @@ -13,13 +13,13 @@ public class DisconnectFromNetworkCmdIT extends CmdIT { @Test - public void disconnectFromNetwork() throws InterruptedException { + public void disconnectFromNetwork() { assumeNotSwarm("no network in swarm", dockerRule); CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withCmd("sleep", "9999").exec(); dockerRule.getClient().startContainerCmd(container.getId()).exec(); - CreateNetworkResponse network = dockerRule.getClient().createNetworkCmd().withName("disconnectNetwork" + dockerRule.getKind()).exec(); + CreateNetworkResponse network = dockerRule.getClient().createNetworkCmd().withName("disconnectNetwork").exec(); dockerRule.getClient().connectToNetworkCmd().withNetworkId(network.getId()).withContainerId(container.getId()).exec(); @@ -35,14 +35,14 @@ public void disconnectFromNetwork() throws InterruptedException { } @Test - public void forceDisconnectFromNetwork() throws InterruptedException { + public void forceDisconnectFromNetwork() { assumeNotSwarm("no network in swarm", dockerRule); - CreateNetworkResponse network = dockerRule.getClient().createNetworkCmd().withName("testNetwork2" + dockerRule.getKind()).exec(); + CreateNetworkResponse network = dockerRule.getClient().createNetworkCmd().withName("testNetwork2").exec(); CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") .withHostConfig(newHostConfig() - .withNetworkMode("testNetwork2" + dockerRule.getKind())) + .withNetworkMode("testNetwork2")) .withCmd("sleep", "9999") .exec(); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/DockerHttpClientLeakDetector.java b/docker-java/src/test/java/com/github/dockerjava/cmd/DockerHttpClientLeakDetector.java new file mode 100644 index 000000000..1da12f3e0 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/DockerHttpClientLeakDetector.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.cmd; + +import org.junit.rules.ExternalResource; + +public class DockerHttpClientLeakDetector extends ExternalResource { + + @Override + protected void before() { + synchronized (TrackingDockerHttpClient.ACTIVE_RESPONSES) { + TrackingDockerHttpClient.ACTIVE_RESPONSES.clear(); + } + } + + @Override + protected void after() { + synchronized (TrackingDockerHttpClient.ACTIVE_RESPONSES) { + if (TrackingDockerHttpClient.ACTIVE_RESPONSES.isEmpty()) { + return; + } + + System.out.println("Leaked responses:"); + IllegalStateException exception = new IllegalStateException("Leaked responses!"); + exception.setStackTrace(new StackTraceElement[0]); + + TrackingDockerHttpClient.ACTIVE_RESPONSES.forEach(response -> { + exception.addSuppressed(response.allocatedAt); + }); + throw exception; + } + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/EventsCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/EventsCmdIT.java index 897c6fd25..2a16e5474 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/EventsCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/EventsCmdIT.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.model.Event; +import com.github.dockerjava.api.model.EventType; import com.github.dockerjava.utils.TestUtils; import org.junit.Test; import org.slf4j.Logger; @@ -10,6 +11,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -113,6 +115,37 @@ public void testEventStreamingWithFilter() throws Exception { } } + @Test + public void testEventStreamingWithEventTypeFilter() throws Exception { + assumeNotSwarm("", dockerRule); + + String startTime = getEpochTime(); + generateEvents(); + String endTime = getEpochTime(); + + for (EventType eventType : EventType.values()) { + List events = new CopyOnWriteArrayList<>(); + try ( + ResultCallback.Adapter eventCallback = dockerRule.getClient().eventsCmd() + .withSince(startTime) + .withUntil(endTime) + .withEventTypeFilter(eventType) + .exec(new ResultCallback.Adapter() { + @Override + public void onNext(Event event) { + events.add(event); + } + }) + ) { + eventCallback.awaitCompletion(30, TimeUnit.SECONDS); + + for (Event event : events) { + assertThat("Received event: " + event, event.getType(), is(eventType)); + } + } + } + } + /** * This method generates some events and returns the number of events being generated */ diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ExecCreateCmdImplIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ExecCreateCmdImplIT.java index 495b8cdb9..2f18d7e85 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/ExecCreateCmdImplIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ExecCreateCmdImplIT.java @@ -8,7 +8,7 @@ import java.security.SecureRandom; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.emptyString; diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ExecStartCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ExecStartCmdIT.java index cf096aa26..fc111f0e2 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/ExecStartCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ExecStartCmdIT.java @@ -4,6 +4,7 @@ import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.core.command.ExecStartResultCallback; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -77,6 +78,7 @@ public void execStartAttached() throws Exception { assertTrue(responseAsString.length() > 0); } + @Ignore @Test(expected = NotFoundException.class) public void execStartWithNonExistentUser() throws Exception { String containerName = "generated_" + new SecureRandom().nextInt(); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/HealthCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/HealthCmdIT.java new file mode 100644 index 000000000..bdca27572 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/HealthCmdIT.java @@ -0,0 +1,88 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.HealthStateLog; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.HealthCheck; +import com.github.dockerjava.core.RemoteApiVersion; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static com.github.dockerjava.junit.DockerMatchers.isGreaterOrEqual; +import static org.awaitility.Awaitility.await; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assume.assumeThat; + +public class HealthCmdIT extends CmdIT { + private final Logger LOG = LoggerFactory.getLogger(HealthCmdIT.class); + + @Test + public void healthiness() { + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") + .withCmd("nc", "-l", "-p", "8080") + .withHealthcheck(new HealthCheck() + .withTest(Arrays.asList("CMD", "sh", "-c", "netstat -ltn | grep 8080")) + .withInterval(TimeUnit.SECONDS.toNanos(1)) + .withTimeout(TimeUnit.MINUTES.toNanos(1)) + .withStartPeriod(TimeUnit.SECONDS.toNanos(30)) + .withRetries(10)) + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(is(emptyString()))); + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + await().atMost(60L, TimeUnit.SECONDS).untilAsserted( + () -> { + InspectContainerResponse inspectContainerResponse = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); + assertThat(inspectContainerResponse.getState().getHealth().getStatus(), is(equalTo("healthy"))); + } + ); + } + + @Test + public void healthiness_startInterval() { + assumeThat("API version should be >= 1.44", dockerRule, isGreaterOrEqual(RemoteApiVersion.VERSION_1_44)); + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") + .withCmd("nc", "-l", "-p", "8080") + .withHealthcheck(new HealthCheck() + .withTest(Arrays.asList("CMD", "sh", "-c", "netstat -ltn | grep 8080")) + .withInterval(TimeUnit.SECONDS.toNanos(5)) + .withTimeout(TimeUnit.MINUTES.toNanos(1)) + .withStartPeriod(TimeUnit.SECONDS.toNanos(2)) + .withStartInterval(TimeUnit.SECONDS.toNanos(1)) + .withRetries(10)) + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(is(emptyString()))); + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + await().atMost(60L, TimeUnit.SECONDS).untilAsserted( + () -> { + InspectContainerResponse inspectContainerResponse = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); + List healthStateLogs = inspectContainerResponse.getState().getHealth().getLog(); + assertThat(healthStateLogs.size(), is(greaterThanOrEqualTo(2))); + healthStateLogs.forEach(log -> LOG.info("Health log: {}", log.getStart())); + HealthStateLog log1 = healthStateLogs.get(healthStateLogs.size() - 1); + HealthStateLog log2 = healthStateLogs.get(healthStateLogs.size() - 2); + long diff = ChronoUnit.NANOS.between(ZonedDateTime.parse(log2.getStart()), ZonedDateTime.parse(log1.getStart())); + assertThat(diff, is(greaterThanOrEqualTo(inspectContainerResponse.getConfig().getHealthcheck().getInterval()))); + } + ); + } + +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ImageHistoryCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ImageHistoryCmdIT.java new file mode 100644 index 000000000..16ae7e6a2 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ImageHistoryCmdIT.java @@ -0,0 +1,29 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.api.model.ImageHistory; +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; + +public class ImageHistoryCmdIT extends CmdIT { + + @Test + public void imageHistory() { + List history = dockerRule.getClient().imageHistoryCmd("busybox").exec(); + + assertThat(history, notNullValue()); + assertThat(history, hasSize(greaterThan(0))); + + ImageHistory entry = history.get(0); + assertThat(entry.getId(), notNullValue()); + assertThat(entry.getCreated(), notNullValue()); + assertThat(entry.getCreatedBy(), notNullValue()); + assertThat(entry.getSize(), notNullValue()); + assertThat(entry.getComment(), notNullValue()); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/InfoCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/InfoCmdIT.java index b4f70fe19..74fc2cbda 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/InfoCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/InfoCmdIT.java @@ -8,7 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static com.github.dockerjava.utils.TestUtils.isNotSwarm; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.greaterThan; @@ -48,6 +48,7 @@ public void infoTest() throws DockerException { assertThat(dockerInfo.getImages(), notNullValue()); assertThat(dockerInfo.getImages(), greaterThan(0)); assertThat(dockerInfo.getDebug(), notNullValue()); + assertThat(dockerInfo.getRuntimes(), notNullValue()); if (isNotSwarm(dockerClient)) { assertThat(dockerInfo.getNFd(), greaterThan(0)); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/InspectContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/InspectContainerCmdIT.java index 25b9aff18..e47a911d7 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/InspectContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/InspectContainerCmdIT.java @@ -6,6 +6,7 @@ import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Container; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,7 +46,7 @@ public void inspectContainer() throws DockerException { assertThat(container.getId(), not(is(emptyString()))); InspectContainerResponse containerInfo = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); - assertEquals(containerInfo.getId(), container.getId()); + assertEquals(container.getId(), containerInfo.getId()); } @@ -100,7 +101,9 @@ public void inspectContainerWithSize() throws DockerException { // TODO check swarm if (isNotSwarm(dockerRule.getClient())) { assertNotNull(containerInfo.getSizeRootFs()); - assertTrue(containerInfo.getSizeRootFs().intValue() > 0); + assertTrue(containerInfo.getSizeRootFs() > 0L); + assertNotNull(containerInfo.getSizeRw()); + assertEquals(4096, containerInfo.getSizeRw().longValue()); } } @@ -125,6 +128,7 @@ public void inspectContainerRestartCount() throws DockerException { } @Test + @Ignore public void inspectContainerNetworkSettings() throws DockerException { CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") @@ -138,4 +142,19 @@ public void inspectContainerNetworkSettings() throws DockerException { assertFalse(inspectContainerResponse.getNetworkSettings().getHairpinMode()); } + + @Test + public void inspectContainerNanoCPUs() throws DockerException { + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") + .withCmd("env").exec(); + + LOG.info("Created container {}", container.toString()); + + assertThat(container.getId(), not(is(emptyString()))); + + InspectContainerResponse inspectContainerResponse = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); + + assertThat(inspectContainerResponse.getHostConfig().getNanoCPUs(), is(0L)); + } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/InspectExecCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/InspectExecCmdIT.java index 3f22fca33..b256c6a7c 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/InspectExecCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/InspectExecCmdIT.java @@ -79,7 +79,7 @@ public void inspectExec() throws Exception { } @Test - public void inspectExecNetworkSettings() throws IOException { + public void inspectExecNetworkSettings() { final RemoteApiVersion apiVersion = getVersion(dockerRule.getClient()); String containerName = "generated_" + new SecureRandom().nextInt(); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/InspectNetworkCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/InspectNetworkCmdIT.java index eca86497d..035d3d767 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/InspectNetworkCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/InspectNetworkCmdIT.java @@ -10,6 +10,7 @@ import static com.github.dockerjava.utils.TestUtils.findNetwork; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; public class InspectNetworkCmdIT extends CmdIT { @@ -28,5 +29,6 @@ public void inspectNetwork() throws DockerException { assertThat(network.getDriver(), equalTo(expected.getDriver())); assertThat(network.getIpam().getConfig().get(0).getSubnet(), equalTo(expected.getIpam().getConfig().get(0).getSubnet())); assertThat(network.getIpam().getDriver(), equalTo(expected.getIpam().getDriver())); + assertThat(network.getCreated().getTime(), greaterThan(0L)); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ListContainersCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ListContainersCmdIT.java index 9ada9d7ad..3490924c7 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/ListContainersCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ListContainersCmdIT.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.TimeUnit; import static ch.lambdaj.Lambda.filter; import static com.github.dockerjava.api.model.HostConfig.newHostConfig; @@ -25,11 +26,12 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.emptyString; -import static org.hamcrest.Matchers.isOneOf; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.oneOf; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertEquals; import static org.testinfected.hamcrest.jpa.PersistenceMatchers.hasField; @@ -59,7 +61,7 @@ public void tearDown() { } @Test - public void testListContainers() throws Exception { + public void testListContainers() { List containers = dockerRule.getClient().listContainersCmd() .withLabelFilter(testLabel) .withShowAll(true) @@ -106,7 +108,7 @@ public void testListContainers() throws Exception { } @Test - public void testListContainersWithLabelsFilter() throws Exception { + public void testListContainersWithLabelsFilter() { // list with filter by Map label dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE).withCmd("echo") .withLabels(testLabel) @@ -138,7 +140,7 @@ public void testListContainersWithLabelsFilter() throws Exception { } @Test - public void testNameFilter() throws Exception { + public void testNameFilter() { String testUUID = testLabel.get("test"); String id1, id2; @@ -160,12 +162,12 @@ public void testNameFilter() throws Exception { .exec(); assertThat(filteredContainers.size(), is(2)); - assertThat(filteredContainers.get(0).getId(), isOneOf(id1, id2)); - assertThat(filteredContainers.get(1).getId(), isOneOf(id1, id2)); + assertThat(filteredContainers.get(0).getId(), is(oneOf(id1, id2))); + assertThat(filteredContainers.get(1).getId(), is(oneOf(id1, id2))); } @Test - public void testIdsFilter() throws Exception { + public void testIdsFilter() { String id1, id2; id1 = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) .withLabels(testLabel) @@ -183,21 +185,13 @@ public void testIdsFilter() throws Exception { .exec(); assertThat(filteredContainers.size(), is(2)); - assertThat(filteredContainers.get(0).getId(), isOneOf(id1, id2)); - assertThat(filteredContainers.get(1).getId(), isOneOf(id1, id2)); + assertThat(filteredContainers.get(0).getId(), is(oneOf(id1, id2))); + assertThat(filteredContainers.get(1).getId(), is(oneOf(id1, id2))); } @Test - public void testStatusFilter() throws Exception { - String id1, id2; - id1 = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) - .withCmd("sh", "-c", "sleep 99999") - .withLabels(testLabel) - .exec() - .getId(); - - id2 = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) - .withCmd("sh", "-c", "sleep 99999") + public void shouldFilterByCreatedStatus() { + String containerId = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) .withLabels(testLabel) .exec() .getId(); @@ -208,46 +202,71 @@ public void testStatusFilter() throws Exception { .withStatusFilter(singletonList("created")) .exec(); - assertThat(filteredContainers.size(), is(2)); - assertThat(filteredContainers.get(1).getId(), isOneOf(id1, id2)); + assertThat(filteredContainers.size(), is(1)); + assertThat(filteredContainers.get(0).getId(), is(containerId)); + } - dockerRule.getClient().startContainerCmd(id1).exec(); + @Test + public void shouldFilterByRunningStatus() { + String containerId = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) + .withLabels(testLabel) + .exec() + .getId(); + dockerRule.getClient().startContainerCmd(containerId).exec(); - filteredContainers = dockerRule.getClient().listContainersCmd() + List filteredContainers = dockerRule.getClient().listContainersCmd() .withShowAll(true) .withLabelFilter(testLabel) .withStatusFilter(singletonList("running")) .exec(); - assertThat(filteredContainers.size(), is(1)); - assertThat(filteredContainers.get(0).getId(), is(id1)); + assertThat(filteredContainers, hasSize(1)); + assertThat(filteredContainers.get(0).getId(), is(containerId)); + } - dockerRule.getClient().pauseContainerCmd(id1).exec(); + @Test + public void shouldFilterByPausedStatus() { + String containerId = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) + .withCmd("sh", "-c", "sleep 99999") + .withLabels(testLabel) + .exec() + .getId(); + dockerRule.getClient().startContainerCmd(containerId).exec(); + dockerRule.getClient().pauseContainerCmd(containerId).exec(); - filteredContainers = dockerRule.getClient().listContainersCmd() + List filteredContainers = dockerRule.getClient().listContainersCmd() .withShowAll(true) .withLabelFilter(testLabel) .withStatusFilter(singletonList("paused")) .exec(); - assertThat(filteredContainers.size(), is(1)); - assertThat(filteredContainers.get(0).getId(), is(id1)); + assertThat(filteredContainers, hasSize(1)); + assertThat(filteredContainers.get(0).getId(), is(containerId)); + } - dockerRule.getClient().unpauseContainerCmd(id1).exec(); - dockerRule.getClient().stopContainerCmd(id1).exec(); + @Test + public void shouldFilterByExitedStatus() throws InterruptedException { + String containerId = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) + .withCmd("sh", "-c", "sleep 99999") + .withLabels(testLabel) + .exec() + .getId(); + dockerRule.getClient().startContainerCmd(containerId).exec(); + dockerRule.getClient().stopContainerCmd(containerId).exec(); + dockerRule.getClient().waitContainerCmd(containerId).start().awaitCompletion(15, TimeUnit.SECONDS); - filteredContainers = dockerRule.getClient().listContainersCmd() + List filteredContainers = dockerRule.getClient().listContainersCmd() .withShowAll(true) .withLabelFilter(testLabel) .withStatusFilter(singletonList("exited")) .exec(); - assertThat(filteredContainers.size(), is(1)); - assertThat(filteredContainers.get(0).getId(), is(id1)); + assertThat(filteredContainers, hasSize(1)); + assertThat(filteredContainers.get(0).getId(), is(containerId)); } @Test - public void testVolumeFilter() throws Exception { + public void testVolumeFilter() { String id; dockerRule.getClient().createVolumeCmd() .withName("TestFilterVolume") @@ -271,12 +290,12 @@ public void testVolumeFilter() throws Exception { .withVolumeFilter(singletonList("TestFilterVolume")) .exec(); - assertThat(filteredContainers.size(), is(1)); + assertThat(filteredContainers, hasSize(1)); assertThat(filteredContainers.get(0).getId(), is(id)); } @Test - public void testNetworkFilter() throws Exception { + public void testNetworkFilter() { String id; dockerRule.getClient().createNetworkCmd() .withName("TestFilterNetwork") @@ -311,11 +330,11 @@ public void testAncestorFilter() throws Exception { DockerAssume.assumeNotSwarm(dockerRule.getClient()); dockerRule.getClient().pullImageCmd("busybox") - .withTag("1.24") + .withTag("1.35") .start() .awaitCompletion(); - dockerRule.getClient().createContainerCmd("busybox:1.24") + dockerRule.getClient().createContainerCmd("busybox:1.35") .withLabels(testLabel) .exec(); @@ -337,7 +356,7 @@ public void testAncestorFilter() throws Exception { } @Test - public void testExitedFilter() throws Exception { + public void testExitedFilter() { dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) .withLabels(testLabel) .exec(); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ListImagesCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ListImagesCmdIT.java index c89b98a0a..67ba85672 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/ListImagesCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ListImagesCmdIT.java @@ -4,10 +4,12 @@ import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.Image; import com.github.dockerjava.api.model.Info; +import org.apache.commons.lang3.RandomUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.List; import static com.github.dockerjava.utils.TestUtils.isNotSwarm; @@ -15,6 +17,7 @@ import static org.hamcrest.Matchers.emptyArray; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.not; @@ -37,9 +40,9 @@ public void listImages() throws DockerException { Image img = images.get(0); assertThat(img.getCreated(), is(greaterThan(0L))); - assertThat(img.getVirtualSize(), is(greaterThan(0L))); + assertThat(img.getSize(), is(greaterThan(0L))); assertThat(img.getId(), not(is(emptyString()))); - assertThat(img.getRepoTags(), not(emptyArray())); + assertThat(img.getRepoTags(), emptyArray()); } @Test @@ -54,6 +57,36 @@ public void listImagesWithDanglingFilter() throws DockerException { assertTrue(imageInFilteredList); } + @Test + public void listImagesWithReferenceFilter() throws DockerException { + String tag = "" + RandomUtils.nextInt(0, Integer.MAX_VALUE); + + dockerRule.getClient().tagImageCmd("busybox:latest", "docker-java/busybox", tag).exec(); + try { + List images = dockerRule.getClient().listImagesCmd().withReferenceFilter("docker-java/busybox") + .exec(); + assertThat(images, hasSize(1)); + } + finally { + dockerRule.getClient().removeImageCmd("docker-java/busybox:" + tag).exec(); + } + } + + @Test + public void listImagesWithFilter() throws DockerException { + String tag = "" + RandomUtils.nextInt(0, Integer.MAX_VALUE); + + dockerRule.getClient().tagImageCmd("busybox:latest", "docker-java/busybox", tag).exec(); + try { + List images = dockerRule.getClient().listImagesCmd().withFilter("reference", Collections.singletonList("docker-java/busybox")) + .exec(); + assertThat(images, hasSize(1)); + } + finally { + dockerRule.getClient().removeImageCmd("docker-java/busybox:" + tag).exec(); + } + } + private boolean isImageInFilteredList(List images, String expectedImageId) { for (Image image : images) { if (expectedImageId.equals(image.getId())) { diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/LoadImageCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/LoadImageCmdIT.java index 5734163f9..36a8d51fc 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/LoadImageCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/LoadImageCmdIT.java @@ -1,5 +1,6 @@ package com.github.dockerjava.cmd; +import com.github.dockerjava.api.command.LoadImageCallback; import com.github.dockerjava.api.model.Image; import com.github.dockerjava.utils.TestResources; import net.jcip.annotations.NotThreadSafe; @@ -24,7 +25,7 @@ public class LoadImageCmdIT extends CmdIT { @Before public void beforeMethod() { - expectedImageId = "sha256:56031f66eb0cef2e2e5cb2d1dabafaa0ebcd0a18a507d313b5bdb8c0472c5eba"; + expectedImageId = "sha256:28a8ed28c8b7bd9d7fc00f22ac7df6d385436b93e88ac978943f3dba06d836b4"; if (findImageWithId(expectedImageId, dockerRule.getClient().listImagesCmd().exec()) != null) { dockerRule.getClient().removeImageCmd(expectedImageId).exec(); } @@ -53,6 +54,19 @@ public void loadImageFromTar() throws Exception { asList(image.getRepoTags()), equalTo(singletonList("docker-java/load:1.0"))); } + @Test + public void loadImageFromTarAsync() throws Exception { + try (InputStream uploadStream = Files.newInputStream(TestResources.getApiImagesLoadTestTarball())) { + dockerRule.getClient().loadImageAsyncCmd(uploadStream).exec(new LoadImageCallback()).awaitMessage(); + } + + final Image image = findImageWithId(expectedImageId, dockerRule.getClient().listImagesCmd().exec()); + + assertThat("Can't find expected image after loading from a tar archive!", image, notNullValue()); + assertThat("Image after loading from a tar archive has wrong tags!", + asList(image.getRepoTags()), equalTo(singletonList("docker-java/load:1.0"))); + } + private Image findImageWithId(final String id, final List images) { for (Image image : images) { if (id.equals(image.getId())) { diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/LogContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/LogContainerCmdIT.java index 37bf5f393..8593d6ccf 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/LogContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/LogContainerCmdIT.java @@ -1,7 +1,10 @@ package com.github.dockerjava.cmd; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.api.model.StreamType; import com.github.dockerjava.utils.LogContainerTestCallback; import org.junit.Test; @@ -9,13 +12,25 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.LongStream; +import static org.awaitility.Awaitility.await; +import static org.hamcrest.CoreMatchers.everyItem; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -51,7 +66,7 @@ public void asyncLogContainerWithTtyEnabled() throws Exception { assertTrue(loggingCallback.toString().contains("hello")); - assertEquals(loggingCallback.getCollectedFrames().get(0).getStreamType(), StreamType.RAW); + assertEquals(StreamType.RAW, loggingCallback.getCollectedFrames().get(0).getStreamType()); } @Test @@ -191,10 +206,59 @@ public void asyncLogContainerWithSince() throws Exception { .withStdErr(true) .withStdOut(true) .withSince(timestamp) + .withUntil(timestamp + 1000) .exec(loggingCallback); loggingCallback.awaitCompletion(); assertThat(loggingCallback.toString(), containsString(snippet)); } + + @Test(timeout = 10_000) + public void simultaneousCommands() throws Exception { + // Create a new client to not affect other tests + DockerClient client = dockerRule.newClient(); + CreateContainerResponse container = client.createContainerCmd("busybox") + .withCmd("/bin/sh", "-c", "echo hello world; sleep infinity") + .exec(); + + client.startContainerCmd(container.getId()).exec(); + + // Simulate 100 simultaneous connections + int connections = 100; + + ExecutorService executor = Executors.newFixedThreadPool(connections); + try { + List firstFrames = new CopyOnWriteArrayList<>(); + executor.invokeAll( + LongStream.range(0, connections).>mapToObj(__ -> { + return () -> { + return client.logContainerCmd(container.getId()) + .withStdOut(true) + .withFollowStream(true) + .exec(new ResultCallback.Adapter() { + + final AtomicBoolean first = new AtomicBoolean(true); + + @Override + public void onNext(Frame object) { + if (first.compareAndSet(true, false)) { + firstFrames.add(object); + } + super.onNext(object); + } + }); + }; + }).collect(Collectors.toList()) + ); + + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(firstFrames, hasSize(connections)); + }); + + assertThat(firstFrames, everyItem(hasToString("STDOUT: hello world"))); + } finally { + executor.shutdownNow(); + } + } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/PullImageCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/PullImageCmdIT.java index 539a2b606..3b8dde3ff 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/PullImageCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/PullImageCmdIT.java @@ -45,7 +45,7 @@ public void testPullImage() throws Exception { // pulled down, preferably small in size. If tag is not used pull will // download all images in that repository but tmpImgs will only // deleted 'latest' image but not images with other tags - String testImage = "hackmann/empty"; + String testImage = "alpine:3.17"; LOG.info("Removing image: {}", testImage); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/PushImageCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/PushImageCmdIT.java index 438748cc0..00cd11d51 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/PushImageCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/PushImageCmdIT.java @@ -14,6 +14,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.UUID; import java.util.concurrent.TimeUnit; import static com.github.dockerjava.utils.TestUtils.getVersion; @@ -30,15 +31,12 @@ public class PushImageCmdIT extends CmdIT { @ClassRule public static PrivateRegistryRule REGISTRY = new PrivateRegistryRule(); - private String username; - @Rule public ExpectedException exception = ExpectedException.none(); private AuthConfig authConfig; @Before - public void beforeTest() throws Exception { - username = dockerRule.getClient().authConfig().getUsername(); + public void beforeTest() { authConfig = REGISTRY.getAuthConfig(); } @@ -50,7 +48,7 @@ public void pushLatest() throws Exception { assertThat(container.getId(), not(is(emptyString()))); LOG.info("Committing container: {}", container.toString()); - String imgName = authConfig.getRegistryAddress() + "/" + dockerRule.getKind() + "-push-latest"; + String imgName = authConfig.getRegistryAddress() + "/push-latest"; String imageId = dockerRule.getClient().commitCmd(container.getId()) .withRepository(imgName) .exec(); @@ -81,7 +79,7 @@ public void pushNonExistentImage() throws Exception { exception.expect(NotFoundException.class); } - dockerRule.getClient().pushImageCmd(username + "/xxx") + dockerRule.getClient().pushImageCmd(UUID.randomUUID().toString().replace("-", "")) .start() .awaitCompletion(30, TimeUnit.SECONDS); // exclude infinite await sleep diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveContainerCmdImplIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveContainerCmdImplIT.java index 01dfd954c..408098148 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveContainerCmdImplIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveContainerCmdImplIT.java @@ -23,7 +23,7 @@ public class RemoveContainerCmdImplIT extends CmdIT { @Test - public void removeContainer() throws Exception { + public void removeContainer() { CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withCmd("true").exec(); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveImageCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveImageCmdIT.java index c072eaf90..00d2e6cc1 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveImageCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveImageCmdIT.java @@ -24,7 +24,7 @@ public class RemoveImageCmdIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(RemoveImageCmdIT.class); @Test - public void removeImage() throws DockerException, InterruptedException { + public void removeImage() throws DockerException { CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withCmd("sleep", "9999").exec(); LOG.info("Created container: {}", container.toString()); @@ -47,7 +47,7 @@ public void removeImage() throws DockerException, InterruptedException { } @Test(expected = NotFoundException.class) - public void removeNonExistingImage() throws DockerException, InterruptedException { + public void removeNonExistingImage() throws DockerException { dockerRule.getClient().removeImageCmd("non-existing").exec(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveVolumeCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveVolumeCmdIT.java index 76037e1e3..6d0fdf981 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveVolumeCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/RemoveVolumeCmdIT.java @@ -17,7 +17,7 @@ public class RemoveVolumeCmdIT extends CmdIT { @Test(expected = NotFoundException.class) public void removeVolume() throws DockerException { - String volumeName = "volume1" + dockerRule.getKind(); + String volumeName = "volume1"; CreateVolumeResponse createVolumeResponse = dockerRule.getClient().createVolumeCmd() .withName(volumeName) diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/RenameContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/RenameContainerCmdIT.java index fed3920b7..c50ebcf43 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/RenameContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/RenameContainerCmdIT.java @@ -31,7 +31,7 @@ public void renameContainer() throws DockerException { String name1 = inspectContainerResponse.getName(); dockerRule.getClient().renameContainerCmd(container.getId()) - .withName(dockerRule.getKind() + "renameContainer") + .withName("renameContainer") .exec(); InspectContainerResponse inspectContainerResponse2 = dockerRule.getClient().inspectContainerCmd(container.getId()).exec(); @@ -45,9 +45,9 @@ public void renameContainer() throws DockerException { } @Test(expected = NotFoundException.class) - public void renameExistingContainer() throws DockerException, InterruptedException { + public void renameExistingContainer() throws DockerException { dockerRule.getClient().renameContainerCmd("non-existing") - .withName(dockerRule.getKind() + "renameExistingContainer") + .withName("renameExistingContainer") .exec(); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeContainerCmdIT.java new file mode 100644 index 000000000..eeb79b2ff --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeContainerCmdIT.java @@ -0,0 +1,39 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.SecureRandom; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class ResizeContainerCmdIT extends CmdIT { + private static final Logger LOG = LoggerFactory.getLogger(ResizeContainerCmdIT.class); + + private static final int TTY_HEIGHT = 30; + private static final int TTY_WIDTH = 120; + + @Test + public void resizeContainerTtyTest() { + String containerName = "generated_" + new SecureRandom().nextInt(); + + // wait until tty size changed to target size + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withUser("root") + .withCmd("sh", "-c", String.format("until stty size | grep '%d %d'; do : ; done", TTY_HEIGHT, TTY_WIDTH)) + .withName(containerName).withTty(true).withStdinOpen(true).exec(); + + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + dockerRule.getClient().resizeContainerCmd(container.getId()).withSize(TTY_HEIGHT, TTY_WIDTH).exec(); + + int exitCode = dockerRule.getClient().waitContainerCmd(container.getId()).start() + .awaitStatusCode(10, TimeUnit.SECONDS); + + LOG.info("Container exit code: {}", exitCode); + + assertThat(exitCode, equalTo(0)); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeExecCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeExecCmdIT.java new file mode 100644 index 000000000..9e5c9b65f --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/ResizeExecCmdIT.java @@ -0,0 +1,48 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.SecureRandom; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + + +public class ResizeExecCmdIT extends CmdIT { + private static final Logger LOG = LoggerFactory.getLogger(ResizeExecCmdIT.class); + + private static final int TTY_HEIGHT = 30; + private static final int TTY_WIDTH = 120; + + @Test + public void resizeExecInstanceTtyTest() throws Exception { + String containerName = "generated_" + new SecureRandom().nextInt(); + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withUser("root") + .withCmd("sleep", "9999").withName(containerName).exec(); + + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + // wait until tty size changed to target size + ExecCreateCmdResponse execCreateCmdResponse = dockerRule.getClient().execCreateCmd(container.getId()).withTty(true) + .withAttachStdout(true).withAttachStderr(true) + .withCmd("sh", "-c", String.format("until stty size | grep '%d %d'; do : ; done", TTY_HEIGHT, TTY_WIDTH)).exec(); + + final ExecStartResultCallback execStartResultCallback = new ExecStartResultCallback(System.out, System.err); + + dockerRule.getClient().execStartCmd(execCreateCmdResponse.getId()).exec(execStartResultCallback).awaitStarted(); + + dockerRule.getClient().resizeExecCmd(execCreateCmdResponse.getId()).withSize(TTY_HEIGHT, TTY_WIDTH).exec(); + + // time out, exec instance resize failed + boolean waitResult = execStartResultCallback.awaitCompletion(10, TimeUnit.SECONDS); + + assertThat(waitResult, equalTo(true)); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/RestartContainerCmdImplIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/RestartContainerCmdImplIT.java index cf2f43e92..592c9c650 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/RestartContainerCmdImplIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/RestartContainerCmdImplIT.java @@ -1,18 +1,24 @@ package com.github.dockerjava.cmd; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.RemoteApiVersion; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.junit.DockerMatchers.isGreaterOrEqual; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.not; +import static org.junit.Assume.assumeThat; public class RestartContainerCmdImplIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(RestartContainerCmdImplIT.class); @@ -44,8 +50,43 @@ public void restartContainer() throws DockerException { dockerRule.getClient().killContainerCmd(container.getId()).exec(); } + @Test + public void restartContainerWithSignal() throws Exception { + assumeThat("API version should be >= 1.42", dockerRule, isGreaterOrEqual(RemoteApiVersion.VERSION_1_42)); + + DefaultDockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withApiVersion(RemoteApiVersion.VERSION_1_44) + .withRegistryUrl("https://index.docker.io/v1/") + .build(); + try (DockerClient dockerClient = createDockerClient(dockerClientConfig)) { + String expectedUserSignal = "10"; + String initialCommandWithTrap = "trap 'echo \"exit trapped\"' %s; while :; do sleep 1; done"; + final String containerId = dockerClient + .createContainerCmd(DEFAULT_IMAGE) + .withCmd( + "/bin/sh", + "-c", + String.format(initialCommandWithTrap, expectedUserSignal)) + .exec() + .getId(); + assertThat(containerId, not(is(emptyString()))); + dockerClient.startContainerCmd(containerId).exec(); + + // Restart container without signal + dockerClient.restartContainerCmd(containerId).exec(); + String log = dockerRule.containerLog(containerId); + assertThat(log.trim(), emptyString()); + + dockerClient.restartContainerCmd(containerId).withSignal(expectedUserSignal).exec(); + log = dockerRule.containerLog(containerId); + assertThat(log.trim(), is("exit trapped")); + + dockerClient.removeContainerCmd(containerId).withForce(true).withRemoveVolumes(true).exec(); + } + } + @Test(expected = NotFoundException.class) - public void restartNonExistingContainer() throws DockerException, InterruptedException { + public void restartNonExistingContainer() throws DockerException { dockerRule.getClient().restartContainerCmd("non-existing").exec(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImageCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImageCmdIT.java index ab2f3aca9..cb5a4666c 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImageCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImageCmdIT.java @@ -16,13 +16,19 @@ public class SaveImageCmdIT extends CmdIT { @Test public void saveImage() throws Exception { - InputStream image = IOUtils.toBufferedInputStream(dockerRule.getClient().saveImageCmd("busybox").exec()); - assertThat(image.read(), not(-1)); - - InputStream image2 = IOUtils.toBufferedInputStream(dockerRule.getClient().saveImageCmd("busybox").withTag("latest").exec()); - assertThat(image2.read(), not(-1)); - - + try ( + InputStream inputStream = dockerRule.getClient().saveImageCmd("busybox").exec(); + InputStream image = IOUtils.toBufferedInputStream(inputStream) + ) { + assertThat(image.read(), not(-1)); + } + + try ( + InputStream inputStream = dockerRule.getClient().saveImageCmd("busybox").withTag("latest").exec(); + InputStream image2 = IOUtils.toBufferedInputStream(inputStream) + ) { + assertThat(image2.read(), not(-1)); + } } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImagesCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImagesCmdIT.java index 2b5305d68..86b246029 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImagesCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/SaveImagesCmdIT.java @@ -15,7 +15,10 @@ public class SaveImagesCmdIT extends CmdIT { @Test public void saveNoImages() throws Exception { - try(final InputStream image = IOUtils.toBufferedInputStream(dockerRule.getClient().saveImagesCmd().exec())){ + try ( + InputStream inputStream = dockerRule.getClient().saveImagesCmd().exec(); + InputStream image = IOUtils.toBufferedInputStream(inputStream) + ){ assertThat(image.read(), not(-1)); } @@ -23,8 +26,10 @@ public void saveNoImages() throws Exception { @Test public void saveImagesWithNameAndTag() throws Exception { - - try(final InputStream image = IOUtils.toBufferedInputStream(dockerRule.getClient().saveImagesCmd().withImage("busybox", "latest").exec())) { + try ( + InputStream inputStream = dockerRule.getClient().saveImagesCmd().withImage("busybox", "latest").exec(); + InputStream image = IOUtils.toBufferedInputStream(inputStream) + ) { assertThat(image.read(), not(-1)); } @@ -32,12 +37,14 @@ public void saveImagesWithNameAndTag() throws Exception { @Test public void saveMultipleImages() throws Exception { - - try(final InputStream image = IOUtils.toBufferedInputStream(dockerRule.getClient().saveImagesCmd() - // Not a real life use-case but "busybox" is the only one I dare to assume is really there. - .withImage("busybox", "latest") - .withImage("busybox", "latest") - .exec())) { + try ( + InputStream inputStream = dockerRule.getClient().saveImagesCmd() + // Not a real life use-case but "busybox" is the only one I dare to assume is really there. + .withImage("busybox", "latest") + .withImage("busybox", "latest") + .exec(); + InputStream image = IOUtils.toBufferedInputStream(inputStream) + ) { assertThat(image.read(), not(-1)); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/StartContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/StartContainerCmdIT.java index 76e4fe329..5d41889ca 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/StartContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/StartContainerCmdIT.java @@ -44,7 +44,7 @@ public class StartContainerCmdIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(StartContainerCmdIT.class); @Test - public void startContainerWithVolumes() throws Exception { + public void startContainerWithVolumes() { // see http://docs.docker.io/use/working_with_volumes/ Volume volume1 = new Volume("/opt/webapp1"); @@ -171,7 +171,7 @@ public void startContainerWithDnsSearch() throws DockerException { @Test public void startContainerWithPortBindings() throws DockerException { - int baseport = 20_000 + (getFactoryType().ordinal() * 1000); + int baseport = 20_000; ExposedPort tcp22 = ExposedPort.tcp(22); ExposedPort tcp23 = ExposedPort.tcp(23); @@ -267,8 +267,8 @@ public void startContainerWithConflictingPortBindings() throws DockerException { @Test public void startContainerWithLinkingDeprecated() throws DockerException { - String container1Name = "containerWithLink1" + dockerRule.getKind(); - String container2Name = "containerWithLink2" + dockerRule.getKind(); + String container1Name = "containerWithLink1"; + String container2Name = "containerWithLink2"; dockerRule.ensureContainerRemoved(container1Name); dockerRule.ensureContainerRemoved(container2Name); @@ -328,8 +328,8 @@ public void startContainerWithLinkingDeprecated() throws DockerException { @Test public void startContainerWithLinking() throws DockerException { - String container1Name = "containerWithLinking1" + dockerRule.getKind(); - String container2Name = "containerWithLinking2" + dockerRule.getKind(); + String container1Name = "containerWithLinking1"; + String container2Name = "containerWithLinking2"; dockerRule.ensureContainerRemoved(container1Name); dockerRule.ensureContainerRemoved(container2Name); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/TagImageCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/TagImageCmdIT.java index 88bd28fd4..fc5894455 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/TagImageCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/TagImageCmdIT.java @@ -1,7 +1,7 @@ package com.github.dockerjava.cmd; import com.github.dockerjava.api.exception.NotFoundException; -import org.apache.commons.lang.math.RandomUtils; +import org.apache.commons.lang3.RandomUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,8 +11,8 @@ public class TagImageCmdIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(TagImageCmdIT.class); @Test - public void tagImage() throws Exception { - String tag = "" + RandomUtils.nextInt(Integer.MAX_VALUE); + public void tagImage() { + String tag = "" + RandomUtils.nextInt(0, Integer.MAX_VALUE); dockerRule.getClient().tagImageCmd("busybox:latest", "docker-java/busybox", tag).exec(); @@ -20,9 +20,9 @@ public void tagImage() throws Exception { } @Test(expected = NotFoundException.class) - public void tagNonExistingImage() throws Exception { + public void tagNonExistingImage() { - String tag = "" + RandomUtils.nextInt(Integer.MAX_VALUE); + String tag = "" + RandomUtils.nextInt(0, Integer.MAX_VALUE); dockerRule.getClient().tagImageCmd("non-existing", "docker-java/busybox", tag).exec(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/TrackingDockerHttpClient.java b/docker-java/src/test/java/com/github/dockerjava/cmd/TrackingDockerHttpClient.java new file mode 100644 index 000000000..3c991a8f1 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/TrackingDockerHttpClient.java @@ -0,0 +1,91 @@ +package com.github.dockerjava.cmd; + +import com.github.dockerjava.transport.DockerHttpClient; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +class TrackingDockerHttpClient implements DockerHttpClient { + + static final Set ACTIVE_RESPONSES = Collections.newSetFromMap(new ConcurrentHashMap<>()); + + private final DockerHttpClient delegate; + + TrackingDockerHttpClient(DockerHttpClient delegate) { + this.delegate = delegate; + } + + @Override + public Response execute(Request request) { + return new TrackedResponse(delegate.execute(request)) { + { + synchronized (ACTIVE_RESPONSES) { + ACTIVE_RESPONSES.add(this); + } + } + + @Override + public void close() { + synchronized (ACTIVE_RESPONSES) { + ACTIVE_RESPONSES.remove(this); + } + super.close(); + } + }; + } + + @Override + public void close() throws IOException { + delegate.close(); + } + + static class TrackedResponse implements Response { + + private static class AllocatedAt extends Exception { + public AllocatedAt(String message) { + super(message); + } + } + + final Exception allocatedAt = new AllocatedAt(this.toString()); + + private final Response delegate; + + TrackedResponse(Response delegate) { + this.delegate = delegate; + } + + @Override + public int getStatusCode() { + return delegate.getStatusCode(); + } + + @Override + public Map> getHeaders() { + return delegate.getHeaders(); + } + + @Override + public InputStream getBody() { + return delegate.getBody(); + } + + @Override + public void close() { + delegate.close(); + } + + @Override + @Nullable + public String getHeader(@Nonnull String name) { + return delegate.getHeader(name); + } + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/UpdateContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/UpdateContainerCmdIT.java index aaa023db8..e1e637809 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/UpdateContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/UpdateContainerCmdIT.java @@ -16,7 +16,7 @@ import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_22; import static com.github.dockerjava.junit.DockerMatchers.isGreaterOrEqual; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static com.github.dockerjava.test.serdes.JSONSamples.testRoundTrip; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -31,7 +31,7 @@ public class UpdateContainerCmdIT extends CmdIT { @Test - public void updateContainer() throws DockerException, IOException { + public void updateContainer() throws DockerException { assumeThat("API version should be >= 1.22", dockerRule, isGreaterOrEqual(VERSION_1_22)); CreateContainerResponse response = dockerRule.getClient().createContainerCmd(DEFAULT_IMAGE) @@ -48,8 +48,8 @@ public void updateContainer() throws DockerException, IOException { dockerRule.getClient().updateContainerCmd(containerId) .withBlkioWeight(300) .withCpuShares(512) - .withCpuPeriod(100000) - .withCpuQuota(50000) + .withCpuPeriod(100000L) + .withCpuQuota(50000L) // .withCpusetCpus("0") // depends on env .withCpusetMems("0") // .withMemory(209715200L + 2L) diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/VersionCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/VersionCmdIT.java index 08a198b9f..90c7e534e 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/VersionCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/VersionCmdIT.java @@ -2,7 +2,7 @@ import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.Version; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +22,7 @@ public void version() throws DockerException { assertTrue(version.getGoVersion().length() > 0); assertTrue(version.getVersion().length() > 0); - assertEquals(StringUtils.split(version.getVersion(), ".").length, 3); + assertEquals(3, StringUtils.split(version.getVersion(), ".").length); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/WaitContainerCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/WaitContainerCmdIT.java index a8269c82f..3a39b3eea 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/WaitContainerCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/WaitContainerCmdIT.java @@ -8,18 +8,25 @@ import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.NotFoundException; +import com.github.dockerjava.api.model.WaitContainerCondition; import com.github.dockerjava.api.model.WaitResponse; +import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.TimeUnit; +import static com.github.dockerjava.api.model.HostConfig.newHostConfig; +import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_25; +import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_30; +import static com.github.dockerjava.junit.DockerMatchers.isGreaterOrEqual; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.emptyString; import static org.hamcrest.Matchers.not; +import static org.junit.Assume.assumeThat; public class WaitContainerCmdIT extends CmdIT { public static final Logger LOG = LoggerFactory.getLogger(BuildImageCmd.class); @@ -84,7 +91,7 @@ public void testWaitContainerAbort() throws Exception { } @Test - public void testWaitContainerTimeout() throws Exception { + public void testWaitContainerTimeout() { CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox").withCmd("sleep", "10").exec(); @@ -102,4 +109,77 @@ public void testWaitContainerTimeout() throws Exception { LOG.info(e.getMessage()); } } + + @Test + public void testWaitNotStartedContainer() { + assumeThat("API version should be > 1.25", dockerRule, isGreaterOrEqual(VERSION_1_25)); + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") + .withHostConfig(newHostConfig().withAutoRemove(true)) + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(is(emptyString()))); + + WaitContainerResultCallback callback = dockerRule.getClient().waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()); + + Integer statusCode = callback.awaitStatusCode(100, TimeUnit.MILLISECONDS); + Assert.assertEquals(0, statusCode.intValue()); + } + + @Test + public void testWaitContainerWithAutoRemoval() { + assumeThat("API version should be > 1.30", dockerRule, isGreaterOrEqual(VERSION_1_30)); + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") + .withCmd("false") + .withHostConfig(newHostConfig().withAutoRemove(true)) + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(is(emptyString()))); + + WaitContainerResultCallback removedCondition = dockerRule.getClient().waitContainerCmd(container.getId()) + .withCondition(WaitContainerCondition.REMOVED) + .exec(new WaitContainerResultCallback()); + + WaitContainerResultCallback nextExitCondition = dockerRule.getClient().waitContainerCmd(container.getId()) + .withCondition(WaitContainerCondition.NEXT_EXIT) + .exec(new WaitContainerResultCallback()); + + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + Assert.assertEquals(1, removedCondition.awaitStatusCode(100, TimeUnit.MILLISECONDS).intValue()); + Assert.assertEquals(1, nextExitCondition.awaitStatusCode(100, TimeUnit.MILLISECONDS).intValue()); + } + + @Test + public void testWaitRestartedContainer() { + assumeThat("API version should be > 1.30", dockerRule, isGreaterOrEqual(VERSION_1_30)); + + CreateContainerResponse container = dockerRule.getClient().createContainerCmd("busybox") + .withCmd("sh", "-c", "[ -f \"$HOME/.first_run_marker\" ] && exit 2 || { touch \"$HOME/.first_run_marker\"; exit 1; }") + .exec(); + + LOG.info("Created container: {}", container.toString()); + assertThat(container.getId(), not(is(emptyString()))); + + WaitContainerResultCallback firstExitCallback = dockerRule.getClient().waitContainerCmd(container.getId()) + .withCondition(WaitContainerCondition.NEXT_EXIT) + .exec(new WaitContainerResultCallback()); + + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + Integer firstStatusCode = firstExitCallback.awaitStatusCode(100, TimeUnit.MILLISECONDS); + Assert.assertEquals(1, firstStatusCode.intValue()); + + WaitContainerResultCallback callback = dockerRule.getClient().waitContainerCmd(container.getId()) + .withCondition(WaitContainerCondition.NEXT_EXIT) + .exec(new WaitContainerResultCallback()); + + dockerRule.getClient().startContainerCmd(container.getId()).exec(); + + Integer statusCode = callback.awaitStatusCode(100, TimeUnit.MILLISECONDS); + Assert.assertEquals(2, statusCode.intValue()); + } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateConfigCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateConfigCmdExecIT.java new file mode 100644 index 000000000..8ebb610b9 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateConfigCmdExecIT.java @@ -0,0 +1,31 @@ +package com.github.dockerjava.cmd.swarm; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateConfigResponse; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; + +public class CreateConfigCmdExecIT extends SwarmCmdIT { + + public static final Logger LOG = LoggerFactory.getLogger(CreateConfigCmdExecIT.class); + + @Test + public void testCreateConfig() { + DockerClient dockerClient = startSwarm(); + String configName = RandomStringUtils.random(10, true, false); + CreateConfigResponse response = dockerClient.createConfigCmd() + .withName(configName) + .withData("configuration data".getBytes()).exec(); + assertThat(response, notNullValue()); + String configId = response.getId(); + assertThat(configId, notNullValue()); + + dockerClient.removeConfigCmd(configId).exec(); + } + +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateSecretCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateSecretCmdExecIT.java index 7fdfeb96e..4644a8330 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateSecretCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateSecretCmdExecIT.java @@ -1,12 +1,11 @@ package com.github.dockerjava.cmd.swarm; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateSecretResponse; -import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.Secret; import com.github.dockerjava.api.model.SecretSpec; -import com.github.dockerjava.api.model.SwarmSpec; import com.google.common.collect.Lists; -import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.hamcrest.collection.IsCollectionWithSize; import org.junit.Test; import org.slf4j.Logger; @@ -20,35 +19,30 @@ public class CreateSecretCmdExecIT extends SwarmCmdIT { public static final Logger LOG = LoggerFactory.getLogger(CreateSecretCmdExecIT.class); - private static final String SERVICE_NAME = "theservice"; @Test - public void testCreateSecret() throws DockerException { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - + public void testCreateSecret() { + DockerClient dockerClient = startSwarm(); int length = 10; boolean useLetters = true; boolean useNumbers = false; String secretName = RandomStringUtils.random(length, useLetters, useNumbers); - CreateSecretResponse exec = dockerRule.getClient().createSecretCmd(new SecretSpec().withName(secretName).withData("mon secret en clair")).exec(); + CreateSecretResponse exec = dockerClient.createSecretCmd(new SecretSpec().withName(secretName).withData("mon secret en clair")).exec(); assertThat(exec, notNullValue()); assertThat(exec.getId(), notNullValue()); LOG.info("Secret created with ID {}", exec.getId()); - List secrets = dockerRule.getClient().listSecretsCmd() + List secrets = dockerClient.listSecretsCmd() .withNameFilter(Lists.newArrayList(secretName)) .exec(); assertThat(secrets, IsCollectionWithSize.hasSize(1)); - dockerRule.getClient().removeSecretCmd(secrets.get(0).getId()) + dockerClient.removeSecretCmd(secrets.get(0).getId()) .exec(); LOG.info("Secret removed with ID {}", exec.getId()); - List secretsAfterRemoved = dockerRule.getClient().listSecretsCmd() + List secretsAfterRemoved = dockerClient.listSecretsCmd() .withNameFilter(Lists.newArrayList(secretName)) .exec(); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateServiceCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateServiceCmdExecIT.java index ca450be02..e221d9cd3 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateServiceCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/CreateServiceCmdExecIT.java @@ -1,5 +1,6 @@ package com.github.dockerjava.cmd.swarm; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.ConflictException; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.AuthConfig; @@ -15,7 +16,6 @@ import com.github.dockerjava.api.model.ServiceModeConfig; import com.github.dockerjava.api.model.ServiceReplicatedModeOptions; import com.github.dockerjava.api.model.ServiceSpec; -import com.github.dockerjava.api.model.SwarmSpec; import com.github.dockerjava.api.model.TaskSpec; import com.github.dockerjava.api.model.TmpfsOptions; import com.github.dockerjava.junit.PrivateRegistryRule; @@ -23,6 +23,7 @@ import com.google.common.collect.Lists; import org.junit.Before; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -32,7 +33,7 @@ import java.util.Collections; import java.util.List; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; @@ -49,43 +50,35 @@ public class CreateServiceCmdExecIT extends SwarmCmdIT { public ExpectedException exception = ExpectedException.none(); private AuthConfig authConfig; + private DockerClient dockerClient; + @Before - public void beforeTest() throws Exception { - super.beforeTest(); + public final void setUpCreateServiceCmdExecIT() { authConfig = REGISTRY.getAuthConfig(); + dockerClient = startSwarm(); } @Test public void testCreateService() throws DockerException { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - - dockerRule.getClient().createServiceCmd(new ServiceSpec() + dockerClient.createServiceCmd(new ServiceSpec() .withName(SERVICE_NAME) .withTaskTemplate(new TaskSpec() .withContainerSpec(new ContainerSpec() .withImage(DEFAULT_IMAGE)))) .exec(); - List services = dockerRule.getClient().listServicesCmd() + List services = dockerClient.listServicesCmd() .withNameFilter(Lists.newArrayList(SERVICE_NAME)) .exec(); assertThat(services, hasSize(1)); - dockerRule.getClient().removeServiceCmd(SERVICE_NAME).exec(); + dockerClient.removeServiceCmd(SERVICE_NAME).exec(); } @Test public void testCreateServiceWithNetworks() { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - - String networkId = dockerRule.getClient().createNetworkCmd().withName("networkname") + String networkId = dockerClient.createNetworkCmd().withName("networkname") .withDriver("overlay") .withIpam(new Network.Ipam() .withDriver("default")) @@ -94,6 +87,7 @@ public void testCreateServiceWithNetworks() { .withName(SERVICE_NAME) .withTaskTemplate(new TaskSpec() .withForceUpdate(0) + .withRuntime("container") .withContainerSpec(new ContainerSpec() .withImage("busybox")) ) @@ -114,9 +108,9 @@ public void testCreateServiceWithNetworks() { .withProtocol(PortConfigProtocol.TCP) ))); - dockerRule.getClient().createServiceCmd(spec).exec(); + dockerClient.createServiceCmd(spec).exec(); - List services = dockerRule.getClient().listServicesCmd() + List services = dockerClient.listServicesCmd() .withNameFilter(Lists.newArrayList(SERVICE_NAME)) .exec(); @@ -124,43 +118,34 @@ public void testCreateServiceWithNetworks() { assertThat(services.get(0).getSpec(), is(spec)); - dockerRule.getClient().removeServiceCmd(SERVICE_NAME).exec(); + dockerClient.removeServiceCmd(SERVICE_NAME).exec(); } @Test public void testCreateServiceWithTmpfs() { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); Mount tmpMount = new Mount().withTmpfsOptions(new TmpfsOptions().withSizeBytes(600L)).withTarget("/tmp/foo"); - dockerRule.getClient().createServiceCmd(new ServiceSpec() + dockerClient.createServiceCmd(new ServiceSpec() .withName(SERVICE_NAME) .withTaskTemplate(new TaskSpec() .withContainerSpec(new ContainerSpec().withImage(DEFAULT_IMAGE).withMounts(Collections.singletonList(tmpMount))))) .exec(); - List services = dockerRule.getClient().listServicesCmd() + List services = dockerClient.listServicesCmd() .withNameFilter(Lists.newArrayList(SERVICE_NAME)) .exec(); assertThat(services, hasSize(1)); - List mounts = dockerRule.getClient().inspectServiceCmd(SERVICE_NAME).exec().getSpec().getTaskTemplate() + List mounts = dockerClient.inspectServiceCmd(SERVICE_NAME).exec().getSpec().getTaskTemplate() .getContainerSpec().getMounts(); assertThat(mounts, hasSize(1)); assertThat(mounts.get(0), is(tmpMount)); - dockerRule.getClient().removeServiceCmd(SERVICE_NAME).exec(); + dockerClient.removeServiceCmd(SERVICE_NAME).exec(); } @Test public void testCreateServiceWithValidAuth() throws DockerException { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - - dockerRule.getClient().createServiceCmd(new ServiceSpec() + dockerClient.createServiceCmd(new ServiceSpec() .withName(SERVICE_NAME) .withTaskTemplate(new TaskSpec() .withContainerSpec(new ContainerSpec() @@ -168,22 +153,18 @@ public void testCreateServiceWithValidAuth() throws DockerException { .withAuthConfig(authConfig) .exec(); - List services = dockerRule.getClient().listServicesCmd() + List services = dockerClient.listServicesCmd() .withNameFilter(Lists.newArrayList(SERVICE_NAME)) .exec(); assertThat(services, hasSize(1)); - dockerRule.getClient().removeServiceCmd(SERVICE_NAME).exec(); + dockerClient.removeServiceCmd(SERVICE_NAME).exec(); } @Test + @Ignore // TODO rework test (does not throw as expected atm) public void testCreateServiceWithInvalidAuth() throws DockerException { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - AuthConfig invalidAuthConfig = new AuthConfig() .withUsername("testuser") .withPassword("testwrongpassword") @@ -192,7 +173,7 @@ public void testCreateServiceWithInvalidAuth() throws DockerException { exception.expect(ConflictException.class); - dockerRule.getClient().createServiceCmd(new ServiceSpec() + dockerClient.createServiceCmd(new ServiceSpec() .withName(SERVICE_NAME) .withTaskTemplate(new TaskSpec() .withContainerSpec(new ContainerSpec() diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/InitializeSwarmCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/InitializeSwarmCmdExecIT.java index 503f22645..6341f4b30 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/InitializeSwarmCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/InitializeSwarmCmdExecIT.java @@ -1,7 +1,7 @@ package com.github.dockerjava.cmd.swarm; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.exception.NotAcceptableException; import com.github.dockerjava.api.model.Swarm; import com.github.dockerjava.api.model.SwarmCAConfig; import com.github.dockerjava.api.model.SwarmDispatcherConfig; @@ -22,9 +22,10 @@ public class InitializeSwarmCmdExecIT extends SwarmCmdIT { public static final Logger LOG = LoggerFactory.getLogger(InitializeSwarmCmdExecIT.class); @Test - public void initializeSwarm() throws DockerException { + public void initializeSwarm() throws Exception { + DockerClient dockerClient = startDockerInDocker(); SwarmSpec swarmSpec = new SwarmSpec() - .withName("swarm") + .withName("default") .withDispatcher(new SwarmDispatcherConfig() .withHeartbeatPeriod(10000000L) ).withOrchestration(new SwarmOrchestration() @@ -38,30 +39,23 @@ public void initializeSwarm() throws DockerException { .withLogEntriesForSlowFollowers(200) ).withTaskDefaults(new TaskDefaults()); - dockerRule.getClient().initializeSwarmCmd(swarmSpec) + dockerClient.initializeSwarmCmd(swarmSpec) .withListenAddr("127.0.0.1") .withAdvertiseAddr("127.0.0.1") .exec(); LOG.info("Initialized swarm: {}", swarmSpec.toString()); - Swarm swarm = dockerRule.getClient().inspectSwarmCmd().exec(); + Swarm swarm = dockerClient.inspectSwarmCmd().exec(); LOG.info("Inspected swarm: {}", swarm.toString()); assertThat(swarm.getSpec(), is(equalTo(swarmSpec))); } - @Test(expected = NotAcceptableException.class) + @Test(expected = DockerException.class) public void initializingSwarmThrowsWhenAlreadyInSwarm() throws DockerException { - SwarmSpec swarmSpec = new SwarmSpec() - .withName("swarm"); - - dockerRule.getClient().initializeSwarmCmd(swarmSpec) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - LOG.info("Initialized swarm: {}", swarmSpec.toString()); + DockerClient dockerClient = startSwarm(); // Initializing a swarm if already in swarm mode should fail - dockerRule.getClient().initializeSwarmCmd(swarmSpec) + dockerClient.initializeSwarmCmd(new SwarmSpec()) .withListenAddr("127.0.0.1") .exec(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/InspectConfigCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/InspectConfigCmdIT.java new file mode 100644 index 000000000..12c69c996 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/InspectConfigCmdIT.java @@ -0,0 +1,33 @@ +package com.github.dockerjava.cmd.swarm; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateConfigResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.Config; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertEquals; + +public class InspectConfigCmdIT extends SwarmCmdIT { + + public static final Logger LOG = LoggerFactory.getLogger(InspectConfigCmdIT.class); + + @Test + public void inspectConfig() throws DockerException { + DockerClient dockerClient = startSwarm(); + + String configName = RandomStringUtils.random(10, true, false); + + CreateConfigResponse configResponse = dockerClient.createConfigCmd() + .withName(configName) + .withData("configuration data".getBytes()).exec(); + LOG.info("Config created with ID {}", configResponse.getId()); + + Config config = dockerClient.inspectConfigCmd(configResponse.getId()).exec(); + assertEquals(configResponse.getId(), config.getId()); + assertEquals(configName, config.getSpec().getName()); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/JoinSwarmCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/JoinSwarmCmdExecIT.java index 383f9e54d..16f1b0911 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/JoinSwarmCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/JoinSwarmCmdExecIT.java @@ -2,13 +2,13 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.exception.NotAcceptableException; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.LocalNodeState; import com.github.dockerjava.api.model.Swarm; import com.github.dockerjava.api.model.SwarmJoinTokens; import com.github.dockerjava.api.model.SwarmSpec; import com.google.common.collect.Lists; +import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,6 +21,16 @@ public class JoinSwarmCmdExecIT extends SwarmCmdIT { public static final Logger LOG = LoggerFactory.getLogger(JoinSwarmCmdExecIT.class); + private DockerClient docker1; + + private DockerClient docker2; + + @Before + public void setUp() throws Exception { + docker1 = startDockerInDocker(); + docker2 = startDockerInDocker(); + } + private SwarmJoinTokens initSwarmOnDocker(DockerClient docker) { SwarmSpec swarmSpec = new SwarmSpec(); docker.initializeSwarmCmd(swarmSpec) @@ -33,10 +43,7 @@ private SwarmJoinTokens initSwarmOnDocker(DockerClient docker) { } @Test - public void joinSwarmAsWorker() throws Exception { - DockerClient docker1 = startDockerInDocker(); - DockerClient docker2 = startDockerInDocker(); - + public void joinSwarmAsWorker() { SwarmJoinTokens tokens = initSwarmOnDocker(docker1); docker2.joinSwarmCmd() @@ -51,10 +58,7 @@ public void joinSwarmAsWorker() throws Exception { } @Test - public void joinSwarmAsManager() throws DockerException, InterruptedException { - DockerClient docker1 = startDockerInDocker(); - DockerClient docker2 = startDockerInDocker(); - + public void joinSwarmAsManager() throws DockerException { SwarmJoinTokens tokens = initSwarmOnDocker(docker1); docker2.joinSwarmCmd() @@ -68,11 +72,8 @@ public void joinSwarmAsManager() throws DockerException, InterruptedException { assertThat(info.getSwarm().getLocalNodeState(), is(equalTo(LocalNodeState.ACTIVE))); } - @Test(expected = NotAcceptableException.class) - public void joinSwarmIfAlreadyInSwarm() throws Exception { - DockerClient docker1 = startDockerInDocker(); - DockerClient docker2 = startDockerInDocker(); - + @Test(expected = DockerException.class) + public void joinSwarmIfAlreadyInSwarm() { SwarmJoinTokens tokens = initSwarmOnDocker(docker1); initSwarmOnDocker(docker2); @@ -82,5 +83,4 @@ public void joinSwarmIfAlreadyInSwarm() throws Exception { .withJoinToken(tokens.getWorker()) .exec(); } - } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LeaveSwarmCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LeaveSwarmCmdExecIT.java index 4f093ca94..e6d652d43 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LeaveSwarmCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LeaveSwarmCmdExecIT.java @@ -1,10 +1,9 @@ package com.github.dockerjava.cmd.swarm; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.exception.NotAcceptableException; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.LocalNodeState; -import com.github.dockerjava.api.model.SwarmSpec; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,36 +14,32 @@ public class LeaveSwarmCmdExecIT extends SwarmCmdIT { public static final Logger LOG = LoggerFactory.getLogger(LeaveSwarmCmdExecIT.class); - + @Test public void leaveSwarmAsMaster() throws DockerException { - SwarmSpec swarmSpec = new SwarmSpec().withName("firstSpec"); - dockerRule.getClient().initializeSwarmCmd(swarmSpec) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - LOG.info("Initialized swarm: {}", swarmSpec.toString()); + DockerClient dockerClient = startSwarm(); - Info info = dockerRule.getClient().infoCmd().exec(); + Info info = dockerClient.infoCmd().exec(); LOG.info("Inspected docker: {}", info.toString()); assertThat(info.getSwarm().getLocalNodeState(), is(LocalNodeState.ACTIVE)); - dockerRule.getClient().leaveSwarmCmd() + dockerClient.leaveSwarmCmd() .withForceEnabled(true) .exec(); LOG.info("Left swarm"); - info = dockerRule.getClient().infoCmd().exec(); + info = dockerClient.infoCmd().exec(); LOG.info("Inspected docker: {}", info.toString()); assertThat(info.getSwarm().getLocalNodeState(), is(LocalNodeState.INACTIVE)); } - @Test(expected = NotAcceptableException.class) - public void leavingSwarmThrowsWhenNotInSwarm() throws DockerException { - dockerRule.getClient().leaveSwarmCmd().exec(); + @Test(expected = DockerException.class) + public void leavingSwarmThrowsWhenNotInSwarm() throws Exception { + DockerClient dockerClient = startDockerInDocker(); + dockerClient.leaveSwarmCmd().exec(); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListConfigCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListConfigCmdExecIT.java new file mode 100644 index 000000000..2c19a7f0e --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListConfigCmdExecIT.java @@ -0,0 +1,54 @@ +package com.github.dockerjava.cmd.swarm; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateConfigResponse; +import com.github.dockerjava.api.exception.DockerException; +import com.github.dockerjava.api.model.Config; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; + +public class ListConfigCmdExecIT extends SwarmCmdIT { + + public static final Logger LOG = LoggerFactory.getLogger(ListConfigCmdExecIT.class); + + @Test + public void tesListConfig() throws DockerException { + DockerClient dockerClient = startSwarm(); + String configName = RandomStringUtils.random(10, true, false); + CreateConfigResponse response = dockerClient.createConfigCmd() + .withName(configName) + .withData("configuration data".getBytes()) + .exec(); + String configId = response.getId(); + + try { + LOG.info("Config created with ID {}", configId); + + List configs = dockerClient.listConfigsCmd() + .withFilters(Collections.singletonMap("name", Arrays.asList(configName))) + .exec(); + + assertThat(configs, hasSize(1)); + } finally { + dockerClient.removeConfigCmd(configId).exec(); + LOG.info("Config removed with ID {}", configId); + } + + List configsAfterRemoved = dockerClient.listConfigsCmd() + .withFilters(Collections.singletonMap("name", Arrays.asList(configName))) + .exec(); + + assertThat(configsAfterRemoved, hasSize(0)); + + } + +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListSecretCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListSecretCmdExecIT.java index bb779e7f3..ce90f23a0 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListSecretCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListSecretCmdExecIT.java @@ -1,12 +1,12 @@ package com.github.dockerjava.cmd.swarm; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateSecretResponse; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.Secret; import com.github.dockerjava.api.model.SecretSpec; -import com.github.dockerjava.api.model.SwarmSpec; import com.google.common.collect.Lists; -import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,31 +23,27 @@ public class ListSecretCmdExecIT extends SwarmCmdIT { @Test public void tesListSecret() throws DockerException { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - + DockerClient dockerClient = startSwarm(); int length = 10; boolean useLetters = true; boolean useNumbers = false; String secretName = RandomStringUtils.random(length, useLetters, useNumbers); - CreateSecretResponse exec = dockerRule.getClient().createSecretCmd(new SecretSpec().withName(secretName).withData("mon secret en clair")).exec(); + CreateSecretResponse exec = dockerClient.createSecretCmd(new SecretSpec().withName(secretName).withData("mon secret en clair")).exec(); assertThat(exec, notNullValue()); assertThat(exec.getId(), notNullValue()); LOG.info("Secret created with ID {}", exec.getId()); - List secrets = dockerRule.getClient().listSecretsCmd() + List secrets = dockerClient.listSecretsCmd() .withNameFilter(Lists.newArrayList(secretName)) .exec(); assertThat(secrets, hasSize(1)); - dockerRule.getClient().removeSecretCmd(secrets.get(0).getId()) + dockerClient.removeSecretCmd(secrets.get(0).getId()) .exec(); LOG.info("Secret removed with ID {}", exec.getId()); - List secretsAfterRemoved = dockerRule.getClient().listSecretsCmd() + List secretsAfterRemoved = dockerClient.listSecretsCmd() .withNameFilter(Lists.newArrayList(secretName)) .exec(); diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListServicesCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListServicesCmdExecIT.java index 27df40001..715ba60c8 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListServicesCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListServicesCmdExecIT.java @@ -2,13 +2,11 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateServiceResponse; -import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.ContainerSpec; import com.github.dockerjava.api.model.Service; import com.github.dockerjava.api.model.ServiceModeConfig; import com.github.dockerjava.api.model.ServiceReplicatedModeOptions; import com.github.dockerjava.api.model.ServiceSpec; -import com.github.dockerjava.api.model.SwarmSpec; import com.github.dockerjava.api.model.TaskSpec; import org.junit.Test; import org.slf4j.Logger; @@ -18,7 +16,7 @@ import java.util.List; import java.util.Map; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; @@ -29,11 +27,10 @@ public class ListServicesCmdExecIT extends SwarmCmdIT { private static final String LABEL_VALUE = "test"; @Test - public void testListServices() throws Exception { - DockerClient docker1 = startDockerInDocker(); - docker1.initializeSwarmCmd(new SwarmSpec()).exec(); + public void testListServices() { + DockerClient dockerClient = startSwarm(); Map serviceLabels = Collections.singletonMap(LABEL_KEY, LABEL_VALUE); - CreateServiceResponse response = docker1.createServiceCmd(new ServiceSpec() + CreateServiceResponse response = dockerClient.createServiceCmd(new ServiceSpec() .withLabels(serviceLabels) .withName(SERVICE_NAME) .withMode(new ServiceModeConfig().withReplicated( @@ -46,14 +43,14 @@ public void testListServices() throws Exception { .exec(); String serviceId = response.getId(); //filtering with service id - List services = docker1.listServicesCmd().withIdFilter(Collections.singletonList(serviceId)).exec(); + List services = dockerClient.listServicesCmd().withIdFilter(Collections.singletonList(serviceId)).exec(); assertThat(services, hasSize(1)); //filtering with service name - services = docker1.listServicesCmd().withNameFilter(Collections.singletonList(SERVICE_NAME)).exec(); + services = dockerClient.listServicesCmd().withNameFilter(Collections.singletonList(SERVICE_NAME)).exec(); assertThat(services, hasSize(1)); //filter labels - services = docker1.listServicesCmd().withLabelFilter(serviceLabels).exec(); + services = dockerClient.listServicesCmd().withLabelFilter(serviceLabels).exec(); assertThat(services, hasSize(1)); - docker1.removeServiceCmd(SERVICE_NAME).exec(); + dockerClient.removeServiceCmd(SERVICE_NAME).exec(); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListSwarmNodesCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListSwarmNodesCmdExecIT.java new file mode 100644 index 000000000..853dc6c03 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListSwarmNodesCmdExecIT.java @@ -0,0 +1,89 @@ +package com.github.dockerjava.cmd.swarm; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.SwarmNode; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class ListSwarmNodesCmdExecIT extends SwarmCmdIT { + @Test + public void testListSwarmNodes() { + DockerClient dockerClient = startSwarm(); + + List nodes = dockerClient.listSwarmNodesCmd().exec(); + assertThat(nodes.size(), is(1)); + } + + @Test + public void testListSwarmNodesWithIdFilter() { + DockerClient dockerClient = startSwarm(); + + List nodes = dockerClient.listSwarmNodesCmd().exec(); + assertThat(nodes.size(), is(1)); + + String nodeId = nodes.get(0).getId(); + List nodesWithId = dockerClient.listSwarmNodesCmd() + .withIdFilter(Collections.singletonList(nodeId)) + .exec(); + assertThat(nodesWithId.size(), is(1)); + + List nodesWithNonexistentId = dockerClient.listSwarmNodesCmd() + .withIdFilter(Collections.singletonList("__nonexistent__")) + .exec(); + assertThat(nodesWithNonexistentId.size(), is(0)); + } + + @Test + public void testListSwarmNodesWithNameFilter() { + DockerClient dockerClient = startSwarm(); + + List nodes = dockerClient.listSwarmNodesCmd().exec(); + assertThat(nodes.size(), is(1)); + + String nodeName = nodes.get(0).getSpec().getName(); + List nodesWithFirstNodesName = dockerClient.listSwarmNodesCmd() + .withNameFilter(Collections.singletonList(nodeName)) + .exec(); + assertThat(nodesWithFirstNodesName.size(), is(1)); + + List nodesWithNonexistentName = dockerClient.listSwarmNodesCmd() + .withNameFilter(Collections.singletonList("__nonexistent__")) + .exec(); + assertThat(nodesWithNonexistentName.size(), is(0)); + } + + @Test + public void testListSwarmNodesWithMembershipFilter() { + DockerClient dockerClient = startSwarm(); + + List nodesWithAcceptedMembership = dockerClient.listSwarmNodesCmd() + .withMembershipFilter(Collections.singletonList("accepted")) + .exec(); + assertThat(nodesWithAcceptedMembership.size(), is(1)); + + List nodesWithPendingMembership = dockerClient.listSwarmNodesCmd() + .withMembershipFilter(Collections.singletonList("pending")) + .exec(); + assertThat(nodesWithPendingMembership.size(), is(0)); + } + + @Test + public void testListSwarmNodesWithRoleFilter() { + DockerClient dockerClient = startSwarm(); + + List nodesWithManagerRole = dockerClient.listSwarmNodesCmd() + .withRoleFilter(Collections.singletonList("manager")) + .exec(); + assertThat(nodesWithManagerRole.size(), is(1)); + + List nodesWithWorkerRole = dockerClient.listSwarmNodesCmd() + .withRoleFilter(Collections.singletonList("worker")) + .exec(); + assertThat(nodesWithWorkerRole.size(), is(0)); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListTasksCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListTasksCmdExecIT.java index 228ccbac8..8ce672b1b 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListTasksCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/ListTasksCmdExecIT.java @@ -1,12 +1,12 @@ package com.github.dockerjava.cmd.swarm; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateServiceResponse; import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.model.ContainerSpec; import com.github.dockerjava.api.model.ServiceModeConfig; import com.github.dockerjava.api.model.ServiceReplicatedModeOptions; import com.github.dockerjava.api.model.ServiceSpec; -import com.github.dockerjava.api.model.SwarmSpec; import com.github.dockerjava.api.model.Task; import com.github.dockerjava.api.model.TaskSpec; import com.github.dockerjava.api.model.TaskState; @@ -17,8 +17,10 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; +import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; @@ -31,12 +33,9 @@ public class ListTasksCmdExecIT extends SwarmCmdIT { @Test public void testListTasks() throws DockerException { - dockerRule.getClient().initializeSwarmCmd(new SwarmSpec()) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); + DockerClient dockerClient = startSwarm(); Map taskLabels = Collections.singletonMap(TASK_LABEL_KEY, TASK_LABEL_VALUE); - CreateServiceResponse response = dockerRule.getClient().createServiceCmd(new ServiceSpec() + CreateServiceResponse response = dockerClient.createServiceCmd(new ServiceSpec() .withName(SERVICE_NAME) .withMode(new ServiceModeConfig().withReplicated( new ServiceReplicatedModeOptions() @@ -48,27 +47,35 @@ public void testListTasks() throws DockerException { .exec(); String serviceId = response.getId(); //filtering with service id - List tasks = dockerRule.getClient().listTasksCmd().withServiceFilter(serviceId).exec(); - assertThat(tasks, hasSize(2)); - String taskId = tasks.get(0).getId(), secondId = tasks.get(1).getId(); + List tasks = await().until( + () -> dockerClient.listTasksCmd().withServiceFilter(serviceId).exec(), + hasSize(2) + ); + String taskId = tasks.get(0).getId(); + String secondTaskId = tasks.get(1).getId(); //filtering with unique id - tasks = dockerRule.getClient().listTasksCmd().withIdFilter(taskId).exec(); + tasks = dockerClient.listTasksCmd().withIdFilter(taskId).exec(); assertThat(tasks, hasSize(1)); assertThat(tasks.get(0).getId(), is(taskId)); //filtering with multiple id - tasks = dockerRule.getClient().listTasksCmd().withIdFilter(secondId, taskId).exec(); + tasks = dockerClient.listTasksCmd().withIdFilter(secondTaskId, taskId).exec(); + assertThat(tasks, hasSize(2)); //filtering node id - String nodeId = tasks.get(0).getNodeId(); - tasks = dockerRule.getClient().listTasksCmd().withNodeFilter(nodeId).exec(); + // Wait for node assignment + String nodeId = await().until(() -> { + return dockerClient.listTasksCmd().withIdFilter(secondTaskId).exec() + .get(0) + .getNodeId(); + }, Objects::nonNull); + tasks = dockerClient.listTasksCmd().withNodeFilter(nodeId).exec(); assertThat(tasks.get(0).getNodeId(), is(nodeId)); //filtering with state - tasks = dockerRule.getClient().listTasksCmd().withStateFilter(TaskState.RUNNING).exec(); + tasks = dockerClient.listTasksCmd().withStateFilter(TaskState.RUNNING).exec(); assertThat(tasks, hasSize(2)); //filter labels - tasks = dockerRule.getClient().listTasksCmd().withLabelFilter(taskLabels).exec(); + tasks = dockerClient.listTasksCmd().withLabelFilter(taskLabels).exec(); assertThat(tasks, hasSize(2)); - tasks = dockerRule.getClient().listTasksCmd().withLabelFilter(TASK_LABEL_KEY + "=" + TASK_LABEL_VALUE).exec(); + tasks = dockerClient.listTasksCmd().withLabelFilter(TASK_LABEL_KEY + "=" + TASK_LABEL_VALUE).exec(); assertThat(tasks, hasSize(2)); - dockerRule.getClient().removeServiceCmd(SERVICE_NAME).exec(); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LogSwarmObjectIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LogSwarmObjectIT.java index 9a3aa3768..11606dce0 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LogSwarmObjectIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/LogSwarmObjectIT.java @@ -8,11 +8,11 @@ import com.github.dockerjava.api.model.ServiceRestartCondition; import com.github.dockerjava.api.model.ServiceRestartPolicy; import com.github.dockerjava.api.model.ServiceSpec; -import com.github.dockerjava.api.model.SwarmSpec; import com.github.dockerjava.api.model.Task; import com.github.dockerjava.api.model.TaskSpec; import com.github.dockerjava.api.model.TaskState; import com.github.dockerjava.utils.LogContainerTestCallback; +import org.junit.Ignore; import org.junit.Test; import java.io.IOException; @@ -22,15 +22,16 @@ import java.util.concurrent.TimeUnit; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.core.Is.is; -import static org.mockito.Matchers.contains; public class LogSwarmObjectIT extends SwarmCmdIT { + + @Ignore @Test public void testLogsCmd() throws InterruptedException, IOException { + DockerClient dockerClient = startSwarm(); String snippet = "hello world"; - DockerClient docker1 = startDockerInDocker(); - docker1.initializeSwarmCmd(new SwarmSpec()).exec(); TaskSpec taskSpec = new TaskSpec().withContainerSpec( new ContainerSpec().withImage("busybox").withCommand(Arrays.asList("echo", snippet))) .withRestartPolicy(new ServiceRestartPolicy().withCondition(ServiceRestartCondition.NONE)); @@ -38,12 +39,12 @@ public void testLogsCmd() throws InterruptedException, IOException { .withMode(new ServiceModeConfig().withReplicated(new ServiceReplicatedModeOptions().withReplicas(1))) .withTaskTemplate(taskSpec) .withName("log-worker"); - String serviceId = docker1.createServiceCmd(serviceSpec).exec().getId(); + String serviceId = dockerClient.createServiceCmd(serviceSpec).exec().getId(); int since = (int) System.currentTimeMillis() / 1000; //wait the service to end List tasks = new ArrayList<>(); for (int i = 0; i < 10; i++) { - tasks = docker1.listTasksCmd().withServiceFilter(serviceId).withStateFilter(TaskState.SHUTDOWN).exec(); + tasks = dockerClient.listTasksCmd().withServiceFilter(serviceId).withStateFilter(TaskState.SHUTDOWN).exec(); if (tasks.size() == 1) { break; } else { @@ -53,23 +54,23 @@ public void testLogsCmd() throws InterruptedException, IOException { assertThat(tasks.size(), is(1)); String taskId = tasks.get(0).getId(); //check service log - validateLog(docker1.logServiceCmd(serviceId).withStdout(true), snippet); + validateLog(dockerClient.logServiceCmd(serviceId).withStdout(true), snippet); //check task log - validateLog(docker1.logTaskCmd(taskId).withStdout(true), snippet); + validateLog(dockerClient.logTaskCmd(taskId).withStdout(true), snippet); //check details/context - validateLog(docker1.logServiceCmd(serviceId).withStdout(true).withDetails(true), "com.docker.swarm.service.id=" + serviceId); - validateLog(docker1.logTaskCmd(taskId).withStdout(true).withDetails(true), "com.docker.swarm.service.id=" + serviceId); + // FIXME + // validateLog(docker1.logServiceCmd(serviceId).withStdout(true).withDetails(true), "com.docker.swarm.service.id=" + serviceId); + // validateLog(docker1.logTaskCmd(taskId).withStdout(true).withDetails(true), "com.docker.swarm.service.id=" + serviceId); //check since - validateLog(docker1.logServiceCmd(serviceId).withStdout(true).withSince(since), snippet); - validateLog(docker1.logTaskCmd(taskId).withStdout(true).withSince(since), snippet); - docker1.removeServiceCmd(serviceId).exec(); + validateLog(dockerClient.logServiceCmd(serviceId).withStdout(true).withSince(since), snippet); + validateLog(dockerClient.logTaskCmd(taskId).withStdout(true).withSince(since), snippet); + dockerClient.removeServiceCmd(serviceId).exec(); } private void validateLog(LogSwarmObjectCmd logCmd, String messsage) throws InterruptedException, IOException { - LogContainerTestCallback loggingCallback = new LogContainerTestCallback(); - logCmd.exec(loggingCallback); - loggingCallback.awaitCompletion(5, TimeUnit.SECONDS); - assertThat(loggingCallback.toString(), is(contains(messsage))); - loggingCallback.close(); + try (LogContainerTestCallback loggingCallback = logCmd.exec(new LogContainerTestCallback(true))) { + loggingCallback.awaitCompletion(5, TimeUnit.SECONDS); + assertThat(loggingCallback.toString(), containsString(messsage)); + } } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/RemoveSwarmNodeCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/RemoveSwarmNodeCmdExecIT.java new file mode 100644 index 000000000..8bdee6947 --- /dev/null +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/RemoveSwarmNodeCmdExecIT.java @@ -0,0 +1,44 @@ +package com.github.dockerjava.cmd.swarm; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Swarm; +import com.github.dockerjava.api.model.SwarmNode; +import com.github.dockerjava.api.model.SwarmNodeRole; +import com.google.common.collect.Lists; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class RemoveSwarmNodeCmdExecIT extends SwarmCmdIT { + + private static final Logger LOGGER = LoggerFactory.getLogger(RemoveSwarmNodeCmdExecIT.class); + + @Test + public void testRemoveSwarmNode() throws Exception { + DockerClient dockerClient = startSwarm(); + Swarm swarm = dockerClient.inspectSwarmCmd().exec(); + + DockerClient docker2 = startDockerInDocker(); + docker2.joinSwarmCmd() + .withRemoteAddrs(Lists.newArrayList("docker1")) + .withJoinToken(swarm.getJoinTokens().getWorker()) + .exec(); + LOGGER.info("docker2 joined docker's swarm"); + + List nodes = dockerClient.listSwarmNodesCmd().exec(); + assertThat(2, is(nodes.size())); + Optional firstWorkNode = nodes.stream().filter(node -> node.getSpec().getRole() == SwarmNodeRole.WORKER) + .findFirst(); + dockerClient.removeSwarmNodeCmd(firstWorkNode.get().getId()) + .withForce(true) + .exec(); + nodes = dockerClient.listSwarmNodesCmd().exec(); + assertThat(nodes.size(), is(1)); + } +} diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/SwarmCmdIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/SwarmCmdIT.java index fd6a0c630..36bcab840 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/SwarmCmdIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/SwarmCmdIT.java @@ -1,58 +1,74 @@ package com.github.dockerjava.cmd.swarm; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.ConflictException; -import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.exception.NotAcceptableException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Ports; +import com.github.dockerjava.api.model.PullResponseItem; +import com.github.dockerjava.api.model.SwarmSpec; import com.github.dockerjava.cmd.CmdIT; import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.junit.category.Integration; import com.github.dockerjava.junit.category.SwarmModeIntegration; import org.junit.After; import org.junit.Before; import org.junit.experimental.categories.Category; +import java.io.IOException; +import java.time.Duration; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + import static com.github.dockerjava.api.model.HostConfig.newHostConfig; import static com.github.dockerjava.core.RemoteApiVersion.VERSION_1_24; import static com.github.dockerjava.junit.DockerMatchers.isGreaterOrEqual; +import static org.awaitility.Awaitility.await; import static org.junit.Assume.assumeThat; @Category({SwarmModeIntegration.class, Integration.class}) public abstract class SwarmCmdIT extends CmdIT { - protected DockerClient secondDockerClient; - private int numberOfDockersInDocker = 0; - private static final int PORT_START = 2378; + private static final String DOCKER_IN_DOCKER_IMAGE_REPOSITORY = "docker"; + + private static final String DOCKER_IN_DOCKER_IMAGE_TAG = "26.1.3-dind"; + private static final String DOCKER_IN_DOCKER_CONTAINER_PREFIX = "docker"; + private static final String NETWORK_NAME = "dind-network"; - private static final String DOCKER_IN_DOCKER_IMAGE_REPOSITORY = "docker"; - private static final String DOCKER_IN_DOCKER_IMAGE_TAG = "17.12-dind"; + + private final AtomicInteger numberOfDockersInDocker = new AtomicInteger(); + + private final Set startedContainerIds = new HashSet<>(); @Before - public void beforeTest() throws Exception { + public final void setUpMultiNodeSwarmCmdIT() { assumeThat(dockerRule, isGreaterOrEqual(VERSION_1_24)); } - @Before - public void beforeMethod() { - leaveIfInSwarm(); + protected DockerClient startSwarm() { + DockerClient dockerClient; + try { + dockerClient = startDockerInDocker(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + dockerClient.initializeSwarmCmd(new SwarmSpec()).exec(); + return dockerClient; } @After - public void afterMethod() { - removeDockersInDocker(); - } - - protected void removeDockersInDocker() { - for (int i = 1; i <= numberOfDockersInDocker; i++) { + public final void tearDownMultiNodeSwarmCmdIT() { + for (String containerId : startedContainerIds) { try { - dockerRule.getClient().removeContainerCmd(DOCKER_IN_DOCKER_CONTAINER_PREFIX + i).withForce(true).exec(); + dockerRule.getClient().removeContainerCmd(containerId).withForce(true).exec(); } catch (NotFoundException e) { // container does not exist } @@ -63,75 +79,67 @@ protected void removeDockersInDocker() { } catch (NotFoundException e) { // network does not exist } - - numberOfDockersInDocker = 0; } protected DockerClient startDockerInDocker() throws InterruptedException { - numberOfDockersInDocker++; - String name = DOCKER_IN_DOCKER_CONTAINER_PREFIX + numberOfDockersInDocker; - - // Delete if already exists - try { - dockerRule.getClient().removeContainerCmd(name).withForce(true).exec(); - } catch (NotFoundException e) { - // container does not exist - } - // Create network if not already exists + DockerClient hostDockerClient = dockerRule.getClient(); try { - dockerRule.getClient().inspectNetworkCmd().withNetworkId(NETWORK_NAME).exec(); + hostDockerClient.inspectNetworkCmd().withNetworkId(NETWORK_NAME).exec(); } catch (NotFoundException e) { try { - dockerRule.getClient().createNetworkCmd().withName(NETWORK_NAME).exec(); + hostDockerClient.createNetworkCmd().withName(NETWORK_NAME).exec(); } catch (ConflictException e2) { // already exists } } - dockerRule.getClient().pullImageCmd(DOCKER_IN_DOCKER_IMAGE_REPOSITORY) + try ( + ResultCallback.Adapter callback = hostDockerClient.pullImageCmd(DOCKER_IN_DOCKER_IMAGE_REPOSITORY) .withTag(DOCKER_IN_DOCKER_IMAGE_TAG) .start() - .awaitCompletion(); + ) { + callback.awaitCompletion(); + } catch (IOException e) { + throw new RuntimeException(e); + } - int port = PORT_START + (numberOfDockersInDocker - 1); - CreateContainerResponse response = dockerRule.getClient() - .createContainerCmd(DOCKER_IN_DOCKER_IMAGE_REPOSITORY + ":" + DOCKER_IN_DOCKER_IMAGE_TAG) - .withHostConfig(newHostConfig() - .withNetworkMode(NETWORK_NAME) - .withPortBindings(new PortBinding( - Ports.Binding.bindIpAndPort("127.0.0.1", port), - ExposedPort.tcp(2375))) - .withPrivileged(true)) - .withName(name) - .withAliases(name) + ExposedPort exposedPort = ExposedPort.tcp(2375); + CreateContainerResponse response = hostDockerClient + .createContainerCmd(DOCKER_IN_DOCKER_IMAGE_REPOSITORY + ":" + DOCKER_IN_DOCKER_IMAGE_TAG) + .withEntrypoint("dockerd") + .withCmd(Arrays.asList("--host=tcp://0.0.0.0:2375", "--host=unix:///var/run/docker.sock", "--tls=false")) + .withHostConfig(newHostConfig() + .withNetworkMode(NETWORK_NAME) + .withPortBindings(new PortBinding( + Ports.Binding.bindIp("127.0.0.1"), + exposedPort)) + .withPrivileged(true)) + .withAliases(DOCKER_IN_DOCKER_CONTAINER_PREFIX + numberOfDockersInDocker.incrementAndGet()) + .exec(); - .exec(); + String containerId = response.getId(); + startedContainerIds.add(containerId); - dockerRule.getClient().startContainerCmd(response.getId()).exec(); + hostDockerClient.startContainerCmd(containerId).exec(); - return initializeDockerClient(port); - } + InspectContainerResponse inspectContainerResponse = hostDockerClient.inspectContainerCmd(containerId).exec(); - private DockerClient initializeDockerClient(int port) { - DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() - .withRegistryUrl("https://index.docker.io/v1/") - .withDockerHost("tcp://localhost:" + port).build(); - return DockerClientBuilder.getInstance(config) - .withDockerCmdExecFactory(getFactoryType().createExecFactory()) - .build(); + Ports.Binding binding = inspectContainerResponse.getNetworkSettings().getPorts().getBindings().get(exposedPort)[0]; + + DockerClient dockerClient = initializeDockerClient(binding); + + await().pollDelay(Duration.ofSeconds(5)).atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + dockerClient.pingCmd().exec(); + }); + + return dockerClient; } - private void leaveIfInSwarm() { - try { - // force in case this is a swarm manager - dockerRule.getClient().leaveSwarmCmd().withForceEnabled(true).exec(); - } catch (NotAcceptableException e) { - // do nothing, node is not part of a swarm - } catch (DockerException ex) { - if (!ex.getMessage().contains("node is not part of a swarm")) { - throw ex; - } - } + private DockerClient initializeDockerClient(Ports.Binding binding) { + DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withRegistryUrl("https://index.docker.io/v1/") + .withDockerHost("tcp://" + binding).build(); + return createDockerClient(config); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmCmdExecIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmCmdExecIT.java index 5886614dd..ea3818836 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmCmdExecIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmCmdExecIT.java @@ -1,7 +1,7 @@ package com.github.dockerjava.cmd.swarm; +import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.DockerException; -import com.github.dockerjava.api.exception.NotAcceptableException; import com.github.dockerjava.api.model.Swarm; import com.github.dockerjava.api.model.SwarmCAConfig; import com.github.dockerjava.api.model.SwarmDispatcherConfig; @@ -22,11 +22,12 @@ public class UpdateSwarmCmdExecIT extends SwarmCmdIT { public static final Logger LOG = LoggerFactory.getLogger(UpdateSwarmCmdExecIT.class); + @Test public void updateSwarm() throws DockerException { - SwarmSpec firstSpec = new SwarmSpec().withName("firstSpec"); + DockerClient dockerClient = startSwarm(); - SwarmSpec secondSpec = new SwarmSpec() - .withName("secondSpec") + SwarmSpec newSpec = new SwarmSpec() + .withName("default") .withDispatcher(new SwarmDispatcherConfig() .withHeartbeatPeriod(10000000L) ).withOrchestration(new SwarmOrchestration() @@ -40,33 +41,25 @@ public void updateSwarm() throws DockerException { .withLogEntriesForSlowFollowers(200) ).withTaskDefaults(new TaskDefaults()); - dockerRule.getClient().initializeSwarmCmd(firstSpec) - .withListenAddr("127.0.0.1") - .withAdvertiseAddr("127.0.0.1") - .exec(); - LOG.info("Initialized swarm: {}", firstSpec.toString()); - - Swarm swarm = dockerRule.getClient().inspectSwarmCmd().exec(); + Swarm swarm = dockerClient.inspectSwarmCmd().exec(); LOG.info("Inspected swarm: {}", swarm.toString()); - assertThat(swarm.getSpec(), is(not(equalTo(secondSpec)))); + assertThat(swarm.getSpec(), is(not(equalTo(newSpec)))); - dockerRule.getClient().updateSwarmCmd(secondSpec) + dockerClient.updateSwarmCmd(newSpec) .withVersion(swarm.getVersion().getIndex()) .exec(); - LOG.info("Updated swarm: {}", secondSpec.toString()); + LOG.info("Updated swarm: {}", newSpec.toString()); - swarm = dockerRule.getClient().inspectSwarmCmd().exec(); + swarm = dockerClient.inspectSwarmCmd().exec(); LOG.info("Inspected swarm: {}", swarm.toString()); - assertThat(swarm.getSpec(), is(equalTo(secondSpec))); + assertThat(swarm.getSpec(), is(equalTo(newSpec))); } - @Test(expected = NotAcceptableException.class) - public void updatingSwarmThrowsWhenNotInSwarm() throws DockerException { - SwarmSpec swarmSpec = new SwarmSpec() - .withName("swarm"); - - dockerRule.getClient().updateSwarmCmd(swarmSpec) - .withVersion(1l) + @Test(expected = DockerException.class) + public void updatingSwarmThrowsWhenNotInSwarm() throws Exception { + DockerClient dockerClient = startDockerInDocker(); + dockerClient.updateSwarmCmd(new SwarmSpec()) + .withVersion(1L) .exec(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmNodeIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmNodeIT.java index d55334ec6..d26e051b1 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmNodeIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmNodeIT.java @@ -5,7 +5,6 @@ import com.github.dockerjava.api.model.SwarmNodeAvailability; import com.github.dockerjava.api.model.SwarmNodeSpec; import com.github.dockerjava.api.model.SwarmNodeState; -import com.github.dockerjava.api.model.SwarmSpec; import org.junit.Test; import java.util.List; @@ -15,18 +14,17 @@ public class UpdateSwarmNodeIT extends SwarmCmdIT { @Test - public void testUpdateSwarmNode() throws Exception { - DockerClient docker1 = startDockerInDocker(); - docker1.initializeSwarmCmd(new SwarmSpec()).exec(); - List nodes = docker1.listSwarmNodesCmd().exec(); + public void testUpdateSwarmNode() { + DockerClient dockerClient = startSwarm(); + List nodes = dockerClient.listSwarmNodesCmd().exec(); assertThat(1, is(nodes.size())); SwarmNode node = nodes.get(0); assertThat(SwarmNodeState.READY, is(node.getStatus().getState())); //update the node availability SwarmNodeSpec nodeSpec = node.getSpec().withAvailability(SwarmNodeAvailability.PAUSE); - docker1.updateSwarmNodeCmd().withSwarmNodeId(node.getId()).withVersion(node.getVersion().getIndex()) + dockerClient.updateSwarmNodeCmd().withSwarmNodeId(node.getId()).withVersion(node.getVersion().getIndex()) .withSwarmNodeSpec(nodeSpec).exec(); - nodes = docker1.listSwarmNodesCmd().exec(); + nodes = dockerClient.listSwarmNodesCmd().exec(); assertThat(nodes.size(), is(1)); assertThat(nodes.get(0).getSpec().getAvailability(), is(SwarmNodeAvailability.PAUSE)); } diff --git a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmServiceIT.java b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmServiceIT.java index 3e5b948b6..c477320bf 100644 --- a/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmServiceIT.java +++ b/docker-java/src/test/java/com/github/dockerjava/cmd/swarm/UpdateSwarmServiceIT.java @@ -8,7 +8,6 @@ import com.github.dockerjava.api.model.ServiceModeConfig; import com.github.dockerjava.api.model.ServiceReplicatedModeOptions; import com.github.dockerjava.api.model.ServiceSpec; -import com.github.dockerjava.api.model.SwarmSpec; import com.github.dockerjava.api.model.TaskSpec; import com.google.common.collect.Lists; import org.junit.Test; @@ -16,34 +15,35 @@ import java.util.Arrays; import java.util.List; +import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; public class UpdateSwarmServiceIT extends SwarmCmdIT { @Test - public void testUpdateServiceReplicate() throws Exception { - DockerClient docker1 = startDockerInDocker(); - docker1.initializeSwarmCmd(new SwarmSpec()).exec(); + public void testUpdateServiceReplicate() { + DockerClient dockerClient = startSwarm(); //create network - String networkId = docker1.createNetworkCmd().withName("networkname").withDriver("overlay") + String networkId = dockerClient.createNetworkCmd().withName("networkname").withDriver("overlay") .withIpam(new Network.Ipam().withDriver("default")).exec().getId(); TaskSpec taskSpec = new TaskSpec().withContainerSpec( - new ContainerSpec().withImage("busybox").withArgs(Arrays.asList("sleep", "3600"))); + new ContainerSpec().withImage("busybox").withArgs(Arrays.asList("sleep", "3600")).withInit(true)); ServiceSpec serviceSpec = new ServiceSpec() .withMode(new ServiceModeConfig().withReplicated(new ServiceReplicatedModeOptions().withReplicas(1))) .withTaskTemplate(taskSpec) .withNetworks(Lists.newArrayList(new NetworkAttachmentConfig().withTarget(networkId))) .withName("worker"); - String serviceId = docker1.createServiceCmd(serviceSpec).exec().getId(); - //list the service - List services = docker1.listServicesCmd().withIdFilter(Arrays.asList(serviceId)).exec(); - assertThat(services.size(), is(1)); - Service service = services.get(0); - ServiceSpec updateServiceSpec = service.getSpec() + String serviceId = dockerClient.createServiceCmd(serviceSpec).exec().getId(); + await().untilAsserted(() -> { + List services = dockerClient.listServicesCmd().withIdFilter(Arrays.asList(serviceId)).exec(); + assertThat(services.size(), is(1)); + Service service = services.get(0); + ServiceSpec updateServiceSpec = service.getSpec() .withMode(new ServiceModeConfig().withReplicated(new ServiceReplicatedModeOptions().withReplicas(2))); - docker1.updateServiceCmd(service.getId(), updateServiceSpec).withVersion(service.getVersion().getIndex()).exec(); - //verify the replicate - Service updateService = docker1.listServicesCmd().withIdFilter(Arrays.asList(serviceId)).exec().get(0); - assertThat(updateService.getSpec().getMode().getReplicated().getReplicas(), is(2L)); + dockerClient.updateServiceCmd(service.getId(), updateServiceSpec).withVersion(service.getVersion().getIndex()).exec(); + //verify the replicate + Service updateService = dockerClient.listServicesCmd().withIdFilter(Arrays.asList(serviceId)).exec().get(0); + assertThat(updateService.getSpec().getMode().getReplicated().getReplicas(), is(2L)); + }); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/core/DefaultDockerClientConfigTest.java b/docker-java/src/test/java/com/github/dockerjava/core/DefaultDockerClientConfigTest.java index 107512da1..6c7787caf 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/DefaultDockerClientConfigTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/DefaultDockerClientConfigTest.java @@ -1,10 +1,10 @@ package com.github.dockerjava.core; -import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.AuthConfigurations; import com.google.common.io.Resources; -import org.apache.commons.lang.SerializationUtils; +import java.io.IOException; +import org.apache.commons.lang3.SerializationUtils; import org.junit.Test; import java.io.File; @@ -15,6 +15,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; +import java.util.UUID; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; @@ -22,17 +23,31 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class DefaultDockerClientConfigTest { public static final DefaultDockerClientConfig EXAMPLE_CONFIG = newExampleConfig(); + public static final DefaultDockerClientConfig EXAMPLE_CONFIG_FULLY_LOADED = newExampleConfigFullyLoaded(); private static DefaultDockerClientConfig newExampleConfig() { - String dockerCertPath = dockerCertPath(); + return new DefaultDockerClientConfig(URI.create("tcp://foo"), null, "dockerConfig", "apiVersion", "registryUrl", + "registryUsername", "registryPassword", "registryEmail", + new LocalDirectorySSLConfig(dockerCertPath)); + } - return new DefaultDockerClientConfig(URI.create("tcp://foo"), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", + private static DefaultDockerClientConfig newExampleConfigFullyLoaded() { + try { + String dockerCertPath = dockerCertPath(); + String dockerConfig = "dockerConfig"; + DockerConfigFile loadedConfigFile = DockerConfigFile.loadConfig(DockerClientConfig.getDefaultObjectMapper(), dockerConfig); + return new DefaultDockerClientConfig(URI.create("tcp://foo"), loadedConfigFile, dockerConfig, "apiVersion", "registryUrl", + "registryUsername", "registryPassword", "registryEmail", new LocalDirectorySSLConfig(dockerCertPath)); + } catch (IOException exception) { + throw new RuntimeException(exception); + } } private static String homeDir() { @@ -44,12 +59,12 @@ private static String dockerCertPath() { } @Test - public void equals() throws Exception { + public void equals() { assertEquals(EXAMPLE_CONFIG, newExampleConfig()); } @Test - public void environmentDockerHost() throws Exception { + public void environmentDockerHost() { // given docker host in env Map env = new HashMap<>(); @@ -65,11 +80,60 @@ public void environmentDockerHost() throws Exception { // when you build a config DefaultDockerClientConfig config = buildConfig(env, systemProperties); - assertEquals(config.getDockerHost(), URI.create("tcp://baz:8768")); + assertEquals(URI.create("tcp://baz:8768"), config.getDockerHost()); + } + + @Test + public void dockerContextFromConfig() { + // given home directory with docker contexts configured + Properties systemProperties = new Properties(); + systemProperties.setProperty("user.home", "target/test-classes/dockerContextHomeDir"); + + // and an empty environment + Map env = new HashMap<>(); + + // when you build a config + DefaultDockerClientConfig config = buildConfig(env, systemProperties); + + assertEquals(URI.create("unix:///configcontext.sock"), config.getDockerHost()); + } + + @Test + public void dockerContextFromEnvironmentVariable() { + // given home directory with docker contexts + Properties systemProperties = new Properties(); + systemProperties.setProperty("user.home", "target/test-classes/dockerContextHomeDir"); + + // and an environment variable that overrides docker context + Map env = new HashMap<>(); + env.put(DefaultDockerClientConfig.DOCKER_CONTEXT, "envvarcontext"); + + // when you build a config + DefaultDockerClientConfig config = buildConfig(env, systemProperties); + + assertEquals(URI.create("unix:///envvarcontext.sock"), config.getDockerHost()); } @Test - public void environment() throws Exception { + public void dockerContextWithDockerHostAndTLS() { + // given home directory with docker contexts + Properties systemProperties = new Properties(); + systemProperties.setProperty("user.home", "target/test-classes/dockerContextHomeDir"); + + // and an environment variable that overrides docker context + Map env = new HashMap<>(); + env.put(DefaultDockerClientConfig.DOCKER_CONTEXT, "remote"); + + // when you build a config + DefaultDockerClientConfig config = buildConfig(env, systemProperties); + + assertEquals(URI.create("tcp://remote:2376"), config.getDockerHost()); + assertTrue("SSL config is set", config.getSSLConfig() instanceof LocalDirectorySSLConfig); + assertTrue("SSL directory is set", ((LocalDirectorySSLConfig)config.getSSLConfig()).getDockerCertPath().endsWith("dockerContextHomeDir/.docker/contexts/tls/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/docker")); + } + + @Test + public void environment() { // given a default config in env properties Map env = new HashMap<>(); @@ -87,7 +151,20 @@ public void environment() throws Exception { DefaultDockerClientConfig config = buildConfig(env, new Properties()); // then we get the example object - assertEquals(config, EXAMPLE_CONFIG); + assertEquals(EXAMPLE_CONFIG_FULLY_LOADED, config); + } + + @Test + public void emptyHost() { + Map env = new HashMap<>(); + env.put(DefaultDockerClientConfig.DOCKER_HOST, " "); + + DefaultDockerClientConfig config = buildConfig(env, new Properties()); + + assertEquals( + DefaultDockerClientConfig.DEFAULT_DOCKER_HOST, + config.getDockerHost().toString() + ); } private DefaultDockerClientConfig buildConfig(Map env, Properties systemProperties) { @@ -95,7 +172,7 @@ private DefaultDockerClientConfig buildConfig(Map env, Propertie } @Test - public void defaults() throws Exception { + public void defaults() { // given default cert path Properties systemProperties = new Properties(); @@ -106,16 +183,16 @@ public void defaults() throws Exception { DefaultDockerClientConfig config = buildConfig(Collections. emptyMap(), systemProperties); // then the cert path is as expected - assertEquals(config.getDockerHost(), URI.create("unix:///var/run/docker.sock")); - assertEquals(config.getRegistryUsername(), "someUserName"); - assertEquals(config.getRegistryUrl(), AuthConfig.DEFAULT_SERVER_ADDRESS); - assertEquals(config.getApiVersion(), RemoteApiVersion.unknown()); - assertEquals(config.getDockerConfigPath(), homeDir() + "/.docker"); + assertEquals(URI.create("unix:///var/run/docker.sock"), config.getDockerHost()); + assertEquals("someUserName", config.getRegistryUsername()); + assertEquals(AuthConfig.DEFAULT_SERVER_ADDRESS, config.getRegistryUrl()); + assertEquals(RemoteApiVersion.unknown(), config.getApiVersion()); + assertEquals(homeDir() + "/.docker", config.getDockerConfigPath()); assertNull(config.getSSLConfig()); } @Test - public void systemProperties() throws Exception { + public void systemProperties() { // given system properties based on the example Properties systemProperties = new Properties(); @@ -133,7 +210,7 @@ public void systemProperties() throws Exception { DefaultDockerClientConfig config = buildConfig(Collections. emptyMap(), systemProperties); // then it is the same as the example - assertEquals(config, EXAMPLE_CONFIG); + assertEquals(EXAMPLE_CONFIG_FULLY_LOADED, config); } @@ -146,41 +223,24 @@ public void serializableTest() { } @Test() - public void testSslContextEmpty() throws Exception { - new DefaultDockerClientConfig(URI.create("tcp://foo"), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", + public void testSslContextEmpty() { + new DefaultDockerClientConfig(URI.create("tcp://foo"), new DockerConfigFile(), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", null); } @Test() - public void testTlsVerifyAndCertPath() throws Exception { - new DefaultDockerClientConfig(URI.create("tcp://foo"), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", + public void testTlsVerifyAndCertPath() { + new DefaultDockerClientConfig(URI.create("tcp://foo"), new DockerConfigFile(), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", new LocalDirectorySSLConfig(dockerCertPath())); } - @Test(expected = DockerClientException.class) - public void testWrongHostScheme() throws Exception { - new DefaultDockerClientConfig(URI.create("http://foo"), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", - null); - } - - @Test() - public void testTcpHostScheme() throws Exception { - new DefaultDockerClientConfig(URI.create("tcp://foo"), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", - null); - } - @Test() - public void testUnixHostScheme() throws Exception { - new DefaultDockerClientConfig(URI.create("unix://foo"), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", - null); - } - - @Test() - public void testNpipeHostScheme() throws Exception { - new DefaultDockerClientConfig(URI.create("npipe://foo"), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", - null); + public void testAnyHostScheme() { + URI dockerHost = URI.create("a" + UUID.randomUUID().toString().replace("-", "") + "://foo"); + new DefaultDockerClientConfig(dockerHost, new DockerConfigFile(), "dockerConfig", "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", + null); } @Test @@ -212,10 +272,52 @@ public void withDockerTlsVerify() throws Exception { } @Test - public void testGetAuthConfigurationsFromDockerCfg() throws URISyntaxException { + public void dockerHostSetExplicitlyOnSetter() { + DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder(Collections.emptyMap(), new Properties()); + assertThat(builder.isDockerHostSetExplicitly(), is(false)); + + builder.withDockerHost("tcp://foo"); + assertThat(builder.isDockerHostSetExplicitly(), is(true)); + } + + @Test + public void dockerHostSetExplicitlyOnSystemProperty() { + Properties systemProperties = new Properties(); + systemProperties.put(DefaultDockerClientConfig.DOCKER_HOST, "tcp://foo"); + + DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder(Collections.emptyMap(), systemProperties); + + assertThat(builder.isDockerHostSetExplicitly(), is(true)); + } + + @Test + public void dockerHostSetExplicitlyOnEnv() { + Map env = new HashMap<>(); + env.put(DefaultDockerClientConfig.DOCKER_HOST, "tcp://foo"); + + DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder(env, new Properties()); + + assertThat(builder.isDockerHostSetExplicitly(), is(true)); + } + + @Test + public void dockerHostSetExplicitlyIfSetToDefaultByUser() { + Map env = new HashMap<>(); + env.put(DefaultDockerClientConfig.DOCKER_HOST, DefaultDockerClientConfig.DEFAULT_DOCKER_HOST); + + DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder(env, new Properties()); + + assertThat(builder.isDockerHostSetExplicitly(), is(true)); + } + + + @Test + public void testGetAuthConfigurationsFromDockerCfg() throws URISyntaxException, IOException { File cfgFile = new File(Resources.getResource("com.github.dockerjava.core/registry.v1").toURI()); + DockerConfigFile dockerConfigFile = + DockerConfigFile.loadConfig(DockerClientConfig.getDefaultObjectMapper(), cfgFile.getAbsolutePath()); DefaultDockerClientConfig clientConfig = new DefaultDockerClientConfig(URI.create( - "unix://foo"), cfgFile.getAbsolutePath(), "apiVersion", "registryUrl", "registryUsername", "registryPassword", + "unix://foo"), dockerConfigFile, cfgFile.getAbsolutePath(), "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", null); AuthConfigurations authConfigurations = clientConfig.getAuthConfigurations(); @@ -228,10 +330,12 @@ public void testGetAuthConfigurationsFromDockerCfg() throws URISyntaxException { } @Test - public void testGetAuthConfigurationsFromConfigJson() throws URISyntaxException { + public void testGetAuthConfigurationsFromConfigJson() throws URISyntaxException, IOException { File cfgFile = new File(Resources.getResource("com.github.dockerjava.core/registry.v2").toURI()); + DockerConfigFile dockerConfigFile = + DockerConfigFile.loadConfig(DockerClientConfig.getDefaultObjectMapper(), cfgFile.getAbsolutePath()); DefaultDockerClientConfig clientConfig = new DefaultDockerClientConfig(URI.create( - "unix://foo"), cfgFile.getAbsolutePath(), "apiVersion", "registryUrl", "registryUsername", "registryPassword", + "unix://foo"), dockerConfigFile, cfgFile.getAbsolutePath(), "apiVersion", "registryUrl", "registryUsername", "registryPassword", "registryEmail", null); AuthConfigurations authConfigurations = clientConfig.getAuthConfigurations(); diff --git a/docker-java/src/test/java/com/github/dockerjava/core/DockerClientBuilderTest.java b/docker-java/src/test/java/com/github/dockerjava/core/DockerClientBuilderTest.java index be0bfda8a..d826a98ce 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/DockerClientBuilderTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/DockerClientBuilderTest.java @@ -34,7 +34,7 @@ public void testConcurrentClientBuilding() throws Exception { parallel(AMOUNT, runnable); // set contains all required unique instances - assertEquals(instances.size(), AMOUNT); + assertEquals(AMOUNT, instances.size()); } public static void parallel(int threads, final Runnable task) throws Exception { diff --git a/docker-java/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java b/docker-java/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java index 08f658d52..6ae88ffd1 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java @@ -10,9 +10,10 @@ public class DockerClientImplTest { @Test - public void configuredInstanceAuthConfig() throws Exception { + public void configuredInstanceAuthConfig() { // given a config with null serverAddress - DefaultDockerClientConfig dockerClientConfig = new DefaultDockerClientConfig(URI.create("tcp://foo"), null, null, null, "", "", "", null); + DefaultDockerClientConfig dockerClientConfig = new DefaultDockerClientConfig(URI.create("tcp://foo"), + new DockerConfigFile(), null, null, null, "", "", "", null); DockerClientImpl dockerClient = DockerClientImpl.getInstance(dockerClientConfig); // when we get the auth config @@ -21,12 +22,12 @@ public void configuredInstanceAuthConfig() throws Exception { throw new AssertionError(); } catch (NullPointerException e) { // then we get a NPE with expected message - assertEquals(e.getMessage(), "Configured serverAddress is null."); + assertEquals("Configured serverAddress is null.", e.getMessage()); } } @Test - public void defaultInstanceAuthConfig() throws Exception { + public void defaultInstanceAuthConfig() { System.setProperty("user.home", "target/test-classes/someHomeDir"); diff --git a/docker-java/src/test/java/com/github/dockerjava/junit/DockerCmdExecFactoryDelegate.java b/docker-java/src/test/java/com/github/dockerjava/core/DockerCmdExecFactoryDelegate.java similarity index 83% rename from docker-java/src/test/java/com/github/dockerjava/junit/DockerCmdExecFactoryDelegate.java rename to docker-java/src/test/java/com/github/dockerjava/core/DockerCmdExecFactoryDelegate.java index 807b92a4b..463c63ffe 100644 --- a/docker-java/src/test/java/com/github/dockerjava/junit/DockerCmdExecFactoryDelegate.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/DockerCmdExecFactoryDelegate.java @@ -1,9 +1,7 @@ -package com.github.dockerjava.junit; +package com.github.dockerjava.core; import com.github.dockerjava.api.command.DelegatingDockerCmdExecFactory; import com.github.dockerjava.api.command.DockerCmdExecFactory; -import com.github.dockerjava.core.DockerClientConfig; -import com.github.dockerjava.core.DockerClientConfigAware; class DockerCmdExecFactoryDelegate extends DelegatingDockerCmdExecFactory implements DockerClientConfigAware { diff --git a/docker-java/src/test/java/com/github/dockerjava/core/DockerConfigFileTest.java b/docker-java/src/test/java/com/github/dockerjava/core/DockerConfigFileTest.java index 83bc124e9..76211fc55 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/DockerConfigFileTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/DockerConfigFileTest.java @@ -150,12 +150,26 @@ public void validDockerConfig() throws IOException { assertThat(runTest("validDockerConfig"), is(expected)); } + @Test + public void validDockerConfigWithCurrentContext() throws IOException { + DockerConfigFile expected = new DockerConfigFile(); + expected.setCurrentContext("expectedContext"); + + assertThat(runTest("validDockerConfigWithCurrentContext"), is(expected)); + } + @Test public void nonExistent() throws IOException { DockerConfigFile expected = new DockerConfigFile(); assertThat(runTest("idontexist"), is(expected)); } + @Test + public void validJsonAuthsNull() throws IOException { + DockerConfigFile expected = new DockerConfigFile(); + assertThat(runTest("validJsonAuthsNull"), is(expected)); + } + private DockerConfigFile runTest(String testFileName) throws IOException { return DockerConfigFile.loadConfig(JSONTestHelper.getMapper(), new File(FILESROOT, testFileName).getAbsolutePath()); } diff --git a/docker-java/src/test/java/com/github/dockerjava/junit/DockerRule.java b/docker-java/src/test/java/com/github/dockerjava/core/DockerRule.java similarity index 72% rename from docker-java/src/test/java/com/github/dockerjava/junit/DockerRule.java rename to docker-java/src/test/java/com/github/dockerjava/core/DockerRule.java index 2edefb14a..af606a5b1 100644 --- a/docker-java/src/test/java/com/github/dockerjava/junit/DockerRule.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/DockerRule.java @@ -1,18 +1,16 @@ -package com.github.dockerjava.junit; +package com.github.dockerjava.core; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.DockerClientDelegate; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.CreateNetworkCmd; import com.github.dockerjava.api.command.CreateNetworkResponse; import com.github.dockerjava.api.command.CreateVolumeCmd; import com.github.dockerjava.api.command.CreateVolumeResponse; -import com.github.dockerjava.api.command.DockerCmdExecFactory; import com.github.dockerjava.api.exception.ConflictException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.cmd.CmdIT; -import com.github.dockerjava.core.DefaultDockerClientConfig; -import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.utils.LogContainerTestCallback; import org.junit.rules.ExternalResource; import org.junit.runner.Description; @@ -33,60 +31,68 @@ public class DockerRule extends ExternalResource { private DockerClient dockerClient; - private CmdIT cmdIT; - private final Set createdContainerIds = new HashSet<>(); private final Set createdNetworkIds = new HashSet<>(); private final Set createdVolumeNames = new HashSet<>(); - public DockerRule(CmdIT cmdIT) { - this.cmdIT = cmdIT; - } - + private final DefaultDockerClientConfig config = config(); + + public DockerClient newClient() { + DockerClientImpl dockerClient = CmdIT.createDockerClient(config); + + dockerClient.withDockerCmdExecFactory( + new DockerCmdExecFactoryDelegate(dockerClient.dockerCmdExecFactory) { + @Override + public CreateContainerCmd.Exec createCreateContainerCmdExec() { + CreateContainerCmd.Exec exec = super.createCreateContainerCmdExec(); + return command -> { + CreateContainerResponse response = exec.exec(command); + createdContainerIds.add(response.getId()); + return response; + }; + } - public DockerClient getClient() { - if (dockerClient != null) { - return dockerClient; - } - DockerCmdExecFactory execFactory = new DockerCmdExecFactoryDelegate( - cmdIT.getFactoryType().createExecFactory() - ) { - @Override - public CreateContainerCmd.Exec createCreateContainerCmdExec() { - CreateContainerCmd.Exec exec = super.createCreateContainerCmdExec(); - return command -> { - CreateContainerResponse response = exec.exec(command); - createdContainerIds.add(response.getId()); - return response; - }; - } + @Override + public CreateNetworkCmd.Exec createCreateNetworkCmdExec() { + CreateNetworkCmd.Exec exec = super.createCreateNetworkCmdExec(); + return command -> { + CreateNetworkResponse response = exec.exec(command); + createdNetworkIds.add(response.getId()); + return response; + }; + } - @Override - public CreateNetworkCmd.Exec createCreateNetworkCmdExec() { - CreateNetworkCmd.Exec exec = super.createCreateNetworkCmdExec(); - return command -> { - CreateNetworkResponse response = exec.exec(command); - createdNetworkIds.add(response.getId()); - return response; - }; + @Override + public CreateVolumeCmd.Exec createCreateVolumeCmdExec() { + CreateVolumeCmd.Exec exec = super.createCreateVolumeCmdExec(); + return command -> { + CreateVolumeResponse response = exec.exec(command); + createdVolumeNames.add(response.getName()); + return response; + }; + } } + ); + return new DockerClientDelegate() { @Override - public CreateVolumeCmd.Exec createCreateVolumeCmdExec() { - CreateVolumeCmd.Exec exec = super.createCreateVolumeCmdExec(); - return command -> { - CreateVolumeResponse response = exec.exec(command); - createdVolumeNames.add(response.getName()); - return response; - }; + protected DockerClient getDockerClient() { + return dockerClient; } }; + } - return dockerClient = DockerClientBuilder.getInstance(config()) - .withDockerCmdExecFactory(execFactory) - .build(); + public DefaultDockerClientConfig getConfig() { + return config; + } + + public DockerClient getClient() { + if (dockerClient != null) { + return dockerClient; + } + return this.dockerClient = newClient(); } @Override @@ -168,6 +174,7 @@ private static DefaultDockerClientConfig config() { public static DefaultDockerClientConfig config(String password) { DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withApiVersion(RemoteApiVersion.VERSION_1_44) .withRegistryUrl("https://index.docker.io/v1/"); if (password != null) { builder = builder.withRegistryPassword(password); @@ -191,10 +198,6 @@ public String containerLog(String containerId) throws Exception { .toString(); } - public String getKind() { - return cmdIT.getFactoryType().name().toLowerCase(); - } - public void ensureContainerRemoved(String container1Name) { try { getClient().removeContainerCmd(container1Name) @@ -206,13 +209,4 @@ public void ensureContainerRemoved(String container1Name) { } } - public void ensureImageRemoved(String imageId) { - try { - getClient().removeImageCmd(imageId) - .withForce(true) - .exec(); - } catch (NotFoundException ex) { - // ignore - } - } } diff --git a/docker-java/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java b/docker-java/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java index b6dde97f5..11ea90e57 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/GoLangFileMatchTest.java @@ -85,7 +85,7 @@ public static Object[][] getTestData() { public MatchTestCase testCase; @Test - public void testMatch() throws IOException { + public void testMatch() { String pattern = testCase.pattern; String s = testCase.s; if (GoLangFileMatch.IS_WINDOWS) { diff --git a/docker-java/src/test/java/com/github/dockerjava/core/NameParserTest.java b/docker-java/src/test/java/com/github/dockerjava/core/NameParserTest.java index 234ed47a1..89ad131f6 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/NameParserTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/NameParserTest.java @@ -7,7 +7,7 @@ import com.github.dockerjava.core.NameParser.HostnameReposName; import com.github.dockerjava.core.NameParser.ReposTag; import com.github.dockerjava.core.exception.InvalidRepositoryNameException; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -21,7 +21,7 @@ public class NameParserTest { @Test - public void testValidateRepoName() throws Exception { + public void testValidateRepoName() { NameParser.validateRepoName("repository"); NameParser.validateRepoName("namespace/repository"); NameParser.validateRepoName("namespace-with-dashes/repository"); @@ -33,118 +33,159 @@ public void testValidateRepoName() throws Exception { } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameEmpty() throws Exception { + public void testValidateRepoNameEmpty() { NameParser.validateRepoName(""); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameExceedsMaxLength() throws Exception { + public void testValidateRepoNameExceedsMaxLength() { NameParser.validateRepoName(StringUtils.repeat("repository", 255)); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameEndWithDash() throws Exception { + public void testValidateRepoNameEndWithDash() { NameParser.validateRepoName("repository-"); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameStartWithDash() throws Exception { + public void testValidateRepoNameStartWithDash() { NameParser.validateRepoName("-repository"); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameEndWithDot() throws Exception { + public void testValidateRepoNameEndWithDot() { NameParser.validateRepoName("repository."); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameStartWithDot() throws Exception { + public void testValidateRepoNameStartWithDot() { NameParser.validateRepoName(".repository"); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameEndWithUnderscore() throws Exception { + public void testValidateRepoNameEndWithUnderscore() { NameParser.validateRepoName("repository_"); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameStartWithUnderscore() throws Exception { + public void testValidateRepoNameStartWithUnderscore() { NameParser.validateRepoName("_repository"); } @Test(expected = InvalidRepositoryNameException.class) - public void testValidateRepoNameWithColon() throws Exception { + public void testValidateRepoNameWithColon() { NameParser.validateRepoName("repository:with:colon"); } @Test - public void testResolveSimpleRepositoryName() throws Exception { + public void testResolveSimpleRepositoryName() { HostnameReposName resolved = NameParser.resolveRepositoryName("repository"); - assertEquals(resolved, new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "repository")); + assertEquals(new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "repository"), resolved); } @Test - public void testResolveRepositoryNameWithNamespace() throws Exception { + public void testResolveRepositoryNameWithTag() { + HostnameReposName resolved = NameParser.resolveRepositoryName("repository:tag"); + assertEquals(new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "repository"), resolved); + } + + @Test + public void testResolveRepositoryNameWithSHA256() { + HostnameReposName resolved = NameParser.resolveRepositoryName("repository@sha256:sha256"); + assertEquals(new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "repository"), resolved); + } + + @Test + public void testResolveRepositoryNameWithTagAndSHA256() { + HostnameReposName resolved = NameParser.resolveRepositoryName("repository:tag@sha256:sha256"); + assertEquals(new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "repository"), resolved); + } + + @Test + public void testResolveRepositoryNameWithNamespace() { HostnameReposName resolved = NameParser.resolveRepositoryName("namespace/repository"); - assertEquals(resolved, new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "namespace/repository")); + assertEquals(new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "namespace/repository"), resolved); } @Test - public void testResolveRepositoryNameWithNamespaceAndSHA256() throws Exception { + public void testResolveRepositoryNameWithNamespaceAndSHA256() { HostnameReposName resolved = NameParser.resolveRepositoryName("namespace/repository@sha256:sha256"); - assertEquals(resolved, new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "namespace/repository@sha256:sha256")); + assertEquals(new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, "namespace/repository"), resolved); } @Test - public void testResolveRepositoryNameWithNamespaceAndHostname() throws Exception { + public void testResolveRepositoryNameWithNamespaceAndHostname() { HostnameReposName resolved = NameParser.resolveRepositoryName("localhost:5000/namespace/repository"); - assertEquals(resolved, new HostnameReposName("localhost:5000", "namespace/repository")); + assertEquals(new HostnameReposName("localhost:5000", "namespace/repository"), resolved); } @Test - public void testResolveRepositoryNameWithNamespaceAndHostnameAndSHA256() throws Exception { + public void testResolveRepositoryNameWithNamespaceAndHostnameAndSHA256() { HostnameReposName resolved = NameParser.resolveRepositoryName("localhost:5000/namespace/repository@sha256:sha256"); - assertEquals(resolved, new HostnameReposName("localhost:5000", "namespace/repository")); + assertEquals(new HostnameReposName("localhost:5000", "namespace/repository"), resolved); + } + + @Test + public void testResolveRepositoryNameWithNamespaceAndHostnameAndTag() { + HostnameReposName resolved = NameParser.resolveRepositoryName("localhost:5000/namespace/repository:tag"); + assertEquals(new HostnameReposName("localhost:5000", "namespace/repository"), resolved); + } + @Test + public void testResolveRepositoryNameWithNamespaceAndHostnameAndTagAndSHA256() { + HostnameReposName resolved = NameParser.resolveRepositoryName("localhost:5000/namespace/repository:tag@sha256:sha256"); + assertEquals(new HostnameReposName("localhost:5000", "namespace/repository"), resolved); } @Test(expected = InvalidRepositoryNameException.class) - public void testResolveRepositoryNameWithIndex() throws Exception { + public void testResolveRepositoryNameWithIndex() { NameParser.resolveRepositoryName("index.docker.io/repository"); } @Test - public void testResolveReposTagWithoutTagSimple() throws Exception { + public void testResolveReposTagWithoutTagSimple() { ReposTag resolved = NameParser.parseRepositoryTag("repository"); - assertEquals(resolved, new ReposTag("repository", "")); + assertEquals(new ReposTag("repository", ""), resolved); resolved = NameParser.parseRepositoryTag("namespace/repository"); - assertEquals(resolved, new ReposTag("namespace/repository", "")); + assertEquals(new ReposTag("namespace/repository", ""), resolved); resolved = NameParser.parseRepositoryTag("localhost:5000/namespace/repository"); - assertEquals(resolved, new ReposTag("localhost:5000/namespace/repository", "")); + assertEquals(new ReposTag("localhost:5000/namespace/repository", ""), resolved); } @Test - public void testResolveReposTagWithTag() throws Exception { + public void testResolveReposTagWithTag() { ReposTag resolved = NameParser.parseRepositoryTag("repository:tag"); - assertEquals(resolved, new ReposTag("repository", "tag")); + assertEquals(new ReposTag("repository", "tag"), resolved); resolved = NameParser.parseRepositoryTag("namespace/repository:tag"); - assertEquals(resolved, new ReposTag("namespace/repository", "tag")); + assertEquals(new ReposTag("namespace/repository", "tag"), resolved); resolved = NameParser.parseRepositoryTag("localhost:5000/namespace/repository:tag"); - assertEquals(resolved, new ReposTag("localhost:5000/namespace/repository", "tag")); + assertEquals(new ReposTag("localhost:5000/namespace/repository", "tag"), resolved); } @Test - public void testResolveReposTagWithSHA256() throws Exception { + public void testResolveReposTagWithSHA256() { ReposTag resolved = NameParser.parseRepositoryTag("repository@sha256:sha256"); - assertEquals(resolved, new ReposTag("repository@sha256:sha256", "")); + assertEquals(new ReposTag("repository@sha256:sha256", ""), resolved); resolved = NameParser.parseRepositoryTag("namespace/repository@sha256:sha256"); - assertEquals(resolved, new ReposTag("namespace/repository@sha256:sha256", "")); + assertEquals(new ReposTag("namespace/repository@sha256:sha256", ""), resolved); resolved = NameParser.parseRepositoryTag("localhost:5000/namespace/repository@sha256:sha256"); - assertEquals(resolved, new ReposTag("localhost:5000/namespace/repository@sha256:sha256", "")); + assertEquals(new ReposTag("localhost:5000/namespace/repository@sha256:sha256", ""), resolved); + } + + @Test + public void testResolveReposTagWithTagAndSHA256() { + ReposTag resolved = NameParser.parseRepositoryTag("repository:tag@sha256:sha256"); + assertEquals(new ReposTag("repository:tag@sha256:sha256", ""), resolved); + + resolved = NameParser.parseRepositoryTag("namespace/repository:tag@sha256:sha256"); + assertEquals(new ReposTag("namespace/repository:tag@sha256:sha256", ""), resolved); + + resolved = NameParser.parseRepositoryTag("localhost:5000/namespace/repository:tag@sha256:sha256"); + assertEquals(new ReposTag("localhost:5000/namespace/repository:tag@sha256:sha256", ""), resolved); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/core/RemoteApiVersionTest.java b/docker-java/src/test/java/com/github/dockerjava/core/RemoteApiVersionTest.java index a9446ffd4..06b825868 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/RemoteApiVersionTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/RemoteApiVersionTest.java @@ -1,6 +1,6 @@ package com.github.dockerjava.core; -import org.apache.commons.lang.SerializationUtils; +import org.apache.commons.lang3.SerializationUtils; import org.junit.Test; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/docker-java/src/test/java/com/github/dockerjava/core/TestDockerCmdExecFactory.java b/docker-java/src/test/java/com/github/dockerjava/core/TestDockerCmdExecFactory.java deleted file mode 100644 index 64280c386..000000000 --- a/docker-java/src/test/java/com/github/dockerjava/core/TestDockerCmdExecFactory.java +++ /dev/null @@ -1,544 +0,0 @@ -package com.github.dockerjava.core; - -import com.github.dockerjava.api.command.AttachContainerCmd; -import com.github.dockerjava.api.command.AuthCmd.Exec; -import com.github.dockerjava.api.command.BuildImageCmd; -import com.github.dockerjava.api.command.CommitCmd; -import com.github.dockerjava.api.command.ConnectToNetworkCmd; -import com.github.dockerjava.api.command.ContainerDiffCmd; -import com.github.dockerjava.api.command.CopyArchiveFromContainerCmd; -import com.github.dockerjava.api.command.CopyArchiveToContainerCmd; -import com.github.dockerjava.api.command.CopyFileFromContainerCmd; -import com.github.dockerjava.api.command.CreateContainerCmd; -import com.github.dockerjava.api.command.CreateContainerResponse; -import com.github.dockerjava.api.command.CreateImageCmd; -import com.github.dockerjava.api.command.CreateImageResponse; -import com.github.dockerjava.api.command.CreateNetworkCmd; -import com.github.dockerjava.api.command.CreateNetworkResponse; -import com.github.dockerjava.api.command.CreateSecretCmd; -import com.github.dockerjava.api.command.CreateServiceCmd; -import com.github.dockerjava.api.command.CreateVolumeCmd; -import com.github.dockerjava.api.command.CreateVolumeResponse; -import com.github.dockerjava.api.command.DisconnectFromNetworkCmd; -import com.github.dockerjava.api.command.DockerCmdExecFactory; -import com.github.dockerjava.api.command.EventsCmd; -import com.github.dockerjava.api.command.ExecCreateCmd; -import com.github.dockerjava.api.command.ExecStartCmd; -import com.github.dockerjava.api.command.InfoCmd; -import com.github.dockerjava.api.command.InitializeSwarmCmd; -import com.github.dockerjava.api.command.InspectContainerCmd; -import com.github.dockerjava.api.command.InspectExecCmd; -import com.github.dockerjava.api.command.InspectImageCmd; -import com.github.dockerjava.api.command.InspectNetworkCmd; -import com.github.dockerjava.api.command.InspectServiceCmd; -import com.github.dockerjava.api.command.InspectSwarmCmd; -import com.github.dockerjava.api.command.InspectSwarmNodeCmd; -import com.github.dockerjava.api.command.InspectVolumeCmd; -import com.github.dockerjava.api.command.JoinSwarmCmd; -import com.github.dockerjava.api.command.KillContainerCmd; -import com.github.dockerjava.api.command.LeaveSwarmCmd; -import com.github.dockerjava.api.command.ListContainersCmd; -import com.github.dockerjava.api.command.ListImagesCmd; -import com.github.dockerjava.api.command.ListNetworksCmd; -import com.github.dockerjava.api.command.ListSecretsCmd; -import com.github.dockerjava.api.command.ListServicesCmd; -import com.github.dockerjava.api.command.ListSwarmNodesCmd; -import com.github.dockerjava.api.command.ListTasksCmd; -import com.github.dockerjava.api.command.ListVolumesCmd; -import com.github.dockerjava.api.command.LoadImageCmd; -import com.github.dockerjava.api.command.LogContainerCmd; -import com.github.dockerjava.api.command.LogSwarmObjectCmd; -import com.github.dockerjava.api.command.PauseContainerCmd; -import com.github.dockerjava.api.command.PingCmd; -import com.github.dockerjava.api.command.PruneCmd; -import com.github.dockerjava.api.command.PullImageCmd; -import com.github.dockerjava.api.command.PushImageCmd; -import com.github.dockerjava.api.command.RemoveContainerCmd; -import com.github.dockerjava.api.command.RemoveImageCmd; -import com.github.dockerjava.api.command.RemoveNetworkCmd; -import com.github.dockerjava.api.command.RemoveSecretCmd; -import com.github.dockerjava.api.command.RemoveServiceCmd; -import com.github.dockerjava.api.command.RemoveSwarmNodeCmd; -import com.github.dockerjava.api.command.RemoveVolumeCmd; -import com.github.dockerjava.api.command.RenameContainerCmd; -import com.github.dockerjava.api.command.RestartContainerCmd; -import com.github.dockerjava.api.command.SaveImageCmd; -import com.github.dockerjava.api.command.SaveImagesCmd; -import com.github.dockerjava.api.command.SearchImagesCmd; -import com.github.dockerjava.api.command.StartContainerCmd; -import com.github.dockerjava.api.command.StatsCmd; -import com.github.dockerjava.api.command.StopContainerCmd; -import com.github.dockerjava.api.command.TagImageCmd; -import com.github.dockerjava.api.command.TopContainerCmd; -import com.github.dockerjava.api.command.UnpauseContainerCmd; -import com.github.dockerjava.api.command.UpdateContainerCmd; -import com.github.dockerjava.api.command.UpdateServiceCmd; -import com.github.dockerjava.api.command.UpdateSwarmCmd; -import com.github.dockerjava.api.command.UpdateSwarmNodeCmd; -import com.github.dockerjava.api.command.VersionCmd; -import com.github.dockerjava.api.command.WaitContainerCmd; - -import java.io.IOException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.List; - -/** - * Special {@link DockerCmdExecFactory} implementation that collects container and image creations while test execution for the purpose of - * automatically cleanup. - * - * @author Marcus Linke - */ -public class TestDockerCmdExecFactory implements DockerCmdExecFactory, DockerClientConfigAware { - - private List containerNames = new ArrayList<>(); - - private List imageNames = new ArrayList<>(); - - private List volumeNames = new ArrayList<>(); - - private List networkIds = new ArrayList<>(); - - private DockerCmdExecFactory delegate; - - public TestDockerCmdExecFactory(DockerCmdExecFactory delegate) { - this.delegate = delegate; - } - - @Override - public void init(DockerClientConfig dockerClientConfig) { - if (delegate instanceof DockerClientConfigAware) { - ((DockerClientConfigAware) delegate).init(dockerClientConfig); - } - } - - @Override - public void close() throws IOException { - delegate.close(); - } - - @Override - public CreateContainerCmd.Exec createCreateContainerCmdExec() { - return command -> { - CreateContainerResponse createContainerResponse = delegate.createCreateContainerCmdExec().exec(command); - containerNames.add(createContainerResponse.getId()); - return createContainerResponse; - }; - } - - @Override - public RemoveContainerCmd.Exec createRemoveContainerCmdExec() { - return command -> { - delegate.createRemoveContainerCmdExec().exec(command); - containerNames.remove(command.getContainerId()); - return null; - }; - } - - @Override - public CreateImageCmd.Exec createCreateImageCmdExec() { - return command -> { - CreateImageResponse createImageResponse = delegate.createCreateImageCmdExec().exec(command); - imageNames.add(createImageResponse.getId()); - return createImageResponse; - }; - } - - @Override - public LoadImageCmd.Exec createLoadImageCmdExec() { - return command -> { - delegate.createLoadImageCmdExec().exec(command); - return null; - }; - } - - @Override - public RemoveImageCmd.Exec createRemoveImageCmdExec() { - return command -> { - delegate.createRemoveImageCmdExec().exec(command); - imageNames.remove(command.getImageId()); - return null; - }; - } - - @Override - public BuildImageCmd.Exec createBuildImageCmdExec() { - return (command, resultCallback) -> { - // can't detect image id here so tagging it - String tag = command.getTag(); - if (tag == null || "".equals(tag.trim())) { - tag = "" + new SecureRandom().nextInt(Integer.MAX_VALUE); - command.withTag(tag); - } - delegate.createBuildImageCmdExec().exec(command, resultCallback); - imageNames.add(tag); - return null; - }; - } - - @Override - public Exec createAuthCmdExec() { - return delegate.createAuthCmdExec(); - } - - @Override - public InfoCmd.Exec createInfoCmdExec() { - return delegate.createInfoCmdExec(); - } - - @Override - public PingCmd.Exec createPingCmdExec() { - return delegate.createPingCmdExec(); - } - - @Override - public ExecCreateCmd.Exec createExecCmdExec() { - return delegate.createExecCmdExec(); - } - - @Override - public VersionCmd.Exec createVersionCmdExec() { - return delegate.createVersionCmdExec(); - } - - @Override - public PullImageCmd.Exec createPullImageCmdExec() { - return delegate.createPullImageCmdExec(); - } - - @Override - public PushImageCmd.Exec createPushImageCmdExec() { - return delegate.createPushImageCmdExec(); - } - - @Override - public SaveImageCmd.Exec createSaveImageCmdExec() { - return delegate.createSaveImageCmdExec(); - } - - @Override - public SaveImagesCmd.Exec createSaveImagesCmdExec() { - return delegate.createSaveImagesCmdExec(); - } - - @Override - public SearchImagesCmd.Exec createSearchImagesCmdExec() { - return delegate.createSearchImagesCmdExec(); - } - - @Override - public ListImagesCmd.Exec createListImagesCmdExec() { - return delegate.createListImagesCmdExec(); - } - - @Override - public InspectImageCmd.Exec createInspectImageCmdExec() { - return delegate.createInspectImageCmdExec(); - } - - @Override - public ListContainersCmd.Exec createListContainersCmdExec() { - return delegate.createListContainersCmdExec(); - } - - @Override - public StartContainerCmd.Exec createStartContainerCmdExec() { - return delegate.createStartContainerCmdExec(); - } - - @Override - public InspectContainerCmd.Exec createInspectContainerCmdExec() { - return delegate.createInspectContainerCmdExec(); - } - - @Override - public WaitContainerCmd.Exec createWaitContainerCmdExec() { - return delegate.createWaitContainerCmdExec(); - } - - @Override - public AttachContainerCmd.Exec createAttachContainerCmdExec() { - return delegate.createAttachContainerCmdExec(); - } - - @Override - public ExecStartCmd.Exec createExecStartCmdExec() { - return delegate.createExecStartCmdExec(); - } - - @Override - public InspectExecCmd.Exec createInspectExecCmdExec() { - return delegate.createInspectExecCmdExec(); - } - - @Override - public LogContainerCmd.Exec createLogContainerCmdExec() { - return delegate.createLogContainerCmdExec(); - } - - @Override - public CopyFileFromContainerCmd.Exec createCopyFileFromContainerCmdExec() { - return delegate.createCopyFileFromContainerCmdExec(); - } - - @Override - public CopyArchiveFromContainerCmd.Exec createCopyArchiveFromContainerCmdExec() { - return delegate.createCopyArchiveFromContainerCmdExec(); - } - - @Override - public CopyArchiveToContainerCmd.Exec createCopyArchiveToContainerCmdExec() { - return delegate.createCopyArchiveToContainerCmdExec(); - } - - @Override - public StopContainerCmd.Exec createStopContainerCmdExec() { - return delegate.createStopContainerCmdExec(); - } - - @Override - public ContainerDiffCmd.Exec createContainerDiffCmdExec() { - return delegate.createContainerDiffCmdExec(); - } - - @Override - public KillContainerCmd.Exec createKillContainerCmdExec() { - return delegate.createKillContainerCmdExec(); - } - - @Override - public UpdateContainerCmd.Exec createUpdateContainerCmdExec() { - return delegate.createUpdateContainerCmdExec(); - } - - @Override - public RenameContainerCmd.Exec createRenameContainerCmdExec() { - return delegate.createRenameContainerCmdExec(); - } - - @Override - public RestartContainerCmd.Exec createRestartContainerCmdExec() { - return delegate.createRestartContainerCmdExec(); - } - - @Override - public CommitCmd.Exec createCommitCmdExec() { - return delegate.createCommitCmdExec(); - } - - @Override - public TopContainerCmd.Exec createTopContainerCmdExec() { - return delegate.createTopContainerCmdExec(); - } - - @Override - public TagImageCmd.Exec createTagImageCmdExec() { - return delegate.createTagImageCmdExec(); - } - - @Override - public PauseContainerCmd.Exec createPauseContainerCmdExec() { - return delegate.createPauseContainerCmdExec(); - } - - @Override - public UnpauseContainerCmd.Exec createUnpauseContainerCmdExec() { - return delegate.createUnpauseContainerCmdExec(); - } - - @Override - public EventsCmd.Exec createEventsCmdExec() { - return delegate.createEventsCmdExec(); - } - - @Override - public StatsCmd.Exec createStatsCmdExec() { - return delegate.createStatsCmdExec(); - } - - @Override - public CreateVolumeCmd.Exec createCreateVolumeCmdExec() { - return command -> { - CreateVolumeResponse result = delegate.createCreateVolumeCmdExec().exec(command); - volumeNames.add(command.getName()); - return result; - }; - } - - @Override - public InspectVolumeCmd.Exec createInspectVolumeCmdExec() { - return delegate.createInspectVolumeCmdExec(); - } - - @Override - public RemoveVolumeCmd.Exec createRemoveVolumeCmdExec() { - return command -> { - delegate.createRemoveVolumeCmdExec().exec(command); - volumeNames.remove(command.getName()); - return null; - }; - } - - @Override - public ListVolumesCmd.Exec createListVolumesCmdExec() { - return delegate.createListVolumesCmdExec(); - } - - @Override - public ListNetworksCmd.Exec createListNetworksCmdExec() { - return delegate.createListNetworksCmdExec(); - } - - @Override - public InspectNetworkCmd.Exec createInspectNetworkCmdExec() { - return delegate.createInspectNetworkCmdExec(); - } - - @Override - public CreateNetworkCmd.Exec createCreateNetworkCmdExec() { - - return command -> { - CreateNetworkResponse result = delegate.createCreateNetworkCmdExec().exec(command); - networkIds.add(result.getId()); - return result; - }; - } - - @Override - public RemoveNetworkCmd.Exec createRemoveNetworkCmdExec() { - return command -> { - delegate.createRemoveNetworkCmdExec().exec(command); - networkIds.remove(command.getNetworkId()); - return null; - }; - } - - @Override - public ConnectToNetworkCmd.Exec createConnectToNetworkCmdExec() { - return delegate.createConnectToNetworkCmdExec(); - } - - @Override - public DisconnectFromNetworkCmd.Exec createDisconnectFromNetworkCmdExec() { - return delegate.createDisconnectFromNetworkCmdExec(); - } - - // swarm - @Override - public InitializeSwarmCmd.Exec createInitializeSwarmCmdExec() { - return delegate.createInitializeSwarmCmdExec(); - } - - @Override - public InspectSwarmCmd.Exec createInspectSwarmCmdExec() { - return delegate.createInspectSwarmCmdExec(); - } - - @Override - public JoinSwarmCmd.Exec createJoinSwarmCmdExec() { - return delegate.createJoinSwarmCmdExec(); - } - - @Override - public LeaveSwarmCmd.Exec createLeaveSwarmCmdExec() { - return delegate.createLeaveSwarmCmdExec(); - } - - @Override - public UpdateSwarmCmd.Exec createUpdateSwarmCmdExec() { - return delegate.createUpdateSwarmCmdExec(); - } - - // services - @Override - public ListServicesCmd.Exec createListServicesCmdExec() { - return delegate.createListServicesCmdExec(); - } - - @Override - public CreateServiceCmd.Exec createCreateServiceCmdExec() { - return delegate.createCreateServiceCmdExec(); - } - - @Override - public InspectServiceCmd.Exec createInspectServiceCmdExec() { - return delegate.createInspectServiceCmdExec(); - } - - @Override - public UpdateServiceCmd.Exec createUpdateServiceCmdExec() { - return delegate.createUpdateServiceCmdExec(); - } - - @Override - public RemoveServiceCmd.Exec createRemoveServiceCmdExec() { - return delegate.createRemoveServiceCmdExec(); - } - - @Override - public LogSwarmObjectCmd.Exec logSwarmObjectExec(String endpoint) { - return delegate.logSwarmObjectExec(endpoint); - } - - // nodes - @Override - public ListSwarmNodesCmd.Exec listSwarmNodeCmdExec() { - return delegate.listSwarmNodeCmdExec(); - } - - @Override - public InspectSwarmNodeCmd.Exec inspectSwarmNodeCmdExec() { - return delegate.inspectSwarmNodeCmdExec(); - } - - @Override - public RemoveSwarmNodeCmd.Exec removeSwarmNodeCmdExec() { - return delegate.removeSwarmNodeCmdExec(); - } - - @Override - public UpdateSwarmNodeCmd.Exec updateSwarmNodeCmdExec() { - return delegate.updateSwarmNodeCmdExec(); - } - - @Override - public ListTasksCmd.Exec listTasksCmdExec() { - return delegate.listTasksCmdExec(); - } - - @Override - public PruneCmd.Exec pruneCmdExec() { - return delegate.pruneCmdExec(); - } - - @Override - public ListSecretsCmd.Exec createListSecretsCmdExec() { - return delegate.createListSecretsCmdExec(); - } - - @Override - public CreateSecretCmd.Exec createCreateSecretCmdExec() { - return delegate.createCreateSecretCmdExec(); - } - - @Override - public RemoveSecretCmd.Exec createRemoveSecretCmdExec() { - return delegate.createRemoveSecretCmdExec(); - } - - public List getContainerNames() { - return new ArrayList<>(containerNames); - } - - public List getImageNames() { - return new ArrayList<>(imageNames); - } - - public List getVolumeNames() { - return new ArrayList<>(volumeNames); - } - - public List getNetworkIds() { - return new ArrayList<>(networkIds); - } -} diff --git a/docker-java/src/test/java/com/github/dockerjava/core/command/DockerfileFixture.java b/docker-java/src/test/java/com/github/dockerjava/core/command/DockerfileFixture.java index 104ea9f6f..913d1758b 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/command/DockerfileFixture.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/command/DockerfileFixture.java @@ -1,6 +1,7 @@ package com.github.dockerjava.core.command; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.exception.DockerException; import com.github.dockerjava.api.exception.InternalServerErrorException; import com.github.dockerjava.api.exception.NotFoundException; import com.github.dockerjava.api.model.Image; @@ -67,7 +68,7 @@ public void close() throws Exception { LOGGER.info("removing repository {}", repository); try { client.removeImageCmd(repository).withForce(true).exec(); - } catch (NotFoundException | InternalServerErrorException e) { + } catch (DockerException e) { LOGGER.info("ignoring {}", e.getMessage()); } repository = null; diff --git a/docker-java/src/test/java/com/github/dockerjava/core/command/FrameReaderTest.java b/docker-java/src/test/java/com/github/dockerjava/core/command/FrameReaderTest.java index e8adff20b..580e278f4 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/command/FrameReaderTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/command/FrameReaderTest.java @@ -34,7 +34,7 @@ public void endOfStreamReturnsNull() throws Exception { @Test public void stdInBytesFrameReturnsFrame() throws Exception { - assertEquals(nextFrame(0, 0, 0, 0, 0, 0, 0, 0), new Frame(StreamType.STDIN, new byte[0])); + assertEquals(new Frame(StreamType.STDIN, new byte[0]), nextFrame(0, 0, 0, 0, 0, 0, 0, 0)); } private Frame nextFrame(int... bytes) throws IOException { @@ -44,12 +44,12 @@ private Frame nextFrame(int... bytes) throws IOException { @Test public void stdOutBytesFrameReturnsFrame() throws Exception { - assertEquals(nextFrame(1, 0, 0, 0, 0, 0, 0, 0), new Frame(StreamType.STDOUT, new byte[0])); + assertEquals(new Frame(StreamType.STDOUT, new byte[0]), nextFrame(1, 0, 0, 0, 0, 0, 0, 0)); } @Test public void stdErrBytesFrameReturnsFrame() throws Exception { - assertEquals(nextFrame(2, 0, 0, 0, 0, 0, 0, 0), new Frame(StreamType.STDERR, new byte[0])); + assertEquals(new Frame(StreamType.STDERR, new byte[0]), nextFrame(2, 0, 0, 0, 0, 0, 0, 0)); } private void setBytes(int... bytes) { diff --git a/docker-java/src/test/java/com/github/dockerjava/core/util/CertificateUtilsTest.java b/docker-java/src/test/java/com/github/dockerjava/core/util/CertificateUtilsTest.java index 28818d24c..c29cedcf9 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/util/CertificateUtilsTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/util/CertificateUtilsTest.java @@ -11,6 +11,8 @@ import java.nio.file.Paths; import java.security.KeyStore; import java.security.Security; +import java.security.cert.Certificate; +import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; @@ -86,6 +88,20 @@ public void readMultipleCaCerts() throws Exception { assertThat(keyStore.isCertificateEntry("ca-2"), is(true)); } + @Test + public void readCert() throws Exception { + String certpem = readFileAsString("caTest/single_ca.pem"); + List certs = CertificateUtils.loadCertificates(certpem); + assertThat(certs.size(), is(1)); + } + + @Test + public void readMultipleCerts() throws Exception { + String certpem = readFileAsString("caTest/multiple_ca.pem"); + List certs = CertificateUtils.loadCertificates(certpem); + assertThat(certs.size(), is(2)); + } + private String readFileAsString(String path) throws IOException { return new String(Files.readAllBytes(Paths.get(new File(baseDir + path).getPath()))); } diff --git a/docker-java/src/test/java/com/github/dockerjava/core/util/CompressArchiveUtilTest.java b/docker-java/src/test/java/com/github/dockerjava/core/util/CompressArchiveUtilTest.java index 720441e20..f15085d1c 100644 --- a/docker-java/src/test/java/com/github/dockerjava/core/util/CompressArchiveUtilTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/core/util/CompressArchiveUtilTest.java @@ -241,7 +241,7 @@ private static void assertTarArchiveEntryIsExecutableFile(File archive, String f TarArchiveEntry tarArchiveEntry = getTarArchiveEntry(archive, fileName); assertNotNull(tarArchiveEntry); assertTrue(tarArchiveEntry.isFile()); - assertEquals("should be executable", (tarArchiveEntry.getMode() & 0755), 0755); + assertEquals("should be executable", 0755, (tarArchiveEntry.getMode() & 0755)); } private static void assertTarArchiveEntryIsSymlink(File archive, String fileName, String expectedTarget) throws IOException { diff --git a/docker-java/src/test/java/com/github/dockerjava/junit/DockerAssume.java b/docker-java/src/test/java/com/github/dockerjava/junit/DockerAssume.java index 011ee2885..2971d7bf3 100644 --- a/docker-java/src/test/java/com/github/dockerjava/junit/DockerAssume.java +++ b/docker-java/src/test/java/com/github/dockerjava/junit/DockerAssume.java @@ -1,6 +1,7 @@ package com.github.dockerjava.junit; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.core.DockerRule; import static com.github.dockerjava.utils.TestUtils.isSwarm; import static org.junit.Assume.assumeFalse; diff --git a/docker-java/src/test/java/com/github/dockerjava/junit/DockerMatchers.java b/docker-java/src/test/java/com/github/dockerjava/junit/DockerMatchers.java index bc71b7dfd..d0c2a22e6 100644 --- a/docker-java/src/test/java/com/github/dockerjava/junit/DockerMatchers.java +++ b/docker-java/src/test/java/com/github/dockerjava/junit/DockerMatchers.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.Volume; +import com.github.dockerjava.core.DockerRule; import com.github.dockerjava.core.RemoteApiVersion; import org.hamcrest.CustomTypeSafeMatcher; import org.hamcrest.Description; diff --git a/docker-java/src/test/java/com/github/dockerjava/junit/PrivateRegistryRule.java b/docker-java/src/test/java/com/github/dockerjava/junit/PrivateRegistryRule.java index cd7989afd..327bfc941 100644 --- a/docker-java/src/test/java/com/github/dockerjava/junit/PrivateRegistryRule.java +++ b/docker-java/src/test/java/com/github/dockerjava/junit/PrivateRegistryRule.java @@ -7,14 +7,15 @@ import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Ports; -import com.github.dockerjava.core.DockerClientBuilder; +import com.github.dockerjava.cmd.CmdIT; +import com.github.dockerjava.core.DockerRule; import org.junit.rules.ExternalResource; import java.io.File; import java.util.concurrent.TimeUnit; import static com.github.dockerjava.api.model.HostConfig.newHostConfig; -import static com.github.dockerjava.junit.DockerRule.DEFAULT_IMAGE; +import static com.github.dockerjava.core.DockerRule.DEFAULT_IMAGE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; @@ -28,7 +29,7 @@ public class PrivateRegistryRule extends ExternalResource { private String containerId; public PrivateRegistryRule() { - this.dockerClient = DockerClientBuilder.getInstance().build(); + this.dockerClient = CmdIT.createDockerClient(DockerRule.config(null)); } public AuthConfig getAuthConfig() { diff --git a/docker-java/src/test/java/com/github/dockerjava/netty/NettyDockerCmdExecFactoryConfigTest.java b/docker-java/src/test/java/com/github/dockerjava/netty/NettyDockerCmdExecFactoryConfigTest.java index 7585a7534..03019f383 100644 --- a/docker-java/src/test/java/com/github/dockerjava/netty/NettyDockerCmdExecFactoryConfigTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/netty/NettyDockerCmdExecFactoryConfigTest.java @@ -43,7 +43,7 @@ public void testNettyDockerCmdExecFactoryConfigWithApiVersion() throws Exception Builder configBuilder = new DefaultDockerClientConfig.Builder() .withDockerTlsVerify(false) .withDockerHost("tcp://localhost:" + dockerPort) - .withApiVersion("1.23"); + .withApiVersion("1.44"); DockerClient client = DockerClientBuilder.getInstance(configBuilder) .withDockerCmdExecFactory(factory) @@ -56,8 +56,8 @@ public void testNettyDockerCmdExecFactoryConfigWithApiVersion() throws Exception List requests = server.getRequests(); - assertEquals(requests.size(), 1); - assertEquals(requests.get(0).uri(), "/v1.23/version"); + assertEquals(1, requests.size()); + assertEquals("/v1.44/version", requests.get(0).uri()); } finally { server.stop(); } @@ -83,8 +83,8 @@ public void testNettyDockerCmdExecFactoryConfigWithoutApiVersion() throws Except List requests = server.getRequests(); - assertEquals(requests.size(), 1); - assertEquals(requests.get(0).uri(), "/version"); + assertEquals(1, requests.size()); + assertEquals("/version", requests.get(0).uri()); } finally { server.stop(); } diff --git a/docker-java/src/test/java/com/github/dockerjava/netty/NettyWebTargetTest.java b/docker-java/src/test/java/com/github/dockerjava/netty/NettyWebTargetTest.java index adef3268f..4e7bb1da2 100644 --- a/docker-java/src/test/java/com/github/dockerjava/netty/NettyWebTargetTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/netty/NettyWebTargetTest.java @@ -17,12 +17,12 @@ public class NettyWebTargetTest { private ChannelProvider channelProvider; @Before - public void setUp() throws Exception { + public void setUp() { MockitoAnnotations.initMocks(this); } @Test - public void verifyImmutability() throws Exception { + public void verifyImmutability() { NettyWebTarget emptyWebTarget = new NettyWebTarget(JSONTestHelper.getMapper(), channelProvider, "DUMMY"); NettyWebTarget initWebTarget = emptyWebTarget.path("/containers/{id}/attach").resolveTemplate("id", "d03da378b592") @@ -31,12 +31,12 @@ public void verifyImmutability() throws Exception { NettyWebTarget anotherWebTarget = emptyWebTarget.path("/containers/{id}/attach") .resolveTemplate("id", "2cfada4e3c07").queryParam("stdin", "true"); - assertEquals(new NettyWebTarget(JSONTestHelper.getMapper(), channelProvider, "DUMMY"), emptyWebTarget); + assertEquals(emptyWebTarget, new NettyWebTarget(JSONTestHelper.getMapper(), channelProvider, "DUMMY")); - assertEquals(new NettyWebTarget(JSONTestHelper.getMapper(), channelProvider, "DUMMY").path("/containers/d03da378b592/attach") - .queryParam("logs", "true"), initWebTarget); + assertEquals(initWebTarget, new NettyWebTarget(JSONTestHelper.getMapper(), channelProvider, "DUMMY").path("/containers/d03da378b592/attach") + .queryParam("logs", "true")); - assertEquals(new NettyWebTarget(JSONTestHelper.getMapper(), channelProvider, "DUMMY").path("/containers/2cfada4e3c07/attach") - .queryParam("stdin", "true"), anotherWebTarget); + assertEquals(anotherWebTarget, new NettyWebTarget(JSONTestHelper.getMapper(), channelProvider, "DUMMY").path("/containers/2cfada4e3c07/attach") + .queryParam("stdin", "true")); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/netty/handler/FramedResponseStreamHandlerTest.java b/docker-java/src/test/java/com/github/dockerjava/netty/handler/FramedResponseStreamHandlerTest.java index 98161b072..ef903f942 100644 --- a/docker-java/src/test/java/com/github/dockerjava/netty/handler/FramedResponseStreamHandlerTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/netty/handler/FramedResponseStreamHandlerTest.java @@ -87,7 +87,7 @@ public void channelRead0rawStream() throws Exception { objectUnderTest.channelRead0(Mockito.mock(ChannelHandlerContext.class), Unpooled.wrappedBuffer(msg)); // Assert result - assertEquals(responseHandler.frames.get(0).toString(), "RAW: "); + assertEquals("RAW: ", responseHandler.frames.get(0).toString()); } @Test @@ -117,7 +117,7 @@ public void channelRead0stdIn() throws Exception { objectUnderTest.channelRead0(Mockito.mock(ChannelHandlerContext.class), Unpooled.wrappedBuffer(msg)); // Assert result - assertEquals(responseHandler.frames.get(0).toString(), "STDIN: "); + assertEquals("STDIN: ", responseHandler.frames.get(0).toString()); } @Test @@ -132,7 +132,7 @@ public void channelRead0stdOut() throws Exception { objectUnderTest.channelRead0(Mockito.mock(ChannelHandlerContext.class), Unpooled.wrappedBuffer(msg)); // Assert result - assertEquals(responseHandler.frames.get(0).toString(), "STDOUT: "); + assertEquals("STDOUT: ", responseHandler.frames.get(0).toString()); } @Test @@ -147,7 +147,7 @@ public void channelRead0stdErr() throws Exception { objectUnderTest.channelRead0(Mockito.mock(ChannelHandlerContext.class), Unpooled.wrappedBuffer(msg)); // Assert result - assertEquals(responseHandler.frames.get(0).toString(), "STDERR: "); + assertEquals("STDERR: ", responseHandler.frames.get(0).toString()); } @Test @@ -162,7 +162,7 @@ public void channelRead0largePayload() throws Exception { objectUnderTest.channelRead0(Mockito.mock(ChannelHandlerContext.class), Unpooled.wrappedBuffer(msg)); // Assert result - assertEquals(responseHandler.frames.get(0).toString(), "STDOUT: "); + assertEquals("STDOUT: ", responseHandler.frames.get(0).toString()); } @Test @@ -179,6 +179,6 @@ public void exceptionCaught() throws Exception { objectUnderTest.exceptionCaught(Mockito.mock(ChannelHandlerContext.class), throwable); // Assert result - assertEquals(responseHandler.exceptions.get(0).getCause(), exception); + assertEquals(exception, responseHandler.exceptions.get(0).getCause()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/netty/handler/HttpResponseStreamHandlerTest.java b/docker-java/src/test/java/com/github/dockerjava/netty/handler/HttpResponseStreamHandlerTest.java index 9433f97d6..9a2492062 100644 --- a/docker-java/src/test/java/com/github/dockerjava/netty/handler/HttpResponseStreamHandlerTest.java +++ b/docker-java/src/test/java/com/github/dockerjava/netty/handler/HttpResponseStreamHandlerTest.java @@ -32,10 +32,10 @@ public void testNoBytesSkipped() throws Exception { ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class); ByteBuf buffer = generateByteBuf(); ByteBuf readBuffer = buffer.copy(); - assertEquals(buffer.refCnt(), 1); + assertEquals(1, buffer.refCnt()); streamHandler.channelRead(ctx, buffer); streamHandler.channelInactive(ctx); - assertEquals(buffer.refCnt(), 0); + assertEquals(0, buffer.refCnt()); try (InputStream inputStream = callback.getInputStream()) { assertTrue(IOUtils.contentEquals(inputStream, new ByteBufInputStream(readBuffer))); } @@ -49,10 +49,10 @@ public void testReadByteByByte() throws Exception { ChannelHandlerContext ctx = Mockito.mock(ChannelHandlerContext.class); ByteBuf buffer = generateByteBuf(); ByteBuf readBuffer = buffer.copy(); - assertEquals(buffer.refCnt(), 1); + assertEquals(1, buffer.refCnt()); streamHandler.channelRead(ctx, buffer); streamHandler.channelInactive(ctx); - assertEquals(buffer.refCnt(), 0); + assertEquals(0, buffer.refCnt()); try (InputStream inputStream = callback.getInputStream()) { for (int i = 0; i < readBuffer.readableBytes(); i++) { int b = inputStream.read(); diff --git a/docker-java/src/test/java/com/github/dockerjava/test/serdes/JSONTestHelper.java b/docker-java/src/test/java/com/github/dockerjava/test/serdes/JSONTestHelper.java index 24d7b1677..0c03bdcc2 100644 --- a/docker-java/src/test/java/com/github/dockerjava/test/serdes/JSONTestHelper.java +++ b/docker-java/src/test/java/com/github/dockerjava/test/serdes/JSONTestHelper.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientConfig; import org.apache.commons.io.IOUtils; import java.io.IOException; @@ -33,7 +33,16 @@ */ public class JSONTestHelper { - static final ObjectMapper MAPPER = DefaultDockerClientConfig.createDefaultConfigBuilder().build().getObjectMapper(); + static final ObjectMapper MAPPER; + + static { + try { + MAPPER = DockerClientConfig.getDefaultObjectMapper(); + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + } /** * Reads JSON String from the specified resource diff --git a/docker-java/src/test/java/com/github/dockerjava/utils/TestResources.java b/docker-java/src/test/java/com/github/dockerjava/utils/TestResources.java index 35ece680f..2a56333f1 100644 --- a/docker-java/src/test/java/com/github/dockerjava/utils/TestResources.java +++ b/docker-java/src/test/java/com/github/dockerjava/utils/TestResources.java @@ -1,5 +1,6 @@ package com.github.dockerjava.utils; +import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; @@ -8,7 +9,7 @@ public class TestResources { private TestResources() { } - public static Path getApiImagesLoadTestTarball() { - return Paths.get("src/test/resources/api/images/load/image.tar"); + public static Path getApiImagesLoadTestTarball() throws URISyntaxException { + return Paths.get(ClassLoader.getSystemResource("api/images/load/image.tar").toURI()); } } diff --git a/docker-java/src/test/java/com/github/dockerjava/utils/TestUtils.java b/docker-java/src/test/java/com/github/dockerjava/utils/TestUtils.java index 87833343b..eb3af8deb 100644 --- a/docker-java/src/test/java/com/github/dockerjava/utils/TestUtils.java +++ b/docker-java/src/test/java/com/github/dockerjava/utils/TestUtils.java @@ -5,7 +5,7 @@ import com.github.dockerjava.core.RemoteApiVersion; import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/docker-java/src/test/resources/attachContainerTestDockerfile/echo.sh b/docker-java/src/test/resources/attachContainerTestDockerfile/echo.sh index 88b444bf0..370cda203 100644 --- a/docker-java/src/test/resources/attachContainerTestDockerfile/echo.sh +++ b/docker-java/src/test/resources/attachContainerTestDockerfile/echo.sh @@ -1,2 +1,2 @@ #!/bin/sh -while sleep 2; do echo stdout && echo stderr >&2; done \ No newline at end of file +echo stdout && echo stderr >&2 diff --git a/docker-java/src/test/resources/buildTests/ADD/url/Dockerfile b/docker-java/src/test/resources/buildTests/ADD/url/Dockerfile index 4fbfa3236..3036dbbe6 100644 --- a/docker-java/src/test/resources/buildTests/ADD/url/Dockerfile +++ b/docker-java/src/test/resources/buildTests/ADD/url/Dockerfile @@ -2,9 +2,9 @@ FROM busybox:latest # Copy testrun.sh files into the container -ADD http://www.example.com/index.html /tmp/some.html +ADD https://www.example.com/ /tmp/some.html ADD ./testrun.sh /tmp/ RUN mkdir -p /usr/local/bin RUN cp /tmp/testrun.sh /usr/local/bin/ && chmod +x /usr/local/bin/testrun.sh -CMD ["testrun.sh"] \ No newline at end of file +CMD ["testrun.sh"] diff --git a/docker-java/src/test/resources/com/github/dockerjava/api/command/inspectContainerResponse_full_1_26a.json b/docker-java/src/test/resources/com/github/dockerjava/api/command/inspectContainerResponse_full_1_26a.json index 2f3428d7a..688ea2689 100644 --- a/docker-java/src/test/resources/com/github/dockerjava/api/command/inspectContainerResponse_full_1_26a.json +++ b/docker-java/src/test/resources/com/github/dockerjava/api/command/inspectContainerResponse_full_1_26a.json @@ -6,6 +6,7 @@ "postgres" ], "SizeRootFs" : null, + "SizeRw" : null, "HostConfig" : { "KernelMemory" : 0, "MemorySwappiness" : -1, diff --git a/docker-java/src/test/resources/com/github/dockerjava/api/command/updateContainerResponse_empty.json b/docker-java/src/test/resources/com/github/dockerjava/api/command/updateContainerResponse_empty.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/docker-java/src/test/resources/com/github/dockerjava/api/command/updateContainerResponse_empty.json @@ -0,0 +1 @@ +{} diff --git a/docker-java/src/test/resources/com/github/dockerjava/api/command/updateContainerResponse_warnings.json b/docker-java/src/test/resources/com/github/dockerjava/api/command/updateContainerResponse_warnings.json new file mode 100644 index 000000000..edeaedc7a --- /dev/null +++ b/docker-java/src/test/resources/com/github/dockerjava/api/command/updateContainerResponse_warnings.json @@ -0,0 +1,5 @@ +{ + "Warnings": [ + "Published ports are discarded when using host network mode" + ] +} diff --git a/docker-java/src/test/resources/com/github/dockerjava/api/model/pullImageResponse_alreadyExists.json b/docker-java/src/test/resources/com/github/dockerjava/api/model/pullImageResponse_alreadyExists.json new file mode 100644 index 000000000..ae318e29d --- /dev/null +++ b/docker-java/src/test/resources/com/github/dockerjava/api/model/pullImageResponse_alreadyExists.json @@ -0,0 +1 @@ +{"status":"Already exists"} diff --git a/docker-java/src/test/resources/dockerContextHomeDir/.docker/config.json b/docker-java/src/test/resources/dockerContextHomeDir/.docker/config.json new file mode 100644 index 000000000..5bb2ebebe --- /dev/null +++ b/docker-java/src/test/resources/dockerContextHomeDir/.docker/config.json @@ -0,0 +1,4 @@ +{ + "auths": {}, + "currentContext": "configcontext" +} diff --git a/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/51699a7c75211315f1dbf6ecc40dfb0ffdd4ee11ecb2ce7853c9751aea1f9444/meta.json b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/51699a7c75211315f1dbf6ecc40dfb0ffdd4ee11ecb2ce7853c9751aea1f9444/meta.json new file mode 100644 index 000000000..c6456d6b8 --- /dev/null +++ b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/51699a7c75211315f1dbf6ecc40dfb0ffdd4ee11ecb2ce7853c9751aea1f9444/meta.json @@ -0,0 +1,12 @@ +{ + "Name": "envvarcontext", + "Metadata": { + "Description": "envvarcontext" + }, + "Endpoints": { + "docker": { + "Host": "unix:///envvarcontext.sock", + "SkipTLSVerify": false + } + } +} diff --git a/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/meta.json b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/meta.json new file mode 100644 index 000000000..a4ff5b460 --- /dev/null +++ b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/meta.json @@ -0,0 +1,15 @@ +{ + "Name": "remote", + "Metadata": { + "Description": "remote" + }, + "Endpoints": { + "docker": { + "Host": "tcp://remote:2376", + "SkipTLSVerify": false + } + }, + "Storage": { + "TLSPath": "target/test-classes/com/github/dockerjava/core/util/CertificateUtilsTest/allFilesExist" + } +} diff --git a/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/d090e08f0c9167acd72adef6d9fa07ec2de3a873cdd545dd8cb7fc7a10a1331a/meta.json b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/d090e08f0c9167acd72adef6d9fa07ec2de3a873cdd545dd8cb7fc7a10a1331a/meta.json new file mode 100644 index 000000000..adff3b1c9 --- /dev/null +++ b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/meta/d090e08f0c9167acd72adef6d9fa07ec2de3a873cdd545dd8cb7fc7a10a1331a/meta.json @@ -0,0 +1,12 @@ +{ + "Name": "configcontext", + "Metadata": { + "Description": "configcontext" + }, + "Endpoints": { + "docker": { + "Host": "unix:///configcontext.sock", + "SkipTLSVerify": false + } + } +} diff --git a/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/tls/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/docker/ca.pem b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/tls/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/docker/ca.pem new file mode 100644 index 000000000..e69de29bb diff --git a/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/tls/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/docker/cert.pem b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/tls/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/docker/cert.pem new file mode 100644 index 000000000..e69de29bb diff --git a/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/tls/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/docker/key.pem b/docker-java/src/test/resources/dockerContextHomeDir/.docker/contexts/tls/b71199ebd070b36beab7317920c2c2f1d777df8d05e5527d8458fda57cb17a7a/docker/key.pem new file mode 100644 index 000000000..e69de29bb diff --git a/docker-java/src/test/resources/logback.xml b/docker-java/src/test/resources/logback.xml index b4309b868..8fb1a7a6d 100644 --- a/docker-java/src/test/resources/logback.xml +++ b/docker-java/src/test/resources/logback.xml @@ -7,13 +7,14 @@ - - - + + + + - \ No newline at end of file + diff --git a/docker-java/src/test/resources/samples/1.22/containers/json/filter1.json b/docker-java/src/test/resources/samples/1.22/containers/json/filter1.json index 159e62da6..51329bb63 100644 --- a/docker-java/src/test/resources/samples/1.22/containers/json/filter1.json +++ b/docker-java/src/test/resources/samples/1.22/containers/json/filter1.json @@ -10,6 +10,7 @@ "Created": 1455662451, "Ports": [], "SizeRootFs": 1113554, + "SizeRw": 0, "Labels": {}, "Status": "Up Less than a second", "HostConfig": { diff --git a/docker-java/src/test/resources/samples/1.22/images/history/history.json b/docker-java/src/test/resources/samples/1.22/images/history/history.json new file mode 100644 index 000000000..a38da2d8f --- /dev/null +++ b/docker-java/src/test/resources/samples/1.22/images/history/history.json @@ -0,0 +1,32 @@ +[ + { + "Id": "3db9c44f45209632d6050b35958829c3a2aa256d81b9a7be45b362ff85c54710", + "Created": 1398108230, + "CreatedBy": "/bin/sh -c #(nop) ADD file:eb15dbd63394e063b805a3c32ca7bf0266ef64676d5a6fab4801f2e81e2a5148 in /", + "Tags": [ + "ubuntu:lucid", + "ubuntu:10.04" + ], + "Size": 182964289, + "Comment": "" + }, + { + "Id": "6cfa4d1f33fb861d4d114f43b25abd0ac737509268065cdfd69d544a59c85ab8", + "Created": 1398108222, + "CreatedBy": "/bin/sh -c #(nop) MAINTAINER Tianon Gravi - mkimage-debootstrap.sh -i iproute,iputils-ping,ubuntu-minimal -t lucid.tar.xz lucid http://archive.ubuntu.com/ubuntu/", + "Tags": [], + "Size": 0, + "Comment": "" + }, + { + "Id": "511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158", + "Created": 1371157430, + "CreatedBy": "", + "Tags": [ + "scratch12:latest", + "scratch:latest" + ], + "Size": 0, + "Comment": "Imported from -" + } +] diff --git a/docker-java/src/test/resources/someHomeDir/.docker/config.json b/docker-java/src/test/resources/someHomeDir/.docker/config.json index 630394039..02ed0cf7f 100644 --- a/docker-java/src/test/resources/someHomeDir/.docker/config.json +++ b/docker-java/src/test/resources/someHomeDir/.docker/config.json @@ -1,9 +1,9 @@ { "auths":{ "https://index.docker.io/v1/":{ - "auth":"XXXX=", + "auth":"dXNlcm5hbWU6cGFzc3dvcmQ=", "email":"foo.bar@test.com" } } -} \ No newline at end of file +} diff --git a/docker-java/src/test/resources/testAuthConfigFile/validDockerConfigWithCurrentContext/config.json b/docker-java/src/test/resources/testAuthConfigFile/validDockerConfigWithCurrentContext/config.json new file mode 100644 index 000000000..8c5963f87 --- /dev/null +++ b/docker-java/src/test/resources/testAuthConfigFile/validDockerConfigWithCurrentContext/config.json @@ -0,0 +1,4 @@ +{ + "auths": {}, + "currentContext": "expectedContext" +} diff --git a/docker-java/src/test/resources/testAuthConfigFile/validJsonAuthsNull/config.json b/docker-java/src/test/resources/testAuthConfigFile/validJsonAuthsNull/config.json new file mode 100644 index 000000000..d104c357c --- /dev/null +++ b/docker-java/src/test/resources/testAuthConfigFile/validJsonAuthsNull/config.json @@ -0,0 +1,9 @@ +{ + "auths": null, + "credsStore": "desktop", + "plugins": { + "-x-cli-hints": { + "enabled": "true" + } + } +} diff --git a/docker-java/template.mf b/docker-java/template.mf index 274e6f917..2ce26d092 100644 --- a/docker-java/template.mf +++ b/docker-java/template.mf @@ -13,7 +13,7 @@ Import-Template: javax.ws.rs.*;version="[2.0.0, 2.1.0)", org.apache.commons.compress.*;version="${commons-compress.version:short}", org.apache.commons.io.*;version="${commons-io.version:short}", - org.apache.commons.lang.*;version="${commons-lang.version:short}", + org.apache.commons.lang3.*;version="${commons-lang3.version:short}", org.apache.http.*;version="[4.4.0, 4.6.0)", org.bouncycastle.*;version="${bouncycastle.version:short}", org.glassfish.jersey.*;version="${jersey.version:default}", diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..4b8ef0798 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,2 @@ +* [Getting Started](./getting_started.md) +* [Available transports](./transports.md) diff --git a/docs/devel.adoc b/docs/devel.adoc deleted file mode 100644 index 1b6295662..000000000 --- a/docs/devel.adoc +++ /dev/null @@ -1,34 +0,0 @@ -### Code Design - * Model is based on Objects and not primitives that allows nullify requests and have null values for data - that wasn't provided by docker daemon. - * For null safeness findbugs annotations are used. - ** Every method that may return `null` (and we are unsure in any fields as docker daemon may change something) - should be annotated with `@CheckForNull` return qualifier from `javax.annotation` package. - ** Methods that can't return `null` must be annotated with `@Nonnull`. - ** The same for Arguments. - ** `@Nullable` must be used only for changing inherited (other typed) qualifier. - * Setters in builder style must be prefixed with `withXX`. - * All classes should provide `toString()` `equals()` and `hashCode()` defined methods. - * Javadocs - ** Provide full information on field: - *** For models define API version with `@since {@link RemoteApiVersion#VERSION_1_X}`. - ** getters/setters should refernce to field `@see #$field`. - * If it is `Serializable` it shall have a `serialVersionUID` field. Unless code has shipped to users, the initial value of the `serialVersionUID` field shall be `1L`. - -### Coding style - * TBD, some initial styling already enforced with checkstyle. - IDEA/checkstyle file analogues will be provided soon. - -### Testing - * Unit tests for serder (serialization-deserialization). - * Integration tests for commands. - * If model object has builders, then fill it with data and compare by `equals()` with expected response - from docker daemon. If failed, then some fields mappings are wrong. - -### Debug - * When there are unreproducible Travis errors: - ** Try locally run test 10-20 times in IDE against the same docker daemon version and same connection type (tcp or socket). - ** Limit `.travis.yml` to single run (to not consume their resources with matrix run). - ** Remove `travis-logback.xml` replacement (build can't output everything in every run because travis has log limitation). - ** Set single test in `pom.xml` `for maven-failsafe-plugin` - ** Make PR or if you are maintainer push to branch, catch log and fix. diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 000000000..7781e38ec --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,129 @@ +# Getting Started + +## Dependencies + +To start using `docker-java` , you need to add at least two dependencies: +1. `com.github.docker-java:docker-java-core` for the `DockerClient` +1. one of `com.github.docker-java:docker-java-transport-*` to communicate with the Docker daemon. See [Available Transports](./transports.md) for more info. + +The latest available version: +[![Maven Central](https://img.shields.io/maven-central/v/com.github.docker-java/docker-java.svg)](https://mvnrepository.com/artifact/com.github.docker-java/docker-java) + + +## Instantiating a `DockerClientConfig` + +You will need an instance of `DockerClientConfig` to tell the library how to access Docker, which credentials to use to pull from Docker registries, etc etc. + +The builder is available and allows you to configure every property of the client: +```java +import com.github.dockerjava.core.DockerClientConfig +import com.github.dockerjava.core.DefaultDockerClientConfig +DockerClientConfig standard = DefaultDockerClientConfig.createDefaultConfigBuilder().build(); +``` + +```java +import com.github.dockerjava.core.DockerClientConfig +import com.github.dockerjava.core.DefaultDockerClientConfig + +DockerClientConfig custom = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerHost("tcp://docker.somewhere.tld:2376") + .withDockerTlsVerify(true) + .withDockerCertPath("/home/user/.docker") + .withRegistryUsername(registryUser) + .withRegistryPassword(registryPass) + .withRegistryEmail(registryMail) + .withRegistryUrl(registryUrl) + .build(); +``` + +Here you can tune registry auth, DOCKER_HOST and other options. + +There are a couple of configuration items, all of which have sensible defaults: + +* `DOCKER_HOST` The Docker Host URL, e.g. `tcp://localhost:2376` or `unix:///var/run/docker.sock` +* `DOCKER_TLS_VERIFY` enable/disable TLS verification (switch between `http` and `https` protocol) +* `DOCKER_CERT_PATH` Path to the certificates needed for TLS verification +* `DOCKER_CONFIG` Path for additional docker configuration files (like `.dockercfg`) +* `api.version` The API version, e.g. `1.23`. +* `registry.url` Your registry's address. +* `registry.username` Your registry username (required to push containers). +* `registry.password` Your registry password. +* `registry.email` Your registry email. + +There are three ways to configure, in descending order of precedence: + +##### Properties (docker-java.properties) + + DOCKER_HOST=tcp://localhost:2376 + DOCKER_TLS_VERIFY=1 + DOCKER_CERT_PATH=/home/user/.docker/certs + DOCKER_CONFIG=/home/user/.docker + api.version=1.23 + registry.url=https://index.docker.io/v1/ + registry.username=dockeruser + registry.password=ilovedocker + registry.email=dockeruser@github.com + +##### System Properties: + + java -DDOCKER_HOST=tcp://localhost:2375 -Dregistry.username=dockeruser pkg.Main + +##### System Environment + + export DOCKER_HOST=tcp://localhost:2376 + export DOCKER_TLS_VERIFY=1 + export DOCKER_CERT_PATH=/home/user/.docker/certs + export DOCKER_CONFIG=/home/user/.docker + +##### File System + +In `$HOME/.docker-java.properties` + +##### Class Path + +In the class path at `/docker-java.properties` + +### Jackson + +Should you need to customize the Jackson's `ObjectMapper` used by `docker-java`, you can create your own `DockerClientConfig` and override `DockerClientConfig#getObjectMapper()`. + +## Instantiating a `DockerHttpClient` +Once you decided which transport to use, you will need to instantiate an HTTP client: +```java +DockerClientConfig config = ...; + +DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder() + .dockerHost(config.getDockerHost()) + .sslConfig(config.getSSLConfig()) + .maxConnections(100) + .connectionTimeout(Duration.ofSeconds(30)) + .responseTimeout(Duration.ofSeconds(45)) + .build(); +``` + +Please refer to selected transport's builder for other available configuration options (like timeouts). + +Once you have an HTTP client, you can make raw requests to the Docker daemon directly: +```java +Request request = Request.builder() + .method(Request.Method.GET) + .path("/_ping") + .build(); + +try (Response response = httpClient.execute(request)) { + assertThat(response.getStatusCode(), equalTo(200)); + assertThat(IOUtils.toString(response.getBody()), equalTo("OK")); +} +``` + +## Instantiating a `DockerClient` + +To get an instance of `DockerClient`, you need to pass both `DockerClientConfig` and `DockerHttpClient`: +```java +DockerClient dockerClient = DockerClientImpl.getInstance(config, httpClient); +``` + +Once you have it, you can start executing Docker commands: +```java +dockerClient.pingCmd().exec(); +``` diff --git a/docs/transports.md b/docs/transports.md new file mode 100644 index 000000000..18a93d9e0 --- /dev/null +++ b/docs/transports.md @@ -0,0 +1,74 @@ +# Available transports + +## Apache HttpClient 5 +| | | +|---|---| +| Maven coordinates | `com.github.docker-java:docker-java-transport-httpclient5` | +| Stability | 🙂| +| Long term support plans | ✅ | +| Unix sockets support | ✅ | +| Windows Npipe support | ✅ | +| Stdin attachment support | ✅ | + +This transport is based on Apache HttpClient library version 5, which has a great flexibility and allows us to implement all Docker-specific features and protocols required, without having to use internal APIs or anything. + +It has everything to become the default transport of docker-java in future releases. + +## "Zerodep" +| | | +|---|---| +| Maven coordinates | `com.github.docker-java:docker-java-transport-zerodep` | +| Stability | 🙂| +| Long term support plans | ✅ | +| Unix sockets support | ✅ | +| Windows Npipe support | ✅ | +| Stdin attachment support | ✅ | + +The idea of this transport is to provide a transport that supports 100% of the features without having to worry about transitive dependencies. + +Note: due to the implementation details, it cannot be true "0 dependencies" module, so it needs to depend on `slf4j-api` and JNA. + +## OkHttp +| | | +|---|---| +| Maven coordinates | `com.github.docker-java:docker-java-transport-okhttp` | +| Stability | 🧐| +| Long term support plans | ❓ | +| Unix sockets support | ✅ | +| Windows Npipe support | ✅ | +| Stdin attachment support | ✅ | + +The OkHttp transport was first implemented in [the Testcontainers library](http://github.com/testcontainers/testcontainers-java) as a replacement for Netty. The main motivation for it was to not have heavy-weight Netty-specific native dependencies and the lack of Npipe support in the Netty one. + +OkHttp's migration to Kotlin and the need to use internal APIs for doing stdin hijacking makes us question the future of this transport (still under the consideration). + +## Netty +| | | +|---|---| +| Maven coordinates | `com.github.docker-java:docker-java-transport-netty` | +| Stability | 🧐| +| Long term support plans | ❌ | +| Unix sockets support | ✅ | +| Windows Npipe support | ❌ | +| Stdin attachment support | ✅ | + +Netty was the first alternative transport introduced as an alternative to Jersey. + +Although it gives a very low level access to the protocol, the lack of Windows Npipe support and the native library dependency for Unix Sockets make it hard to maintain and there are no plans to continue including this transport option in future versions. + +The community may decide to pick it up and continue the development as a 3rd party transport based on the existing abstractions `docker-java` provides. + +## Jersey +| | | +|---|---| +| Maven coordinates | `com.github.docker-java:docker-java-transport-jersey` | +| Stability | 🙃| +| Long term support plans | ❌ | +| Unix sockets support | ✅ | +| Windows Npipe support | ❌ | +| Stdin attachment support | ❌ | + +Jersey was the initial transport of the project. And, while working well, it was lacking support for connection hijacking (e.g. stdin attachment) or Windows Npipes. +The big amount of dependencies was also causing issues. + +Since Apache HttpClient 5-based transport is available now, there is no reason to keep Jersey and it will eventually be removed. diff --git a/mvnw b/mvnw index 41c0f0c23..bd8896bf2 100755 --- a/mvnw +++ b/mvnw @@ -19,292 +19,277 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac -fi +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 fi fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" +} - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" done + printf %x\\n $h +} - saveddir=`pwd` +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - M2_HOME=`dirname "$PRG"`/.. +die() { + printf %s\\n "$1" >&2 + exit 1 +} - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" fi -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi +mkdir -p -- "${MAVEN_HOME%/*}" -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; fi -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi fi -########################################################################################## -# End of extension -########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f fi -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 86115719e..92450f932 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,3 +1,4 @@ +<# : batch portion @REM ---------------------------------------------------------------------------- @REM Licensed to the Apache Software Foundation (ASF) under one @REM or more contributor license agreements. See the NOTICE file @@ -18,165 +19,171 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir +@REM Apache Maven Wrapper startup batch script, version 3.3.4 @REM @REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output @REM ---------------------------------------------------------------------------- -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) ) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml index 76a0c1bd9..72add3980 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.github.docker-java docker-java-parent pom - 3.2.2-SNAPSHOT + 0-SNAPSHOT docker-java-parent https://github.com/docker-java/docker-java @@ -42,6 +42,11 @@ Konstantin Pelykh kpelykh@gmail.com + + bsideup + Sergei Egorov + bsideup@gmail.com + @@ -52,23 +57,20 @@ 1.8 1.8 - 2.30.1 - 2.10.3 - 2.10.3 + 2.47 4.5.12 - 1.20 - 1.11 - 2.6 - 2.6 + 1.28.0 + 2.21.0 + 3.19.0 1.7.30 - 1.64 - 2.3.2 - 19.0 + 1.82 + 2.10.1 + 33.4.8-jre 1.2.3 - 4.1.46.Final + 4.2.7.Final 2.2 1.8 2.3.3 @@ -88,22 +90,18 @@ docker-java-api + docker-java-bom docker-java-core + docker-java-transport + docker-java-transport-tck docker-java-transport-netty docker-java-transport-jersey docker-java-transport-okhttp docker-java-transport-httpclient5 + docker-java-transport-zerodep docker-java - - - bintray-docker-java-releases - docker-java-releases - https://api.bintray.com/maven/docker-java/releases/docker-java/;publish=0 - - - @@ -148,6 +146,7 @@ ${jdk.target} ${jdk.debug} ${jdk.optimize} + true @@ -162,6 +161,13 @@ + + + + ${automatic.module.name} + + + @@ -236,13 +242,13 @@ com.github.siom79.japicmp japicmp-maven-plugin - 0.14.3 + 0.24.2 com.github.docker-java ${project.artifactId} - 3.2.0 + 3.3.4 jar @@ -278,6 +284,17 @@ + + org.sonatype.central + central-publishing-maven-plugin + 0.9.0 + true + + central + docker-java-transport-tck + com.github.docker-java + + @@ -289,6 +306,9 @@ org.apache.maven.plugins maven-javadoc-plugin + + org.sonatype.central + central-publishing-maven-plugin @@ -300,6 +320,13 @@ org.apache.maven.plugins maven-gpg-plugin + + + + --pinentry-mode + loopback + + sign-artifacts @@ -348,59 +375,6 @@ - - com.github.spotbugs - spotbugs-maven-plugin - 3.1.12.2 - - Max - Low - true - - false - - - - - check - - - - - - org.jacoco - jacoco-maven-plugin - 0.8.5 - - - - prepare-agent - - - - - post-unit-test - test - - report - - - - - pre-integration-test - pre-integration-test - - prepare-agent-integration - - - - report-integration - - report-integration - - - -