Compare commits
24 Commits
9.3.2.0-r2
...
9.3.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3599852fc1 | ||
|
|
05fe51d96d | ||
|
|
1f7334e3d1 | ||
|
|
dfa8e1ba41 | ||
|
|
9a8582a7a9 | ||
|
|
57ffe4011d | ||
|
|
1d60dd7ce5 | ||
|
|
dc71321648 | ||
|
|
bc4f246a75 | ||
|
|
cc619bdd86 | ||
|
|
784f03875e | ||
|
|
1b7dd14555 | ||
|
|
91603a08b0 | ||
|
|
1766663a78 | ||
|
|
8ca5f31853 | ||
|
|
447e1c57ce | ||
|
|
0e95c1ca9e | ||
|
|
7d093b4340 | ||
|
|
33566bed16 | ||
|
|
e14ffb261a | ||
|
|
1d239647f4 | ||
|
|
f10e2facf8 | ||
|
|
bad1cfaa96 | ||
|
|
bddb9bfd3a |
16
.travis.yml
16
.travis.yml
@@ -18,7 +18,7 @@ sudo: required
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- "1.18.9"
|
- "1.19.9"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
name: "Basic AMD64 build"
|
name: "Basic AMD64 build"
|
||||||
os: linux
|
os: linux
|
||||||
env:
|
env:
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_932_ARCHIVE_REPOSITORY_DEV_AMD64
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
|
|
||||||
# CD Build
|
# CD Build
|
||||||
@@ -58,8 +58,8 @@ jobs:
|
|||||||
os: linux
|
os: linux
|
||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_932_ARCHIVE_REPOSITORY_AMD64
|
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_AMD64
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_932_ARCHIVE_REPOSITORY_DEV_AMD64
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
- stage: build
|
- stage: build
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = private-master OR tag =~ ^release-candidate*
|
||||||
@@ -68,8 +68,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_932_ARCHIVE_REPOSITORY_S390X
|
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_S390X
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_932_ARCHIVE_REPOSITORY_DEV_S390X
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_S390X
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
- stage: build
|
- stage: build
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = private-master OR tag =~ ^release-candidate*
|
||||||
@@ -78,8 +78,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_932_ARCHIVE_REPOSITORY_PPC64LE
|
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_PPC64LE
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_932_ARCHIVE_REPOSITORY_DEV_PPC64LE
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_PPC64LE
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
- stage: push-manifest
|
- stage: push-manifest
|
||||||
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
|
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Change log
|
# Change log
|
||||||
|
|
||||||
|
## 9.3.3.0 (2023-06)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.3.3.0
|
||||||
|
|
||||||
## 9.3.2.0 (2023-02)
|
## 9.3.2.0 (2023-02)
|
||||||
|
|
||||||
* Updated to MQ version 9.3.2.0
|
* Updated to MQ version 9.3.2.0
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal
|
ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal
|
||||||
ARG BASE_TAG=8.7-1049.1675784874
|
ARG BASE_TAG=8.8-860
|
||||||
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
|
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
|
||||||
ARG BUILDER_TAG=1.18.9-8.1675807488
|
ARG BUILDER_TAG=1.19.9-2
|
||||||
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
|
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
|
||||||
ARG MQ_ARCHIVE="downloads/9.3.2.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
|
ARG MQ_ARCHIVE="downloads/9.3.3.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build stage to build Go code
|
# Build stage to build Go code
|
||||||
|
|||||||
44
Makefile
44
Makefile
@@ -45,10 +45,10 @@ MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH)_NOI
|
|||||||
MQ_ARCHIVE_DEV ?= $(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-$(MQ_ARCHIVE_DEV_TYPE)$(MQ_ARCHIVE_DEV_ARCH).tar.gz
|
MQ_ARCHIVE_DEV ?= $(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-$(MQ_ARCHIVE_DEV_TYPE)$(MQ_ARCHIVE_DEV_ARCH).tar.gz
|
||||||
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
||||||
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
# Options to `go test` for the Docker tests
|
# Options to `go test` for the Container tests
|
||||||
TEST_OPTS_DOCKER ?=
|
TEST_OPTS_CONTAINER ?=
|
||||||
# Timeout for the Docker tests
|
# Timeout for the tests
|
||||||
TEST_TIMEOUT_DOCKER ?= 45m
|
TEST_TIMEOUT_CONTAINER ?= 45m
|
||||||
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
||||||
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
||||||
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
||||||
@@ -278,9 +278,9 @@ cache-mq-tag:
|
|||||||
# Test targets
|
# Test targets
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# Vendor Go dependencies for the Docker tests
|
# Vendor Go dependencies for the Container tests
|
||||||
test/docker/vendor:
|
test/container/vendor:
|
||||||
cd test/docker && go mod vendor
|
cd test/container && go mod vendor
|
||||||
|
|
||||||
# Shortcut to just run the unit tests
|
# Shortcut to just run the unit tests
|
||||||
.PHONY: test-unit
|
.PHONY: test-unit
|
||||||
@@ -288,28 +288,28 @@ test-unit:
|
|||||||
$(COMMAND) build --target builder --file Dockerfile-server .
|
$(COMMAND) build --target builder --file Dockerfile-server .
|
||||||
|
|
||||||
.PHONY: test-advancedserver
|
.PHONY: test-advancedserver
|
||||||
test-advancedserver: test/docker/vendor
|
test-advancedserver: test/container/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||||
$(COMMAND) inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
$(COMMAND) inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) $(TEST_OPTS_DOCKER)
|
cd test/container && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production DOCKER_API_VERSION=$(DOCKER_API_VERSION) COMMAND=$(COMMAND) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_CONTAINER) $(TEST_OPTS_CONTAINER)
|
||||||
|
|
||||||
.PHONY: build-devjmstest
|
.PHONY: build-devjmstest
|
||||||
build-devjmstest:
|
build-devjmstest:
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
||||||
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
|
cd test/messaging && $(COMMAND) build --tag $(DEV_JMS_IMAGE) .
|
||||||
|
|
||||||
.PHONY: test-devserver
|
.PHONY: test-devserver
|
||||||
test-devserver: test/docker/vendor
|
test-devserver: test/container/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||||
$(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
$(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=false DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER)
|
cd test/container && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=false DOCKER_API_VERSION=$(DOCKER_API_VERSION) COMMAND=$(COMMAND) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_CONTAINER) -tags mqdev $(TEST_OPTS_CONTAINER)
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
coverage:
|
coverage:
|
||||||
mkdir coverage
|
mkdir coverage
|
||||||
|
|
||||||
.PHONY: test-advancedserver-cover
|
.PHONY: test-advancedserver-cover
|
||||||
test-advancedserver-cover: test/docker/vendor coverage
|
test-advancedserver-cover: test/container/vendor coverage
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell $(COMMAND) --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell $(COMMAND) --version)"$(END)))
|
||||||
rm -f ./coverage/unit*.cov
|
rm -f ./coverage/unit*.cov
|
||||||
# Run unit tests with coverage, for each package under 'internal'
|
# Run unit tests with coverage, for each package under 'internal'
|
||||||
@@ -319,16 +319,16 @@ test-advancedserver-cover: test/docker/vendor coverage
|
|||||||
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
|
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
|
||||||
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
|
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
|
||||||
|
|
||||||
rm -f ./test/docker/coverage/*.cov
|
rm -f ./test/container/coverage/*.cov
|
||||||
rm -f ./coverage/docker.*
|
rm -f ./coverage/container.*
|
||||||
mkdir -p ./test/docker/coverage/
|
mkdir -p ./test/container/coverage/
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test $(TEST_OPTS_DOCKER)
|
cd test/container && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test $(TEST_OPTS_CONTAINER)
|
||||||
echo 'mode: count' > ./coverage/docker.cov
|
echo 'mode: count' > ./coverage/container.cov
|
||||||
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
|
tail -q -n +2 ./test/container/coverage/*.cov >> ./coverage/container.cov
|
||||||
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
|
go tool cover -html=./coverage/container.cov -o ./coverage/container.html
|
||||||
|
|
||||||
echo 'mode: count' > ./coverage/combined.cov
|
echo 'mode: count' > ./coverage/combined.cov
|
||||||
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
|
tail -q -n +2 ./coverage/unit.cov ./coverage/container.cov >> ./coverage/combined.cov
|
||||||
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -569,4 +569,4 @@ ifneq (,$(findstring docker,$(COMMAND)))
|
|||||||
endif
|
endif
|
||||||
ifneq (,$(findstring podman,$(COMMAND)))
|
ifneq (,$(findstring podman,$(COMMAND)))
|
||||||
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
|
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
|
||||||
endif
|
endif
|
||||||
@@ -48,8 +48,8 @@ For issues relating specifically to the container image or Helm chart, please us
|
|||||||
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
||||||
Licenses for the products installed within the images are as follows:
|
Licenses for the products installed within the images are as follows:
|
||||||
|
|
||||||
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-CAUEQC) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-AXAF-JLZ53A) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||||
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-UPFX-8MW49T) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-AMRD-XH6P3Q) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||||
|
|
||||||
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine.
|
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine.
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ func mirrorHTPasswdLogs(ctx context.Context, wg *sync.WaitGroup, name string, fr
|
|||||||
|
|
||||||
// mirrorWebServerLogs starts a goroutine to mirror the contents of the Liberty web server messages.log
|
// mirrorWebServerLogs starts a goroutine to mirror the contents of the Liberty web server messages.log
|
||||||
func mirrorWebServerLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
func mirrorWebServerLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
||||||
return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", false, mf, true)
|
return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", fromStart, mf, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDebug() bool {
|
func getDebug() bool {
|
||||||
|
|||||||
@@ -165,6 +165,27 @@ func doMain() error {
|
|||||||
log.Println("One or more invalid value is provided for MQ_LOGGING_CONSOLE_SOURCE. Allowed values are 'qmgr' & 'web' in csv format")
|
log.Println("One or more invalid value is provided for MQ_LOGGING_CONSOLE_SOURCE. Allowed values are 'qmgr' & 'web' in csv format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
defer func() {
|
||||||
|
log.Debug("Waiting for log mirroring to complete")
|
||||||
|
wg.Wait()
|
||||||
|
}()
|
||||||
|
ctx, cancelMirror := context.WithCancel(context.Background())
|
||||||
|
defer func() {
|
||||||
|
log.Debug("Cancel log mirroring")
|
||||||
|
cancelMirror()
|
||||||
|
}()
|
||||||
|
|
||||||
|
//For mirroring web server logs if source variable is set
|
||||||
|
if checkLogSourceForMirroring("web") {
|
||||||
|
// Always log from the end of the web server messages.log, because the log rotation should happen as soon as the web server starts
|
||||||
|
_, err = mirrorWebServerLogs(ctx, &wg, name, false, mf)
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = postInit(name, keyLabel, defaultP12Truststore)
|
err = postInit(name, keyLabel, defaultP12Truststore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
@@ -205,17 +226,6 @@ func doMain() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
defer func() {
|
|
||||||
log.Debug("Waiting for log mirroring to complete")
|
|
||||||
wg.Wait()
|
|
||||||
}()
|
|
||||||
ctx, cancelMirror := context.WithCancel(context.Background())
|
|
||||||
defer func() {
|
|
||||||
log.Debug("Cancel log mirroring")
|
|
||||||
cancelMirror()
|
|
||||||
}()
|
|
||||||
|
|
||||||
//For mirroring mq system logs and qm logs, if environment variable is set
|
//For mirroring mq system logs and qm logs, if environment variable is set
|
||||||
if checkLogSourceForMirroring("qmgr") {
|
if checkLogSourceForMirroring("qmgr") {
|
||||||
//Mirror MQ system logs
|
//Mirror MQ system logs
|
||||||
@@ -241,17 +251,6 @@ func doMain() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//For mirroring web server logs if source variable is set
|
|
||||||
if checkLogSourceForMirroring("web") {
|
|
||||||
// Always log from the start of the web server messages.log, as
|
|
||||||
// Liberty resets it.
|
|
||||||
_, err = mirrorWebServerLogs(ctx, &wg, name, true, mf)
|
|
||||||
if err != nil {
|
|
||||||
logTermination(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = updateCommandLevel()
|
err = updateCommandLevel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
###########################################################################################################################################################
|
###########################################################################################################################################################
|
||||||
|
|
||||||
# MQ_VERSION is the fully qualified MQ version number to build
|
# MQ_VERSION is the fully qualified MQ version number to build
|
||||||
MQ_VERSION ?= 9.3.2.0
|
MQ_VERSION ?= 9.3.3.0
|
||||||
|
|
||||||
###########################################################################################################################################################
|
###########################################################################################################################################################
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ docker run \
|
|||||||
--env LICENSE=accept \
|
--env LICENSE=accept \
|
||||||
--env MQ_QMGR_NAME=QM1 \
|
--env MQ_QMGR_NAME=QM1 \
|
||||||
--detach \
|
--detach \
|
||||||
ibm-mqadvanced-server:9.3.2.0-amd64
|
ibm-mqadvanced-server:9.3.3.0-amd64
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ make test-advancedserver
|
|||||||
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
||||||
|
|
||||||
```
|
```
|
||||||
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.3.2.0-amd64 make test-advancedserver
|
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.3.3.0-amd64 make test-advancedserver
|
||||||
```
|
```
|
||||||
|
|
||||||
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command:
|
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command:
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module github.com/ibm-messaging/mq-container
|
module github.com/ibm-messaging/mq-container
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/genuinetools/amicontained v0.4.3
|
github.com/genuinetools/amicontained v0.4.3
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2015, 2022
|
# © Copyright IBM Corporation 2015, 2023
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -42,21 +42,12 @@ if ($UBUNTU); then
|
|||||||
echo "deb ${APT_URL} ${UBUNTU_CODENAME}-security main restricted" >> /etc/apt/sources.list
|
echo "deb ${APT_URL} ${UBUNTU_CODENAME}-security main restricted" >> /etc/apt/sources.list
|
||||||
# Install additional packages required by MQ, this install process and the runtime scripts
|
# Install additional packages required by MQ, this install process and the runtime scripts
|
||||||
EXTRA_DEBS="bash bc ca-certificates coreutils curl debianutils file findutils gawk grep libc-bin mount passwd procps sed tar util-linux"
|
EXTRA_DEBS="bash bc ca-certificates coreutils curl debianutils file findutils gawk grep libc-bin mount passwd procps sed tar util-linux"
|
||||||
# On ARM CPUs, there is no IBM JRE, so install another one
|
|
||||||
if [ "${CPU_ARCH}" == "aarch64" ]; then
|
|
||||||
EXTRA_DEBS="${EXTRA_DEBS} openjdk-8-jre"
|
|
||||||
fi
|
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y --no-install-recommends ${EXTRA_DEBS}
|
apt-get install -y --no-install-recommends ${EXTRA_DEBS}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ($RPM); then
|
if ($RPM); then
|
||||||
EXTRA_RPMS="bash bc ca-certificates file findutils gawk glibc-common grep ncurses-compat-libs passwd procps-ng sed shadow-utils tar util-linux which"
|
EXTRA_RPMS="bash bc ca-certificates file findutils gawk glibc-common grep ncurses-compat-libs passwd procps-ng sed shadow-utils tar util-linux which"
|
||||||
# On ARM CPUs, there is no IBM JRE, so install another one
|
|
||||||
if [ "${CPU_ARCH}" == "aarch64" ]; then
|
|
||||||
EXTRA_RPMS="${EXTRA_RPMS} java-1.8.0-openjdk-headless"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install additional packages required by MQ, this install process and the runtime scripts
|
# Install additional packages required by MQ, this install process and the runtime scripts
|
||||||
$YUM && yum -y install --setopt install_weak_deps=false ${EXTRA_RPMS}
|
$YUM && yum -y install --setopt install_weak_deps=false ${EXTRA_RPMS}
|
||||||
$MICRODNF && microdnf --disableplugin=subscription-manager install ${EXTRA_RPMS}
|
$MICRODNF && microdnf --disableplugin=subscription-manager install ${EXTRA_RPMS}
|
||||||
|
|||||||
669
test/container/containerengine/containerengine.go
Normal file
669
test/container/containerengine/containerengine.go
Normal file
@@ -0,0 +1,669 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2017, 2023
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package containerengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContainerInterface interface {
|
||||||
|
ContainerCreate(config *ContainerConfig, hostConfig *ContainerHostConfig, networkingConfig *ContainerNetworkSettings, containerName string) (string, error)
|
||||||
|
ContainerStop(container string, timeout *time.Duration) error
|
||||||
|
ContainerKill(container string, signal string) error
|
||||||
|
ContainerRemove(container string, options ContainerRemoveOptions) error
|
||||||
|
ContainerStart(container string, options ContainerStartOptions) error
|
||||||
|
ContainerWait(ctx context.Context, container string, condition string) (<-chan int64, <-chan error)
|
||||||
|
GetContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (string, error)
|
||||||
|
CopyFromContainer(container, srcPath string) ([]byte, error)
|
||||||
|
|
||||||
|
GetContainerPort(ID string, hostPort int) (string, error)
|
||||||
|
GetContainerIPAddress(ID string) (string, error)
|
||||||
|
ContainerInspectWithFormat(format string, ID string) (string, error)
|
||||||
|
ExecContainer(ID string, user string, cmd []string) (int, string)
|
||||||
|
GetMQVersion(image string) (string, error)
|
||||||
|
ContainerInspect(containerID string) (ContainerDetails, error)
|
||||||
|
|
||||||
|
NetworkCreate(name string, options NetworkCreateOptions) (string, error)
|
||||||
|
NetworkRemove(network string) error
|
||||||
|
|
||||||
|
VolumeCreate(options VolumeCreateOptions) (string, error)
|
||||||
|
VolumeRemove(volumeID string, force bool) error
|
||||||
|
|
||||||
|
ImageBuild(context io.Reader, tag string, dockerfilename string) (string, error)
|
||||||
|
ImageRemove(image string, options ImageRemoveOptions) (bool, error)
|
||||||
|
ImageInspectWithFormat(format string, ID string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerClient struct {
|
||||||
|
ContainerTool string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
// objects
|
||||||
|
var objVolume = "volume"
|
||||||
|
var objImage = "image"
|
||||||
|
var objPort = "port"
|
||||||
|
var objNetwork = "network"
|
||||||
|
|
||||||
|
// verbs
|
||||||
|
var listContainers = "ps"
|
||||||
|
var listImages = "images"
|
||||||
|
var create = "create"
|
||||||
|
var startContainer = "start"
|
||||||
|
var waitContainer = "wait"
|
||||||
|
var execContainer = "exec"
|
||||||
|
var getLogs = "logs"
|
||||||
|
var stopContainer = "stop"
|
||||||
|
var remove = "rm"
|
||||||
|
var inspect = "inspect"
|
||||||
|
var copyFile = "cp"
|
||||||
|
var build = "build"
|
||||||
|
var killContainer = "kill"
|
||||||
|
|
||||||
|
// args
|
||||||
|
var argEntrypoint = "--entrypoint"
|
||||||
|
var argUser = "--user"
|
||||||
|
var argExpose = "--expose"
|
||||||
|
var argVolume = "--volume"
|
||||||
|
var argPublish = "--publish"
|
||||||
|
var argPrivileged = "--privileged"
|
||||||
|
var argAddCapability = "--cap-add"
|
||||||
|
var argDropCapability = "--cap-drop"
|
||||||
|
var argName = "--name"
|
||||||
|
var argCondition = "--condition"
|
||||||
|
var argEnvironmentVariable = "--env"
|
||||||
|
var argTail = "--tail"
|
||||||
|
var argForce = "--force"
|
||||||
|
var argVolumes = "--volumes"
|
||||||
|
var argHostname = "--hostname"
|
||||||
|
var argDriver = "--driver"
|
||||||
|
var argFile = "--file"
|
||||||
|
var argQuiet = "--quiet"
|
||||||
|
var argTag = "--tag"
|
||||||
|
var argFormat = "--format"
|
||||||
|
var argNetwork = "--network"
|
||||||
|
var argSecurityOptions = "--security-opt"
|
||||||
|
var argSignal = "--signal"
|
||||||
|
|
||||||
|
// generic
|
||||||
|
var toolVersion = "version"
|
||||||
|
var ContainerStateNotRunning = "not-running"
|
||||||
|
var ContainerStateStopped = "stopped"
|
||||||
|
|
||||||
|
type ContainerConfig struct {
|
||||||
|
Image string
|
||||||
|
Hostname string
|
||||||
|
User string
|
||||||
|
Entrypoint []string
|
||||||
|
Env []string
|
||||||
|
ExposedPorts []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerDetails struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Image string
|
||||||
|
Path string
|
||||||
|
Args []string
|
||||||
|
Config ContainerConfig
|
||||||
|
HostConfig ContainerHostConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerDetailsLogging struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Image string
|
||||||
|
Path string
|
||||||
|
Args []string
|
||||||
|
CapAdd []string
|
||||||
|
CapDrop []string
|
||||||
|
User string
|
||||||
|
Env []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerHostConfig struct {
|
||||||
|
Binds []string // Bindings onto a volume
|
||||||
|
PortBindings []PortBinding //Bindings from a container port to a port on the host
|
||||||
|
Privileged bool // Give extended privileges to container
|
||||||
|
CapAdd []string // Linux capabilities to add to the container
|
||||||
|
CapDrop []string // Linux capabilities to drop from the container
|
||||||
|
SecurityOpt []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerNetworkSettings struct {
|
||||||
|
Networks []string // A list of networks to connect the container to
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerRemoveOptions struct {
|
||||||
|
Force bool
|
||||||
|
RemoveVolumes bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerStartOptions struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkCreateOptions struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerLogsOptions struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageRemoveOptions struct {
|
||||||
|
Force bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type VolumeCreateOptions struct {
|
||||||
|
Name string
|
||||||
|
Driver string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binding from a container port to a port on the host
|
||||||
|
type PortBinding struct {
|
||||||
|
HostIP string
|
||||||
|
HostPort string //Port to map to on the host
|
||||||
|
ContainerPort string //Exposed port on the container
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContainerClient returns a new container client
|
||||||
|
// Defaults to using podman
|
||||||
|
func NewContainerClient() ContainerClient {
|
||||||
|
tool, set := os.LookupEnv("COMMAND")
|
||||||
|
if !set {
|
||||||
|
tool = "podman"
|
||||||
|
}
|
||||||
|
return ContainerClient{
|
||||||
|
ContainerTool: tool,
|
||||||
|
Version: GetContainerToolVersion(tool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainerToolVersion returns the version of the container tool being used
|
||||||
|
func GetContainerToolVersion(containerTool string) string {
|
||||||
|
if containerTool == "docker" {
|
||||||
|
args := []string{"version", "--format", "'{{.Client.Version}}'"}
|
||||||
|
v, err := exec.Command("docker", args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "0.0.0"
|
||||||
|
}
|
||||||
|
return string(v)
|
||||||
|
} else if containerTool == "podman" {
|
||||||
|
//Default to checking the version of podman
|
||||||
|
args := []string{"version", "--format", "'{{.Version}}'"}
|
||||||
|
v, err := exec.Command("podman", args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "0.0.0"
|
||||||
|
}
|
||||||
|
return string(v)
|
||||||
|
}
|
||||||
|
return "0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMQVersion returns the MQ version of a given container image
|
||||||
|
func (cli ContainerClient) GetMQVersion(image string) (string, error) {
|
||||||
|
v, err := cli.ImageInspectWithFormat("{{.Config.Labels.version}}", image)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageInspectWithFormat inspects an image with a given formatting string
|
||||||
|
func (cli ContainerClient) ImageInspectWithFormat(format string, ID string) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
objImage,
|
||||||
|
inspect,
|
||||||
|
ID,
|
||||||
|
}
|
||||||
|
if format != "" {
|
||||||
|
args = append(args, []string{argFormat, format}...)
|
||||||
|
}
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerInspectWithFormat inspects a container with a given formatting string
|
||||||
|
func (cli ContainerClient) ContainerInspectWithFormat(format string, ID string) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
inspect,
|
||||||
|
ID,
|
||||||
|
}
|
||||||
|
if format != "" {
|
||||||
|
args = append(args, []string{argFormat, format}...)
|
||||||
|
}
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainerPort gets the ports on a container
|
||||||
|
func (cli ContainerClient) GetContainerPort(ID string, hostPort int) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
objPort,
|
||||||
|
ID,
|
||||||
|
strconv.Itoa(hostPort),
|
||||||
|
}
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
o := SanitizeString(string(output))
|
||||||
|
return strings.Split((o), ":")[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainerIPAddress gets the IP address of a container
|
||||||
|
func (cli ContainerClient) GetContainerIPAddress(ID string) (string, error) {
|
||||||
|
v, err := cli.ContainerInspectWithFormat("{{.NetworkSettings.IPAddress}}", ID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFromContainer copies a file from a container and returns its contents
|
||||||
|
func (cli ContainerClient) CopyFromContainer(container, srcPath string) ([]byte, error) {
|
||||||
|
tmpDir, err := os.MkdirTemp("", "tmp")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
args := []string{
|
||||||
|
copyFile,
|
||||||
|
container + ":" + srcPath,
|
||||||
|
tmpDir + "/.",
|
||||||
|
}
|
||||||
|
_, err = exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//Get file name
|
||||||
|
fname := filepath.Base(srcPath)
|
||||||
|
data, err := os.ReadFile(filepath.Join(tmpDir, fname))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove the file
|
||||||
|
err = os.Remove(filepath.Join(tmpDir, fname))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ContainerInspect(containerID string) (ContainerDetails, error) {
|
||||||
|
args := []string{
|
||||||
|
inspect,
|
||||||
|
containerID,
|
||||||
|
}
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return ContainerDetails{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var container ContainerDetails
|
||||||
|
err = json.Unmarshal(output, &container)
|
||||||
|
if err != nil {
|
||||||
|
return ContainerDetails{}, err
|
||||||
|
}
|
||||||
|
return container, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ContainerStop(container string, timeout *time.Duration) error {
|
||||||
|
args := []string{
|
||||||
|
stopContainer,
|
||||||
|
container,
|
||||||
|
}
|
||||||
|
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ContainerKill(container string, signal string) error {
|
||||||
|
args := []string{
|
||||||
|
killContainer,
|
||||||
|
container,
|
||||||
|
}
|
||||||
|
if signal != "" {
|
||||||
|
args = append(args, []string{argSignal, signal}...)
|
||||||
|
}
|
||||||
|
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ContainerRemove(container string, options ContainerRemoveOptions) error {
|
||||||
|
args := []string{
|
||||||
|
remove,
|
||||||
|
container,
|
||||||
|
}
|
||||||
|
if options.Force {
|
||||||
|
args = append(args, argForce)
|
||||||
|
}
|
||||||
|
if options.RemoveVolumes {
|
||||||
|
args = append(args, argVolumes)
|
||||||
|
}
|
||||||
|
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
//Silently error as the exit code 125 is present on sucessful deletion
|
||||||
|
if strings.Contains(err.Error(), "125") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ExecContainer(ID string, user string, cmd []string) (int, string) {
|
||||||
|
args := []string{
|
||||||
|
execContainer,
|
||||||
|
}
|
||||||
|
if user != "" {
|
||||||
|
args = append(args, []string{argUser, user}...)
|
||||||
|
}
|
||||||
|
args = append(args, ID)
|
||||||
|
args = append(args, cmd...)
|
||||||
|
ctx := context.Background()
|
||||||
|
output, err := exec.CommandContext(ctx, cli.ContainerTool, args...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
if err.(*exec.ExitError) != nil {
|
||||||
|
return err.(*exec.ExitError).ExitCode(), string(output)
|
||||||
|
} else {
|
||||||
|
return 9897, string(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, string(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ContainerStart(container string, options ContainerStartOptions) error {
|
||||||
|
args := []string{
|
||||||
|
startContainer,
|
||||||
|
container,
|
||||||
|
}
|
||||||
|
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerWait starts waiting for a container. It returns an int64 channel for receiving an exit code and an error channel for receiving errors.
|
||||||
|
// The channels returned from this function should be used to receive the results from the wait command.
|
||||||
|
func (cli ContainerClient) ContainerWait(ctx context.Context, container string, condition string) (<-chan int64, <-chan error) {
|
||||||
|
args := []string{
|
||||||
|
waitContainer,
|
||||||
|
container,
|
||||||
|
}
|
||||||
|
if cli.ContainerTool == "podman" {
|
||||||
|
if condition == ContainerStateNotRunning {
|
||||||
|
condition = ContainerStateStopped
|
||||||
|
}
|
||||||
|
args = append(args, []string{argCondition, string(condition)}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultC := make(chan int64)
|
||||||
|
errC := make(chan error, 1)
|
||||||
|
|
||||||
|
output, err := exec.CommandContext(ctx, cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
errC <- err
|
||||||
|
return resultC, errC
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
out := strings.TrimSuffix(string(output), "\n")
|
||||||
|
exitCode, err := strconv.Atoi(out)
|
||||||
|
if err != nil {
|
||||||
|
errC <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resultC <- int64(exitCode)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return resultC, errC
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) GetContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
getLogs,
|
||||||
|
container,
|
||||||
|
}
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) NetworkCreate(name string, options NetworkCreateOptions) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
objNetwork,
|
||||||
|
create,
|
||||||
|
}
|
||||||
|
netID, err := exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
networkID := SanitizeString(string(netID))
|
||||||
|
|
||||||
|
return networkID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) NetworkRemove(network string) error {
|
||||||
|
args := []string{
|
||||||
|
objNetwork,
|
||||||
|
remove,
|
||||||
|
}
|
||||||
|
_, err := exec.Command(cli.ContainerTool, args...).CombinedOutput()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) VolumeCreate(options VolumeCreateOptions) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
objVolume,
|
||||||
|
create,
|
||||||
|
options.Name,
|
||||||
|
}
|
||||||
|
if options.Driver != "" {
|
||||||
|
args = append(args, []string{argDriver, options.Driver}...)
|
||||||
|
}
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
name := SanitizeString(string(output))
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) VolumeRemove(volumeID string, force bool) error {
|
||||||
|
args := []string{
|
||||||
|
objVolume,
|
||||||
|
remove,
|
||||||
|
volumeID,
|
||||||
|
}
|
||||||
|
if force {
|
||||||
|
args = append(args, argForce)
|
||||||
|
}
|
||||||
|
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ImageBuild(context io.Reader, tag string, dockerfilename string) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
objImage,
|
||||||
|
build,
|
||||||
|
}
|
||||||
|
//dockerfilename includes the path to the dockerfile
|
||||||
|
//When using podman use the full path including the name of the Dockerfile
|
||||||
|
if cli.ContainerTool == "podman" {
|
||||||
|
args = append(args, []string{argFile, dockerfilename}...)
|
||||||
|
}
|
||||||
|
if tag != "" {
|
||||||
|
args = append(args, []string{argTag, tag}...)
|
||||||
|
}
|
||||||
|
args = append(args, argQuiet)
|
||||||
|
//When using docker remove the name 'DockerFile' from the string
|
||||||
|
if cli.ContainerTool == "docker" {
|
||||||
|
dfn := strings.ReplaceAll(dockerfilename, "Dockerfile", "")
|
||||||
|
args = append(args, dfn)
|
||||||
|
}
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sha := SanitizeString(string(output))
|
||||||
|
return sha, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ImageRemove(image string, options ImageRemoveOptions) (bool, error) {
|
||||||
|
args := []string{
|
||||||
|
objImage,
|
||||||
|
remove,
|
||||||
|
image,
|
||||||
|
}
|
||||||
|
if options.Force {
|
||||||
|
args = append(args, argForce)
|
||||||
|
}
|
||||||
|
_, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli ContainerClient) ContainerCreate(config *ContainerConfig, hostConfig *ContainerHostConfig, networkingConfig *ContainerNetworkSettings, containerName string) (string, error) {
|
||||||
|
args := []string{
|
||||||
|
create,
|
||||||
|
argName,
|
||||||
|
containerName,
|
||||||
|
}
|
||||||
|
args = getHostConfigArgs(args, hostConfig)
|
||||||
|
args = getNetworkConfigArgs(args, networkingConfig)
|
||||||
|
args = getContainerConfigArgs(args, config, cli.ContainerTool)
|
||||||
|
output, err := exec.Command(cli.ContainerTool, args...).Output()
|
||||||
|
lines := strings.Split(strings.ReplaceAll(string(output), "\r\n", "\n"), "\n")
|
||||||
|
if err != nil {
|
||||||
|
return lines[0], err
|
||||||
|
}
|
||||||
|
return lines[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getContainerConfigArgs converts a ContainerConfig into a set of cli arguments
|
||||||
|
func getContainerConfigArgs(args []string, config *ContainerConfig, toolName string) []string {
|
||||||
|
argList := []string{}
|
||||||
|
if config.Entrypoint != nil && toolName == "podman" {
|
||||||
|
entrypoint := "[\""
|
||||||
|
for i, commandPart := range config.Entrypoint {
|
||||||
|
if i != len(config.Entrypoint)-1 {
|
||||||
|
entrypoint += commandPart + "\",\""
|
||||||
|
} else {
|
||||||
|
//terminate list
|
||||||
|
entrypoint += commandPart + "\"]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args = append(args, []string{argEntrypoint, entrypoint}...)
|
||||||
|
}
|
||||||
|
if config.Entrypoint != nil && toolName == "docker" {
|
||||||
|
ep1 := ""
|
||||||
|
for i, commandPart := range config.Entrypoint {
|
||||||
|
if i == 0 {
|
||||||
|
ep1 = commandPart
|
||||||
|
} else {
|
||||||
|
argList = append(argList, commandPart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args = append(args, []string{argEntrypoint, ep1}...)
|
||||||
|
}
|
||||||
|
if config.User != "" {
|
||||||
|
args = append(args, []string{argUser, config.User}...)
|
||||||
|
}
|
||||||
|
if config.ExposedPorts != nil {
|
||||||
|
for _, port := range config.ExposedPorts {
|
||||||
|
args = append(args, []string{argExpose, port}...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config.Hostname != "" {
|
||||||
|
args = append(args, []string{argHostname, config.Hostname}...)
|
||||||
|
}
|
||||||
|
for _, env := range config.Env {
|
||||||
|
args = append(args, []string{argEnvironmentVariable, env}...)
|
||||||
|
}
|
||||||
|
if config.Image != "" {
|
||||||
|
args = append(args, config.Image)
|
||||||
|
}
|
||||||
|
if config.Entrypoint != nil && toolName == "docker" {
|
||||||
|
args = append(args, argList...)
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// getHostConfigArgs converts a ContainerHostConfig into a set of cli arguments
|
||||||
|
func getHostConfigArgs(args []string, hostConfig *ContainerHostConfig) []string {
|
||||||
|
if hostConfig.Binds != nil {
|
||||||
|
for _, volume := range hostConfig.Binds {
|
||||||
|
args = append(args, []string{argVolume, volume}...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hostConfig.PortBindings != nil {
|
||||||
|
for _, binding := range hostConfig.PortBindings {
|
||||||
|
pub := binding.HostIP + ":" + binding.HostPort + ":" + binding.ContainerPort
|
||||||
|
args = append(args, []string{argPublish, pub}...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hostConfig.Privileged {
|
||||||
|
args = append(args, []string{argPrivileged}...)
|
||||||
|
}
|
||||||
|
if hostConfig.CapAdd != nil {
|
||||||
|
for _, capability := range hostConfig.CapAdd {
|
||||||
|
args = append(args, []string{argAddCapability, string(capability)}...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hostConfig.CapDrop != nil {
|
||||||
|
for _, capability := range hostConfig.CapDrop {
|
||||||
|
args = append(args, []string{argDropCapability, string(capability)}...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hostConfig.SecurityOpt != nil {
|
||||||
|
for _, securityOption := range hostConfig.SecurityOpt {
|
||||||
|
args = append(args, []string{argSecurityOptions, string(securityOption)}...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// getNetworkConfigArgs converts a set of ContainerNetworkSettings into a set of cli arguments
|
||||||
|
func getNetworkConfigArgs(args []string, networkingConfig *ContainerNetworkSettings) []string {
|
||||||
|
if networkingConfig.Networks != nil {
|
||||||
|
for _, netID := range networkingConfig.Networks {
|
||||||
|
args = append(args, []string{argNetwork, netID}...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func SanitizeString(s string) string {
|
||||||
|
s = strings.Replace(s, " ", "", -1)
|
||||||
|
s = strings.Replace(s, "\t", "", -1)
|
||||||
|
s = strings.Replace(s, "\n", "", -1)
|
||||||
|
return s
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2022
|
© Copyright IBM Corporation 2018, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -19,37 +19,30 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"crypto/tls"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
"github.com/docker/docker/api/types/network"
|
|
||||||
"github.com/docker/docker/client"
|
|
||||||
"github.com/docker/go-connections/nat"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestDevGoldenPath tests using the default values for the default developer config.
|
// TestDevGoldenPath tests using the default values for the default developer config.
|
||||||
// Note: This test requires a separate container image to be available for the JMS tests.
|
// Note: This test requires a separate container image to be available for the JMS tests.
|
||||||
func TestDevGoldenPath(t *testing.T) {
|
func TestDevGoldenPath(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
cli := ce.NewContainerClient()
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
qm := "qm1"
|
qm := "qm1"
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + qm,
|
"MQ_QMGR_NAME=" + qm,
|
||||||
"DEBUG=true",
|
"DEBUG=true",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443, 1414})
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
waitForReady(t, cli, id)
|
waitForReady(t, cli, id)
|
||||||
waitForWebReady(t, cli, id, insecureTLSConfig)
|
waitForWebReady(t, cli, id, insecureTLSConfig)
|
||||||
@@ -74,15 +67,12 @@ func TestDevGoldenPath(t *testing.T) {
|
|||||||
func TestDevSecure(t *testing.T) {
|
func TestDevSecure(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const tlsPassPhrase string = "passw0rd"
|
const tlsPassPhrase string = "passw0rd"
|
||||||
qm := "qm1"
|
qm := "qm1"
|
||||||
appPassword := "differentPassw0rd"
|
appPassword := "differentPassw0rd"
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + qm,
|
"MQ_QMGR_NAME=" + qm,
|
||||||
@@ -93,67 +83,67 @@ func TestDevSecure(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
},
|
},
|
||||||
// Assign a random port for the web server on the host
|
|
||||||
// TODO: Don't do this for all tests
|
|
||||||
PortBindings: nat.PortMap{
|
|
||||||
"9443/tcp": []nat.PortBinding{
|
|
||||||
{
|
|
||||||
HostIP: "0.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
// Assign a random port for the web server on the host
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
// TODO: Don't do this for all tests
|
||||||
|
var binding ce.PortBinding
|
||||||
|
ports := []int{9443, 1414}
|
||||||
|
for _, p := range ports {
|
||||||
|
port := fmt.Sprintf("%v/tcp", p)
|
||||||
|
binding = ce.PortBinding{
|
||||||
|
ContainerPort: port,
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
}
|
||||||
|
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
||||||
|
}
|
||||||
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
||||||
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
waitForWebReady(t, cli, ID, createTLSConfig(t, cert, tlsPassPhrase))
|
||||||
|
|
||||||
t.Run("JMS", func(t *testing.T) {
|
t.Run("JMS", func(t *testing.T) {
|
||||||
// OpenJDK is used for running tests, hence pass "false" for 7th parameter.
|
// OpenJDK is used for running tests, hence pass "false" for 7th parameter.
|
||||||
// Cipher name specified is compliant with non-IBM JRE naming.
|
// Cipher name specified is compliant with non-IBM JRE naming.
|
||||||
runJMSTests(t, cli, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
runJMSTests(t, cli, ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
||||||
})
|
})
|
||||||
t.Run("REST admin", func(t *testing.T) {
|
t.Run("REST admin", func(t *testing.T) {
|
||||||
testRESTAdmin(t, cli, ctr.ID, insecureTLSConfig, "")
|
testRESTAdmin(t, cli, ID, insecureTLSConfig, "")
|
||||||
})
|
})
|
||||||
t.Run("REST messaging", func(t *testing.T) {
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
testRESTMessaging(t, cli, ctr.ID, insecureTLSConfig, qm, "app", appPassword, "")
|
testRESTMessaging(t, cli, ID, insecureTLSConfig, qm, "app", appPassword, "")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDevWebDisabled(t *testing.T) {
|
func TestDevWebDisabled(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
containerConfig := ce.ContainerConfig{
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
containerConfig := container.Config{
|
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=qm1",
|
"MQ_QMGR_NAME=qm1",
|
||||||
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
id := runContainer(t, cli, &containerConfig)
|
id := runContainerWithPorts(t, cli, &containerConfig, []int{1414})
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
waitForReady(t, cli, id)
|
waitForReady(t, cli, id)
|
||||||
t.Run("Web", func(t *testing.T) {
|
t.Run("Web", func(t *testing.T) {
|
||||||
_, dspmqweb := execContainer(t, cli, id, "", []string{"dspmqweb"})
|
_, dspmqweb := cli.ExecContainer(id, "", []string{"dspmqweb"})
|
||||||
if !strings.Contains(dspmqweb, "Server mqweb is not running.") && !strings.Contains(dspmqweb, "MQWB1125I") {
|
if !strings.Contains(dspmqweb, "Server mqweb is not running.") && !strings.Contains(dspmqweb, "MQWB1125I") {
|
||||||
t.Errorf("Expected dspmqweb to say 'Server is not running' or 'MQWB1125I'; got \"%v\"", dspmqweb)
|
t.Errorf("Expected dspmqweb to say 'Server is not running' or 'MQWB1125I'; got \"%v\"", dspmqweb)
|
||||||
}
|
}
|
||||||
@@ -171,11 +161,8 @@ func TestDevWebDisabled(t *testing.T) {
|
|||||||
func TestDevConfigDisabled(t *testing.T) {
|
func TestDevConfigDisabled(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
containerConfig := ce.ContainerConfig{
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
containerConfig := container.Config{
|
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=qm1",
|
"MQ_QMGR_NAME=qm1",
|
||||||
@@ -199,11 +186,8 @@ func TestDevConfigDisabled(t *testing.T) {
|
|||||||
func TestSSLKEYRBlank(t *testing.T) {
|
func TestSSLKEYRBlank(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
containerConfig := ce.ContainerConfig{
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
containerConfig := container.Config{
|
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"MQ_QMGR_NAME=QM1",
|
||||||
@@ -246,12 +230,9 @@ func TestSSLKEYRBlank(t *testing.T) {
|
|||||||
func TestSSLKEYRWithSuppliedKeyAndCert(t *testing.T) {
|
func TestSSLKEYRWithSuppliedKeyAndCert(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"MQ_QMGR_NAME=QM1",
|
||||||
@@ -259,24 +240,24 @@ func TestSSLKEYRWithSuppliedKeyAndCert(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
|
|
||||||
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
||||||
// Search the console output for exepcted values
|
// Search the console output for exepcted values
|
||||||
_, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
_, sslkeyROutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") || !strings.Contains(sslkeyROutput, "CERTLABL(default)") {
|
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") || !strings.Contains(sslkeyROutput, "CERTLABL(default)") {
|
||||||
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
||||||
// Hence wait for a second and retry few times before giving up.
|
// Hence wait for a second and retry few times before giving up.
|
||||||
@@ -284,33 +265,30 @@ func TestSSLKEYRWithSuppliedKeyAndCert(t *testing.T) {
|
|||||||
var i int
|
var i int
|
||||||
for i = 0; i < waitCount; i++ {
|
for i = 0; i < waitCount; i++ {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
_, sslkeyROutput = execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
_, sslkeyROutput = execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
if strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") && strings.Contains(sslkeyROutput, "CERTLABL(default)") {
|
if strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") && strings.Contains(sslkeyROutput, "CERTLABL(default)") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Failed to get expected output? dump the contents of mqsc files.
|
// Failed to get expected output? dump the contents of mqsc files.
|
||||||
if i == waitCount {
|
if i == waitCount {
|
||||||
_, tls15mqsc := execContainer(t, cli, ctr.ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
_, tls15mqsc := execContainer(t, cli, ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
||||||
_, autoMQSC := execContainer(t, cli, ctr.ID, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
|
_, autoMQSC := execContainer(t, cli, ID, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
|
||||||
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\" \n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\" \n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with CA cert
|
// Test with CA cert
|
||||||
func TestSSLKEYRWithCACert(t *testing.T) {
|
func TestSSLKEYRWithCACert(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"MQ_QMGR_NAME=QM1",
|
||||||
@@ -318,32 +296,35 @@ func TestSSLKEYRWithCACert(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDirWithCA(t, false) + ":/etc/mqm/pki/keys/QM1CA",
|
tlsDirWithCA(t, false) + ":/etc/mqm/pki/keys/QM1CA",
|
||||||
},
|
},
|
||||||
// Assign a random port for the web server on the host
|
|
||||||
PortBindings: nat.PortMap{
|
|
||||||
"9443/tcp": []nat.PortBinding{
|
|
||||||
{
|
|
||||||
HostIP: "0.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
// Assign a random port for the web server on the host
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
var binding ce.PortBinding
|
||||||
|
ports := []int{9443}
|
||||||
|
for _, p := range ports {
|
||||||
|
port := fmt.Sprintf("%v/tcp", p)
|
||||||
|
binding = ce.PortBinding{
|
||||||
|
ContainerPort: port,
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
}
|
||||||
|
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
||||||
|
}
|
||||||
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
|
|
||||||
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
||||||
// Search the console output for exepcted values
|
// Search the console output for exepcted values
|
||||||
_, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
_, sslkeyROutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
|
|
||||||
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
||||||
@@ -352,38 +333,35 @@ func TestSSLKEYRWithCACert(t *testing.T) {
|
|||||||
var i int
|
var i int
|
||||||
for i = 0; i < waitCount; i++ {
|
for i = 0; i < waitCount; i++ {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
_, sslkeyROutput = execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
_, sslkeyROutput = execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
if strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
if strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Failed to get expected output? dump the contents of mqsc files.
|
// Failed to get expected output? dump the contents of mqsc files.
|
||||||
if i == waitCount {
|
if i == waitCount {
|
||||||
_, tls15mqsc := execContainer(t, cli, ctr.ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
_, tls15mqsc := execContainer(t, cli, ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
||||||
_, autoMQSC := execContainer(t, cli, ctr.ID, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
|
_, autoMQSC := execContainer(t, cli, ID, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
|
||||||
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"\n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"\n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(sslkeyROutput, "CERTLABL(QM1CA)") {
|
if !strings.Contains(sslkeyROutput, "CERTLABL(QM1CA)") {
|
||||||
_, autoMQSC := execContainer(t, cli, ctr.ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
_, autoMQSC := execContainer(t, cli, ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
||||||
t.Errorf("Expected CERTLABL to be 'QM1CA' but it is not; got \"%v\" \n MQSC File contents %v", sslkeyROutput, autoMQSC)
|
t.Errorf("Expected CERTLABL to be 'QM1CA' but it is not; got \"%v\" \n MQSC File contents %v", sslkeyROutput, autoMQSC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=false
|
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=false
|
||||||
func TestSSLFIPSNO(t *testing.T) {
|
func TestSSLFIPSNO(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"MQ_QMGR_NAME=QM1",
|
||||||
@@ -392,24 +370,24 @@ func TestSSLFIPSNO(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
|
|
||||||
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
// Search the console output for exepcted values
|
// Search the console output for exepcted values
|
||||||
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
}
|
}
|
||||||
@@ -422,7 +400,7 @@ func TestSSLFIPSNO(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies SSLFIPS is set to YES if certificates for queue manager
|
// Verifies SSLFIPS is set to YES if certificates for queue manager
|
||||||
@@ -430,13 +408,10 @@ func TestSSLFIPSNO(t *testing.T) {
|
|||||||
func TestSSLFIPSYES(t *testing.T) {
|
func TestSSLFIPSYES(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
appPassword := "differentPassw0rd"
|
appPassword := "differentPassw0rd"
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_APP_PASSWORD=" + appPassword,
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
@@ -446,30 +421,40 @@ func TestSSLFIPSYES(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
var binding ce.PortBinding
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
ports := []int{1414}
|
||||||
|
for _, p := range ports {
|
||||||
|
port := fmt.Sprintf("%v/tcp", p)
|
||||||
|
binding = ce.PortBinding{
|
||||||
|
ContainerPort: port,
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
}
|
||||||
|
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
||||||
|
}
|
||||||
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
|
|
||||||
// Check for expected message on container log
|
// Check for expected message on container log
|
||||||
logs := inspectLogs(t, cli, ctr.ID)
|
logs := inspectLogs(t, cli, ID)
|
||||||
if !strings.Contains(logs, "FIPS cryptography is enabled.") {
|
if !strings.Contains(logs, "FIPS cryptography is enabled.") {
|
||||||
t.Errorf("Expected 'FIPS cryptography is enabled.' but got %v\n", logs)
|
t.Errorf("Expected 'FIPS cryptography is enabled.' but got %v\n", logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
// Search the console output for exepcted values
|
// Search the console output for exepcted values
|
||||||
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
}
|
}
|
||||||
@@ -483,26 +468,23 @@ func TestSSLFIPSYES(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("JMS", func(t *testing.T) {
|
t.Run("JMS", func(t *testing.T) {
|
||||||
// Run the JMS tests, with no password specified
|
// Run the JMS tests, with no password specified
|
||||||
runJMSTests(t, cli, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
runJMSTests(t, cli, ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDevSecureFIPSYESWeb verifies if the MQ Web Server is running in FIPS mode
|
// TestDevSecureFIPSYESWeb verifies if the MQ Web Server is running in FIPS mode
|
||||||
func TestDevSecureFIPSTrueWeb(t *testing.T) {
|
func TestDevSecureFIPSTrueWeb(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const tlsPassPhrase string = "passw0rd"
|
const tlsPassPhrase string = "passw0rd"
|
||||||
qm := "qm1"
|
qm := "qm1"
|
||||||
appPassword := "differentPassw0rd"
|
appPassword := "differentPassw0rd"
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + qm,
|
"MQ_QMGR_NAME=" + qm,
|
||||||
@@ -514,65 +496,65 @@ func TestDevSecureFIPSTrueWeb(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
||||||
},
|
},
|
||||||
// Assign a random port for the web server on the host
|
|
||||||
// TODO: Don't do this for all tests
|
|
||||||
PortBindings: nat.PortMap{
|
|
||||||
"9443/tcp": []nat.PortBinding{
|
|
||||||
{
|
|
||||||
HostIP: "0.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
// Assign a random port for the web server on the host
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
// TODO: Don't do this for all tests
|
||||||
|
var binding ce.PortBinding
|
||||||
|
ports := []int{9443}
|
||||||
|
for _, p := range ports {
|
||||||
|
port := fmt.Sprintf("%v/tcp", p)
|
||||||
|
binding = ce.PortBinding{
|
||||||
|
ContainerPort: port,
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
}
|
||||||
|
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
||||||
|
}
|
||||||
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
|
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
||||||
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
waitForWebReady(t, cli, ID, createTLSConfig(t, cert, tlsPassPhrase))
|
||||||
|
|
||||||
// Create a TLS Config with a cipher to use when connecting over HTTPS
|
// Create a TLS Config with a cipher to use when connecting over HTTPS
|
||||||
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
||||||
// Put a message to queue
|
// Put a message to queue
|
||||||
t.Run("REST messaging", func(t *testing.T) {
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
testRESTMessaging(t, cli, ctr.ID, secureTLSConfig, qm, "app", appPassword, "")
|
testRESTMessaging(t, cli, ID, secureTLSConfig, qm, "app", appPassword, "")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create a TLS Config with a non-FIPS cipher to use when connecting over HTTPS
|
// Create a TLS Config with a non-FIPS cipher to use when connecting over HTTPS
|
||||||
var secureNonFIPSCipherConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA})
|
var secureNonFIPSCipherConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA})
|
||||||
// Put a message to queue - the attempt to put message will fail with a EOF return message.
|
// Put a message to queue - the attempt to put message will fail with a EOF return message.
|
||||||
t.Run("REST messaging", func(t *testing.T) {
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
testRESTMessaging(t, cli, ctr.ID, secureNonFIPSCipherConfig, qm, "app", appPassword, "EOF")
|
testRESTMessaging(t, cli, ID, secureNonFIPSCipherConfig, qm, "app", appPassword, "EOF")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDevSecureNOFIPSWeb verifies if the MQ Web Server is not running in FIPS mode
|
// TestDevSecureNOFIPSWeb verifies if the MQ Web Server is not running in FIPS mode
|
||||||
func TestDevSecureFalseFIPSWeb(t *testing.T) {
|
func TestDevSecureFalseFIPSWeb(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const tlsPassPhrase string = "passw0rd"
|
const tlsPassPhrase string = "passw0rd"
|
||||||
qm := "qm1"
|
qm := "qm1"
|
||||||
appPassword := "differentPassw0rd"
|
appPassword := "differentPassw0rd"
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + qm,
|
"MQ_QMGR_NAME=" + qm,
|
||||||
@@ -584,38 +566,41 @@ func TestDevSecureFalseFIPSWeb(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
||||||
},
|
},
|
||||||
// Assign a random port for the web server on the host
|
|
||||||
PortBindings: nat.PortMap{
|
|
||||||
"9443/tcp": []nat.PortBinding{
|
|
||||||
{
|
|
||||||
HostIP: "0.0.0.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
// Assign a random port for the web server on the host
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
var binding ce.PortBinding
|
||||||
|
ports := []int{9443}
|
||||||
|
for _, p := range ports {
|
||||||
|
port := fmt.Sprintf("%v/tcp", p)
|
||||||
|
binding = ce.PortBinding{
|
||||||
|
ContainerPort: port,
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
}
|
||||||
|
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
||||||
|
}
|
||||||
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
|
|
||||||
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
||||||
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
waitForWebReady(t, cli, ID, createTLSConfig(t, cert, tlsPassPhrase))
|
||||||
|
|
||||||
// As FIPS is not enabled, the MQ WebServer (actually Java) will choose a JSSE provider from the list
|
// As FIPS is not enabled, the MQ WebServer (actually Java) will choose a JSSE provider from the list
|
||||||
// specified in java.security file. We will need to enable java.net.debug and then parse the web server
|
// specified in java.security file. We will need to enable java.net.debug and then parse the web server
|
||||||
// logs to check what JJSE provider is being used. Hence just check the jvm.options file does not contain
|
// logs to check what JJSE provider is being used. Hence just check the jvm.options file does not contain
|
||||||
// -Dcom.ibm.jsse2.usefipsprovider line.
|
// -Dcom.ibm.jsse2.usefipsprovider line.
|
||||||
_, jvmOptionsOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "cat /var/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults/jvm.options"})
|
_, jvmOptionsOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "cat /var/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults/jvm.options"})
|
||||||
if strings.Contains(jvmOptionsOutput, "-Dcom.ibm.jsse2.usefipsprovider") {
|
if strings.Contains(jvmOptionsOutput, "-Dcom.ibm.jsse2.usefipsprovider") {
|
||||||
t.Errorf("Did not expect -Dcom.ibm.jsse2.usefipsprovider but it is not; got \"%v\"", jvmOptionsOutput)
|
t.Errorf("Did not expect -Dcom.ibm.jsse2.usefipsprovider but it is not; got \"%v\"", jvmOptionsOutput)
|
||||||
}
|
}
|
||||||
@@ -623,24 +608,21 @@ func TestDevSecureFalseFIPSWeb(t *testing.T) {
|
|||||||
// Just do a HTTPS GET as well to query installation details.
|
// Just do a HTTPS GET as well to query installation details.
|
||||||
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
||||||
t.Run("REST admin", func(t *testing.T) {
|
t.Run("REST admin", func(t *testing.T) {
|
||||||
testRESTAdmin(t, cli, ctr.ID, secureTLSConfig, "")
|
testRESTAdmin(t, cli, ID, secureTLSConfig, "")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify SSLFIPS is set to NO if no certificates were supplied
|
// Verify SSLFIPS is set to NO if no certificates were supplied
|
||||||
func TestSSLFIPSTrueNoCerts(t *testing.T) {
|
func TestSSLFIPSTrueNoCerts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
appPassword := "differentPassw0rd"
|
appPassword := "differentPassw0rd"
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_APP_PASSWORD=" + appPassword,
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
@@ -650,23 +632,23 @@ func TestSSLFIPSTrueNoCerts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
|
|
||||||
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
// Search the console output for exepcted values
|
// Search the console output for exepcted values
|
||||||
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
if !strings.Contains(sslFIPSOutput, "SSLKEYR( )") {
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR( )") {
|
||||||
t.Errorf("Expected SSLKEYR to be ' ' but it is not; got \"%v\"", sslFIPSOutput)
|
t.Errorf("Expected SSLKEYR to be ' ' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
}
|
}
|
||||||
@@ -679,19 +661,16 @@ func TestSSLFIPSTrueNoCerts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=tru (invalid value)
|
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=tru (invalid value)
|
||||||
func TestSSLFIPSInvalidValue(t *testing.T) {
|
func TestSSLFIPSInvalidValue(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"MQ_QMGR_NAME=QM1",
|
||||||
@@ -700,24 +679,24 @@ func TestSSLFIPSInvalidValue(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ID)
|
||||||
|
|
||||||
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
// Search the console output for exepcted values
|
// Search the console output for exepcted values
|
||||||
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
}
|
}
|
||||||
@@ -731,19 +710,16 @@ func TestSSLFIPSInvalidValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container creation fails when invalid certs are passed and MQ_ENABLE_FIPS set true
|
// Container creation fails when invalid certs are passed and MQ_ENABLE_FIPS set true
|
||||||
func TestSSLFIPSBadCerts(t *testing.T) {
|
func TestSSLFIPSBadCerts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"MQ_QMGR_NAME=QM1",
|
||||||
@@ -752,25 +728,25 @@ func TestSSLFIPSBadCerts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDirInvalid(t, false) + ":/etc/mqm/pki/keys/default",
|
tlsDirInvalid(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, ID)
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
|
|
||||||
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
|
rc := waitForContainer(t, cli, ID, 20*time.Second)
|
||||||
// Expect return code 1 if container failed to create.
|
// Expect return code 1 if container failed to create.
|
||||||
if rc == 1 {
|
if rc == 1 {
|
||||||
// Get container logs and search for specific message.
|
// Get container logs and search for specific message.
|
||||||
logs := inspectLogs(t, cli, ctr.ID)
|
logs := inspectLogs(t, cli, ID)
|
||||||
if strings.Contains(logs, "Failed to parse private key") {
|
if strings.Contains(logs, "Failed to parse private key") {
|
||||||
t.Logf("Container creating failed because of invalid certifates")
|
t.Logf("Container creating failed because of invalid certifates")
|
||||||
}
|
}
|
||||||
@@ -780,5 +756,5 @@ func TestSSLFIPSBadCerts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ID)
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2022
|
© Copyright IBM Corporation 2018, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -34,9 +34,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
"github.com/docker/docker/api/types/network"
|
|
||||||
"github.com/docker/docker/client"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultAdminPassword string = "passw0rd"
|
const defaultAdminPassword string = "passw0rd"
|
||||||
@@ -49,7 +47,7 @@ var insecureTLSConfig *tls.Config = &tls.Config{
|
|||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
|
func waitForWebReady(t *testing.T, cli ce.ContainerInterface, ID string, tlsConfig *tls.Config) {
|
||||||
t.Logf("%s Waiting for web server to be ready", time.Now().Format(time.RFC3339))
|
t.Logf("%s Waiting for web server to be ready", time.Now().Format(time.RFC3339))
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(10 * time.Second),
|
Timeout: time.Duration(10 * time.Second),
|
||||||
@@ -57,7 +55,11 @@ func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls
|
|||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
|
port, err := cli.GetContainerPort(ID, 9443)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", port)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -91,11 +93,16 @@ func tlsDirInvalid(t *testing.T, unixPath bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID
|
// runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID
|
||||||
func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string, ibmjre string, cipherName string) {
|
func runJMSTests(t *testing.T, cli ce.ContainerInterface, ID string, tls bool, user, password string, ibmjre string, cipherName string) {
|
||||||
containerConfig := container.Config{
|
port, err := cli.GetContainerPort(ID, 1414)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
containerConfig := ce.ContainerConfig{
|
||||||
// -e MQ_PORT_1414_TCP_ADDR=9.145.14.173 -e MQ_USERNAME=app -e MQ_PASSWORD=passw0rd -e MQ_CHANNEL=DEV.APP.SVRCONN -e MQ_TLS_TRUSTSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest
|
// -e MQ_PORT_1414_TCP_ADDR=9.145.14.173 -e MQ_USERNAME=app -e MQ_PASSWORD=passw0rd -e MQ_CHANNEL=DEV.APP.SVRCONN -e MQ_TLS_TRUSTSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
|
"MQ_PORT_1414_TCP_ADDR=127.0.0.1",
|
||||||
|
"MQ_PORT_1414_OVERRIDE=" + port,
|
||||||
"MQ_USERNAME=" + user,
|
"MQ_USERNAME=" + user,
|
||||||
"MQ_CHANNEL=DEV.APP.SVRCONN",
|
"MQ_CHANNEL=DEV.APP.SVRCONN",
|
||||||
"IBMJRE=" + ibmjre,
|
"IBMJRE=" + ibmjre,
|
||||||
@@ -114,26 +121,28 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa
|
|||||||
"MQ_TLS_CIPHER=" + cipherName,
|
"MQ_TLS_CIPHER=" + cipherName,
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/var/tls",
|
tlsDir(t, false) + ":/var/tls",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, strings.Replace(t.Name()+"JMS", "/", "", -1))
|
Networks: []string{"host"},
|
||||||
|
}
|
||||||
|
jmsID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, strings.Replace(t.Name()+"JMS", "/", "", -1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, jmsID)
|
||||||
rc := waitForContainer(t, cli, ctr.ID, 2*time.Minute)
|
rc := waitForContainer(t, cli, jmsID, 2*time.Minute)
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
t.Errorf("JUnit container failed with rc=%v", rc)
|
t.Errorf("JUnit container failed with rc=%v", rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get console output of the container and process the lines
|
// Get console output of the container and process the lines
|
||||||
// to see if we have any failures
|
// to see if we have any failures
|
||||||
scanner := bufio.NewScanner(strings.NewReader(inspectLogs(t, cli, ctr.ID)))
|
scanner := bufio.NewScanner(strings.NewReader(inspectLogs(t, cli, jmsID)))
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
s := scanner.Text()
|
s := scanner.Text()
|
||||||
if processJunitLogLine(s) {
|
if processJunitLogLine(s) {
|
||||||
@@ -141,7 +150,7 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defer cleanContainer(t, cli, ctr.ID)
|
defer cleanContainer(t, cli, jmsID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse JUnit log line and return true if line contains failed or aborted tests
|
// Parse JUnit log line and return true if line contains failed or aborted tests
|
||||||
@@ -205,14 +214,18 @@ func createTLSConfig(t *testing.T, certFile, password string) *tls.Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRESTAdmin(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config, errorExpected string) {
|
func testRESTAdmin(t *testing.T, cli ce.ContainerInterface, ID string, tlsConfig *tls.Config, errorExpected string) {
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(30 * time.Second),
|
Timeout: time.Duration(30 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
|
port, err := cli.GetContainerPort(ID, 9443)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", port)
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
req.SetBasicAuth("admin", defaultAdminPassword)
|
req.SetBasicAuth("admin", defaultAdminPassword)
|
||||||
resp, err := httpClient.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
@@ -248,7 +261,7 @@ func logHTTPResponse(t *testing.T, resp *http.Response) {
|
|||||||
t.Logf("HTTP response: %v", string(d))
|
t.Logf("HTTP response: %v", string(d))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config, qmName string, user string, password string, errorExpected string) {
|
func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsConfig *tls.Config, qmName string, user string, password string, errorExpected string) {
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(30 * time.Second),
|
Timeout: time.Duration(30 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
@@ -256,7 +269,11 @@ func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *t
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
q := "DEV.QUEUE.1"
|
q := "DEV.QUEUE.1"
|
||||||
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/messaging/qmgr/%s/queue/%s/message", getPort(t, cli, ID, 9443), qmName, q)
|
port, err := cli.GetContainerPort(ID, 9443)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/messaging/qmgr/%s/queue/%s/message", port, qmName, q)
|
||||||
putMessage := []byte("Hello")
|
putMessage := []byte("Hello")
|
||||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(putMessage))
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(putMessage))
|
||||||
req.SetBasicAuth(user, password)
|
req.SetBasicAuth(user, password)
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -34,28 +34,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
"github.com/docker/docker/api/types/container"
|
|
||||||
"github.com/docker/docker/api/types/network"
|
|
||||||
"github.com/docker/docker/api/types/volume"
|
|
||||||
"github.com/docker/docker/client"
|
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
|
||||||
"github.com/docker/docker/pkg/stdcopy"
|
|
||||||
"github.com/docker/go-connections/nat"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type containerDetails struct {
|
|
||||||
ID string
|
|
||||||
Name string
|
|
||||||
Image string
|
|
||||||
Path string
|
|
||||||
Args []string
|
|
||||||
CapAdd []string
|
|
||||||
CapDrop []string
|
|
||||||
User string
|
|
||||||
Env []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func imageName() string {
|
func imageName() string {
|
||||||
image, ok := os.LookupEnv("TEST_IMAGE")
|
image, ok := os.LookupEnv("TEST_IMAGE")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -73,7 +54,7 @@ func imageNameDevJMS() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// baseImage returns the ID of the underlying base image (e.g. "ubuntu" or "rhel")
|
// baseImage returns the ID of the underlying base image (e.g. "ubuntu" or "rhel")
|
||||||
func baseImage(t *testing.T, cli *client.Client) string {
|
func baseImage(t *testing.T, cli ce.ContainerInterface) string {
|
||||||
rc, out := runContainerOneShot(t, cli, "grep", "^ID=", "/etc/os-release")
|
rc, out := runContainerOneShot(t, cli, "grep", "^ID=", "/etc/os-release")
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
t.Fatal("Couldn't determine base image")
|
t.Fatal("Couldn't determine base image")
|
||||||
@@ -87,7 +68,7 @@ func baseImage(t *testing.T, cli *client.Client) string {
|
|||||||
|
|
||||||
// devImage returns true if the image under test is a developer image,
|
// devImage returns true if the image under test is a developer image,
|
||||||
// determined by use of the MQ_ADMIN_PASSWORD environment variable
|
// determined by use of the MQ_ADMIN_PASSWORD environment variable
|
||||||
func devImage(t *testing.T, cli *client.Client) bool {
|
func devImage(t *testing.T, cli ce.ContainerInterface) bool {
|
||||||
rc, _ := runContainerOneShot(t, cli, "printenv", "MQ_ADMIN_PASSWORD")
|
rc, _ := runContainerOneShot(t, cli, "printenv", "MQ_ADMIN_PASSWORD")
|
||||||
if rc == 0 {
|
if rc == 0 {
|
||||||
return true
|
return true
|
||||||
@@ -107,6 +88,11 @@ func isWSL(t *testing.T) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isARM returns whether we are running an arm64 MacOS machine
|
||||||
|
func isARM(t *testing.T) bool {
|
||||||
|
return runtime.GOARCH == "arm64"
|
||||||
|
}
|
||||||
|
|
||||||
// getCwd returns the working directory, in an os-specific or UNIX form
|
// getCwd returns the working directory, in an os-specific or UNIX form
|
||||||
func getCwd(t *testing.T, unixPath bool) string {
|
func getCwd(t *testing.T, unixPath bool) string {
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
@@ -161,29 +147,17 @@ func getTempDir(t *testing.T, unixStylePath bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// terminationMessage return the termination message, or an empty string if not set
|
// terminationMessage return the termination message, or an empty string if not set
|
||||||
func terminationMessage(t *testing.T, cli *client.Client, ID string) string {
|
func terminationMessage(t *testing.T, cli ce.ContainerInterface, ID string) string {
|
||||||
r, _, err := cli.CopyFromContainer(context.Background(), ID, "/run/termination-log")
|
r, err := cli.CopyFromContainer(ID, "/run/termination-log")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
|
t.Log(string(r))
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
b, err := ioutil.ReadAll(r)
|
return string(r)
|
||||||
tr := tar.NewReader(bytes.NewReader(b))
|
|
||||||
_, err = tr.Next()
|
|
||||||
if err != nil {
|
|
||||||
t.Log(err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
// read the complete content of the file h.Name into the bs []byte
|
|
||||||
content, err := ioutil.ReadAll(tr)
|
|
||||||
if err != nil {
|
|
||||||
t.Log(err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return string(content)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectTerminationMessage(t *testing.T, cli *client.Client, ID string) {
|
func expectTerminationMessage(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
m := terminationMessage(t, cli, ID)
|
m := terminationMessage(t, cli, ID)
|
||||||
if m == "" {
|
if m == "" {
|
||||||
t.Error("Expected termination message to be set")
|
t.Error("Expected termination message to be set")
|
||||||
@@ -191,10 +165,10 @@ func expectTerminationMessage(t *testing.T, cli *client.Client, ID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// logContainerDetails logs selected details about the container
|
// logContainerDetails logs selected details about the container
|
||||||
func logContainerDetails(t *testing.T, cli *client.Client, ID string) {
|
func logContainerDetails(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
i, err := cli.ContainerInspect(context.Background(), ID)
|
i, err := cli.ContainerInspect(ID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
d := containerDetails{
|
d := ce.ContainerDetailsLogging{
|
||||||
ID: ID,
|
ID: ID,
|
||||||
Name: i.Name,
|
Name: i.Name,
|
||||||
Image: i.Image,
|
Image: i.Image,
|
||||||
@@ -210,29 +184,29 @@ func logContainerDetails(t *testing.T, cli *client.Client, ID string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanContainerQuiet(t *testing.T, cli *client.Client, ID string) {
|
func cleanContainerQuiet(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
timeout := 10 * time.Second
|
timeout := 10 * time.Second
|
||||||
err := cli.ContainerStop(context.Background(), ID, &timeout)
|
err := cli.ContainerStop(ID, &timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Just log the error and continue
|
// Just log the error and continue
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
opts := types.ContainerRemoveOptions{
|
opts := ce.ContainerRemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
Force: true,
|
Force: true,
|
||||||
}
|
}
|
||||||
err = cli.ContainerRemove(context.Background(), ID, opts)
|
err = cli.ContainerRemove(ID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanContainer(t *testing.T, cli *client.Client, ID string) {
|
func cleanContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
logContainerDetails(t, cli, ID)
|
logContainerDetails(t, cli, ID)
|
||||||
t.Logf("Stopping container: %v", ID)
|
t.Logf("Stopping container: %v", ID)
|
||||||
timeout := 10 * time.Second
|
timeout := 10 * time.Second
|
||||||
// Stop the container. This allows the coverage output to be generated.
|
// Stop the container. This allows the coverage output to be generated.
|
||||||
err := cli.ContainerStop(context.Background(), ID, &timeout)
|
err := cli.ContainerStop(ID, &timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Just log the error and continue
|
// Just log the error and continue
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@@ -250,11 +224,11 @@ func cleanContainer(t *testing.T, cli *client.Client, ID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Removing container: %s", ID)
|
t.Logf("Removing container: %s", ID)
|
||||||
opts := types.ContainerRemoveOptions{
|
opts := ce.ContainerRemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
Force: true,
|
Force: true,
|
||||||
}
|
}
|
||||||
err = cli.ContainerRemove(context.Background(), ID, opts)
|
err = cli.ContainerRemove(ID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -268,17 +242,17 @@ func generateRandomUID() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getDefaultHostConfig creates a HostConfig and populates it with the defaults used in testing
|
// getDefaultHostConfig creates a HostConfig and populates it with the defaults used in testing
|
||||||
func getDefaultHostConfig(t *testing.T, cli *client.Client) *container.HostConfig {
|
func getDefaultHostConfig(t *testing.T, cli ce.ContainerInterface) *ce.ContainerHostConfig {
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
PortBindings: []ce.PortBinding{},
|
||||||
coverageBind(t),
|
|
||||||
},
|
|
||||||
PortBindings: nat.PortMap{},
|
|
||||||
CapDrop: []string{
|
CapDrop: []string{
|
||||||
"ALL",
|
"ALL",
|
||||||
},
|
},
|
||||||
Privileged: false,
|
Privileged: false,
|
||||||
}
|
}
|
||||||
|
if coverage() {
|
||||||
|
hostConfig.Binds = append(hostConfig.Binds, coverageBind(t))
|
||||||
|
}
|
||||||
if devImage(t, cli) {
|
if devImage(t, cli) {
|
||||||
// Only needed for a RHEL-based image
|
// Only needed for a RHEL-based image
|
||||||
if baseImage(t, cli) != "ubuntu" {
|
if baseImage(t, cli) != "ubuntu" {
|
||||||
@@ -292,7 +266,7 @@ func getDefaultHostConfig(t *testing.T, cli *client.Client) *container.HostConfi
|
|||||||
|
|
||||||
// runContainerWithHostConfig creates and starts a container, using the supplied HostConfig.
|
// runContainerWithHostConfig creates and starts a container, using the supplied HostConfig.
|
||||||
// Note that a default HostConfig can be created using getDefaultHostConfig.
|
// Note that a default HostConfig can be created using getDefaultHostConfig.
|
||||||
func runContainerWithHostConfig(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig) string {
|
func runContainerWithHostConfig(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, hostConfig *ce.ContainerHostConfig) string {
|
||||||
if containerConfig.Image == "" {
|
if containerConfig.Image == "" {
|
||||||
containerConfig.Image = imageName()
|
containerConfig.Image = imageName()
|
||||||
}
|
}
|
||||||
@@ -300,22 +274,23 @@ func runContainerWithHostConfig(t *testing.T, cli *client.Client, containerConfi
|
|||||||
if containerConfig.User == "" {
|
if containerConfig.User == "" {
|
||||||
containerConfig.User = generateRandomUID()
|
containerConfig.User = generateRandomUID()
|
||||||
}
|
}
|
||||||
// if coverage
|
if coverage() {
|
||||||
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
networkingConfig := network.NetworkingConfig{}
|
}
|
||||||
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
t.Logf("Running container (%s)", containerConfig.Image)
|
t.Logf("Running container (%s)", containerConfig.Image)
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, &networkingConfig, t.Name())
|
ID, err := cli.ContainerCreate(containerConfig, hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
return ctr.ID
|
return ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
||||||
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
||||||
func runContainerWithAllConfig(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) string {
|
func runContainerWithAllConfig(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, hostConfig *ce.ContainerHostConfig, networkingConfig *ce.ContainerNetworkSettings, containerName string) string {
|
||||||
if containerName == "" {
|
if containerName == "" {
|
||||||
containerName = t.Name()
|
containerName = t.Name()
|
||||||
}
|
}
|
||||||
@@ -326,30 +301,32 @@ func runContainerWithAllConfig(t *testing.T, cli *client.Client, containerConfig
|
|||||||
if containerConfig.User == "" {
|
if containerConfig.User == "" {
|
||||||
containerConfig.User = generateRandomUID()
|
containerConfig.User = generateRandomUID()
|
||||||
}
|
}
|
||||||
// if coverage
|
if coverage() {
|
||||||
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
|
}
|
||||||
t.Logf("Running container (%s)", containerConfig.Image)
|
t.Logf("Running container (%s)", containerConfig.Image)
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkingConfig, containerName)
|
ID, err := cli.ContainerCreate(containerConfig, hostConfig, networkingConfig, containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ID)
|
||||||
return ctr.ID
|
return ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
|
// runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
|
||||||
// If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
|
// If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
|
||||||
// environment variable.
|
// environment variable.
|
||||||
func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *container.Config, ports []int) string {
|
func runContainerWithPorts(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, ports []int) string {
|
||||||
hostConfig := getDefaultHostConfig(t, cli)
|
hostConfig := getDefaultHostConfig(t, cli)
|
||||||
|
var binding ce.PortBinding
|
||||||
for _, p := range ports {
|
for _, p := range ports {
|
||||||
port := nat.Port(fmt.Sprintf("%v/tcp", p))
|
port := fmt.Sprintf("%v/tcp", p)
|
||||||
hostConfig.PortBindings[port] = []nat.PortBinding{
|
binding = ce.PortBinding{
|
||||||
{
|
ContainerPort: port,
|
||||||
HostIP: "0.0.0.0",
|
HostIP: "0.0.0.0",
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
||||||
}
|
}
|
||||||
return runContainerWithHostConfig(t, cli, containerConfig, hostConfig)
|
return runContainerWithHostConfig(t, cli, containerConfig, hostConfig)
|
||||||
}
|
}
|
||||||
@@ -357,161 +334,160 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co
|
|||||||
// runContainer creates and starts a container. If no image is specified in
|
// runContainer creates and starts a container. If no image is specified in
|
||||||
// the container config, then the image name is retrieved from the TEST_IMAGE
|
// the container config, then the image name is retrieved from the TEST_IMAGE
|
||||||
// environment variable.
|
// environment variable.
|
||||||
func runContainer(t *testing.T, cli *client.Client, containerConfig *container.Config) string {
|
func runContainer(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig) string {
|
||||||
return runContainerWithPorts(t, cli, containerConfig, nil)
|
return runContainerWithPorts(t, cli, containerConfig, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
||||||
// user and with default capabilities
|
// user and with default capabilities
|
||||||
func runContainerOneShot(t *testing.T, cli *client.Client, command ...string) (int64, string) {
|
func runContainerOneShot(t *testing.T, cli ce.ContainerInterface, command ...string) (int64, string) {
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Entrypoint: command,
|
Entrypoint: command,
|
||||||
User: "root",
|
User: "root",
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{}
|
hostConfig := ce.ContainerHostConfig{}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
t.Logf("Running one shot container (%s): %v", containerConfig.Image, command)
|
t.Logf("Running one shot container (%s): %v", containerConfig.Image, command)
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShot")
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShot")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startOptions := types.ContainerStartOptions{}
|
startOptions := ce.ContainerStartOptions{}
|
||||||
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
|
err = cli.ContainerStart(ID, startOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainerQuiet(t, cli, ctr.ID)
|
defer cleanContainerQuiet(t, cli, ID)
|
||||||
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
|
rc := waitForContainer(t, cli, ID, 20*time.Second)
|
||||||
out := inspectLogs(t, cli, ctr.ID)
|
out := inspectLogs(t, cli, ID)
|
||||||
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
||||||
return rc, out
|
return rc, out
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
||||||
// user, with default capabilities, and a volume mounted
|
// user, with default capabilities, and a volume mounted
|
||||||
func runContainerOneShotWithVolume(t *testing.T, cli *client.Client, bind string, command ...string) (int64, string) {
|
func runContainerOneShotWithVolume(t *testing.T, cli ce.ContainerInterface, bind string, command ...string) (int64, string) {
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Entrypoint: command,
|
Entrypoint: command,
|
||||||
User: "root",
|
User: "root",
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
bind,
|
bind,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command)
|
t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command)
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShotVolume")
|
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShotVolume")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startOptions := types.ContainerStartOptions{}
|
startOptions := ce.ContainerStartOptions{}
|
||||||
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
|
err = cli.ContainerStart(ID, startOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainerQuiet(t, cli, ctr.ID)
|
defer cleanContainerQuiet(t, cli, ID)
|
||||||
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
|
rc := waitForContainer(t, cli, ID, 20*time.Second)
|
||||||
out := inspectLogs(t, cli, ctr.ID)
|
out := inspectLogs(t, cli, ID)
|
||||||
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
||||||
return rc, out
|
return rc, out
|
||||||
}
|
}
|
||||||
|
|
||||||
func startMultiVolumeQueueManager(t *testing.T, cli *client.Client, dataVol bool, qmsharedlogs string, qmshareddata string, env []string) (error, string, string) {
|
func startMultiVolumeQueueManager(t *testing.T, cli ce.ContainerInterface, dataVol bool, qmsharedlogs string, qmshareddata string, env []string) (error, string, string) {
|
||||||
id := strconv.FormatInt(time.Now().UnixNano(), 10)
|
id := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||||
qmdata := createVolume(t, cli, id)
|
volume := createVolume(t, cli, id)
|
||||||
containerConfig := container.Config{
|
containerConfig := ce.ContainerConfig{
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
Env: env,
|
Env: env,
|
||||||
}
|
}
|
||||||
var hostConfig container.HostConfig
|
var hostConfig ce.ContainerHostConfig
|
||||||
|
|
||||||
if !dataVol {
|
if !dataVol {
|
||||||
hostConfig = container.HostConfig{}
|
hostConfig = ce.ContainerHostConfig{}
|
||||||
} else if qmsharedlogs == "" && qmshareddata == "" {
|
} else if qmsharedlogs == "" && qmshareddata == "" {
|
||||||
hostConfig = getHostConfig(t, 1, "", "", qmdata.Name)
|
hostConfig = getHostConfig(t, 1, "", "", volume)
|
||||||
} else if qmsharedlogs == "" {
|
} else if qmsharedlogs == "" {
|
||||||
hostConfig = getHostConfig(t, 2, "", qmshareddata, qmdata.Name)
|
hostConfig = getHostConfig(t, 2, "", qmshareddata, volume)
|
||||||
} else if qmshareddata == "" {
|
} else if qmshareddata == "" {
|
||||||
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", qmdata.Name)
|
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", volume)
|
||||||
} else {
|
} else {
|
||||||
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, qmdata.Name)
|
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, volume)
|
||||||
}
|
}
|
||||||
networkingConfig := network.NetworkingConfig{}
|
networkingConfig := ce.ContainerNetworkSettings{}
|
||||||
qm, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
|
qmID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, "", ""
|
return err, "", ""
|
||||||
}
|
}
|
||||||
startContainer(t, cli, qm.ID)
|
startContainer(t, cli, qmID)
|
||||||
|
|
||||||
return nil, qm.ID, qmdata.Name
|
return nil, qmID, volume
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHostConfig(t *testing.T, mounts int, qmsharedlogs string, qmshareddata string, qmdata string) container.HostConfig {
|
func getHostConfig(t *testing.T, mounts int, qmsharedlogs string, qmshareddata string, qmdata string) ce.ContainerHostConfig {
|
||||||
|
|
||||||
var hostConfig container.HostConfig
|
var hostConfig ce.ContainerHostConfig
|
||||||
|
|
||||||
switch mounts {
|
switch mounts {
|
||||||
case 1:
|
case 1:
|
||||||
hostConfig = container.HostConfig{
|
hostConfig = ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
hostConfig = container.HostConfig{
|
hostConfig = ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
qmshareddata + ":/mnt/mqm-data",
|
qmshareddata + ":/mnt/mqm-data",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
hostConfig = container.HostConfig{
|
hostConfig = ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
qmsharedlogs + ":/mnt/mqm-log",
|
qmsharedlogs + ":/mnt/mqm-log",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
hostConfig = container.HostConfig{
|
hostConfig = ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
qmsharedlogs + ":/mnt/mqm-log",
|
qmsharedlogs + ":/mnt/mqm-log",
|
||||||
qmshareddata + ":/mnt/mqm-data",
|
qmshareddata + ":/mnt/mqm-data",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if coverage() {
|
||||||
|
hostConfig.Binds = append(hostConfig.Binds, coverageBind(t))
|
||||||
|
}
|
||||||
return hostConfig
|
return hostConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func startContainer(t *testing.T, cli *client.Client, ID string) {
|
func startContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
t.Logf("Starting container: %v", ID)
|
t.Logf("Starting container: %v", ID)
|
||||||
startOptions := types.ContainerStartOptions{}
|
startOptions := ce.ContainerStartOptions{}
|
||||||
err := cli.ContainerStart(context.Background(), ID, startOptions)
|
err := cli.ContainerStart(ID, startOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopContainer(t *testing.T, cli *client.Client, ID string) {
|
func stopContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
t.Logf("Stopping container: %v", ID)
|
t.Logf("Stopping container: %v", ID)
|
||||||
timeout := 10 * time.Second
|
timeout := 10 * time.Second
|
||||||
err := cli.ContainerStop(context.Background(), ID, &timeout) //Duration(20)*time.Second)
|
err := cli.ContainerStop(ID, &timeout) //Duration(20)*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
// Just log the error and continue
|
||||||
|
t.Log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func killContainer(t *testing.T, cli *client.Client, ID string, signal string) {
|
func killContainer(t *testing.T, cli ce.ContainerInterface, ID string, signal string) {
|
||||||
t.Logf("Killing container: %v", ID)
|
t.Logf("Killing container: %v", ID)
|
||||||
err := cli.ContainerKill(context.Background(), ID, signal)
|
err := cli.ContainerKill(ID, signal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -545,17 +521,17 @@ func getCoverageExitCode(t *testing.T, orig int64) int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// waitForContainer waits until a container has exited
|
// waitForContainer waits until a container has exited
|
||||||
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.Duration) int64 {
|
func waitForContainer(t *testing.T, cli ce.ContainerInterface, ID string, timeout time.Duration) int64 {
|
||||||
c, cancel := context.WithTimeout(context.Background(), timeout)
|
c, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
t.Logf("Waiting for container for %s", timeout)
|
t.Logf("Waiting for container for %s", timeout)
|
||||||
okC, errC := cli.ContainerWait(c, ID, container.WaitConditionNotRunning)
|
okC, errC := cli.ContainerWait(c, ID, ce.ContainerStateNotRunning)
|
||||||
var rc int64
|
var rc int64
|
||||||
select {
|
select {
|
||||||
case err := <-errC:
|
case err := <-errC:
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
case ok := <-okC:
|
case ok := <-okC:
|
||||||
rc = ok.StatusCode
|
rc = ok
|
||||||
}
|
}
|
||||||
if coverage() {
|
if coverage() {
|
||||||
// COVERAGE: When running coverage, the exit code is written to a file,
|
// COVERAGE: When running coverage, the exit code is written to a file,
|
||||||
@@ -567,78 +543,15 @@ func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// execContainer runs a command in a running container, and returns the exit code and output
|
// execContainer runs a command in a running container, and returns the exit code and output
|
||||||
func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd []string) (int, string) {
|
func execContainer(t *testing.T, cli ce.ContainerInterface, ID string, user string, cmd []string) (int, string) {
|
||||||
t.Logf("Running command: %v", cmd)
|
t.Logf("Running command: %v", cmd)
|
||||||
config := types.ExecConfig{
|
exitcode, outputStr := cli.ExecContainer(ID, user, cmd)
|
||||||
User: user,
|
|
||||||
Privileged: false,
|
|
||||||
Tty: false,
|
|
||||||
AttachStdin: false,
|
|
||||||
// Note that you still need to attach stdout/stderr, even though they're not wanted
|
|
||||||
AttachStdout: true,
|
|
||||||
AttachStderr: true,
|
|
||||||
Detach: false,
|
|
||||||
Cmd: cmd,
|
|
||||||
}
|
|
||||||
resp, err := cli.ContainerExecCreate(context.Background(), ID, config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
hijack, err := cli.ContainerExecAttach(context.Background(), resp.ID, types.ExecStartCheck{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer hijack.Close()
|
|
||||||
time.Sleep(time.Millisecond * 10)
|
|
||||||
err = cli.ContainerExecStart(context.Background(), resp.ID, types.ExecStartCheck{
|
|
||||||
Detach: false,
|
|
||||||
Tty: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
// Wait for the command to finish
|
|
||||||
var exitcode int
|
|
||||||
var outputStr string
|
|
||||||
for {
|
|
||||||
inspect, err := cli.ContainerExecInspect(context.Background(), resp.ID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if inspect.Running {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
exitcode = inspect.ExitCode
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
// Each output line has a header, which needs to be removed
|
|
||||||
_, err = stdcopy.StdCopy(buf, buf, hijack.Reader)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outputStr = strings.TrimSpace(buf.String())
|
|
||||||
|
|
||||||
/* Commented out on 14/06/2018 as it might not be needed after adding
|
|
||||||
* pause between ContainerExecAttach and ContainerExecStart.
|
|
||||||
* TODO If intermittent failures do not occur, remove and refactor.
|
|
||||||
*
|
|
||||||
* // Before we go let's just double check it did actually finish running
|
|
||||||
* // because sometimes we get a "Exec command already running error"
|
|
||||||
* alreadyRunningErr := regexp.MustCompile("Error: Exec command .* is already running")
|
|
||||||
* if alreadyRunningErr.MatchString(outputStr) {
|
|
||||||
* continue
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return exitcode, outputStr
|
return exitcode, outputStr
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForReady(t *testing.T, cli *client.Client, ID string) {
|
func waitForReady(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -662,57 +575,47 @@ func waitForReady(t *testing.T, cli *client.Client, ID string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIPAddress(t *testing.T, cli *client.Client, ID string) string {
|
func createNetwork(t *testing.T, cli ce.ContainerInterface) string {
|
||||||
ctr, err := cli.ContainerInspect(context.Background(), ID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return ctr.NetworkSettings.IPAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNetwork(t *testing.T, cli *client.Client) string {
|
|
||||||
name := "test"
|
name := "test"
|
||||||
t.Logf("Creating network: %v", name)
|
t.Logf("Creating network: %v", name)
|
||||||
opts := types.NetworkCreate{}
|
opts := ce.NetworkCreateOptions{}
|
||||||
net, err := cli.NetworkCreate(context.Background(), name, opts)
|
netID, err := cli.NetworkCreate(name, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Logf("Created network %v with ID %v", name, net.ID)
|
t.Logf("Created network %v with ID %v", name, netID)
|
||||||
return net.ID
|
return netID
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeNetwork(t *testing.T, cli *client.Client, ID string) {
|
func removeNetwork(t *testing.T, cli ce.ContainerInterface, ID string) {
|
||||||
t.Logf("Removing network ID: %v", ID)
|
t.Logf("Removing network ID: %v", ID)
|
||||||
err := cli.NetworkRemove(context.Background(), ID)
|
err := cli.NetworkRemove(ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVolume(t *testing.T, cli *client.Client, name string) types.Volume {
|
func createVolume(t *testing.T, cli ce.ContainerInterface, name string) string {
|
||||||
v, err := cli.VolumeCreate(context.Background(), volume.VolumeCreateBody{
|
v, err := cli.VolumeCreate(ce.VolumeCreateOptions{
|
||||||
Driver: "local",
|
Driver: "local",
|
||||||
DriverOpts: map[string]string{},
|
Name: name,
|
||||||
Labels: map[string]string{},
|
|
||||||
Name: name,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Logf("Created volume %v", v.Name)
|
t.Logf("Created volume %v", v)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeVolume(t *testing.T, cli *client.Client, name string) {
|
func removeVolume(t *testing.T, cli ce.ContainerInterface, name string) {
|
||||||
t.Logf("Removing volume %v", name)
|
t.Logf("Removing volume %v", name)
|
||||||
err := cli.VolumeRemove(context.Background(), name, true)
|
err := cli.VolumeRemove(name, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspectTextLogs(t *testing.T, cli *client.Client, ID string) string {
|
func inspectTextLogs(t *testing.T, cli ce.ContainerInterface, ID string) string {
|
||||||
jsonLogs := inspectLogs(t, cli, ID)
|
jsonLogs := inspectLogs(t, cli, ID)
|
||||||
scanner := bufio.NewScanner(strings.NewReader(jsonLogs))
|
scanner := bufio.NewScanner(strings.NewReader(jsonLogs))
|
||||||
b := make([]byte, 64*1024)
|
b := make([]byte, 64*1024)
|
||||||
@@ -720,9 +623,11 @@ func inspectTextLogs(t *testing.T, cli *client.Client, ID string) string {
|
|||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
text := scanner.Text()
|
text := scanner.Text()
|
||||||
if strings.HasPrefix(text, "{") {
|
if strings.HasPrefix(text, "{") {
|
||||||
|
// If it's a JSON log message, it makes it hard to debug the test, as the JSON
|
||||||
|
// is embedded in the long test output. So just summarize the JSON instead.
|
||||||
var e map[string]interface{}
|
var e map[string]interface{}
|
||||||
json.Unmarshal([]byte(text), &e)
|
json.Unmarshal([]byte(text), &e)
|
||||||
fmt.Fprintf(buf, "{\"message\": \"%v\"}\n", e["message"])
|
fmt.Fprintf(buf, "{\"ibm_datetime\": \"%v\", \"message\": \"%v\", ...}\n", e["ibm_datetime"], e["message"])
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(buf, text)
|
fmt.Fprintln(buf, text)
|
||||||
}
|
}
|
||||||
@@ -734,24 +639,14 @@ func inspectTextLogs(t *testing.T, cli *client.Client, ID string) string {
|
|||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspectLogs(t *testing.T, cli *client.Client, ID string) string {
|
func inspectLogs(t *testing.T, cli ce.ContainerInterface, ID string) string {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
reader, err := cli.ContainerLogs(ctx, ID, types.ContainerLogsOptions{
|
logs, err := cli.GetContainerLogs(ctx, ID, ce.ContainerLogsOptions{})
|
||||||
ShowStdout: true,
|
|
||||||
ShowStderr: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
buf := new(bytes.Buffer)
|
return logs
|
||||||
|
|
||||||
// Each output line has a header, which needs to be removed
|
|
||||||
_, err = stdcopy.StdCopy(buf, buf, reader)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateTAR creates a TAR-formatted []byte, with the specified files included.
|
// generateTAR creates a TAR-formatted []byte, with the specified files included.
|
||||||
@@ -781,76 +676,54 @@ func generateTAR(t *testing.T, files []struct{ Name, Body string }) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createImage creates a new Docker image with the specified files included.
|
// createImage creates a new Docker image with the specified files included.
|
||||||
func createImage(t *testing.T, cli *client.Client, files []struct{ Name, Body string }) string {
|
func createImage(t *testing.T, cli ce.ContainerInterface, files []struct{ Name, Body string }) string {
|
||||||
r := bytes.NewReader(generateTAR(t, files))
|
r := bytes.NewReader(generateTAR(t, files))
|
||||||
tag := strings.ToLower(t.Name())
|
tag := strings.ToLower(t.Name())
|
||||||
buildOptions := types.ImageBuildOptions{
|
|
||||||
Context: r,
|
tmpDir, err := os.MkdirTemp("", "tmp")
|
||||||
Tags: []string{tag},
|
|
||||||
}
|
|
||||||
resp, err := cli.ImageBuild(context.Background(), r, buildOptions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// resp (ImageBuildResponse) contains a series of JSON messages
|
|
||||||
dec := json.NewDecoder(resp.Body)
|
defer os.RemoveAll(tmpDir)
|
||||||
for {
|
|
||||||
m := jsonmessage.JSONMessage{}
|
//Write files to temp directory
|
||||||
err := dec.Decode(&m)
|
for _, file := range files {
|
||||||
if m.Error != nil {
|
//Add tag to file name to allow parallel testing
|
||||||
t.Fatal(m.ErrorMessage)
|
f, err := os.Create(filepath.Join(tmpDir, file.Name))
|
||||||
}
|
|
||||||
t.Log(strings.TrimSpace(m.Stream))
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
body := []byte(file.Body)
|
||||||
|
_, err = f.Write(body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = cli.ImageBuild(r, tag, filepath.Join(tmpDir, files[0].Name))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteImage deletes a Docker image
|
// deleteImage deletes a Docker image
|
||||||
func deleteImage(t *testing.T, cli *client.Client, id string) {
|
func deleteImage(t *testing.T, cli ce.ContainerInterface, id string) {
|
||||||
cli.ImageRemove(context.Background(), id, types.ImageRemoveOptions{
|
cli.ImageRemove(id, ce.ImageRemoveOptions{
|
||||||
Force: true,
|
Force: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFromContainer(t *testing.T, cli *client.Client, id string, file string) []byte {
|
func copyFromContainer(t *testing.T, cli ce.ContainerInterface, id string, file string) []byte {
|
||||||
reader, _, err := cli.CopyFromContainer(context.Background(), id, file)
|
b, err := cli.CopyFromContainer(id, file)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer reader.Close()
|
|
||||||
b, err := ioutil.ReadAll(reader)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPort(t *testing.T, cli *client.Client, ID string, port int) string {
|
|
||||||
var inspectInfo types.ContainerJSON
|
|
||||||
var err error
|
|
||||||
for attemptsRemaining := 3; attemptsRemaining > 0; attemptsRemaining-- {
|
|
||||||
inspectInfo, err = cli.ContainerInspect(context.Background(), ID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
portNat := nat.Port(fmt.Sprintf("%d/tcp", port))
|
|
||||||
if inspectInfo.NetworkSettings.Ports[portNat] == nil || len(inspectInfo.NetworkSettings.Ports[portNat]) == 0 {
|
|
||||||
t.Log("Container port not yet bound")
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return inspectInfo.NetworkSettings.Ports[portNat][0].HostPort
|
|
||||||
}
|
|
||||||
t.Fatal("Failed to get port")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func countLines(t *testing.T, r io.Reader) int {
|
func countLines(t *testing.T, r io.Reader) int {
|
||||||
scanner := bufio.NewScanner(r)
|
scanner := bufio.NewScanner(r)
|
||||||
count := 0
|
count := 0
|
||||||
@@ -882,15 +755,6 @@ func countTarLines(t *testing.T, b []byte) int {
|
|||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMQVersion(t *testing.T, cli *client.Client) (string, error) {
|
|
||||||
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
version := inspect.ContainerConfig.Labels["version"]
|
|
||||||
return version, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanForExcludedEntries scans for default excluded messages
|
// scanForExcludedEntries scans for default excluded messages
|
||||||
func scanForExcludedEntries(msg string) bool {
|
func scanForExcludedEntries(msg string) bool {
|
||||||
if strings.Contains(msg, "AMQ5041I") || strings.Contains(msg, "AMQ5052I") ||
|
if strings.Contains(msg, "AMQ5041I") || strings.Contains(msg, "AMQ5052I") ||
|
||||||
@@ -917,7 +781,7 @@ func checkLogForValidJSON(jsonLogs string) bool {
|
|||||||
|
|
||||||
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
||||||
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
||||||
func runContainerWithAllConfigError(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (string, error) {
|
func runContainerWithAllConfigError(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, hostConfig *ce.ContainerHostConfig, networkingConfig *ce.ContainerNetworkSettings, containerName string) (string, error) {
|
||||||
if containerName == "" {
|
if containerName == "" {
|
||||||
containerName = t.Name()
|
containerName = t.Name()
|
||||||
}
|
}
|
||||||
@@ -928,25 +792,26 @@ func runContainerWithAllConfigError(t *testing.T, cli *client.Client, containerC
|
|||||||
if containerConfig.User == "" {
|
if containerConfig.User == "" {
|
||||||
containerConfig.User = generateRandomUID()
|
containerConfig.User = generateRandomUID()
|
||||||
}
|
}
|
||||||
// if coverage
|
if coverage() {
|
||||||
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
|
}
|
||||||
t.Logf("Running container (%s)", containerConfig.Image)
|
t.Logf("Running container (%s)", containerConfig.Image)
|
||||||
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkingConfig, containerName)
|
ID, err := cli.ContainerCreate(containerConfig, hostConfig, networkingConfig, containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
err = startContainerError(t, cli, ctr.ID)
|
err = startContainerError(t, cli, ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return ctr.ID, nil
|
return ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startContainerError(t *testing.T, cli *client.Client, ID string) error {
|
func startContainerError(t *testing.T, cli ce.ContainerInterface, ID string) error {
|
||||||
t.Logf("Starting container: %v", ID)
|
t.Logf("Starting container: %v", ID)
|
||||||
startOptions := types.ContainerStartOptions{}
|
startOptions := ce.ContainerStartOptions{}
|
||||||
err := cli.ContainerStart(context.Background(), ID, startOptions)
|
err := cli.ContainerStart(ID, startOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -955,7 +820,7 @@ func startContainerError(t *testing.T, cli *client.Client, ID string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// testLogFilePages validates that the specified number of logFilePages is present in the qm.ini file.
|
// testLogFilePages validates that the specified number of logFilePages is present in the qm.ini file.
|
||||||
func testLogFilePages(t *testing.T, cli *client.Client, id string, qmName string, expectedLogFilePages string) {
|
func testLogFilePages(t *testing.T, cli ce.ContainerInterface, id string, qmName string, expectedLogFilePages string) {
|
||||||
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/" + qmName + "/qm.ini")
|
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/" + qmName + "/qm.ini")
|
||||||
_, iniContent := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand})
|
_, iniContent := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand})
|
||||||
|
|
||||||
@@ -964,8 +829,8 @@ func testLogFilePages(t *testing.T, cli *client.Client, id string, qmName string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//waitForMessageInLog will check for a particular message with wait
|
// waitForMessageInLog will check for a particular message with wait
|
||||||
func waitForMessageInLog(t *testing.T, cli *client.Client, id string, expecteMessageId string) (string, error) {
|
func waitForMessageInLog(t *testing.T, cli ce.ContainerInterface, id string, expectedMessageId string) (string, error) {
|
||||||
var jsonLogs string
|
var jsonLogs string
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -973,11 +838,29 @@ func waitForMessageInLog(t *testing.T, cli *client.Client, id string, expecteMes
|
|||||||
select {
|
select {
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(1 * time.Second):
|
||||||
jsonLogs = inspectLogs(t, cli, id)
|
jsonLogs = inspectLogs(t, cli, id)
|
||||||
if strings.Contains(jsonLogs, expecteMessageId) {
|
if strings.Contains(jsonLogs, expectedMessageId) {
|
||||||
return jsonLogs, nil
|
return jsonLogs, nil
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return "", fmt.Errorf("Expected message Id %s was not logged.", expecteMessageId)
|
return "", fmt.Errorf("expected message Id %s was not logged", expectedMessageId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForMessageCountInLog will check for a particular message with wait and must occur exact number of times in log as specified by count
|
||||||
|
func waitForMessageCountInLog(t *testing.T, cli ce.ContainerInterface, id string, expectedMessageId string, count int) (string, error) {
|
||||||
|
var jsonLogs string
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
jsonLogs = inspectLogs(t, cli, id)
|
||||||
|
if strings.Contains(jsonLogs, expectedMessageId) && strings.Count(jsonLogs, expectedMessageId) == count {
|
||||||
|
return jsonLogs, nil
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
return "", fmt.Errorf("expected message Id %s was not logged or it was not logged %v times", expectedMessageId, count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
3
test/container/go.mod
Normal file
3
test/container/go.mod
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/ibm-messaging/mq-container/test/container
|
||||||
|
|
||||||
|
go 1.19
|
||||||
0
test/container/go.sum
Normal file
0
test/container/go.sum
Normal file
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019, 2022
|
© Copyright IBM Corporation 2019, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/client"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
)
|
)
|
||||||
|
|
||||||
var miEnv = []string{
|
var miEnv = []string{
|
||||||
@@ -34,10 +34,7 @@ var miEnv = []string{
|
|||||||
// and starts/stop them checking we always have an active and standby
|
// and starts/stop them checking we always have an active and standby
|
||||||
func TestMultiInstanceStartStop(t *testing.T) {
|
func TestMultiInstanceStartStop(t *testing.T) {
|
||||||
t.Skipf("Skipping %v until test defect fixed", t.Name())
|
t.Skipf("Skipping %v until test defect fixed", t.Name())
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -76,10 +73,7 @@ func TestMultiInstanceStartStop(t *testing.T) {
|
|||||||
// TestMultiInstanceContainerStop starts 2 containers in a multi instance queue manager configuration,
|
// TestMultiInstanceContainerStop starts 2 containers in a multi instance queue manager configuration,
|
||||||
// stops the active queue manager, then checks to ensure the backup queue manager becomes active
|
// stops the active queue manager, then checks to ensure the backup queue manager becomes active
|
||||||
func TestMultiInstanceContainerStop(t *testing.T) {
|
func TestMultiInstanceContainerStop(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -122,21 +116,16 @@ func TestMultiInstanceContainerStop(t *testing.T) {
|
|||||||
// configuration, then checks to ensure that both an active and standby queue manager have been started
|
// configuration, then checks to ensure that both an active and standby queue manager have been started
|
||||||
func TestMultiInstanceRace(t *testing.T) {
|
func TestMultiInstanceRace(t *testing.T) {
|
||||||
t.Skipf("Skipping %v until file lock is implemented", t.Name())
|
t.Skipf("Skipping %v until file lock is implemented", t.Name())
|
||||||
|
cli := ce.NewContainerClient()
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
||||||
defer removeVolume(t, cli, qmsharedlogs.Name)
|
defer removeVolume(t, cli, qmsharedlogs)
|
||||||
qmshareddata := createVolume(t, cli, "qmshareddata")
|
qmshareddata := createVolume(t, cli, "qmshareddata")
|
||||||
defer removeVolume(t, cli, qmshareddata.Name)
|
defer removeVolume(t, cli, qmshareddata)
|
||||||
|
|
||||||
qmsChannel := make(chan QMChan)
|
qmsChannel := make(chan QMChan)
|
||||||
|
|
||||||
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs.Name, qmshareddata.Name, qmsChannel)
|
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs, qmshareddata, qmsChannel)
|
||||||
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs.Name, qmshareddata.Name, qmsChannel)
|
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs, qmshareddata, qmsChannel)
|
||||||
|
|
||||||
qm1a := <-qmsChannel
|
qm1a := <-qmsChannel
|
||||||
if qm1a.Error != nil {
|
if qm1a.Error != nil {
|
||||||
@@ -159,7 +148,7 @@ func TestMultiInstanceRace(t *testing.T) {
|
|||||||
waitForReady(t, cli, qm1aId)
|
waitForReady(t, cli, qm1aId)
|
||||||
waitForReady(t, cli, qm1bId)
|
waitForReady(t, cli, qm1bId)
|
||||||
|
|
||||||
err, _, _ = getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
|
err, _, _ := getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -169,10 +158,7 @@ func TestMultiInstanceRace(t *testing.T) {
|
|||||||
// mounts, then checks to ensure that the container terminates with the expected message
|
// mounts, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", "", miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", "", miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -188,15 +174,12 @@ func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
|||||||
// TestMultiInstanceNoSharedLogs starts 2 multi instance queue managers without providing a shared log
|
// TestMultiInstanceNoSharedLogs starts 2 multi instance queue managers without providing a shared log
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
qmshareddata := createVolume(t, cli, "qmshareddata")
|
qmshareddata := createVolume(t, cli, "qmshareddata")
|
||||||
defer removeVolume(t, cli, qmshareddata.Name)
|
defer removeVolume(t, cli, qmshareddata)
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", qmshareddata.Name, miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", qmshareddata, miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -210,15 +193,12 @@ func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
|||||||
// TestMultiInstanceNoSharedData starts 2 multi instance queue managers without providing a shared data
|
// TestMultiInstanceNoSharedData starts 2 multi instance queue managers without providing a shared data
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedData(t *testing.T) {
|
func TestMultiInstanceNoSharedData(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
||||||
defer removeVolume(t, cli, qmsharedlogs.Name)
|
defer removeVolume(t, cli, qmsharedlogs)
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, "", miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, "", miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -232,10 +212,7 @@ func TestMultiInstanceNoSharedData(t *testing.T) {
|
|||||||
// TestMultiInstanceNoMounts starts 2 multi instance queue managers without providing a shared data
|
// TestMultiInstanceNoMounts starts 2 multi instance queue managers without providing a shared data
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoMounts(t *testing.T) {
|
func TestMultiInstanceNoMounts(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, false, "", "", miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, false, "", "", miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019, 2022
|
© Copyright IBM Corporation 2019, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/client"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
)
|
)
|
||||||
|
|
||||||
type QMChan struct {
|
type QMChan struct {
|
||||||
@@ -34,27 +34,27 @@ type QMChan struct {
|
|||||||
|
|
||||||
// configureMultiInstance creates the volumes and containers required for basic testing
|
// configureMultiInstance creates the volumes and containers required for basic testing
|
||||||
// of multi instance queue managers. Returns error, qm1a ID, qm1b ID, slice of volume names
|
// of multi instance queue managers. Returns error, qm1a ID, qm1b ID, slice of volume names
|
||||||
func configureMultiInstance(t *testing.T, cli *client.Client) (error, string, string, []string) {
|
func configureMultiInstance(t *testing.T, cli ce.ContainerInterface) (error, string, string, []string) {
|
||||||
|
|
||||||
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
||||||
qmshareddata := createVolume(t, cli, "qmshareddata")
|
qmshareddata := createVolume(t, cli, "qmshareddata")
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, qmshareddata.Name, miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, "", "", []string{}
|
return err, "", "", []string{}
|
||||||
}
|
}
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
err, qm1bId, qm1bData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, qmshareddata.Name, miEnv)
|
err, qm1bId, qm1bData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, "", "", []string{}
|
return err, "", "", []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
volumes := []string{qmsharedlogs.Name, qmshareddata.Name, qm1aData, qm1bData}
|
volumes := []string{qmsharedlogs, qmshareddata, qm1aData, qm1bData}
|
||||||
|
|
||||||
return nil, qm1aId, qm1bId, volumes
|
return nil, qm1aId, qm1bId, volumes
|
||||||
}
|
}
|
||||||
|
|
||||||
func singleMultiInstanceQueueManager(t *testing.T, cli *client.Client, qmsharedlogs string, qmshareddata string, qmsChannel chan QMChan) {
|
func singleMultiInstanceQueueManager(t *testing.T, cli ce.ContainerInterface, qmsharedlogs string, qmshareddata string, qmsChannel chan QMChan) {
|
||||||
err, qmId, qmData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
|
err, qmId, qmData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
qmsChannel <- QMChan{Error: err}
|
qmsChannel <- QMChan{Error: err}
|
||||||
@@ -62,7 +62,7 @@ func singleMultiInstanceQueueManager(t *testing.T, cli *client.Client, qmsharedl
|
|||||||
qmsChannel <- QMChan{QMId: qmId, QMData: qmData}
|
qmsChannel <- QMChan{QMId: qmId, QMData: qmData}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getActiveStandbyQueueManager(t *testing.T, cli *client.Client, qm1aId string, qm1bId string) (error, string, string) {
|
func getActiveStandbyQueueManager(t *testing.T, cli ce.ContainerInterface, qm1aId string, qm1bId string) (error, string, string) {
|
||||||
qm1aStatus := getQueueManagerStatus(t, cli, qm1aId, "QM1")
|
qm1aStatus := getQueueManagerStatus(t, cli, qm1aId, "QM1")
|
||||||
qm1bStatus := getQueueManagerStatus(t, cli, qm1bId, "QM1")
|
qm1bStatus := getQueueManagerStatus(t, cli, qm1bId, "QM1")
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ func getActiveStandbyQueueManager(t *testing.T, cli *client.Client, qm1aId strin
|
|||||||
return err, "", ""
|
return err, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func getQueueManagerStatus(t *testing.T, cli *client.Client, containerID string, queueManagerName string) string {
|
func getQueueManagerStatus(t *testing.T, cli ce.ContainerInterface, containerID string, queueManagerName string) string {
|
||||||
_, dspmqOut := execContainer(t, cli, containerID, "", []string{"bash", "-c", "dspmq", "-m", queueManagerName})
|
_, dspmqOut := execContainer(t, cli, containerID, "", []string{"bash", "-c", "dspmq", "-m", queueManagerName})
|
||||||
t.Logf("dspmq for %v (%v) returned: %v", containerID, queueManagerName, dspmqOut)
|
t.Logf("dspmq for %v (%v) returned: %v", containerID, queueManagerName, dspmqOut)
|
||||||
regex := regexp.MustCompile(`STATUS\(.*\)`)
|
regex := regexp.MustCompile(`STATUS\(.*\)`)
|
||||||
@@ -84,7 +84,7 @@ func getQueueManagerStatus(t *testing.T, cli *client.Client, containerID string,
|
|||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForTerminationMessage(t *testing.T, cli *client.Client, qmId string, terminationString string, timeout time.Duration) {
|
func waitForTerminationMessage(t *testing.T, cli ce.ContainerInterface, qmId string, terminationString string, timeout time.Duration) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
for {
|
for {
|
||||||
@@ -93,7 +93,7 @@ func waitForTerminationMessage(t *testing.T, cli *client.Client, qmId string, te
|
|||||||
m := terminationMessage(t, cli, qmId)
|
m := terminationMessage(t, cli, qmId)
|
||||||
if m != "" {
|
if m != "" {
|
||||||
if !strings.Contains(m, terminationString) {
|
if !strings.Contains(m, terminationString) {
|
||||||
t.Fatalf("Expected container to fail on missing required mount. Got termination message: %v", m)
|
t.Fatalf("Expected container to fail with termination message %v. Got termination message: %v", terminationString, m)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2021, 2022
|
© Copyright IBM Corporation 2021, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,20 +16,19 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/docker/client"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestNativeHABasic creates 3 containers in a Native HA queue manager configuration
|
// TestNativeHABasic creates 3 containers in a Native HA queue manager configuration
|
||||||
// and ensures the queue manger and replicas start as expected
|
// and ensures the queue manger and replicas start as expected
|
||||||
func TestNativeHABasic(t *testing.T) {
|
func TestNativeHABasic(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := getMQVersion(t, cli)
|
version, err := cli.GetMQVersion(imageName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -40,21 +39,18 @@ func TestNativeHABasic(t *testing.T) {
|
|||||||
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
qmReplicaIDs := [3]string{}
|
qmReplicaIDs := [3]string{}
|
||||||
qmVolumes := []string{}
|
qmVolumes := []string{}
|
||||||
qmNetwork, err := createBridgeNetwork(cli, t)
|
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
|
||||||
if err != nil {
|
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
|
||||||
t.Fatal(err)
|
basePort := 14551
|
||||||
}
|
|
||||||
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
|
||||||
|
|
||||||
for i := 0; i <= 2; i++ {
|
for i := 0; i <= 2; i++ {
|
||||||
|
nhaPort := basePort + i
|
||||||
vol := createVolume(t, cli, containerNames[i])
|
vol := createVolume(t, cli, containerNames[i])
|
||||||
defer removeVolume(t, cli, vol.Name)
|
defer removeVolume(t, cli, vol)
|
||||||
qmVolumes = append(qmVolumes, vol.Name)
|
qmVolumes = append(qmVolumes, vol)
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, basePort)
|
||||||
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
hostConfig := getHostConfig(t, 1, "", "", vol)
|
||||||
hostConfig := getHostConfig(t, 1, "", "", vol.Name)
|
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
|
||||||
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
networkingConfig := getNativeHANetworkConfig("host")
|
||||||
|
|
||||||
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
defer cleanContainer(t, cli, ctr)
|
defer cleanContainer(t, cli, ctr)
|
||||||
qmReplicaIDs[i] = ctr
|
qmReplicaIDs[i] = ctr
|
||||||
@@ -74,12 +70,9 @@ func TestNativeHABasic(t *testing.T) {
|
|||||||
// queue manager comes back as a replica
|
// queue manager comes back as a replica
|
||||||
func TestNativeHAFailover(t *testing.T) {
|
func TestNativeHAFailover(t *testing.T) {
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := getMQVersion(t, cli)
|
version, err := cli.GetMQVersion(imageName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -90,21 +83,18 @@ func TestNativeHAFailover(t *testing.T) {
|
|||||||
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
qmReplicaIDs := [3]string{}
|
qmReplicaIDs := [3]string{}
|
||||||
qmVolumes := []string{}
|
qmVolumes := []string{}
|
||||||
qmNetwork, err := createBridgeNetwork(cli, t)
|
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
|
||||||
if err != nil {
|
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
|
||||||
t.Fatal(err)
|
basePort := 14551
|
||||||
}
|
|
||||||
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
|
||||||
|
|
||||||
for i := 0; i <= 2; i++ {
|
for i := 0; i <= 2; i++ {
|
||||||
|
nhaPort := basePort + i
|
||||||
vol := createVolume(t, cli, containerNames[i])
|
vol := createVolume(t, cli, containerNames[i])
|
||||||
defer removeVolume(t, cli, vol.Name)
|
defer removeVolume(t, cli, vol)
|
||||||
qmVolumes = append(qmVolumes, vol.Name)
|
qmVolumes = append(qmVolumes, vol)
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, basePort)
|
||||||
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
hostConfig := getHostConfig(t, 1, "", "", vol)
|
||||||
hostConfig := getHostConfig(t, 1, "", "", vol.Name)
|
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
|
||||||
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
networkingConfig := getNativeHANetworkConfig("host")
|
||||||
|
|
||||||
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
defer cleanContainer(t, cli, ctr)
|
defer cleanContainer(t, cli, ctr)
|
||||||
qmReplicaIDs[i] = ctr
|
qmReplicaIDs[i] = ctr
|
||||||
@@ -132,33 +122,31 @@ func TestNativeHAFailover(t *testing.T) {
|
|||||||
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
|
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
|
||||||
// with HA TLS enabled, and ensures the queue manger and replicas start as expected
|
// with HA TLS enabled, and ensures the queue manger and replicas start as expected
|
||||||
func TestNativeHASecure(t *testing.T) {
|
func TestNativeHASecure(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := getMQVersion(t, cli)
|
version, err := cli.GetMQVersion(imageName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if version < "9.2.2.0" {
|
if version < "9.2.2.0" {
|
||||||
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
||||||
}
|
}
|
||||||
|
if isARM(t) {
|
||||||
|
t.Skip("Skipping as an issue has been identified for the arm64 MQ image")
|
||||||
|
}
|
||||||
|
|
||||||
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
qmReplicaIDs := [3]string{}
|
qmReplicaIDs := [3]string{}
|
||||||
qmNetwork, err := createBridgeNetwork(cli, t)
|
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
|
||||||
if err != nil {
|
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
|
||||||
t.Fatal(err)
|
basePort := 14551
|
||||||
}
|
|
||||||
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
|
||||||
|
|
||||||
for i := 0; i <= 2; i++ {
|
for i := 0; i <= 2; i++ {
|
||||||
|
nhaPort := basePort + i
|
||||||
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true")
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true")
|
||||||
hostConfig := getNativeHASecureHostConfig(t)
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
|
||||||
|
networkingConfig := getNativeHANetworkConfig("host")
|
||||||
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
defer cleanContainer(t, cli, ctr)
|
defer cleanContainer(t, cli, ctr)
|
||||||
qmReplicaIDs[i] = ctr
|
qmReplicaIDs[i] = ctr
|
||||||
@@ -177,12 +165,9 @@ func TestNativeHASecure(t *testing.T) {
|
|||||||
// with HA TLS enabled, overrides the default CipherSpec, and ensures the queue manger
|
// with HA TLS enabled, overrides the default CipherSpec, and ensures the queue manger
|
||||||
// and replicas start as expected
|
// and replicas start as expected
|
||||||
func TestNativeHASecureCipherSpec(t *testing.T) {
|
func TestNativeHASecureCipherSpec(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := getMQVersion(t, cli)
|
version, err := cli.GetMQVersion(imageName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -192,18 +177,16 @@ func TestNativeHASecureCipherSpec(t *testing.T) {
|
|||||||
|
|
||||||
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
qmReplicaIDs := [3]string{}
|
qmReplicaIDs := [3]string{}
|
||||||
qmNetwork, err := createBridgeNetwork(cli, t)
|
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
|
||||||
if err != nil {
|
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
|
||||||
t.Fatal(err)
|
basePort := 14551
|
||||||
}
|
|
||||||
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
|
||||||
|
|
||||||
for i := 0; i <= 2; i++ {
|
for i := 0; i <= 2; i++ {
|
||||||
|
nhaPort := basePort + i
|
||||||
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_AES_256_GCM_SHA384")
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_AES_256_GCM_SHA384")
|
||||||
hostConfig := getNativeHASecureHostConfig(t)
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
|
||||||
|
networkingConfig := getNativeHANetworkConfig("host")
|
||||||
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
defer cleanContainer(t, cli, ctr)
|
defer cleanContainer(t, cli, ctr)
|
||||||
qmReplicaIDs[i] = ctr
|
qmReplicaIDs[i] = ctr
|
||||||
@@ -222,12 +205,9 @@ func TestNativeHASecureCipherSpec(t *testing.T) {
|
|||||||
// with HA TLS FIPS enabled, overrides the default CipherSpec, and ensures the queue manger
|
// with HA TLS FIPS enabled, overrides the default CipherSpec, and ensures the queue manger
|
||||||
// and replicas start as expected. This test uses FIPS compliant cipher.
|
// and replicas start as expected. This test uses FIPS compliant cipher.
|
||||||
func TestNativeHASecureCipherSpecFIPS(t *testing.T) {
|
func TestNativeHASecureCipherSpecFIPS(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := getMQVersion(t, cli)
|
version, err := cli.GetMQVersion(imageName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -237,19 +217,17 @@ func TestNativeHASecureCipherSpecFIPS(t *testing.T) {
|
|||||||
|
|
||||||
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
qmReplicaIDs := [3]string{}
|
qmReplicaIDs := [3]string{}
|
||||||
qmNetwork, err := createBridgeNetwork(cli, t)
|
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
|
||||||
if err != nil {
|
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
|
||||||
t.Fatal(err)
|
basePort := 14551
|
||||||
}
|
|
||||||
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
|
||||||
|
|
||||||
for i := 0; i <= 2; i++ {
|
for i := 0; i <= 2; i++ {
|
||||||
|
nhaPort := basePort + i
|
||||||
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
// MQ_NATIVE_HA_CIPHERSPEC is set a FIPS compliant cipherspec.
|
// MQ_NATIVE_HA_CIPHERSPEC is set a FIPS compliant cipherspec.
|
||||||
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_RSA_WITH_AES_128_GCM_SHA256", "MQ_ENABLE_FIPS=true")
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_RSA_WITH_AES_128_GCM_SHA256", "MQ_ENABLE_FIPS=true")
|
||||||
hostConfig := getNativeHASecureHostConfig(t)
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
|
||||||
|
networkingConfig := getNativeHANetworkConfig("host")
|
||||||
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
defer cleanContainer(t, cli, ctr)
|
defer cleanContainer(t, cli, ctr)
|
||||||
qmReplicaIDs[i] = ctr
|
qmReplicaIDs[i] = ctr
|
||||||
@@ -272,12 +250,9 @@ func TestNativeHASecureCipherSpecFIPS(t *testing.T) {
|
|||||||
// with HA TLS FIPS enabled with non-FIPS cipher, overrides the default CipherSpec, and
|
// with HA TLS FIPS enabled with non-FIPS cipher, overrides the default CipherSpec, and
|
||||||
// ensures the queue manger and replicas don't start as expected
|
// ensures the queue manger and replicas don't start as expected
|
||||||
func TestNativeHASecureCipherSpecNonFIPSCipher(t *testing.T) {
|
func TestNativeHASecureCipherSpecNonFIPSCipher(t *testing.T) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
version, err := getMQVersion(t, cli)
|
version, err := cli.GetMQVersion(imageName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -287,26 +262,24 @@ func TestNativeHASecureCipherSpecNonFIPSCipher(t *testing.T) {
|
|||||||
|
|
||||||
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
qmReplicaIDs := [3]string{}
|
qmReplicaIDs := [3]string{}
|
||||||
qmNetwork, err := createBridgeNetwork(cli, t)
|
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
|
||||||
if err != nil {
|
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
|
||||||
t.Fatal(err)
|
basePort := 14551
|
||||||
}
|
|
||||||
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
|
||||||
|
|
||||||
for i := 0; i <= 2; i++ {
|
for i := 0; i <= 2; i++ {
|
||||||
|
nhaPort := basePort + i
|
||||||
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
// MQ_NATIVE_HA_CIPHERSPEC is set a FIPS non-compliant cipherspec - SSL_ECDHE_ECDSA_WITH_RC4_128_SHA
|
// MQ_NATIVE_HA_CIPHERSPEC is set a FIPS non-compliant cipherspec - SSL_ECDHE_ECDSA_WITH_RC4_128_SHA
|
||||||
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_RSA_WITH_AES_128_GCM_SHA256", "MQ_ENABLE_FIPS=true")
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=SSL_ECDHE_ECDSA_WITH_RC4_128_SHA", "MQ_ENABLE_FIPS=true")
|
||||||
hostConfig := getNativeHASecureHostConfig(t)
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
|
||||||
|
networkingConfig := getNativeHANetworkConfig("host")
|
||||||
ctr, err := runContainerWithAllConfigError(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
defer cleanContainer(t, cli, ctr)
|
defer cleanContainer(t, cli, ctr)
|
||||||
// We expect container to fail in this case because the cipher is non-FIPS and we have asked for FIPS compliance
|
// We expect container to fail in this case because the cipher is non-FIPS and we have asked for FIPS compliance
|
||||||
// by setting MQ_ENABLE_FIPS=true
|
// by setting MQ_ENABLE_FIPS=true
|
||||||
if err == nil {
|
|
||||||
t.Logf("Container start expected to fail but did not. %v", err)
|
|
||||||
}
|
|
||||||
qmReplicaIDs[i] = ctr
|
qmReplicaIDs[i] = ctr
|
||||||
}
|
}
|
||||||
|
for i := 0; i <= 2; i++ {
|
||||||
|
waitForTerminationMessage(t, cli, qmReplicaIDs[i], "/opt/mqm/bin/strmqm: exit status 23", 60*time.Second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2021
|
© Copyright IBM Corporation 2021, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -19,13 +19,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
"github.com/docker/docker/api/types/container"
|
|
||||||
"github.com/docker/docker/api/types/network"
|
|
||||||
"github.com/docker/docker/client"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultHAPort = 9414
|
const defaultHAPort = 9414
|
||||||
@@ -36,16 +34,8 @@ type HAReplicaStatus struct {
|
|||||||
Replica [2]string
|
Replica [2]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBridgeNetwork(cli *client.Client, t *testing.T) (types.NetworkCreateResponse, error) {
|
func getNativeHAContainerConfig(containerName string, replicaNames [3]string, haPort int) ce.ContainerConfig {
|
||||||
return cli.NetworkCreate(context.Background(), t.Name(), types.NetworkCreate{})
|
return ce.ContainerConfig{
|
||||||
}
|
|
||||||
|
|
||||||
func removeBridgeNetwork(cli *client.Client, networkID string) error {
|
|
||||||
return cli.NetworkRemove(context.Background(), networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNativeHAContainerConfig(containerName string, replicaNames [3]string, haPort int) container.Config {
|
|
||||||
return container.Config{
|
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"MQ_QMGR_NAME=QM1",
|
||||||
@@ -55,15 +45,18 @@ func getNativeHAContainerConfig(containerName string, replicaNames [3]string, ha
|
|||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_NAME=%s", replicaNames[0]),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_NAME=%s", replicaNames[0]),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_NAME=%s", replicaNames[1]),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_NAME=%s", replicaNames[1]),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_NAME=%s", replicaNames[2]),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_NAME=%s", replicaNames[2]),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_REPLICATION_ADDRESS=%s(%d)", replicaNames[0], haPort),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_REPLICATION_ADDRESS=%s(%d)", "127.0.0.1", haPort+0),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_REPLICATION_ADDRESS=%s(%d)", replicaNames[1], haPort),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_REPLICATION_ADDRESS=%s(%d)", "127.0.0.1", haPort+1),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_REPLICATION_ADDRESS=%s(%d)", replicaNames[2], haPort),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_REPLICATION_ADDRESS=%s(%d)", "127.0.0.1", haPort+2),
|
||||||
},
|
},
|
||||||
|
//When using the host for networking a consistent user was required. If a random user is used then the following example error was recorded.
|
||||||
|
//AMQ3209E: Native HA connection rejected due to configuration mismatch of 'QmgrUserId=5024'
|
||||||
|
User: "1111",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNativeHASecureHostConfig(t *testing.T) container.HostConfig {
|
func getNativeHASecureHostConfig(t *testing.T) ce.ContainerHostConfig {
|
||||||
return container.HostConfig{
|
return ce.ContainerHostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
filepath.Join(getCwd(t, true), "../tls") + ":/etc/mqm/ha/pki/keys/ha",
|
filepath.Join(getCwd(t, true), "../tls") + ":/etc/mqm/ha/pki/keys/ha",
|
||||||
@@ -71,15 +64,30 @@ func getNativeHASecureHostConfig(t *testing.T) container.HostConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNativeHANetworkConfig(networkID string) network.NetworkingConfig {
|
func getNativeHANetworkConfig(networkID string) ce.ContainerNetworkSettings {
|
||||||
return network.NetworkingConfig{
|
return ce.ContainerNetworkSettings{
|
||||||
EndpointsConfig: map[string]*network.EndpointSettings{
|
Networks: []string{networkID},
|
||||||
networkID: &network.EndpointSettings{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getActiveReplicaInstances(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) (HAReplicaStatus, error) {
|
// populatePortBindings writes port bindings to the host config
|
||||||
|
func populateNativeHAPortBindings(ports []int, nativeHaPort int, hostConfig ce.ContainerHostConfig) ce.ContainerHostConfig {
|
||||||
|
hostConfig.PortBindings = []ce.PortBinding{}
|
||||||
|
var binding ce.PortBinding
|
||||||
|
for i, p := range ports {
|
||||||
|
port := fmt.Sprintf("%v/tcp", p)
|
||||||
|
binding = ce.PortBinding{
|
||||||
|
ContainerPort: port,
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
//Offset the ports by 50 if there are multiple
|
||||||
|
HostPort: strconv.Itoa(nativeHaPort + 50*i),
|
||||||
|
}
|
||||||
|
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
||||||
|
}
|
||||||
|
return hostConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func getActiveReplicaInstances(t *testing.T, cli ce.ContainerInterface, qmReplicaIDs [3]string) (HAReplicaStatus, error) {
|
||||||
|
|
||||||
var actives []string
|
var actives []string
|
||||||
var replicas []string
|
var replicas []string
|
||||||
@@ -104,7 +112,7 @@ func getActiveReplicaInstances(t *testing.T, cli *client.Client, qmReplicaIDs [3
|
|||||||
return HAReplicaStatus{actives[0], [2]string{replicas[0], replicas[1]}}, nil
|
return HAReplicaStatus{actives[0], [2]string{replicas[0], replicas[1]}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForReadyHA(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) {
|
func waitForReadyHA(t *testing.T, cli ce.ContainerInterface, qmReplicaIDs [3]string) {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -129,7 +137,7 @@ func waitForReadyHA(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForFailoverHA(t *testing.T, cli *client.Client, replicas [2]string) {
|
func waitForFailoverHA(t *testing.T, cli ce.ContainerInterface, replicas [2]string) {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2022
|
© Copyright IBM Corporation 2018, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -22,20 +22,20 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/client"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGoldenPathMetric(t *testing.T) {
|
func TestGoldenPathMetric(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
|
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -55,14 +55,14 @@ func TestGoldenPathMetric(t *testing.T) {
|
|||||||
func TestMetricNames(t *testing.T) {
|
func TestMetricNames(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
|
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -99,14 +99,14 @@ func TestMetricNames(t *testing.T) {
|
|||||||
func TestMetricLabels(t *testing.T) {
|
func TestMetricLabels(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
cli := ce.NewContainerClient()
|
||||||
requiredLabels := []string{"qmgr"}
|
requiredLabels := []string{"qmgr"}
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -148,13 +148,13 @@ func TestMetricLabels(t *testing.T) {
|
|||||||
func TestRapidFirePrometheus(t *testing.T) {
|
func TestRapidFirePrometheus(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -182,13 +182,13 @@ func TestRapidFirePrometheus(t *testing.T) {
|
|||||||
func TestSlowPrometheus(t *testing.T) {
|
func TestSlowPrometheus(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -213,15 +213,14 @@ func TestSlowPrometheus(t *testing.T) {
|
|||||||
func TestContainerRestart(t *testing.T) {
|
func TestContainerRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -239,7 +238,10 @@ func TestContainerRestart(t *testing.T) {
|
|||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
// Start the container cleanly
|
// Start the container cleanly
|
||||||
startContainer(t, cli, id)
|
startContainer(t, cli, id)
|
||||||
port = getPort(t, cli, id, defaultMetricPort)
|
port, err = cli.GetContainerPort(id, defaultMetricPort)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -261,15 +263,14 @@ func TestContainerRestart(t *testing.T) {
|
|||||||
func TestQMRestart(t *testing.T) {
|
func TestQMRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
|
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -319,14 +320,14 @@ func TestQMRestart(t *testing.T) {
|
|||||||
func TestValidValues(t *testing.T) {
|
func TestValidValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
// hostname := getIPAddress(t, cli, id)
|
// hostname := getIPAddress(t, cli, id)
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -343,7 +344,7 @@ func TestValidValues(t *testing.T) {
|
|||||||
// Check that the values for each metric are valid numbers
|
// Check that the values for each metric are valid numbers
|
||||||
// can be either int, float or exponential - all these can be parsed by ParseFloat function
|
// can be either int, float or exponential - all these can be parsed by ParseFloat function
|
||||||
for _, e := range metrics {
|
for _, e := range metrics {
|
||||||
if _, err = strconv.ParseFloat(e.Value, 64); err != nil {
|
if _, err := strconv.ParseFloat(e.Value, 64); err != nil {
|
||||||
t.Errorf("Value (%s) for key (%s) is not a valid number", e.Value, e.Key)
|
t.Errorf("Value (%s) for key (%s) is not a valid number", e.Value, e.Key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,14 +356,14 @@ func TestValidValues(t *testing.T) {
|
|||||||
func TestChangingValues(t *testing.T) {
|
func TestChangingValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli := ce.NewContainerClient()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{1414, defaultMetricPort})
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{1414, defaultMetricPort})
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
// hostname := getIPAddress(t, cli, id)
|
// hostname := getIPAddress(t, cli, id)
|
||||||
port := getPort(t, cli, id, defaultMetricPort)
|
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -386,7 +387,11 @@ func TestChangingValues(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send invalid data to the MQ listener to generate a FDC
|
// Send invalid data to the MQ listener to generate a FDC
|
||||||
listener := fmt.Sprintf("localhost:%s", getPort(t, cli, id, 1414))
|
noport, err := cli.GetContainerPort(id, 1414)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
listener := fmt.Sprintf("localhost:%s", noport)
|
||||||
conn, err := net.Dial("tcp", listener)
|
conn, err := net.Dial("tcp", listener)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Could not connect to the listener - %v", err)
|
t.Fatalf("Could not connect to the listener - %v", err)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mqmetric struct {
|
type mqmetric struct {
|
||||||
@@ -146,8 +146,8 @@ func waitForMetricReady(t *testing.T, port string) {
|
|||||||
t.Fatalf("Metric endpoint failed to startup in timely manner")
|
t.Fatalf("Metric endpoint failed to startup in timely manner")
|
||||||
}
|
}
|
||||||
|
|
||||||
func metricsContainerConfig() *container.Config {
|
func metricsContainerConfig() *ce.ContainerConfig {
|
||||||
return &container.Config{
|
return &ce.ContainerConfig{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + defaultMetricQMName,
|
"MQ_QMGR_NAME=" + defaultMetricQMName,
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
module github.com/ibm-messaging/mq-container/test/docker
|
|
||||||
|
|
||||||
go 1.18
|
|
||||||
|
|
||||||
require (
|
|
||||||
// Note: This is not actually Docker v17.12!
|
|
||||||
// Go modules require the use of semver, but Docker does not use semver and has not
|
|
||||||
// [opted-in to use Go modules](https://github.com/golang/go/wiki/Modules#can-a-module-consume-a-package-that-has-not-opted-in-to-modules)
|
|
||||||
// This means that when you `go get` Docker, you need to do so based on a commit,
|
|
||||||
// e.g. `go get -v github.com/docker/docker@420b1d36250f9cfdc561f086f25a213ecb669b6f`,
|
|
||||||
// which uses the commit for [Docker v19.03.15](https://github.com/moby/moby/releases/tag/v19.03.15)
|
|
||||||
// Go will then find the latest tag with a semver-compatible tag. In Docker's case,
|
|
||||||
// v17.12.0 is valid semver, but v18.09 and v19.03 are not.
|
|
||||||
// Also note: Docker v20.10 is valid semver, but the v20.10 client API requires use of Docker API
|
|
||||||
// version 1.41 on the server, which is currently too new for the version of Docker in Travis (Ubuntu Bionic)
|
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible
|
|
||||||
github.com/docker/go-connections v0.4.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
|
||||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
|
||||||
github.com/containerd/containerd v1.6.6 // indirect
|
|
||||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
|
||||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
|
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
|
||||||
google.golang.org/grpc v1.46.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
|
||||||
gotest.tools v2.2.0+incompatible // indirect
|
|
||||||
)
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
|
||||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0=
|
|
||||||
github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
|
||||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible h1:nhVo1udYfMj0Jsw0lnqrTjjf33aLpdgW9Wve9fHVzhQ=
|
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
|
||||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
|
||||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
|
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
|
||||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
|
||||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
|
||||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
|
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
|
||||||
google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
|
|
||||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2022
|
© Copyright IBM Corporation 2018, 2023
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -51,6 +51,7 @@ class JMSTests {
|
|||||||
private static final Logger LOGGER = Logger.getLogger(JMSTests.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(JMSTests.class.getName());
|
||||||
protected static final String ADDR = System.getenv("MQ_PORT_1414_TCP_ADDR");
|
protected static final String ADDR = System.getenv("MQ_PORT_1414_TCP_ADDR");
|
||||||
protected static final String USER = System.getenv("MQ_USERNAME");
|
protected static final String USER = System.getenv("MQ_USERNAME");
|
||||||
|
protected static final String PORT = System.getenv().getOrDefault("MQ_PORT_1414_OVERRIDE", "1414");
|
||||||
protected static final String PASSWORD = System.getenv("MQ_PASSWORD");
|
protected static final String PASSWORD = System.getenv("MQ_PASSWORD");
|
||||||
protected static final String CHANNEL = System.getenv("MQ_CHANNEL");
|
protected static final String CHANNEL = System.getenv("MQ_CHANNEL");
|
||||||
protected static final String TRUSTSTORE = System.getenv("MQ_TLS_TRUSTSTORE");
|
protected static final String TRUSTSTORE = System.getenv("MQ_TLS_TRUSTSTORE");
|
||||||
@@ -67,11 +68,11 @@ class JMSTests {
|
|||||||
return ctx.getSocketFactory();
|
return ctx.getSocketFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
static MQConnectionFactory createMQConnectionFactory(String channel, String addr) throws JMSException, IOException, GeneralSecurityException {
|
static MQConnectionFactory createMQConnectionFactory(String channel, String addr, String port) throws JMSException, IOException, GeneralSecurityException {
|
||||||
MQConnectionFactory factory = new MQConnectionFactory();
|
MQConnectionFactory factory = new MQConnectionFactory();
|
||||||
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
|
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
|
||||||
factory.setChannel(channel);
|
factory.setChannel(channel);
|
||||||
factory.setConnectionNameList(String.format("%s(1414)", addr));
|
factory.setConnectionNameList(String.format("%s(%s)", addr, port));
|
||||||
if (TRUSTSTORE == null) {
|
if (TRUSTSTORE == null) {
|
||||||
LOGGER.info("Not using TLS");
|
LOGGER.info("Not using TLS");
|
||||||
}
|
}
|
||||||
@@ -83,7 +84,7 @@ class JMSTests {
|
|||||||
if (ibmjre){
|
if (ibmjre){
|
||||||
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
|
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
|
||||||
} else {
|
} else {
|
||||||
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
|
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
|
||||||
}
|
}
|
||||||
factory.setSSLCipherSuite(System.getenv("MQ_TLS_CIPHER"));
|
factory.setSSLCipherSuite(System.getenv("MQ_TLS_CIPHER"));
|
||||||
}
|
}
|
||||||
@@ -93,9 +94,9 @@ class JMSTests {
|
|||||||
/**
|
/**
|
||||||
* Create a JMSContext with the supplied user and password.
|
* Create a JMSContext with the supplied user and password.
|
||||||
*/
|
*/
|
||||||
static JMSContext create(String channel, String addr, String user, String password) throws JMSException, IOException, GeneralSecurityException {
|
static JMSContext create(String channel, String addr, String port, String user, String password) throws JMSException, IOException, GeneralSecurityException {
|
||||||
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as %s", channel, addr, user));
|
LOGGER.info(String.format("Connecting to %s/TCP/%s(%s) as %s", channel, addr, port, user));
|
||||||
MQConnectionFactory factory = createMQConnectionFactory(channel, addr);
|
MQConnectionFactory factory = createMQConnectionFactory(channel, addr, port);
|
||||||
// If a password is set, make sure it gets sent to the queue manager for authentication
|
// If a password is set, make sure it gets sent to the queue manager for authentication
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
factory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
|
factory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
|
||||||
@@ -107,9 +108,9 @@ class JMSTests {
|
|||||||
/**
|
/**
|
||||||
* Create a JMSContext with the default user identity (from the OS)
|
* Create a JMSContext with the default user identity (from the OS)
|
||||||
*/
|
*/
|
||||||
static JMSContext create(String channel, String addr) throws JMSException, IOException, GeneralSecurityException {
|
static JMSContext create(String channel, String addr, String port) throws JMSException, IOException, GeneralSecurityException {
|
||||||
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as OS user '%s'", channel, addr, System.getProperty("user.name")));
|
LOGGER.info(String.format("Connecting to %s/TCP/%s(%s) as OS user '%s'", channel, addr, port, System.getProperty("user.name")));
|
||||||
MQConnectionFactory factory = createMQConnectionFactory(channel, addr);
|
MQConnectionFactory factory = createMQConnectionFactory(channel, addr, port);
|
||||||
LOGGER.info(String.format("CSP authentication: %s", factory.getBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP)));
|
LOGGER.info(String.format("CSP authentication: %s", factory.getBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP)));
|
||||||
return factory.createContext();
|
return factory.createContext();
|
||||||
}
|
}
|
||||||
@@ -118,7 +119,7 @@ class JMSTests {
|
|||||||
private static void waitForQueueManager() {
|
private static void waitForQueueManager() {
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
try {
|
try {
|
||||||
Socket s = new Socket(ADDR, 1414);
|
Socket s = new Socket(ADDR, Integer.parseInt(PORT));
|
||||||
s.close();
|
s.close();
|
||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -132,7 +133,7 @@ class JMSTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void putGetTest(TestInfo t) throws Exception {
|
void putGetTest(TestInfo t) throws Exception {
|
||||||
context = create(CHANNEL, ADDR, USER, PASSWORD);
|
context = create(CHANNEL, ADDR, PORT, USER, PASSWORD);
|
||||||
Queue queue = new MQQueue("DEV.QUEUE.1");
|
Queue queue = new MQQueue("DEV.QUEUE.1");
|
||||||
context.createProducer().send(queue, t.getDisplayName());
|
context.createProducer().send(queue, t.getDisplayName());
|
||||||
Message m = context.createConsumer(queue).receive();
|
Message m = context.createConsumer(queue).receive();
|
||||||
@@ -144,7 +145,7 @@ class JMSTests {
|
|||||||
LOGGER.info(String.format("Password='%s'", PASSWORD));
|
LOGGER.info(String.format("Password='%s'", PASSWORD));
|
||||||
try {
|
try {
|
||||||
// Don't pass a user/password, which should cause the default identity to be used
|
// Don't pass a user/password, which should cause the default identity to be used
|
||||||
context = create(CHANNEL, ADDR);
|
context = create(CHANNEL, ADDR, PORT);
|
||||||
} catch (DetailedJMSSecurityRuntimeException ex) {
|
} catch (DetailedJMSSecurityRuntimeException ex) {
|
||||||
Throwable cause = ex.getCause();
|
Throwable cause = ex.getCause();
|
||||||
assertNotNull(cause);
|
assertNotNull(cause);
|
||||||
|
|||||||
Reference in New Issue
Block a user