Compare commits

..

9 Commits

Author SHA1 Message Date
Alex Mirski-Fitton
d7c7b52492 Merge pull request #485 from mirskifa/v9.2.4
V9.2.4
2021-12-06 16:22:21 +00:00
Alex Mirski-Fitton
60ad8f01da Merge branch 'master' into v9.2.4 2021-12-06 16:17:13 +00:00
Alex Mirski-Fitton
e9982081e9 [ci skip]: Setting up v9.2.4 branch 2021-11-29 14:32:21 +00:00
David
7fbb8ff076 Merge pull request #464 from david-r-bell/v9.2.3
V9.2.3
2021-07-22 13:50:03 +01:00
David Bell
cc956b29f4 Merge branch 'ibm-messaging-master' into v9.2.3 2021-07-22 12:18:26 +01:00
David Bell
786e26bccc fix merge conflict 2021-07-22 12:16:39 +01:00
David Bell
b074eed754 [ci skip]: Setting up v9.2.3 branch 2021-07-12 15:40:16 +01:00
LPowlett
4580cecf49 Updated README copyright date 2021-03-24 13:59:10 +00:00
Amrit Kandola
684106452b [ci skip]: Setting up v9.2.2 branch 2021-03-17 13:48:20 +00:00
808 changed files with 49775 additions and 102225 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
downloads
.git

9
.gitignore vendored
View File

@@ -1,4 +1,3 @@
.dockerignore
.DS_Store
.vscode
test/docker/coverage
@@ -6,7 +5,7 @@ test/docker/vendor
test/kubernetes/vendor
build
coverage
#downloads
downloads
incubating/mqipt/ms81*
vendor/github.com/prometheus/client_model/bin/
vendor/github.com/prometheus/client_model/.classpath
@@ -15,9 +14,3 @@ vendor/github.com/prometheus/client_model/.settings*
gosec_results.json
internal/qmgrauth/qmgroam/patch
.tagcache
# Nix
*.nix
.envrc
.direnv
result

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2023
# © Copyright IBM Corporation 2018, 2020
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,16 +18,18 @@ sudo: required
language: go
go:
- "1.19.9"
- "1.16.7"
services:
- docker
env:
global:
- MAIN_BRANCH=private-master
- MAIN_BRANCH=v9.2.4
- MQ_LTS_VERSION=9.2.0.2
- TAGCACHE_FILE=tagcache
- RELEASE=r1
- RELEASE_LTS=r2
go_import_path: "github.com/ibm-messaging/mq-container"
@@ -38,56 +40,101 @@ go_import_path: "github.com/ibm-messaging/mq-container"
jobs:
include:
- stage: basic-build
if: branch != private-master AND tag IS blank
if: branch != v9.2.4 AND tag IS blank
name: "Basic AMD64 build"
os: linux
env:
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_924_ARCHIVE_REPOSITORY_DEV_AMD64
script: bash -e travis-build-scripts/run.sh
# CD Build
- stage: global-tag
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
if: branch = v9.2.4 AND type != pull_request OR tag =~ ^release-candidate*
name: "Generate Global Tag"
os: linux
script: bash -e travis-build-scripts/global-tag.sh
- stage: build
if: branch = private-master OR tag =~ ^release-candidate*
if: branch = v9.2.4 OR tag =~ ^release-candidate*
name: "Multi-Arch AMD64 build"
os: linux
env:
- BUILD_ALL=true
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_AMD64
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
- MQ_ARCHIVE_REPOSITORY=$MQ_924_ARCHIVE_REPOSITORY_AMD64
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_924_ARCHIVE_REPOSITORY_DEV_AMD64
script: bash -e travis-build-scripts/run.sh
# - if: branch = v9.2.4 OR tag =~ ^release-candidate*
# name: "Multi-Arch PPC64LE build"
# os: linux-ppc64le
# env:
# - BUILD_ALL=true
# - TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
# # - MQ_ARCHIVE_REPOSITORY=$MQ_924_ARCHIVE_REPOSITORY_PPC64LE
# - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_924_ARCHIVE_REPOSITORY_DEV_PPC64LE
# script: bash -e travis-build-scripts/run.sh
- stage: build
if: branch = private-master OR tag =~ ^release-candidate*
if: branch = v9.2.4 OR tag =~ ^release-candidate*
name: "Multi-Arch S390X build"
os: linux-s390
env:
- BUILD_ALL=true
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_S390X
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_S390X
script: bash -e travis-build-scripts/run.sh
- stage: build
if: branch = private-master OR tag =~ ^release-candidate*
name: "Multi-Arch PPC64LE build"
os: linux-ppc64le
env:
- BUILD_ALL=true
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_PPC64LE
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_PPC64LE
- MQ_ARCHIVE_REPOSITORY=$MQ_924_ARCHIVE_REPOSITORY_S390X
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_924_ARCHIVE_REPOSITORY_DEV_S390X
script: bash -e travis-build-scripts/run.sh
- stage: push-manifest
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
if: branch = v9.2.4 AND type != pull_request OR tag =~ ^release-candidate*
name: "Push Manifest-list to registry"
env:
- PUSH_MANIFEST_ONLY=true
script: bash -e travis-build-scripts/run.sh
# LTS Build
- stage: global-tag
if: branch = v9.2.4 AND type != pull_request OR tag =~ ^release-candidate*
name: "Generate Global Tag"
os: linux
env:
- LTS=true
- TAGCACHE_FILE=tagcache-lts
- MQ_VERSION=$MQ_LTS_VERSION
- RELEASE=$RELEASE_LTS
script: bash -e travis-build-scripts/global-tag.sh
- stage: build
if: branch = v9.2.4 OR tag =~ ^release-candidate*
name: "Multi-Arch AMD64 build"
os: linux
env:
- LTS=true
- TAGCACHE_FILE=tagcache-lts
- MQ_VERSION=$MQ_LTS_VERSION
- MQ_ARCHIVE_REPOSITORY=$MQ_9201_EUS_ARCHIVE_REPOSITORY_AMD64
- RELEASE=$RELEASE_LTS
script: bash -e travis-build-scripts/run.sh
- stage: build
if: branch = v9.2.4 OR tag =~ ^release-candidate*
name: "Multi-Arch S390X build"
os: linux-s390
env:
- LTS=true
- TAGCACHE_FILE=tagcache-lts
- MQ_VERSION=$MQ_LTS_VERSION
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
- MQ_ARCHIVE_REPOSITORY=$MQ_9201_EUS_ARCHIVE_REPOSITORY_S390X
- RELEASE=$RELEASE_LTS
script: bash -e travis-build-scripts/run.sh
- stage: push-manifest
if: branch = v9.2.4 AND type != pull_request OR tag =~ ^release-candidate*
name: "Push Manifest-list to registry"
env:
- LTS=true
- TAGCACHE_FILE=tagcache-lts
- MQ_VERSION=$MQ_LTS_VERSION
- PUSH_MANIFEST_ONLY=true
- RELEASE=$RELEASE_LTS
script: bash -e travis-build-scripts/run.sh
before_install:
- make install-build-deps
- make install-credential-helper

View File

@@ -1,10 +1,6 @@
{
"settingsInheritedFrom": "whitesource-config/whitesource-config@master",
"scanSettings": {
"configMode": "LOCAL",
"baseBranches": ["private-master", "v9.2.0.x-eus", "v9.3.0.x"]
},
"issueSettings": {
"issueRepoName": "whitesource-scan-issues"
}
"baseBranches": ["private-master", "v9.2.0.x-eus"]
}
}

39
CBO.md
View File

@@ -1,39 +0,0 @@
# MQ in Docker
## Download new version
Download IBM MQ Advanced for Developers here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/
Place the file in the downloads folder of this repo.
```bash
mkdir -p downloads
wget -P downloads https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/9.3.3.1-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz
wget -P downloads https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/9.3.3.1-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxARM64.tar.gz
```
# Build Docker image
Update ```MQ_ARCHIVE``` with the new filename in the two Dockerfiles
```bash
nano Dockerfile-server-arm
nano Dockerfile-server-x64
```
Build the new images
```bash
docker buildx build -t <tag> -f <dockerfile> .
# Build for various architechtures
docker buildx build --platform linux/amd64 -t git.cbo.dk/academy/mq:9.3.3.1-amd64 -f Dockerfile-server-x64 .
docker buildx build --platform linux/arm64 -t git.cbo.dk/academy/mq:9.3.3.1-arm64 -f Dockerfile-server-arm .
docker image tag git.cbo.dk/academy/mq:9.3.3.1-amd64 git.cbo.dk/academy/mq:latest
# Push to registry (Optional)
docker login git.cbo.dk
docker push --all-tags git.cbo.dk/academy/mq
```
# Deploy MQ
```bash
docker stop ibmmq
docker rm ibmmq
docker run --name "ibmmq" -d -p 1414:1414 -p 9157:9157 -p 9443:9443 -e LICENSE=accept -e MQ_ADMIN_PASSWORD=passw0rd -e MQ_QMGR_NAME=MQDOCKER -e MQ_ENABLE_METRICS=true --name ibmmq git.cbo.dk/academy/mq:latest
```

View File

@@ -1,39 +1,6 @@
# Change log
## 9.3.3.0 (2023-06)
* Updated to MQ version 9.3.3.0
## 9.3.2.0 (2023-02)
* Updated to MQ version 9.3.2.0
* Queue manager certificates with the same Subject Distinguished Name (DN) as the issuer (CA) certificate are not supported. A certificate must have a unique Subject Distinguished Name.
* New logging environment variables: MQ_LOGGING_CONSOLE_SOURCE, MQ_LOGGING_CONSOLE_FORMAT, MQ_LOGGING_CONSOLE_EXCLUDE_ID. The LOG_FORMAT variable is deprecated.
* New environment variable: MQ_QMGR_LOG_FILE_PAGES
## 9.3.1.0-r2 (2022-11)
* Queue manager attribute SSLKEYR is now set to blank instead of '/run/runmqserver/tls/key' if key and certificate are not supplied.
## 9.3.1.0 (2022-10)
* Updated to MQ version 9.3.1.0
## 9.3.0.0 (2022-06)
* Updated to MQ version 9.3.0.0
* Use `registry.access.redhat.com` instead of `registry.redhat.io`, so that you don't need to login with a Red Hat account.
* Updated default developer config to use TLS cipher `ANY_TLS12_OR_HIGHER` instead of `ANY_TLS12`
* Added default `jvm.options` file fix issue with missing preferences file causing an error in the web server log.
* Updated to allow building image from Podman on macOS (requires Podman 4.1)
* Container builds are now faster
* Updated signal handling to use a buffer, as recommended by the Go 1.17 vetting tool
## 9.2.5.0 (2022-03)
* Updated to MQ version 9.2.5.0
## 9.2.4.0 (2021-11)
## 9.2.4.0 (2021-09-06)
* Updated to MQ version 9.2.4.0

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2023
# © Copyright IBM Corporation 2015, 2021
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,118 +12,88 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Download IBM MQ Advanced for Developers here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/
# mkdir downloads
# Kopier 9.3.3.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz ind i downloads.
# Opdater .dockerignore
# docker build -t mqserver -f Dockerfile-server-x64 .
# docker run -d -p 1414:1414 -p 9157:9157 -p 9443:9443 -e LICENSE=accept --name mqserver mqserver
ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal
ARG BASE_TAG=8.10-896.1716497715
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
ARG BUILDER_TAG=1.21.9-3.1716505664
ARG BASE_IMAGE=registry.redhat.io/ubi8/ubi-minimal
ARG BASE_TAG=8.5-204
ARG BUILDER_IMAGE=registry.redhat.io/ubi8/go-toolset
ARG BUILDER_TAG=1.16.7-5
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
ARG MQ_ARCHIVE="downloads/9.3.3.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/9.2.4.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
###############################################################################
# Build stage to build Go code
###############################################################################
FROM $BUILDER_IMAGE:$BUILDER_TAG as builder
# The URL to download the MQ installer from in tar.gz format
# This assumes an archive containing the MQ Non-Install packages
ARG MQ_URL
ARG IMAGE_REVISION="Not specified"
ARG IMAGE_SOURCE="Not specified"
ARG IMAGE_TAG="Not specified"
ARG GO_WORKDIR
ARG MQ_ARCHIVE
USER 0
COPY install-mq.sh /usr/local/bin/
RUN mkdir /opt/mqm \
&& chmod a+x /usr/local/bin/install-mq.sh \
&& sleep 1 \
&& INSTALL_SDK=1 install-mq.sh \
&& chown -R 1001:root /opt/mqm/*
WORKDIR $GO_WORKDIR/
ADD $MQ_ARCHIVE /opt/mqm
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
PATH="${PATH}:/opt/mqm/bin"
COPY go.mod go.sum ./
COPY cmd/ ./cmd
COPY internal/ ./internal
COPY pkg/ ./pkg
COPY vendor/ ./vendor
RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\" -X \"main.ImageTag=$IMAGE_TAG\"" ./cmd/runmqserver/ \
&& go build ./cmd/chkmqready/ \
&& go build ./cmd/chkmqhealthy/ \
&& go build ./cmd/chkmqstarted/ \
&& go build ./cmd/runmqdevserver/ \
&& go test -v ./cmd/runmqdevserver/... \
&& go test -v ./cmd/runmqserver/ \
&& go test -v ./cmd/chkmqready/ \
&& go test -v ./cmd/chkmqhealthy/ \
&& go test -v ./cmd/chkmqstarted/ \
&& go test -v ./pkg/... \
&& go test -v ./internal/... \
&& go vet ./cmd/... ./internal/...
###############################################################################
# Build stage to reduce MQ packages included using genmqpkg
###############################################################################
FROM $BASE_IMAGE:$BASE_TAG AS mq-redux
ARG BASE_IMAGE
ARG BASE_TAG
ARG MQ_ARCHIVE
WORKDIR /tmp/mq
ENV genmqpkg_inc32=0 \
genmqpkg_incadm=1 \
genmqpkg_incamqp=0 \
genmqpkg_incams=1 \
genmqpkg_inccbl=0 \
genmqpkg_inccics=0 \
genmqpkg_inccpp=0 \
genmqpkg_incdnet=0 \
genmqpkg_incjava=1 \
genmqpkg_incjre=1 \
genmqpkg_incman=0 \
genmqpkg_incmqbc=0 \
genmqpkg_incmqft=0 \
genmqpkg_incmqsf=0 \
genmqpkg_incmqxr=0 \
genmqpkg_incnls=1 \
genmqpkg_incras=1 \
genmqpkg_incsamp=1 \
genmqpkg_incsdk=0 \
genmqpkg_inctls=1 \
genmqpkg_incunthrd=0 \
genmqpkg_incweb=1
ADD $MQ_ARCHIVE /opt/mqm-noinstall
# Run genmqpkg to reduce the MQ packages included
RUN /opt/mqm-noinstall/bin/genmqpkg.sh -b /opt/mqm-redux
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*"
ENV PATH="${PATH}:/opt/mqm/bin"
RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\" -X \"main.ImageTag=$IMAGE_TAG\"" ./cmd/runmqserver/
RUN go build ./cmd/chkmqready/
RUN go build ./cmd/chkmqhealthy/
RUN go build ./cmd/chkmqstarted/
RUN go build ./cmd/runmqdevserver/
RUN go test -v ./cmd/runmqdevserver/...
RUN go test -v ./cmd/runmqserver/
RUN go test -v ./cmd/chkmqready/
RUN go test -v ./cmd/chkmqhealthy/
RUN go test -v ./cmd/chkmqstarted/
RUN go test -v ./pkg/...
RUN go test -v ./internal/...
RUN go vet ./cmd/... ./internal/...
###############################################################################
# Main build stage, to build MQ image
###############################################################################
FROM $BASE_IMAGE:$BASE_TAG AS mq-server
# The MQ packages to install - see install-mq.sh for default value
ARG MQ_URL
ARG BASE_IMAGE
ARG BASE_TAG
ARG GO_WORKDIR
LABEL summary="IBM MQ Advanced Server" \
description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
vendor="IBM" \
maintainer="IBM" \
distribution-scope="private" \
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
url="https://www.ibm.com/products/mq/advanced" \
io.openshift.tags="mq messaging" \
io.k8s.display-name="IBM MQ Advanced Server" \
io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
base-image=$BASE_IMAGE \
base-image-release=$BASE_TAG
COPY --from=mq-redux /opt/mqm-redux/ /opt/mqm/
COPY setup-image.sh /usr/local/bin/
LABEL summary="IBM MQ Advanced Server"
LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL vendor="IBM"
LABEL maintainer="IBM"
LABEL distribution-scope="private"
LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/"
LABEL url="https://www.ibm.com/products/mq/advanced"
LABEL io.openshift.tags="mq messaging"
LABEL io.k8s.display-name="IBM MQ Advanced Server"
LABEL io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL base-image=$BASE_IMAGE
LABEL base-image-release=$BASE_TAG
COPY install-mq.sh /usr/local/bin/
COPY install-mq-server-prereqs.sh /usr/local/bin/
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
RUN env \
&& mkdir /opt/mqm \
&& chmod u+x /usr/local/bin/install-*.sh \
&& chmod u+x /usr/local/bin/setup-image.sh \
&& sleep 1 \
&& install-mq-server-prereqs.sh \
&& setup-image.sh \
&& install-mq.sh \
&& /opt/mqm/bin/security/amqpamcf \
&& chown -R 1001:root /opt/mqm/*
# Create a directory for runtime data from runmqserver
RUN mkdir -p /run/runmqserver \
&& chown 1001:root /run/runmqserver
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/
COPY --from=builder $GO_WORKDIR/chkmq* /usr/local/bin/
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
@@ -144,9 +114,7 @@ RUN chmod ug+x /usr/local/bin/runmqserver \
EXPOSE 1414 9157 9443
ENV MQ_OVERRIDE_DATA_PATH=/mnt/mqm/data MQ_OVERRIDE_INSTALLATION_NAME=Installation1 MQ_USER_NAME="mqm" PATH="${PATH}:/opt/mqm/bin"
ENV MQ_GRACE_PERIOD=30
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1
ENV MQ_LOGGING_CONSOLE_EXCLUDE_ID=AMQ5041I,AMQ5052I,AMQ5051I,AMQ5037I,AMQ5975I
ENV WLP_LOGGING_MESSAGE_FORMAT=json
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic
# We can run as any UID
USER 1001
ENV MQ_CONNAUTH_USE_HTP=false
@@ -155,11 +123,20 @@ ENTRYPOINT ["runmqserver"]
###############################################################################
# Build stage to build C code for custom authorization service (developer-only)
###############################################################################
# Use the Go toolset image, which already includes gcc and the MQ SDK
FROM builder as cbuilder
FROM registry.redhat.io/rhel8/gcc-toolset-9-toolchain as cbuilder
# The URL to download the MQ installer from in tar.gz format
# This assumes an archive containing the MQ Non-Install packages
ARG MQ_URL
USER 0
# Install the Apache Portable Runtime code (used for htpasswd hash checking)
RUN yum --assumeyes --disableplugin=subscription-manager install apr-devel apr-util-openssl apr-util-devel
RUN yum -y install apr-devel apr-util-openssl apr-util-devel
# Install MQ client
COPY install-mq.sh /usr/local/bin/
RUN mkdir /opt/mqm \
&& chmod a+x /usr/local/bin/install-mq.sh \
&& sleep 1 \
&& INSTALL_SDK=1 install-mq.sh \
&& chown -R 1001:root /opt/mqm/*
COPY authservice/ /opt/app-root/src/authservice/
WORKDIR /opt/app-root/src/authservice/mqhtpass
RUN make all
@@ -171,25 +148,31 @@ FROM mq-server AS mq-dev-server
ARG BASE_IMAGE
ARG BASE_TAG
ARG GO_WORKDIR
LABEL summary="IBM MQ Advanced for Developers Server" \
description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
vendor="IBM" \
distribution-scope="private" \
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
url="https://www.ibm.com/products/mq/advanced" \
io.openshift.tags="mq messaging" \
io.k8s.display-name="IBM MQ Advanced for Developers Server" \
io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
base-image=$BASE_IMAGE \
base-image-release=$BASE_TAG
# Enable MQ developer default configuration
ENV MQ_DEV=true
LABEL summary="IBM MQ Advanced for Developers Server"
LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL vendor="IBM"
LABEL distribution-scope="private"
LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/"
LABEL url="https://www.ibm.com/products/mq/advanced"
LABEL io.openshift.tags="mq messaging"
LABEL io.k8s.display-name="IBM MQ Advanced for Developers Server"
LABEL io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL base-image=$BASE_IMAGE
LABEL base-image-release=$BASE_TAG
USER 0
COPY --from=cbuilder /opt/app-root/src/authservice/mqhtpass/build/mqhtpass.so /opt/mqm/lib64/
COPY etc/mqm/*.ini /etc/mqm/
COPY etc/mqm/mq.htpasswd /etc/mqm/
RUN chmod 0660 /etc/mqm/mq.htpasswd
COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/install-extra-packages.sh \
&& sleep 1 \
&& install-extra-packages.sh
# Create a directory for runtime data from runmqserver
RUN mkdir -p /run/runmqdevserver \
&& chown 1001:root /run/runmqdevserver
COPY --from=builder $GO_WORKDIR/runmqdevserver /usr/local/bin/
# Copy template files
COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/
@@ -198,13 +181,10 @@ COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
RUN chown -R 1001:root /etc/mqm/* \
&& chmod -R g+w /etc/mqm/web \
&& chmod +x /usr/local/bin/runmq* \
&& chmod 0660 /etc/mqm/mq.htpasswd \
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqdevserver
ENV MQ_DEV=true \
MQ_ENABLE_EMBEDDED_WEB_SERVER=1 \
MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost \
LD_LIBRARY_PATH=/opt/mqm/lib64 \
MQ_CONNAUTH_USE_HTP=true \
MQS_PERMIT_UNKNOWN_ID=true
ENV MQ_ENABLE_EMBEDDED_WEB_SERVER=1 MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost
ENV LD_LIBRARY_PATH=/opt/mqm/lib64
ENV MQ_CONNAUTH_USE_HTP=true
ENV MQS_PERMIT_UNKNOWN_ID=true
USER 1001
ENTRYPOINT ["runmqdevserver"]

View File

@@ -1,210 +0,0 @@
# © Copyright IBM Corporation 2015, 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.
# Download IBM MQ Advanced for Developers here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/
# mkdir downloads
# Kopier 9.3.3.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxARM64.tar.gz ind i downloads.
# Opdater .dockerignore
# docker build -t mqserver -f Dockerfile-server-arm .
# docker run -d -p 1414:1414 -p 9157:9157 -p 9443:9443 -e LICENSE=accept --name mqserver mqserver
ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal
ARG BASE_TAG=8.10-896.1716497715
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
ARG BUILDER_TAG=1.21.9-3.1716505664
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
ARG MQ_ARCHIVE="downloads/9.3.3.1-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxARM64.tar.gz"
###############################################################################
# Build stage to build Go code
###############################################################################
FROM $BUILDER_IMAGE:$BUILDER_TAG as builder
ARG IMAGE_REVISION="Not specified"
ARG IMAGE_SOURCE="Not specified"
ARG IMAGE_TAG="Not specified"
ARG GO_WORKDIR
ARG MQ_ARCHIVE
USER 0
WORKDIR $GO_WORKDIR/
ADD $MQ_ARCHIVE /opt/mqm
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
PATH="${PATH}:/opt/mqm/bin"
COPY go.mod go.sum ./
COPY cmd/ ./cmd
COPY internal/ ./internal
COPY pkg/ ./pkg
COPY vendor/ ./vendor
RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\" -X \"main.ImageTag=$IMAGE_TAG\"" ./cmd/runmqserver/ \
&& go build ./cmd/chkmqready/ \
&& go build ./cmd/chkmqhealthy/ \
&& go build ./cmd/chkmqstarted/ \
&& go build ./cmd/runmqdevserver/ \
&& go test -v ./cmd/runmqdevserver/... \
&& go test -v ./cmd/runmqserver/ \
&& go test -v ./cmd/chkmqready/ \
&& go test -v ./cmd/chkmqhealthy/ \
&& go test -v ./cmd/chkmqstarted/ \
&& go test -v ./pkg/... \
&& go test -v ./internal/... \
&& go vet ./cmd/... ./internal/...
###############################################################################
# Build stage to reduce MQ packages included using genmqpkg
###############################################################################
FROM $BASE_IMAGE:$BASE_TAG AS mq-redux
ARG BASE_IMAGE
ARG BASE_TAG
ARG MQ_ARCHIVE
WORKDIR /tmp/mq
ENV genmqpkg_inc32=0 \
genmqpkg_incadm=1 \
genmqpkg_incamqp=0 \
genmqpkg_incams=1 \
genmqpkg_inccbl=0 \
genmqpkg_inccics=0 \
genmqpkg_inccpp=0 \
genmqpkg_incdnet=0 \
genmqpkg_incjava=1 \
genmqpkg_incjre=1 \
genmqpkg_incman=0 \
genmqpkg_incmqbc=0 \
genmqpkg_incmqft=0 \
genmqpkg_incmqsf=0 \
genmqpkg_incmqxr=0 \
genmqpkg_incnls=1 \
genmqpkg_incras=1 \
genmqpkg_incsamp=1 \
genmqpkg_incsdk=0 \
genmqpkg_inctls=1 \
genmqpkg_incunthrd=0 \
genmqpkg_incweb=1
ADD $MQ_ARCHIVE /opt/mqm-noinstall
# Run genmqpkg to reduce the MQ packages included
RUN /opt/mqm-noinstall/bin/genmqpkg.sh -b /opt/mqm-redux
###############################################################################
# Main build stage, to build MQ image
###############################################################################
FROM $BASE_IMAGE:$BASE_TAG AS mq-server
ARG MQ_URL
ARG BASE_IMAGE
ARG BASE_TAG
ARG GO_WORKDIR
LABEL summary="IBM MQ Advanced Server" \
description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
vendor="IBM" \
maintainer="IBM" \
distribution-scope="private" \
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
url="https://www.ibm.com/products/mq/advanced" \
io.openshift.tags="mq messaging" \
io.k8s.display-name="IBM MQ Advanced Server" \
io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
base-image=$BASE_IMAGE \
base-image-release=$BASE_TAG
COPY --from=mq-redux /opt/mqm-redux/ /opt/mqm/
COPY setup-image.sh /usr/local/bin/
COPY install-mq-server-prereqs.sh /usr/local/bin/
RUN env \
&& chmod u+x /usr/local/bin/install-*.sh \
&& chmod u+x /usr/local/bin/setup-image.sh \
&& install-mq-server-prereqs.sh \
&& setup-image.sh \
&& /opt/mqm/bin/security/amqpamcf \
&& chown -R 1001:root /opt/mqm/*
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/
COPY --from=builder $GO_WORKDIR/chkmq* /usr/local/bin/
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
COPY ha/native-ha.ini.tpl /etc/mqm/native-ha.ini.tpl
# Copy web XML files
COPY web /etc/mqm/web
COPY etc/mqm/*.tpl /etc/mqm/
RUN chmod ug+x /usr/local/bin/runmqserver \
&& chown 1001:root /usr/local/bin/*mq* \
&& chmod ug+x /usr/local/bin/chkmq* \
&& chown -R 1001:root /etc/mqm/* \
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqserver \
&& touch /run/termination-log \
&& chown 1001:root /run/termination-log \
&& chmod 0660 /run/termination-log \
&& chmod -R g+w /etc/mqm/web
# Always use port 1414 for MQ & 9157 for the metrics
EXPOSE 1414 9157 9443
ENV MQ_OVERRIDE_DATA_PATH=/mnt/mqm/data MQ_OVERRIDE_INSTALLATION_NAME=Installation1 MQ_USER_NAME="mqm" PATH="${PATH}:/opt/mqm/bin"
ENV MQ_GRACE_PERIOD=30
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1
ENV MQ_LOGGING_CONSOLE_EXCLUDE_ID=AMQ5041I,AMQ5052I,AMQ5051I,AMQ5037I,AMQ5975I
ENV WLP_LOGGING_MESSAGE_FORMAT=json
# We can run as any UID
USER 1001
ENV MQ_CONNAUTH_USE_HTP=false
ENTRYPOINT ["runmqserver"]
###############################################################################
# Build stage to build C code for custom authorization service (developer-only)
###############################################################################
# Use the Go toolset image, which already includes gcc and the MQ SDK
FROM builder as cbuilder
USER 0
# Install the Apache Portable Runtime code (used for htpasswd hash checking)
RUN yum --assumeyes --disableplugin=subscription-manager install apr-devel apr-util-openssl apr-util-devel
COPY authservice/ /opt/app-root/src/authservice/
WORKDIR /opt/app-root/src/authservice/mqhtpass
RUN make all
###############################################################################
# Add default developer config
###############################################################################
FROM mq-server AS mq-dev-server
ARG BASE_IMAGE
ARG BASE_TAG
ARG GO_WORKDIR
LABEL summary="IBM MQ Advanced for Developers Server" \
description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
vendor="IBM" \
distribution-scope="private" \
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
url="https://www.ibm.com/products/mq/advanced" \
io.openshift.tags="mq messaging" \
io.k8s.display-name="IBM MQ Advanced for Developers Server" \
io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" \
base-image=$BASE_IMAGE \
base-image-release=$BASE_TAG
USER 0
COPY --from=cbuilder /opt/app-root/src/authservice/mqhtpass/build/mqhtpass.so /opt/mqm/lib64/
COPY etc/mqm/*.ini /etc/mqm/
COPY etc/mqm/mq.htpasswd /etc/mqm/
COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/install-extra-packages.sh \
&& sleep 1 \
&& install-extra-packages.sh
COPY --from=builder $GO_WORKDIR/runmqdevserver /usr/local/bin/
# Copy template files
COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/
# Copy web XML files for default developer configuration
COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
RUN chown -R 1001:root /etc/mqm/* \
&& chmod -R g+w /etc/mqm/web \
&& chmod +x /usr/local/bin/runmq* \
&& chmod 0660 /etc/mqm/mq.htpasswd \
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqdevserver
ENV MQ_DEV=true \
MQ_ENABLE_EMBEDDED_WEB_SERVER=1 \
MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost \
LD_LIBRARY_PATH=/opt/mqm/lib64 \
MQ_CONNAUTH_USE_HTP=true \
MQS_PERMIT_UNKNOWN_ID=true
USER 1001
ENTRYPOINT ["runmqdevserver"]

View File

@@ -15,7 +15,7 @@
ARG BASE_IMAGE
# Build stage to build Go code
FROM golang:1.22 as builder
FROM golang:1.10 as builder
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
COPY cmd/ ./cmd
COPY internal/ ./internal

275
Makefile
View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2017, 2023
# © Copyright IBM Corporation 2017, 2021
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,15 +18,7 @@
###############################################################################
include config.env
include source-branch.env
# arch_uname is the platform architecture according to the uname program. Can be differ by OS, e.g. `arm64` on macOS, but `aarch64` on Linux.
arch_uname := $(shell uname -m)
# arch_go is the platform architecture in Go-style (e.g. amd64, ppc64le, s390x or arm64).
arch_go := $(if $(findstring x86_64,$(arch_uname)),amd64,$(if $(findstring aarch64,$(arch_uname)),arm64,$(arch_uname)))
# ARCH is the platform architecture in Go-style (e.g. amd64, ppc64le, s390x or arm64).
# Override this to build an image for a different architecture. Note that RUN instructions will not be able to succeed without the help of emulation provided by packages like qemu-user-static.
ARCH ?= $(arch_go)
# RELEASE shows what release of the container code has been built
RELEASE ?=
# MQ_ARCHIVE_REPOSITORY is a remote repository from which to pull the MQ_ARCHIVE (if required)
@@ -45,10 +37,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_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))
# Options to `go test` for the Container tests
TEST_OPTS_CONTAINER ?=
# Timeout for the tests
TEST_TIMEOUT_CONTAINER ?= 45m
# Options to `go test` for the Docker tests
TEST_OPTS_DOCKER ?=
# Timeout for the Docker tests
TEST_TIMEOUT_DOCKER ?= 30m
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
@@ -67,26 +59,28 @@ MQ_DELIVERY_REGISTRY_NAMESPACE ?=
MQ_DELIVERY_REGISTRY_USER ?=
# MQ_DELIVERY_REGISTRY_CREDENTIAL is the password/API key for the remote registry (if required)
MQ_DELIVERY_REGISTRY_CREDENTIAL ?=
# REGISTRY_USER is the username used to login to the Red Hat registry
REGISTRY_USER ?=
# REGISTRY_PASS is the password used to login to the Red Hat registry
REGISTRY_PASS ?=
# ARCH is the platform architecture (e.g. amd64, ppc64le or s390x)
ARCH ?= $(if $(findstring x86_64,$(shell uname -m)),amd64,$(shell uname -m))
# LTS is a boolean value to enable/disable LTS container build
LTS ?= false
# VOLUME_MOUNT_OPTIONS is used when bind-mounting files from the "downloads" directory into the container. By default, SELinux labels are automatically re-written, but this doesn't work on some filesystems with extended attributes (xattrs). You can turn off the label re-writing by setting this variable to be blank.
VOLUME_MOUNT_OPTIONS ?= :Z
###############################################################################
# Other variables
###############################################################################
# Lock Docker API version for compatibility with Podman and with the Docker version in Travis' Ubuntu Bionic
DOCKER_API_VERSION=1.40
# Build doesn't work if BuildKit is enabled
DOCKER_BUILDKIT=0
GO_PKG_DIRS = ./cmd ./internal ./test
MQ_ARCHIVE_TYPE=LINUX
MQ_ARCHIVE_DEV_TYPE=Linux
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
BUILD_SERVER_CONTAINER=build-server
# BUILD_SERVER_NETWORK is the name of the network to use for the web server container used at build time
BUILD_SERVER_NETWORK=build
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
# test run in parallel
NUM_CPU ?= $(or $(shell $(COMMAND) info --format "{{ .NCPU }}"),2)
NUM_CPU ?= $(or $(shell docker info --format "{{ .NCPU }}"),2)
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
BASE_IMAGE_TAG=$(lastword $(subst /, ,$(subst :,-,$(BASE_IMAGE))))
#BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
@@ -111,22 +105,12 @@ endif
# Try to figure out which archive to use from the architecture
ifeq "$(ARCH)" "amd64"
MQ_ARCHIVE_ARCH:=X86-64
MQ_ARCHIVE_DEV_ARCH:=X64
MQ_ARCHIVE_ARCH=X86-64
MQ_ARCHIVE_DEV_ARCH=X64
else ifeq "$(ARCH)" "ppc64le"
MQ_ARCHIVE_ARCH:=PPC64LE
MQ_ARCHIVE_DEV_ARCH:=PPC64LE
MQ_ARCHIVE_ARCH=PPC64LE
else ifeq "$(ARCH)" "s390x"
MQ_ARCHIVE_ARCH:=S390X
MQ_ARCHIVE_DEV_ARCH:=S390X
else ifeq "$(ARCH)" "arm64"
MQ_ARCHIVE_ARCH:=ARM64
MQ_ARCHIVE_DEV_ARCH:=ARM64
endif
# If this is a fake master build, push images to alternative location (pipeline wont consider these images GA candidates)
ifeq ($(shell [ "$(TRAVIS)" = "true" ] && [ -n "$(MAIN_BRANCH)" ] && [ -n "$(SOURCE_BRANCH)" ] && [ "$(MAIN_BRANCH)" != "$(SOURCE_BRANCH)" ] && echo "true"), true)
MQ_DELIVERY_REGISTRY_NAMESPACE="master-fake"
MQ_ARCHIVE_ARCH=S390X
endif
# LTS_TAG is the tag modifier for an LTS container build
@@ -154,16 +138,10 @@ endif
# image tagging
ifneq "$(RELEASE)" "$(EMPTY)"
EXTRA_LABELS_RELEASE=--label "release=$(RELEASE)"
EXTRA_LABELS=--label release=$(RELEASE)
RELEASE_TAG="-$(RELEASE)"
endif
ifneq "$(MQ_ARCHIVE_LEVEL)" "$(EMPTY)"
EXTRA_LABELS_LEVEL=--label "mq-build=$(MQ_ARCHIVE_LEVEL)"
endif
EXTRA_LABELS=$(EXTRA_LABELS_RELEASE) $(EXTRA_LABELS_LEVEL)
ifeq "$(TIMESTAMPFLAT)" "$(EMPTY)"
TIMESTAMPFLAT=$(shell date "+%Y%m%d%H%M%S")
endif
@@ -176,13 +154,6 @@ ifeq ($(shell [ ! -z $(TRAVIS) ] && [ "$(TRAVIS_PULL_REQUEST)" = "false" ] && [
MQ_MANIFEST_TAG_SUFFIX=.$(TIMESTAMPFLAT).$(GIT_COMMIT)
endif
# Make sure we don't use VOLUME_MOUNT_OPTIONS for Podman on macOS
ifeq "$(COMMAND)" "podman"
ifeq "$(shell uname -s)" "Darwin"
VOLUME_MOUNT_OPTIONS:=
endif
endif
PATH_TO_MQ_TAG_CACHE=$(TRAVIS_BUILD_DIR)/.tagcache
ifneq "$(TRAVIS)" "$(EMPTY)"
ifneq ("$(wildcard $(PATH_TO_MQ_TAG_CACHE))","")
@@ -192,7 +163,6 @@ endif
MQ_AMD64_TAG=$(MQ_MANIFEST_TAG)-amd64
MQ_S390X_TAG?=$(MQ_MANIFEST_TAG)-s390x
MQ_PPC64LE_TAG?=$(MQ_MANIFEST_TAG)-ppc64le
# end image tagging
@@ -204,10 +174,8 @@ MQ_IMAGE_DEVSERVER_MANIFEST=$(MQ_IMAGE_DEVSERVER):$(MQ_MANIFEST_TAG)
MQ_IMAGE_ADVANCEDSERVER_MANIFEST=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_MANIFEST_TAG)
MQ_IMAGE_DEVSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_AMD64_TAG)
MQ_IMAGE_DEVSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_S390X_TAG)
MQ_IMAGE_DEVSERVER_PPC64LE=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_PPC64LE_TAG)
MQ_IMAGE_ADVANCEDSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_AMD64_TAG)
MQ_IMAGE_ADVANCEDSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_S390X_TAG)
MQ_IMAGE_ADVANCEDSERVER_PPC64LE=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_PPC64LE_TAG)
###############################################################################
# Build targets
@@ -237,16 +205,16 @@ downloads/$(MQ_ARCHIVE_DEV):
mkdir -p downloads
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)"
# Use key which is not stored in the repository to fetch the files from the fileserver
curl --fail --location $(BUILD_RSYNC_ENCRYPTED_KEY_URL) --output ./host.key.gpg
curl -L $(BUILD_RSYNC_ENCRYPTED_KEY_URL) -o ./host.key.gpg
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --batch --passphrase-fd 0 ./host.key.gpg
chmod 600 ./host.key
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE_DEV)
-@rm host.key.gpg host.key
else
ifneq "$(MQ_ARCHIVE_REPOSITORY_DEV)" "$(EMPTY)"
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" --output downloads/$(MQ_ARCHIVE_DEV)
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" -o downloads/$(MQ_ARCHIVE_DEV)
else
curl --fail --location https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV) --output downloads/$(MQ_ARCHIVE_DEV)
curl -L https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV) -o downloads/$(MQ_ARCHIVE_DEV)
endif
endif
@@ -256,14 +224,14 @@ downloads/$(MQ_ARCHIVE):
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)"
# Use key which is not stored in the repository to fetch the files from the fileserver
-@rm host.key.gpg host.key
curl --fail --location $(BUILD_RSYNC_ENCRYPTED_KEY_URL) --output ./host.key.gpg
curl -L $(BUILD_RSYNC_ENCRYPTED_KEY_URL) -o ./host.key.gpg
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --batch --passphrase-fd 0 ./host.key.gpg
chmod 600 ./host.key
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE)
-@rm host.key.gpg host.key
else
ifneq "$(MQ_ARCHIVE_REPOSITORY)" "$(EMPTY)"
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY)" --output downloads/$(MQ_ARCHIVE)
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY)" -o downloads/$(MQ_ARCHIVE)
endif
endif
@@ -274,43 +242,39 @@ downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
cache-mq-tag:
@printf "MQ_MANIFEST_TAG=$(MQ_MANIFEST_TAG)\n" | tee $(PATH_TO_MQ_TAG_CACHE)
###############################################################################
# Test targets
###############################################################################
# Vendor Go dependencies for the Container tests
test/container/vendor:
cd test/container && go mod vendor
# Vendor Go dependencies for the Docker tests
test/docker/vendor:
cd test/docker && go mod vendor
# Shortcut to just run the unit tests
.PHONY: test-unit
test-unit:
$(COMMAND) build --target builder --file Dockerfile-server .
docker build --target builder --file Dockerfile-server .
.PHONY: test-advancedserver
test-advancedserver: test/container/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
$(COMMAND) inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
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)
test-advancedserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
docker inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) $(TEST_OPTS_DOCKER)
.PHONY: build-devjmstest
build-devjmstest:
build-devjmstest: registry-login
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
cd test/messaging && $(COMMAND) build --tag $(DEV_JMS_IMAGE) .
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
.PHONY: test-devserver
test-devserver: test/container/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
$(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
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)
test-devserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
docker 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=true go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER)
.PHONY: coverage
coverage:
mkdir coverage
.PHONY: test-advancedserver-cover
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)))
test-advancedserver-cover: test/docker/vendor coverage
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell docker --version)"$(END)))
rm -f ./coverage/unit*.cov
# Run unit tests with coverage, for each package under 'internal'
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
@@ -319,57 +283,65 @@ test-advancedserver-cover: test/container/vendor coverage
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
rm -f ./test/container/coverage/*.cov
rm -f ./coverage/container.*
mkdir -p ./test/container/coverage/
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/container.cov
tail -q -n +2 ./test/container/coverage/*.cov >> ./coverage/container.cov
go tool cover -html=./coverage/container.cov -o ./coverage/container.html
rm -f ./test/docker/coverage/*.cov
rm -f ./coverage/docker.*
mkdir -p ./test/docker/coverage/
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true go test $(TEST_OPTS_DOCKER)
echo 'mode: count' > ./coverage/docker.cov
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
echo 'mode: count' > ./coverage/combined.cov
tail -q -n +2 ./coverage/unit.cov ./coverage/container.cov >> ./coverage/combined.cov
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
###############################################################################
# Build functions
###############################################################################
# Command to build the image
# Args: imageName, imageTag, dockerfile, extraArgs, dockerfileTarget
# If the ARCH variable has been changed from the default value (arch_go variable), then the `--platform` parameter is added
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
# Build an MQ image. The commands used are slightly different between Docker and Podman
define build-mq
rm -f .dockerignore && echo ".git\ndownloads\n!downloads/$4" > .dockerignore
$(if $(findstring docker,$(COMMAND)), @docker network create build,)
$(if $(findstring docker,$(COMMAND)), @docker run --rm --name $(BUILD_SERVER_CONTAINER) --network build --network-alias build --volume $(DOWNLOADS_DIR):/opt/app-root/src:ro --detach registry.redhat.io/ubi8/nginx-118 nginx -g "daemon off;",)
$(eval EXTRA_ARGS=$(if $(findstring docker,$(COMMAND)), --network build --build-arg MQ_URL=http://build:8080/$4, --volume $(DOWNLOADS_DIR):/var/downloads --build-arg MQ_URL=file:///var/downloads/$4))
# Build the new image
$(COMMAND) build \
--tag $1:$2 \
--file $3 \
$(EXTRA_ARGS) \
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
--build-arg IMAGE_TAG="$1:$2" \
--build-arg MQ_ARCHIVE="downloads/$4" \
--label version=$(MQ_VERSION) \
--label name=$1 \
--label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \
--label architecture="$(ARCH)" \
--label run="podman run -d -e LICENSE=accept $1:$2" \
--label run="docker run -d -e LICENSE=accept $1:$2" \
--label vcs-ref=$(IMAGE_REVISION) \
--label vcs-type=git \
--label vcs-url=$(IMAGE_SOURCE) \
$(if $(findstring $(arch_go),$(ARCH)),,--platform=linux/$(ARCH)) \
$(EXTRA_LABELS) \
--target $5 \
.
$(if $(findstring docker,$(COMMAND)), @docker kill $(BUILD_SERVER_CONTAINER))
$(if $(findstring docker,$(COMMAND)), @docker network rm build)
endef
###############################################################################
# Build targets
###############################################################################
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
DOCKER_CLIENT_VERSION=$(shell docker version --format "{{ .Client.Version }}")
PODMAN_VERSION=$(shell podman version --format "{{ .Version }}")
.PHONY: command-version
command-version:
# If we're using Docker, then check it's recent enough to support multi-stage builds
ifneq (,$(findstring docker,$(COMMAND)))
@test "$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
endif
ifneq (,$(findstring podman,$(COMMAND)))
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
endif
.PHONY: build-advancedserver-host
build-advancedserver-host: build-advancedserver
.PHONY: build-advancedserver
build-advancedserver: log-build-env downloads/$(MQ_ARCHIVE) command-version
build-advancedserver: registry-login log-build-env downloads/$(MQ_ARCHIVE) command-version
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)"$(END)))
$(call build-mq,$(MQ_IMAGE_ADVANCEDSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE),mq-server)
@@ -377,39 +349,40 @@ build-advancedserver: log-build-env downloads/$(MQ_ARCHIVE) command-version
build-devserver-host: build-devserver
.PHONY: build-devserver
build-devserver: log-build-env downloads/$(MQ_ARCHIVE_DEV) command-version
build-devserver: registry-login log-build-env downloads/$(MQ_ARCHIVE_DEV) command-version
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)"$(END)))
$(call build-mq,$(MQ_IMAGE_DEVSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE_DEV),mq-dev-server)
.PHONY: build-advancedserver-cover
build-advancedserver-cover: command-version
build-advancedserver-cover: registry-login command-version
$(COMMAND) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) -t $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover -f Dockerfile-server.cover .
.PHONY: build-explorer
build-explorer: downloads/$(MQ_ARCHIVE_DEV)
build-explorer: registry-login downloads/$(MQ_ARCHIVE_DEV)
$(call build-mq,mq-explorer,latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),mq-explorer)
.PHONY: build-sdk
build-sdk: downloads/$(MQ_ARCHIVE_DEV)
build-sdk: registry-login downloads/$(MQ_ARCHIVE_DEV)
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_SDK)"$(END)))
$(call build-mq,mq-sdk,$(MQ_TAG),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),mq-sdk)
###############################################################################
# Logging targets
###############################################################################
.PHONY: registry-login
registry-login:
ifneq ($(REGISTRY_USER),)
$(COMMAND) login -u $(REGISTRY_USER) -p $(REGISTRY_PASS) registry.redhat.io
endif
.PHONY: log-build-env
log-build-vars:
$(info $(SPACER)$(shell printf $(TITLE)"Build environment"$(END)))
@echo arch_uname=$(arch_uname)
@echo arch_go=$(arch_go)
@echo "ARCH=$(ARCH) (origin:$(origin ARCH))"
@echo MQ_VERSION="$(MQ_VERSION) (origin:$(origin MQ_VERSION))"
@echo MQ_ARCHIVE="$(MQ_ARCHIVE) (origin:$(origin MQ_ARCHIVE))"
@echo MQ_ARCHIVE_DEV_ARCH=$(MQ_ARCHIVE_DEV_ARCH)
@echo ARCH=$(ARCH)
@echo MQ_VERSION=$(MQ_VERSION)
@echo MQ_ARCHIVE=$(MQ_ARCHIVE)
@echo MQ_ARCHIVE_DEV=$(MQ_ARCHIVE_DEV)
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
@echo COMMAND=$(COMMAND)
@echo REGISTRY_USER=$(REGISTRY_USER)
.PHONY: log-build-env
log-build-env: log-build-vars
@@ -419,22 +392,16 @@ log-build-env: log-build-vars
include formatting.mk
###############################################################################
# Push/pull targets
###############################################################################
.PHONY: pull-mq-archive
pull-mq-archive:
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY)" --output downloads/$(MQ_ARCHIVE)
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY)" -o downloads/$(MQ_ARCHIVE)
.PHONY: pull-mq-archive-dev
pull-mq-archive-dev:
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" --output downloads/$(MQ_ARCHIVE_DEV)
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" -o downloads/$(MQ_ARCHIVE_DEV)
.PHONY: push-advancedserver
push-advancedserver:
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
fi
$(info $(SPACER)$(shell printf $(TITLE)"Push production image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) tag $(MQ_IMAGE_ADVANCEDSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
@@ -442,9 +409,6 @@ push-advancedserver:
.PHONY: push-devserver
push-devserver:
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
fi
$(info $(SPACER)$(shell printf $(TITLE)"Push developer image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) tag $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
@@ -468,33 +432,25 @@ pull-devserver:
push-manifest: build-skopeo-container
$(info $(SPACER)$(shell printf $(TITLE)"** Determining the image digests **"$(END)))
ifneq "$(LTS)" "true"
$(eval MQ_IMAGE_DEVSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_AMD64) | jq -r .Digest))
$(eval MQ_IMAGE_DEVSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux --override-arch s390x inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_AMD64) | jq -r .Digest))
$(eval MQ_IMAGE_DEVSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_S390X) | jq -r .Digest))
$(eval MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_PPC64LE) | jq -r .Digest))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_AMD64) has a digest of $(MQ_IMAGE_DEVSERVER_AMD64_DIGEST)**"$(END)))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_S390X) has a digest of $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)**"$(END)))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_PPC64LE) has a digest of $(MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST)**"$(END)))
endif
$(eval MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_AMD64) | jq -r .Digest))
$(eval MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_S390X) | jq -r .Digest))
$(eval MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_PPC64LE) | jq -r .Digest))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_AMD64) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST)**"$(END)))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_S390X) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)**"$(END)))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST)**"$(END)))
ifneq "$(LTS)" "true"
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_DEVSERVER_MANIFEST)**"$(END)))
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_DEVSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_DEVSERVER_AMD64_DIGEST) $(MQ_IMAGE_DEVSERVER_S390X_DIGEST) $(MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST)" $(END))
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_DEVSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_DEVSERVER_AMD64_DIGEST) $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)" $(END))
endif
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_ADVANCEDSERVER_MANIFEST)**"$(END)))
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST)" $(END))
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)" $(END))
.PHONY: build-skopeo-container
build-skopeo-container:
$(COMMAND) images | grep -q "skopeo"; if [ $$? != 0 ]; then $(COMMAND) build -t skopeo:latest ./docker-builds/skopeo/; fi
###############################################################################
# Other targets
###############################################################################
$(COMMAND) images | grep -q "skopeo"; if [ $$? != 0 ]; then docker build -t skopeo:latest ./docker-builds/skopeo/; fi
.PHONY: clean
clean:
@@ -533,20 +489,35 @@ lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
.PHONY: gosec
gosec:
$(info $(SPACER)$(shell printf "Running gosec test"$(END)))
@gosecrc=0; gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null || gosecrc=$$?; \
cat gosec_results.json | jq '{"GolangErrors": (.["Golang errors"]|length>0),"Issues":(.Issues|length>0)}' | grep 'true' >/dev/null ;\
if [ $$? -eq 0 ] || [ $$gosecrc -ne 0 ]; then \
printf "FAILURE: Issues found running gosec - see gosec_results.json\n" ;\
cat "gosec_results.json" ;\
@gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\
cat "gosec_results.json" ;\
cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\
if [ $$? -eq 0 ]; then \
printf "\nFAILURE: gosec found files containing HIGH severity issues - see results.json\n" ;\
exit 1 ;\
else \
printf "gosec found no issues\n" ;\
cat "gosec_results.json" ;\
fi
printf "\ngosec found no HIGH severity issues\n" ;\
fi ;\
cat gosec_results.json | grep MEDIUM | grep severity > /dev/null ;\
if [ $$? -eq 0 ]; then \
printf "\nFAILURE: gosec found files containing MEDIUM severity issues - see results.json\n" ;\
exit 1 ;\
else \
printf "\ngosec found no MEDIUM severity issues\n" ;\
fi ;\
cat gosec_results.json | grep LOW | grep severity > /dev/null;\
if [ $$? -eq 0 ]; then \
printf "\nFAILURE: gosec found files containing LOW severity issues - see results.json\n" ;\
exit 1;\
else \
printf "\ngosec found no LOW severity issues\n" ;\
fi ;\
include formatting.mk
.PHONY: update-release-information
update-release-information:
sed -i.bak 's/ARG MQ_ARCHIVE=.*-LinuxX64.tar.gz"/ARG MQ_ARCHIVE="downloads\/$(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"/g' Dockerfile-server && rm Dockerfile-server.bak
sed -i.bak 's/ARG MQ_URL=.*-LinuxX64.tar.gz"/ARG MQ_URL="https:\/\/public.dhe.ibm.com\/ibmdl\/export\/pub\/software\/websphere\/messaging\/mqadv\/$(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"/g' Dockerfile-server && rm Dockerfile-server.bak
$(eval MQ_VERSION_1=$(shell echo '${MQ_VERSION}' | rev | cut -c 3- | rev))
sed -i.bak 's/IBM_MQ_.*_LINUX_X86-64_NOINST.tar.gz/IBM_MQ_${MQ_VERSION_1}_LINUX_X86-64_NOINST.tar.gz/g' docs/building.md && rm docs/building.md.bak
sed -i.bak 's/ibm-mqadvanced-server:.*-amd64/ibm-mqadvanced-server:$(MQ_VERSION)-amd64/g' docs/security.md
@@ -556,17 +527,3 @@ update-release-information:
sed -i.bak 's/knowledgecenter\/SSFKSJ_.*\/com/knowledgecenter\/SSFKSJ_${MQ_VERSION_2}.0\/com/g' docs/usage.md && rm docs/usage.md.bak
$(eval MQ_VERSION_3=$(shell echo '${MQ_VERSION_1}' | sed "s/\.//g"))
sed -i.bak 's/MQ_..._ARCHIVE_REPOSITORY/MQ_${MQ_VERSION_3}_ARCHIVE_REPOSITORY/g' .travis.yml && rm .travis.yml.bak
COMMAND_SERVER_VERSION=$(shell $(COMMAND) version --format "{{ .Server.Version }}")
COMMAND_CLIENT_VERSION=$(shell $(COMMAND) version --format "{{ .Client.Version }}")
PODMAN_VERSION=$(shell podman version --format "{{ .Version }}")
.PHONY: command-version
command-version:
# If we're using Docker, then check it's recent enough to support multi-stage builds
ifneq (,$(findstring docker,$(COMMAND)))
@test "$(word 1,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
@test "$(word 1,$(subst ., ,$(COMMAND_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(COMMAND_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
endif
ifneq (,$(findstring podman,$(COMMAND)))
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
endif

View File

@@ -27,33 +27,30 @@ Note that in order to use the image, it is necessary to accept the terms of the
- **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
- **LANG** - Set this to the language you would like the license to be printed in.
- **MQ_QMGR_NAME** - Set this to the name you want your Queue Manager to be created with.
- **MQ_QMGR_LOG_FILE_PAGES** - Set this to control the value for LogFilePages passed to the "crtmqm" command. Cannot be changed after queue manager creation.
- **MQ_LOGGING_CONSOLE_SOURCE** - Specifies a comma-separated list of sources for logs which are mirrored to the container's stdout. The valid values are "qmgr" and "web". Defaults to "qmgr".
- **MQ_LOGGING_CONSOLE_FORMAT** - Changes the format of the logs which are printed on the container's stdout. Set to "json" to use JSON format (JSON object per line); set to "basic" to use a simple human-readable format. Defaults to "basic".
- **MQ_LOGGING_CONSOLE_EXCLUDE_ID** - Excludes log messages with the specified ID. The log messages still appear in the log file on disk, but are excluded from the container's stdout. Defaults to "AMQ5041I,AMQ5052I,AMQ5051I,AMQ5037I,AMQ5975I".
- **LOG_FORMAT** - Set this to change the format of the logs which are printed on the container's stdout. Set to "json" to use JSON format (JSON object per line); set to "basic" to use a simple human-readable format. Defaults to "basic".
- **MQ_ENABLE_METRICS** - Set this to `true` to generate Prometheus metrics for your Queue Manager.
See the [default developer configuration docs](docs/developer-config.md) for the extra environment variables supported by the MQ Advanced for Developers image.
### Kubernetes
If you want to use IBM MQ on [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM MQ Sample Helm Chart](https://github.com/ibm-messaging/mq-helm). This can be used to run the container on a Kubernetes cluster, such as the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
If you want to use IBM MQ in [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM charts](https://github.com/IBM/charts). This can be used to run the container on a cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
## Issues and contributions
For issues relating specifically to the container image or Helm chart, please use the [GitHub issue tracker](https://github.com/ibm-messaging/mq-container/issues). Pull requests are not currently accepted.
For issues relating specifically to the container image or Helm chart, please use the [GitHub issue tracker](https://github.com/ibm-messaging/mq-container/issues). If you do submit a Pull Request related to this Docker image, please indicate in the Pull Request that you accept and agree to be bound by the terms of the [IBM Contributor License Agreement](CLA.md).
## License
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:
- [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-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.
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-BYHCL7) (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-APIG-BZDDDY) (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.
## Copyright
© Copyright IBM Corporation 2015, 2023
© Copyright IBM Corporation 2015, 2021

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2017, 2022
# © Copyright IBM Corporation 2017, 2020
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,31 +20,19 @@
SRC_DIR = src
BUILD_DIR = ./build
ARCH ?= $(if $(findstring x86_64,$(shell uname -m)),amd64,$(if $(findstring aarch64,$(shell uname -m)),aarch64,$(shell uname -m)))
# Flags passed to the C compiler. Need to use gnu11 to get POSIX functions needed for file locking.
CFLAGS.amd64 := -m64
CFLAGS.ppc64le := -m64
CFLAGS.s390x := -m64
# -m64 is not a valid compiler option on aarch64/arm64 (ARM)
CFLAGS.arm64 :=
CFLAGS += -std=gnu11 -fPIC -Wall ${CFLAGS.${ARCH}}
CFLAGS += -std=gnu11 -fPIC -Wall -m64
LIB_APR = -L/usr/lib64 -lapr-1 -laprutil-1
LIB_MQ = -L/opt/mqm/lib64 -lmqm_r
all: $(BUILD_DIR)/mqhtpass.so $(BUILD_DIR)/htpass_test $(BUILD_DIR)/log_test
all: $(BUILD_DIR)/mqhtpass.so $(BUILD_DIR)/htpass_test
$(BUILD_DIR)/log.o : $(SRC_DIR)/log.c $(SRC_DIR)/log.h
mkdir -p ${dir $@}
gcc $(CFLAGS) -c $(SRC_DIR)/log.c -o $@
$(BUILD_DIR)/log_test : $(BUILD_DIR)/log.o
mkdir -p ${dir $@}
gcc $(CFLAGS) $(SRC_DIR)/log_test.c $^ -o $@
# Run Logging tests, and print log if they fail
$@ || (cat log_test*.log && exit 1)
$(BUILD_DIR)/htpass.o : $(SRC_DIR)/htpass.c $(SRC_DIR)/htpass.h
mkdir -p ${dir $@}
gcc $(CFLAGS) -c $(SRC_DIR)/htpass.c -I /usr/include/apr-1 -o $@

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2021, 2022
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -124,7 +124,7 @@ void log_printf(const char *source_file, int source_line, const char *level, con
if (strftime(date_buf, sizeof date_buf, "%FT%T", utc))
{
// Round microseconds down to milliseconds, for consistency
cur += snprintf(cur, end-cur, ", \"ibm_datetime\":\"%s.%03ldZ\"", date_buf, now.tv_usec / (long)1000);
cur += snprintf(cur, end-cur, ", \"ibm_datetime\":\"%s.%03ldZ\"", date_buf, now.tv_usec / 1000);
}
cur += snprintf(cur, end-cur, ", \"ibm_processId\":\"%d\"", pid);
cur += snprintf(cur, end-cur, ", \"host\":\"%s\"", hostname);
@@ -146,17 +146,7 @@ void log_printf(const char *source_file, int source_line, const char *level, con
// Important: Just do one file write, to prevent problems with multi-threading.
// This only works if the log message is not too long for the buffer.
fprintf(fp, "%s", buf);
fprintf(fp, buf);
}
}
int trimmed_len(char *s, int max_len)
{
int i;
for (i = max_len - 1; i >= 0; i--)
{
if (s[i] != ' ')
break;
}
return i+1;
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2021, 2022
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -59,12 +59,5 @@ void log_close();
*/
#define log_debugf(format,...) log_printf(__FILE__, __LINE__, "DEBUG", format, ##__VA_ARGS__)
/**
* Return the length of the string when trimmed of trailing spaces.
* IBM MQ uses fixed length strings, so this function can be used to print
* a trimmed version of a string using the "%.*s" printf format string.
* For example, `log_printf("%.*s", trimmed_len(fw_str, 48), fw_str)`
*/
int trimmed_len(char *s, int);
#endif

View File

@@ -1,120 +0,0 @@
/*
© Copyright IBM Corporation 2022
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.
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"
// Headers for multi-threaded tests
#include <pthread.h>
// Start a test and log the function name
#define test_start() printf("=== RUN: %s\n", __func__)
// Indicate test has passed
#define test_pass() printf("--- PASS: %s\n", __func__)
// The length of strings used in the tests
#define STR_LEN 5
// Indicate test has failed
void test_fail(const char *test_name)
{
printf("--- FAIL: %s\n", test_name);
exit(1);
}
// Print a fixed-width string in hexadecimal
void print_hex(char fw_string[STR_LEN])
{
printf("[");
for (int i=0; i<STR_LEN; i++)
{
printf("%02x", fw_string[i]);
if (i < STR_LEN-1)
printf(",");
}
printf("]");
}
// ----------------------------------------------------------------------------
// Tests for string manipulation
// ----------------------------------------------------------------------------
void test_trimmed_len(const char *test_name, char fw_string[STR_LEN], int expected_len)
{
printf("=== RUN: %s\n", test_name);
int len;
// Create a copy of the fixed-width string
char fw_string2[STR_LEN];
memcpy(fw_string2, fw_string, STR_LEN * sizeof(char));
// Call the function under test
len = trimmed_len(fw_string, STR_LEN);
// Check the result is correct
if (len != expected_len)
{
printf("%s: Expected result to be %d; got %d\n", __func__, expected_len, len);
test_fail(test_name);
}
// Check that the original string has not been changed
for (int i=0; i<STR_LEN; i++)
{
if (fw_string[i] != fw_string2[i])
{
printf("%c-%c\n", fw_string[i], fw_string2[i]);
printf("%s: Expected string to be identical to input hex ", __func__);
print_hex(fw_string2);
printf("; got hex ");
print_hex(fw_string);
printf("\n");
test_fail(test_name);
}
}
printf("--- PASS: %s\n", test_name);
}
void test_trimmed_len_normal()
{
char fw_string[STR_LEN] = {'a','b','c',' ',' '};
test_trimmed_len(__func__, fw_string, 3);
}
void test_trimmed_len_full()
{
char fw_string[STR_LEN] = {'a','b','c','d','e'};
test_trimmed_len(__func__, fw_string, 5);
}
void test_trimmed_len_empty()
{
char fw_string[STR_LEN] = {' ',' ',' ',' ',' '};
test_trimmed_len(__func__, fw_string, 0);
}
// ----------------------------------------------------------------------------
int main()
{
// Turn on debugging for the tests
setenv("DEBUG", "true", true);
log_init("log_test.log");
test_trimmed_len_normal();
test_trimmed_len_full();
test_trimmed_len_empty();
log_close();
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2021, 2022
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -34,6 +34,8 @@ static MQZ_TERM_AUTHORITY mqhtpass_terminate;
#define HTPASSWD_FILE "/etc/mqm/mq.htpasswd"
#define NAME "MQ Advanced for Developers custom authentication service"
static char *trim(char *s);
/**
* Initialization and entrypoint for the dynamically loaded
* authorization installable service. It registers the addresses of the
@@ -78,7 +80,7 @@ void MQENTRY MQStart(
{
log_infof("Initializing %s", NAME);
}
log_debugf("MQStart options=%s qmgr=%.*s", ((Options == MQZIO_SECONDARY) ? "Secondary" : "Primary"), trimmed_len(QMgrName, MQ_Q_MGR_NAME_LENGTH), QMgrName);
log_debugf("MQStart options=%s qmgr=%s", ((Options == MQZIO_SECONDARY) ? "Secondary" : "Primary"), trim(QMgrName));
if (!htpass_valid_file(HTPASSWD_FILE))
{
@@ -174,14 +176,11 @@ static void MQENTRY mqhtpass_authenticate_user_csp(
// Tell the queue manager to continue trying other authorization services, as they might have the user.
*pContinuation = MQZCI_CONTINUE;
log_debugf(
"User authentication failed due to invalid user. user=%.*s effuser=%.*s applname=%.*s csp_user=%s cc=%d reason=%d",
trimmed_len(pIdentityContext->UserIdentifier, MQ_USER_ID_LENGTH),
pIdentityContext->UserIdentifier,
trimmed_len(pApplicationContext->EffectiveUserID, MQ_USER_ID_LENGTH),
pApplicationContext->EffectiveUserID,
trimmed_len(pApplicationContext->ApplName, MQ_APPL_NAME_LENGTH),
pApplicationContext->ApplName,
csp_user,
"User authentication failed due to invalid user. user=%s effuser=%s applname=%s csp_user=%s cc=%d reason=%d",
trim(pIdentityContext->UserIdentifier),
trim(pApplicationContext->EffectiveUserID),
trim(pApplicationContext->ApplName),
trim(csp_user),
*pCompCode,
*pReason);
}
@@ -193,14 +192,11 @@ static void MQENTRY mqhtpass_authenticate_user_csp(
// Tell the queue manager to stop trying other authorization services.
*pContinuation = MQZCI_STOP;
log_debugf(
"User authentication failed due to invalid password. user=%.*s effuser=%.*s applname=%.*s csp_user=%s cc=%d reason=%d",
trimmed_len(pIdentityContext->UserIdentifier, MQ_USER_ID_LENGTH),
pIdentityContext->UserIdentifier,
trimmed_len(pApplicationContext->EffectiveUserID, MQ_USER_ID_LENGTH),
pApplicationContext->EffectiveUserID,
trimmed_len(pApplicationContext->ApplName, MQ_APPL_NAME_LENGTH),
pApplicationContext->ApplName,
csp_user,
"User authentication failed due to invalid password. user=%s effuser=%s applname=%s csp_user=%s cc=%d reason=%d",
trim(pIdentityContext->UserIdentifier),
trim(pApplicationContext->EffectiveUserID),
trim(pApplicationContext->ApplName),
trim(csp_user),
*pCompCode,
*pReason);
}
@@ -231,6 +227,7 @@ static void MQENTRY mqhtpass_authenticate_user(
PMQLONG pReason)
{
char *spuser = NULL;
char *sppass = NULL;
// By default, return a warning, which indicates to MQ that this
// authorization service hasn't authenticated the user.
*pCompCode = MQCC_WARNING;
@@ -279,14 +276,11 @@ static void MQENTRY mqhtpass_authenticate_user(
else
{
log_debugf(
"User authentication failed user=%.*s effuser=%.*s applname=%.*s cspuser=%s cc=%d reason=%d",
trimmed_len(pIdentityContext->UserIdentifier, MQ_USER_ID_LENGTH),
pIdentityContext->UserIdentifier,
trimmed_len(pApplicationContext->EffectiveUserID, MQ_USER_ID_LENGTH),
pApplicationContext->EffectiveUserID,
trimmed_len(pApplicationContext->ApplName, MQ_APPL_NAME_LENGTH),
pApplicationContext->ApplName,
spuser,
"User authentication failed user=%s effuser=%s applname=%s cspuser=%s cc=%d reason=%d",
trim(pIdentityContext->UserIdentifier),
trim(pApplicationContext->EffectiveUserID),
trim(pApplicationContext->ApplName),
trim(spuser),
*pCompCode,
*pReason);
}
@@ -340,3 +334,18 @@ static void MQENTRY mqhtpass_terminate(
*pReason = MQRC_NONE;
}
/**
* Remove trailing spaces from a string.
*/
static char *trim(char *s)
{
int i;
for (i = strlen(s) - 1; i >= 0; i--)
{
if (s[i] == ' ')
s[i] = 0;
else
break;
}
return s;
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2022
© Copyright IBM Corporation 2017, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,24 +18,22 @@ limitations under the License.
package main
import (
"context"
"fmt"
"os"
"os/exec"
"os/signal"
"strings"
"github.com/ibm-messaging/mq-container/pkg/name"
)
func queueManagerHealthy(ctx context.Context) (bool, error) {
func queueManagerHealthy() (bool, error) {
name, err := name.GetQueueManagerName()
if err != nil {
return false, err
}
// Specify the queue manager name, just in case someone's created a second queue manager
// #nosec G204
cmd := exec.CommandContext(ctx, "dspmq", "-n", "-m", name)
cmd := exec.Command("dspmq", "-n", "-m", name)
// Run the command and wait for completion
out, err := cmd.CombinedOutput()
fmt.Printf("%s", out)
@@ -49,20 +47,13 @@ func queueManagerHealthy(ctx context.Context) (bool, error) {
return true, nil
}
func doMain() int {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
defer cancel()
healthy, err := queueManagerHealthy(ctx)
func main() {
healthy, err := queueManagerHealthy()
if err != nil {
return 2
os.Exit(2)
}
if !healthy {
return 1
os.Exit(1)
}
return 0
}
func main() {
os.Exit(doMain())
os.Exit(0)
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2023
© Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,59 +18,44 @@ limitations under the License.
package main
import (
"context"
"fmt"
"net"
"os"
"os/signal"
"github.com/ibm-messaging/mq-container/internal/ready"
"github.com/ibm-messaging/mq-container/pkg/name"
)
func doMain() int {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
defer cancel()
func main() {
// Check if runmqserver has indicated that it's finished configuration
r, err := ready.Check()
if !r || err != nil {
return 1
os.Exit(1)
}
name, err := name.GetQueueManagerName()
if err != nil {
fmt.Println(err)
return 1
os.Exit(1)
}
// Check if the queue manager has a running listener
status, err := ready.Status(ctx, name)
if err != nil {
return 1
}
switch status {
case ready.StatusActiveQM:
if active, _ := ready.IsRunningAsActiveQM(name); active {
conn, err := net.Dial("tcp", "127.0.0.1:1414")
if err != nil {
fmt.Println(err)
return 1
os.Exit(1)
}
err = conn.Close()
if err != nil {
fmt.Println(err)
}
return 0
case ready.StatusStandbyQM:
} else if standby, _ := ready.IsRunningAsStandbyQM(name); standby {
fmt.Printf("Detected queue manager running in standby mode")
return 10
case ready.StatusReplicaQM:
os.Exit(10)
} else if replica, _ := ready.IsRunningAsReplicaQM(name); replica {
fmt.Printf("Detected queue manager running in replica mode")
return 20
default:
return 1
os.Exit(20)
} else {
os.Exit(1)
}
}
func main() {
os.Exit(doMain())
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2021, 2022
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,24 +18,22 @@ limitations under the License.
package main
import (
"context"
"fmt"
"os"
"os/exec"
"os/signal"
"strings"
"github.com/ibm-messaging/mq-container/pkg/name"
)
func queueManagerStarted(ctx context.Context) (bool, error) {
func queueManagerStarted() (bool, error) {
name, err := name.GetQueueManagerName()
if err != nil {
return false, err
}
// Specify the queue manager name, just in case someone's created a second queue manager
// #nosec G204
cmd := exec.CommandContext(ctx, "dspmq", "-n", "-m", name)
cmd := exec.Command("dspmq", "-n", "-m", name)
// Run the command and wait for completion
out, err := cmd.CombinedOutput()
if err != nil {
@@ -48,20 +46,13 @@ func queueManagerStarted(ctx context.Context) (bool, error) {
return true, nil
}
func doMain() int {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
defer cancel()
started, err := queueManagerStarted(ctx)
func main() {
started, err := queueManagerStarted()
if err != nil {
return 2
os.Exit(2)
}
if !started {
return 1
os.Exit(1)
}
return 0
}
func main() {
os.Exit(doMain())
os.Exit(0)
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ import (
"fmt"
"io/ioutil"
"os"
"strings"
"syscall"
"github.com/ibm-messaging/mq-container/internal/htpasswd"
@@ -31,20 +30,7 @@ import (
var log *logger.Logger
func getLogFormat() string {
logFormat := strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_FORMAT")))
//old-style env var is used.
if logFormat == "" {
logFormat = strings.ToLower(strings.TrimSpace(os.Getenv("LOG_FORMAT")))
}
if logFormat != "" && (logFormat == "basic" || logFormat == "json") {
return logFormat
} else {
//this is the case where value is either empty string or set to something other than "basic"/"json"
logFormat = "basic"
}
return logFormat
return os.Getenv("LOG_FORMAT")
}
func getDebug() bool {
@@ -91,7 +77,6 @@ func logTermination(args ...interface{}) {
// Write the message to the termination log. This is not the default place
// that Kubernetes will look for termination information.
log.Debugf("Writing termination message: %v", msg)
// #nosec G306 - its a read by owner/s group, and pose no harm.
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
if err != nil {
log.Debug(err)

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2023
© Copyright IBM Corporation 2017, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -46,7 +46,6 @@ func logTermination(args ...interface{}) {
// Write the message to the termination log. This is not the default place
// that Kubernetes will look for termination information.
log.Debugf("Writing termination message: %v", msg)
// #nosec G306 - its a read by owner/s group, and pose no harm.
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
if err != nil {
log.Debug(err)
@@ -59,20 +58,7 @@ func logTermination(args ...interface{}) {
}
func getLogFormat() string {
logFormat := strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_FORMAT")))
//old-style env var is used.
if logFormat == "" {
logFormat = strings.ToLower(strings.TrimSpace(os.Getenv("LOG_FORMAT")))
}
if logFormat != "" && (logFormat == "basic" || logFormat == "json") {
return logFormat
} else {
//this is the case where value is either empty string or set to something other than "basic"/"json"
logFormat = "basic"
}
return logFormat
return os.Getenv("LOG_FORMAT")
}
// formatBasic formats a log message parsed from JSON, as "basic" text
@@ -95,94 +81,6 @@ func formatBasic(obj map[string]interface{}) string {
}
// Convert time zone information from some logs (e.g. Liberty) for consistency
obj["ibm_datetime"] = strings.Replace(obj["ibm_datetime"].(string), "+0000", "Z", 1)
// Escape any new-line characters, so that we don't get multi-line messages messing up the output
obj["message"] = strings.ReplaceAll(obj["message"].(string), "\n", "\\n")
if obj["type"] != nil && (obj["type"] == "liberty_trace") {
timeStamp := obj["ibm_datetime"]
threadID := ""
srtModuleName := ""
logLevel := ""
ibmClassName := ""
srtIbmClassName := ""
ibmMethodName := ""
message := ""
if obj["loglevel"] != nil {
//threadID is captured below
if obj["ibm_threadId"] != nil {
threadID = obj["ibm_threadId"].(string)
}
//logLevel character to be mirrored in console web server logging is decided below
logLevelTmp := obj["loglevel"].(string)
switch logLevelTmp {
case "AUDIT":
logLevel = "A"
case "INFO":
logLevel = "I"
case "EVENT":
logLevel = "1"
case "ENTRY":
logLevel = ">"
case "EXIT":
logLevel = "<"
case "FINE":
logLevel = "1"
case "FINER":
logLevel = "2"
case "FINEST":
logLevel = "3"
default:
logLevel = string(logLevelTmp[0])
}
//This is a 13 characters string present in extracted out of module node
if obj["module"] != nil {
srtModuleNameArr := strings.Split(obj["module"].(string), ".")
arrLen := len(srtModuleNameArr)
srtModuleName = srtModuleNameArr[arrLen-1]
if len(srtModuleName) > 13 {
srtModuleName = srtModuleName[0:13]
}
}
if obj["ibm_className"] != nil {
ibmClassName = obj["ibm_className"].(string)
//A 13 character string is extracted from class name. This is required for FINE, FINER & FINEST log lines
ibmClassNameArr := strings.Split(ibmClassName, ".")
arrLen := len(ibmClassNameArr)
srtIbmClassName = ibmClassNameArr[arrLen-1]
if len(srtModuleName) > 13 {
srtIbmClassName = srtIbmClassName[0:13]
}
}
if obj["ibm_methodName"] != nil {
ibmMethodName = obj["ibm_methodName"].(string)
}
if obj["message"] != nil {
message = obj["message"].(string)
}
//For AUDIT & INFO logging
if logLevel == "A" || logLevel == "I" {
return fmt.Sprintf("%s %s %-13s %s %s %s %s\n", timeStamp, threadID, srtModuleName, logLevel, ibmClassName, ibmMethodName, message)
}
//For EVENT logLevel
if logLevelTmp == "EVENT" {
return fmt.Sprintf("%s %s %-13s %s %s\n", timeStamp, threadID, srtModuleName, logLevel, message)
}
//For ENTRY & EXIT
if logLevel == ">" || logLevel == "<" {
return fmt.Sprintf("%s %s %-13s %s %s %s\n", timeStamp, threadID, srtModuleName, logLevel, ibmMethodName, message)
}
//For deeper log levels
if logLevelTmp == "FINE" || logLevel == "2" || logLevel == "3" {
return fmt.Sprintf("%s %s %-13s %s %s %s %s\n", timeStamp, threadID, srtIbmClassName, logLevel, ibmClassName, ibmMethodName, message)
}
}
}
return fmt.Sprintf("%s %s\n", obj["ibm_datetime"], obj["message"])
}
@@ -211,7 +109,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
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", fromStart, mf, true)
return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", false, mf, true)
}
func getDebug() bool {
@@ -233,11 +131,6 @@ func configureLogger(name string) (mirrorFunc, error) {
return nil, err
}
return func(msg string, isQMLog bool) bool {
arrLoggingConsoleExcludeIds := strings.Split(strings.ToUpper(os.Getenv("MQ_LOGGING_CONSOLE_EXCLUDE_ID")), ",")
if isExcludedMsgIdPresent(msg, arrLoggingConsoleExcludeIds) {
//If excluded id is present do not mirror it, return back
return false
}
// Check if the message is JSON
if len(msg) > 0 && msg[0] == '{' {
obj, err := processLogMessage(msg)
@@ -262,11 +155,6 @@ func configureLogger(name string) (mirrorFunc, error) {
return nil, err
}
return func(msg string, isQMLog bool) bool {
arrLoggingConsoleExcludeIds := strings.Split(strings.ToUpper(os.Getenv("MQ_LOGGING_CONSOLE_EXCLUDE_ID")), ",")
if isExcludedMsgIdPresent(msg, arrLoggingConsoleExcludeIds) {
//If excluded id is present do not mirror it, return back
return false
}
// Check if the message is JSON
if len(msg) > 0 && msg[0] == '{' {
// Parse the JSON message, and print a simplified version
@@ -277,7 +165,7 @@ func configureLogger(name string) (mirrorFunc, error) {
if err != nil {
log.Printf("Failed to unmarshall JSON in log message - %v", err)
} else {
fmt.Print(formatBasic(obj))
fmt.Printf(formatBasic(obj))
}
} else {
// The log being mirrored isn't JSON, so just print it.
@@ -309,16 +197,6 @@ func filterQMLogMessage(obj map[string]interface{}) bool {
return false
}
// Function to check if ids provided in MQ_LOGGING_CONSOLE_EXCLUDE_ID are present in given log line or not
func isExcludedMsgIdPresent(msg string, envExcludeIds []string) bool {
for _, id := range envExcludeIds {
if id != "" && strings.Contains(msg, strings.TrimSpace(id)) {
return true
}
}
return false
}
func logDiagnostics() {
if getDebug() {
log.Debug("--- Start Diagnostics ---")
@@ -360,73 +238,3 @@ func logDiagnostics() {
log.Debug("--- End Diagnostics ---")
}
}
// Returns the value of MQ_LOGGING_CONSOLE_SOURCE environment variable
func getMQLogConsoleSource() string {
return strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_SOURCE")))
}
// Function to check if valid values are provided for environment variable MQ_LOGGING_CONSOLE_SOURCE. If not valid, main program throws a warning to console
func isLogConsoleSourceValid() bool {
mqLogSource := getMQLogConsoleSource()
retValue := false
//If nothing is set, we will mirror qmgr, so valid
if mqLogSource == "" {
return true
}
logConsoleSource := strings.Split(mqLogSource, ",")
//This will find out if the environment variable contains permitted values and is comma separated
for _, src := range logConsoleSource {
switch strings.TrimSpace(src) {
//If it is a permitted value, it is valid. Keep it as true, but dont return it. We may encounter something junk soon
case "qmgr", "web", "":
retValue = true
//If invalid entry arrives in-between/anywhere, just return false, there is no turning back
default:
return false
}
}
return retValue
}
// To check which all logs have to be mirrored
func checkLogSourceForMirroring(source string) bool {
logsrcs := getMQLogConsoleSource()
//Nothing set, this is when we mirror qmgr
if logsrcs == "" {
if source == "qmgr" {
return true
} else {
return false
}
}
//Split the csv environment value so that we get an accurate comparison instead of a contains() check
logSrcArr := strings.Split(logsrcs, ",")
//Iterate through the array to decide on mirroring
for _, arr := range logSrcArr {
switch strings.TrimSpace(arr) {
case "qmgr":
//If value of source is qmgr and it exists in environment variable, mirror qmgr logs
if source == "qmgr" {
return true
}
case "web":
//If value of source is web and it exists in environment variable, and mirror web logs
if source == "web" {
//If older environment variable is set make sure to print appropriate message
if os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG") != "" {
log.Println("Environment variable MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG has now been replaced. Use MQ_LOGGING_CONSOLE_SOURCE instead.")
}
return true
}
}
}
return false
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020, 2023
© Copyright IBM Corporation 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package main
import (
"encoding/json"
"fmt"
"os"
"strings"
"testing"
)
@@ -54,86 +53,3 @@ func TestFormatBasic(t *testing.T) {
})
}
}
// This test covers for functions isLogConsoleSourceValid() & checkLogSourceForMirroring()
var mqLogSourcesTests = []struct {
testNum int
logsrc string
exptValid bool
exptQmgrSrc bool
exptWebSrc bool
}{
{1, "qmgr,web", true, true, true},
{2, "qmgr", true, true, false},
{3, "web,qmgr", true, true, true},
{4, "web", true, false, true},
{5, " ", true, true, false},
{6, "QMGR,WEB", true, true, true},
{7, "qmgr, ", true, true, false},
{8, "qmgr , web", true, true, true},
{9, "qmgr,dummy", false, true, false},
{10, "fake,dummy", false, false, false},
{11, "qmgr,fake,dummy", false, true, false},
{12, "fake,dummy,web", false, false, true},
{13, "true", false, false, false},
{14, "false", false, false, false},
{15, "", true, true, false},
}
func TestLoggingConsoleSourceInputs(t *testing.T) {
for _, mqlogsrctest := range mqLogSourcesTests {
err := os.Setenv("MQ_LOGGING_CONSOLE_SOURCE", mqlogsrctest.logsrc)
if err != nil {
t.Error(err)
}
isValid := isLogConsoleSourceValid()
if isValid != mqlogsrctest.exptValid {
t.Errorf("Expected return value from isLogConsoleSourceValid() is %v for MQ_LOGGING_CONSOLE_SOURCE='%v', got %v\n", mqlogsrctest.exptValid, mqlogsrctest.logsrc, isValid)
}
isLogSrcQmgr := checkLogSourceForMirroring("qmgr")
if isLogSrcQmgr != mqlogsrctest.exptQmgrSrc {
t.Errorf("Expected return value from checkLogSourceForMirroring() is %v for MQ_LOGGING_CONSOLE_SOURCE='%v', got %v\n", mqlogsrctest.exptQmgrSrc, mqlogsrctest.logsrc, isLogSrcQmgr)
}
isLogSrcWeb := checkLogSourceForMirroring("web")
if isLogSrcWeb != mqlogsrctest.exptWebSrc {
t.Errorf("Expected return value from checkLogSourceForMirroring() is %v for MQ_LOGGING_CONSOLE_SOURCE='%v', got %v\n", mqlogsrctest.exptWebSrc, mqlogsrctest.logsrc, isLogSrcWeb)
}
}
}
// This test covers for function isExcludedMsgIdPresent()
var mqExcludeIDTests = []struct {
testNum int
exculdeIDsArr []string
expectedRetVal bool
logEntry string
}{
{
1,
[]string{"AMQ5051I", "AMQ5037I", "AMQ5975I"},
true,
"{\"ibm_messageId\":\"AMQ5051I\",\"ibm_arithInsert1\":0,\"ibm_arithInsert2\":1,\"message\":\"AMQ5051I: The queue manager task 'AUTOCONFIG' has started.\"}",
},
{
2,
[]string{"AMQ5975I", "AMQ5037I"},
false,
"{\"ibm_messageId\":\"AMQ5051I\",\"ibm_arithInsert1\":0,\"ibm_arithInsert2\":1,\"message\":\"AMQ5051I: The queue manager task 'AUTOCONFIG' has started.\"}",
},
{
3,
[]string{""},
false,
"{\"ibm_messageId\":\"AMQ5051I\",\"ibm_arithInsert1\":0,\"ibm_arithInsert2\":1,\"message\":\"AMQ5051I: The queue manager task 'AUTOCONFIG' has started.\"}",
},
}
func TestIsExcludedMsgIDPresent(t *testing.T) {
for _, excludeIDTest := range mqExcludeIDTests {
retVal := isExcludedMsgIdPresent(excludeIDTest.logEntry, excludeIDTest.exculdeIDsArr)
if retVal != excludeIDTest.expectedRetVal {
t.Errorf("%v. Expected return value from isExcludedMsgIdPresent() is %v for MQ_LOGGING_CONSOLE_EXCLUDE_ID='%v', got %v\n",
excludeIDTest.testNum, excludeIDTest.expectedRetVal, excludeIDTest.exculdeIDsArr, retVal)
}
}
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2023
© Copyright IBM Corporation 2017, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@ import (
"os"
"sync"
"github.com/ibm-messaging/mq-container/internal/fips"
"github.com/ibm-messaging/mq-container/internal/ha"
"github.com/ibm-messaging/mq-container/internal/metrics"
"github.com/ibm-messaging/mq-container/internal/ready"
@@ -145,9 +144,6 @@ func doMain() error {
// Print out versioning information
logVersionInfo()
// Determine FIPS compliance level
fips.ProcessFIPSType(log)
keyLabel, defaultCmsKeystore, defaultP12Truststore, err := tls.ConfigureDefaultTLSKeystores()
if err != nil {
logTermination(err)
@@ -160,32 +156,6 @@ func doMain() error {
return err
}
//Validate MQ_LOG_CONSOLE_SOURCE variable
if !isLogConsoleSourceValid() {
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)
if err != nil {
logTermination(err)
@@ -200,9 +170,6 @@ func doMain() error {
}
}
// Post FIPS initialization processing
fips.PostInit(log)
enableTraceCrtmqm := os.Getenv("MQ_ENABLE_TRACE_CRTMQM")
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
err = startMQTrace()
@@ -226,25 +193,38 @@ func doMain() error {
}
}
//For mirroring mq system logs and qm logs, if environment variable is set
if checkLogSourceForMirroring("qmgr") {
//Mirror MQ system logs
_, err = mirrorSystemErrorLogs(ctx, &wg, mf)
if err != nil {
logTermination(err)
return err
}
//Mirror queue manager logs
_, err = mirrorQueueManagerErrorLogs(ctx, &wg, name, newQM, mf)
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()
}()
// TODO: Use the error channel
_, err = mirrorSystemErrorLogs(ctx, &wg, mf)
if err != nil {
logTermination(err)
return err
}
_, err = mirrorQueueManagerErrorLogs(ctx, &wg, name, newQM, mf)
if err != nil {
logTermination(err)
return err
}
if *devFlag {
_, err = mirrorHTPasswdLogs(ctx, &wg, name, newQM, mf)
if err != nil {
logTermination(err)
return err
}
}
if *devFlag {
_, err = mirrorHTPasswdLogs(ctx, &wg, name, newQM, mf)
// Recommended to use this option in conjunction with setting WLP_LOGGING_MESSAGE_FORMAT=JSON
mirrorWebLog := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG")
if mirrorWebLog == "true" || mirrorWebLog == "1" {
_, err = mirrorWebServerLogs(ctx, &wg, name, newQM, mf)
if err != nil {
logTermination(err)
return err

View File

@@ -95,7 +95,6 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
// the file is open before the queue manager is created or started.
// Otherwise, there would be the potential for a nearly-full file to
// rotate before the goroutine had a chance to open it.
// #nosec G304 - no harm, we open readonly and check error.
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
return nil, err
@@ -123,7 +122,6 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
return
}
log.Debugf("File exists: %v, %v", path, fi.Size())
// #nosec G304 - no harm, we open readonly and check error.
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
log.Error(err)
@@ -171,7 +169,6 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
}
// Re-open file
log.Debugf("Re-opening error log file %v", path)
// #nosec G304 - no harm, we open readonly and check error.
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
log.Error(err)

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package main
import (
"os"
"github.com/ibm-messaging/mq-container/internal/fips"
"github.com/ibm-messaging/mq-container/internal/tls"
)
@@ -26,15 +25,6 @@ import (
func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error {
enableWebServer := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER")
if enableWebServer == "true" || enableWebServer == "1" {
// Enable FIPS for MQ Web Server if asked for.
if fips.IsFIPSEnabled() {
err := configureFIPSWebServer(p12Truststore)
if err != nil {
return err
}
}
// Configure the web server (if enabled)
webKeystore, err := configureWebServer(keyLabel, p12Truststore)
if err != nil {
@@ -45,7 +35,6 @@ func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error {
if len(p12Truststore.TrustedCerts) == 0 {
webTruststoreRef = "MQWebKeyStore"
}
// Start the web server, in the background (if installed)
// WARNING: No error handling or health checking available for the web server
go func() {

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2023
© Copyright IBM Corporation 2017, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@ limitations under the License.
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
@@ -55,36 +54,23 @@ func createDirStructure() error {
func createQueueManager(name string, devMode bool) (bool, error) {
log.Printf("Creating queue manager %v", name)
// Run 'dspmqinf' to check if 'mqs.ini' configuration file exists
// If command succeeds, the queue manager (or standby queue manager) has already been created
_, _, err := command.Run("dspmqinf", name)
if err == nil {
log.Printf("Detected existing queue manager %v", name)
return false, nil
}
mounts, err := containerruntime.GetMounts()
if err != nil {
log.Printf("Error getting mounts for queue manager")
return false, err
}
dataDir := getQueueManagerDataDir(mounts, name)
// Run 'dspmqinf' to check if 'mqs.ini' configuration file exists
// If command succeeds, the queue manager (or standby queue manager) has already been created
_, _, err = command.Run("dspmqinf", name)
if err == nil {
log.Printf("Detected existing queue manager %v", name)
// Check if MQ_QMGR_LOG_FILE_PAGES matches the value set in qm.ini
lfp := os.Getenv("MQ_QMGR_LOG_FILE_PAGES")
if lfp != "" {
qmIniBytes, err := readQMIni(dataDir)
if err != nil {
log.Printf("Error reading qm.ini : %v", err)
return false, err
}
if !validateLogFilePageSetting(qmIniBytes, lfp) {
log.Println("Warning: the value of MQ_QMGR_LOG_FILE_PAGES does not match the value of 'LogFilePages' in the qm.ini. This setting cannot be altered after Queue Manager creation.")
}
}
return false, nil
}
// Check if 'qm.ini' configuration file exists for the queue manager
// TODO : handle possible race condition - use a file lock?
dataDir := getQueueManagerDataDir(mounts, name)
_, err = os.Stat(filepath.Join(dataDir, "qm.ini"))
if err != nil {
// If 'qm.ini' is not found - run 'crtmqm' to create a new queue manager
@@ -109,25 +95,6 @@ func createQueueManager(name string, devMode bool) (bool, error) {
return true, nil
}
//readQMIni reads the qm.ini file and returns it as a byte array
//This function is specific to comply with the nosec.
func readQMIni(dataDir string) ([]byte, error) {
qmgrDir := filepath.Join(dataDir, "qm.ini")
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
iniFileBytes, err := ioutil.ReadFile(qmgrDir)
if err != nil {
return nil, err
}
return iniFileBytes, err
}
//validateLogFilePageSetting validates if the specified logFilePage number is equal to the existing value in the qm.ini
func validateLogFilePageSetting(iniFileBytes []byte, logFilePages string) bool {
lfpString := "LogFilePages=" + logFilePages
qminiConfigStr := string(iniFileBytes)
return strings.Contains(qminiConfigStr, lfpString)
}
func updateCommandLevel() error {
level, ok := os.LookupEnv("MQ_CMDLEVEL")
if ok && level != "" {
@@ -164,18 +131,17 @@ func startQueueManager(name string) error {
func stopQueueManager(name string) error {
log.Println("Stopping queue manager")
qmGracePeriod := os.Getenv("MQ_GRACE_PERIOD")
status, err := ready.Status(context.Background(), name)
isStandby, err := ready.IsRunningAsStandbyQM(name)
if err != nil {
log.Printf("Error getting status for queue manager %v: %v", name, err.Error())
return err
}
isStandby := status.StandbyQM()
args := []string{"-w", "-r", "-tp", qmGracePeriod, name}
if os.Getenv("MQ_MULTI_INSTANCE") == "true" {
if isStandby {
args = []string{"-x", name}
} else {
args = []string{"-s", "-w", "-tp", qmGracePeriod, name}
args = []string{"-s", "-w", "-r", "-tp", qmGracePeriod, name}
}
}
out, rc, err := command.Run("endmqm", args...)
@@ -271,14 +237,6 @@ func getCreateQueueManagerArgs(mounts map[string]string, name string, devMode bo
if _, ok := mounts["/mnt/mqm-data"]; ok {
args = append(args, "-md", "/mnt/mqm-data/qmgrs")
}
if os.Getenv("MQ_QMGR_LOG_FILE_PAGES") != "" {
_, err = strconv.Atoi(os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
if err != nil {
log.Printf("Error processing MQ_QMGR_LOG_FILE_PAGES, the default value for LogFilePages will be used. Err: %v", err)
} else {
args = append(args, "-lf", os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
}
}
args = append(args, name)
return args
}
@@ -328,8 +286,7 @@ func updateQMini(qmname string) error {
if strings.Contains(qminiConfigStr, "ServiceComponent:") {
var re = regexp.MustCompile(`(?m)^.*ServiceComponent.*$\s^.*Service.*$\s^.*Name.*$\s^.*Module.*$\s^.*ComponentDataSize.*$`)
curFile := re.ReplaceAllString(qminiConfigStr, "")
// #nosec G304 G306 - qmgrDir filepath is derived from dspmqinf and
// its a read by owner/s group, and pose no harm.
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
err := ioutil.WriteFile(qmgrDir, []byte(curFile), 0660)
if err != nil {
return err

View File

@@ -1,86 +0,0 @@
/*
© Copyright IBM Corporation 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 main
import (
"io/ioutil"
"testing"
)
func Test_validateLogFilePageSetting(t *testing.T) {
type args struct {
iniFilePath string
isValid bool
logFilePagesValue string
}
tests := []struct {
name string
args args
}{
{
name: "TestLogFilePages1",
args: args{
iniFilePath: "./test-files/testvalidateLogFilePages_1.ini",
isValid: true,
logFilePagesValue: "1235",
},
},
{
name: "TestLogFilePages2",
args: args{
iniFilePath: "./test-files/testvalidateLogFilePages_2.ini",
isValid: true,
logFilePagesValue: "2224",
},
},
{
name: "TestLogFilePages3",
args: args{
iniFilePath: "./test-files/testvalidateLogFilePages_3.ini",
isValid: false,
logFilePagesValue: "1235",
},
},
{
name: "TestLogFilePages4",
args: args{
iniFilePath: "./test-files/testvalidateLogFilePages_4.ini",
isValid: false,
logFilePagesValue: "1235",
},
},
{
name: "TestLogFilePages5",
args: args{
iniFilePath: "./test-files/testvalidateLogFilePages_5.ini",
isValid: false,
logFilePagesValue: "1235",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
iniFileBytes, err := ioutil.ReadFile(tt.args.iniFilePath)
if err != nil {
t.Fatal(err)
}
validate := validateLogFilePageSetting(iniFileBytes, tt.args.logFilePagesValue)
if validate != tt.args.isValid {
t.Fatalf("Expected ini file validation output to be %v got %v", tt.args.isValid, validate)
}
})
}
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2022
© Copyright IBM Corporation 2017, 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -33,8 +33,8 @@ func signalHandler(qmgr string) chan int {
control := make(chan int)
// Use separate channels for the signals, to avoid SIGCHLD signals swamping
// the buffer, and preventing other signals.
stopSignals := make(chan os.Signal, 1)
reapSignals := make(chan os.Signal, 1)
stopSignals := make(chan os.Signal)
reapSignals := make(chan os.Signal)
signal.Notify(stopSignals, syscall.SIGTERM, syscall.SIGINT)
go func() {
for {

View File

@@ -1,9 +0,0 @@
ExitPath:
ExitsDefaultPath=/mnt/mqm/data/exits
ExitsDefaultPath64=/mnt/mqm/data/exits64
Log:
LogPrimaryFiles=3
LogSecondaryFiles=2
LogFilePages=1235
LogBufferPages=0
LogWriteIntegrity=TripleWrite

View File

@@ -1,9 +0,0 @@
ExitPath:
ExitsDefaultPath=/mnt/mqm/data/exits
ExitsDefaultPath64=/mnt/mqm/data/exits64
Log:
LogPrimaryFiles=3
LogSecondaryFiles=2
LogFilePages=2224
LogBufferPages=0
LogWriteIntegrity=TripleWrite

View File

@@ -1,9 +0,0 @@
ExitPath:
ExitsDefaultPath=/mnt/mqm/data/exits
ExitsDefaultPath64=/mnt/mqm/data/exits64
Log:
LogPrimaryFiles=3
LogSecondaryFiles=2
LogFilePages=6002
LogBufferPages=0
LogWriteIntegrity=TripleWrite

View File

@@ -1,8 +0,0 @@
ExitPath:
ExitsDefaultPath=/mnt/mqm/data/exits
ExitsDefaultPath64=/mnt/mqm/data/exits64
Log:
LogPrimaryFiles=3
LogSecondaryFiles=2
LogBufferPages=0
LogWriteIntegrity=TripleWrite

View File

@@ -1,8 +0,0 @@
ExitPath:
ExitsDefaultPath=/mnt/mqm/data/exits
ExitsDefaultPath64=/mnt/mqm/data/exits64
Log:
LogPrimaryFiles=3
LogSecondaryFiles=2
LogBufferPages=1235
LogWriteIntegrity=TripleWrite

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2022
© Copyright IBM Corporation 2018, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -197,25 +197,3 @@ func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string
return webKeystore, err
}
// Configure FIPS mode for MQ Web Server
func configureFIPSWebServer(p12TrustStore tls.KeyStoreData) error {
var errOut error
// Need to update jvm.options file of MQ Web Server. We don't update the jvm.options file
// in /etc/mqm/web/installations/Installation1/servers/mqweb directory. Instead we update
// the one in /etc/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults.
// During runtime MQ Web Server merges the data from two files.
mqwebJvmOptsDir := "/etc/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults"
_, errOut = os.Stat(mqwebJvmOptsDir)
if errOut == nil {
// Update the jvm.options file using the data from template file. Tell the MQ Web Server
// use a FIPS provider by setting "-Dcom.ibm.jsse2.usefipsprovider=true" and then tell it
// use a specific FIPS provider by setting "Dcom.ibm.jsse2.usefipsProviderName=IBMJCEPlusFIPS".
errOut = mqtemplate.ProcessTemplateFile(mqwebJvmOptsDir+"/jvm.options.tpl",
mqwebJvmOptsDir+"/jvm.options", map[string]string{
"FipsProvider": "true",
"FipsProviderName": "IBMJCEPlusFIPS",
}, log)
}
return errOut
}

View File

@@ -1,6 +1,6 @@
###########################################################################################################################################################
# MQ_VERSION is the fully qualified MQ version number to build
MQ_VERSION ?= 9.3.3.0
MQ_VERSION ?= 9.2.4.0
###########################################################################################################################################################

View File

@@ -12,6 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM fedora:41
FROM fedora:32
RUN yum install skopeo -y -qq
ENTRYPOINT [ "skopeo" ]

38
docs/building.md Executable file → Normal file
View File

@@ -4,44 +4,58 @@
You need to have the following tools installed:
* [Docker](https://www.docker.com/) 17.06.1 or later, or [Podman](https://podman.io) 1.0 or later (Podman 4.1 on macOS).
* [Docker](https://www.docker.com/) V17.06.1 or later, or [Podman](https://podman.io) V1.0 or later
* [GNU make](https://www.gnu.org/software/make/)
If you are working in the Windows Subsystem for Linux, follow [this guide by Microsoft to set up Docker](https://blogs.msdn.microsoft.com/commandline/2017/12/08/cross-post-wsl-interoperability-with-docker/) first.
You will also need a [Red Hat Account](https://access.redhat.com) to be able to access the Red Hat Registry.
## Building a production image
From MQ 9.2.X, the MQ container adds support for MQ Long Term Support (LTS) **production licensed** releases.
### Building MQ 9.3 Long Term Support (LTS) and Continuous Delivery (CD)
### MQ Continuous Delivery (CD)
**Note**: MQ 9.3 is the latest MQ version with MQ Long Term Support (LTS), as well as being the latest Continuous Delivery (CD) version.
The procedure below is for building the 9.3 release, on `amd64`, `ppc64le` and `s390x` architectures.
This procedure works for building the MQ Continuous Delivery release, on `amd64`, `ppc64le` and `s390x` architectures.
1. Create a `downloads` directory in the root of this repository
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/). Identify the correct 'Long Term Support Release for Containers' eImage part number for your architecture from the 9.3.0 LTS tab at https://www.ibm.com/support/pages/downloading-ibm-mq-930
3. Ensure the `tar.gz` file is in the `downloads` directory
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/) or [IBM Fix Central](https://www.ibm.com/support/fixcentral), and place the downloaded file (for example, `IBM_MQ_9.2.4_LINUX_X86-64_NOINST.tar.gz`) in the `downloads` directory
3. Login to the Red Hat Registry: `docker login registry.redhat.io` using your Customer Portal credentials.
4. Run `make build-advancedserver`
> **Warning**: Note that from MQ 9.2.X CD, the MQ container build uses a 'No-Install' MQ Package, available under `IBM MQ V9.2.x Continuous Delivery Release components eAssembly, part no. CJ7CNML`
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
```bash
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
```
### Building previous MQ Long Term Support (LTS)
### MQ Long Term Support (LTS)
**Note**: MQ 9.3 is the latest MQ version with MQ Long Term Support (LTS), as well as being the latest Continuous Delivery (CD) version. Therefore, to build build 9.3.0.X, follow the [instructions above for MQ 9.3](#building-mq-93-long-term-support-lts-and-continuous-delivery-cd).
This procedure works for building the MQ Long Term Support release, on `amd64`, `ppc64le` and `s390x` architectures.
However, if you wish to build the previous MQ LTS, use the [instructions](https://github.ibm.com/mq-cloudpak/mq-container/blob/v9.2.0.x-eus/docs/building.md#mq-long-term-support-lts) in the `v9.2.0.x-eus` branch.
1. Create a `downloads` directory in the root of this repository
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/) or [IBM Fix Central](https://www.ibm.com/support/fixcentral), and place the downloaded file (for example, `9.2.0.1-IBM-MQ-Advanced-Non-Install-LinuxX86.tar.gz`) in the `downloads` directory
3. Login to the Red Hat Registry: `docker login registry.redhat.io` using your Customer Portal credentials.
4. Run `LTS=true make build-advancedserver`
> **Warning**: Note that from MQ 9.2 LTS, the MQ container build uses a 'No-Install' MQ Package, available under `IBM MQ V9.2 Long Term Support Release components eAssembly, part no. CXXXXXX`
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
```bash
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 LTS=true make build-advancedserver
```
## Building a developer image
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers. This is available on the `amd64` and `arm64` (Apple Silicon) architectures.
Login to the Red Hat Registry: `docker login registry.redhat.io` using your Customer Portal credentials.
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers from IBM developerWorks. This is currently only available on the `amd64` architecture.
You can use the environment variable `MQ_ARCHIVE_DEV` to specify an alternative local file to install from (which must be in the `downloads` directory).
## Installed components
This image includes the core MQ server, Java, language packs, GSKit, and web server. This is configured in the `mq-redux` build stage in `Dockerfile-server`.
This image includes the core MQ server, Java, language packs, GSKit, and web server. This is configured in the `Generate MQ package in INSTALLATION_DIR` section [here](../install-mq.sh), with the configured options being picked up at build time.

View File

@@ -34,7 +34,7 @@ Two channels are created, one for administration, the other for normal messaging
## Web Console
By default the MQ Advanced for Developers image will start the IBM MQ Web Console that allows you to administer your Queue Manager running on your container. When the web console has been started, you can access it by opening a web browser and navigating to `https://<Container IP>:9443/ibmmq/console`. Where `<Container IP>` is replaced by the IP address of your running container.
By default the MQ Advanced for Developers image will start the IBM MQ Web Console that allows you to administer your Queue Manager running on your container. When the web console has been started, you can access it by opening a web browser and navigating to https://<Container IP>:9443/ibmmq/console. Where <Container IP> is replaced by the IP address of your running container.
When you navigate to this page you may be presented with a security exception warning. This happens because, by default, the web console creates a self-signed certificate to use for the HTTPS operations. This certificate is not trusted by your browser and has an incorrect distinguished name.

View File

@@ -16,5 +16,5 @@ docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--detach \
ibm-mqadvanced-server:9.3.3.0-amd64
ibm-mqadvanced-server:9.2.4.0-amd64
```

View File

@@ -2,9 +2,10 @@
## Prerequisites
You need to ensure you have the following tools installed:
* [Docker](https://www.docker.com/) 19.03 or higher (API version 1.40)
* [Docker](https://www.docker.com/)
* [GNU make](https://www.gnu.org/software/make/)
* [Go](https://golang.org/) - only needed for running the tests
* [dep](https://github.com/golang/dep) (official Go dependency management tool) - needed to prepare for running the tests
## Running the tests
There are two main sets of tests:
@@ -17,14 +18,14 @@ There are two main sets of tests:
The Docker tests can be run locally on a machine with Docker. For example:
```
make test-devserver
make test-advancedserver
make devserver
make advancedserver
```
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.3.0-amd64 make test-advancedserver
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.2.4.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:

View File

@@ -14,7 +14,7 @@ docker run \
--publish 1414:1414 \
--publish 9443:9443 \
--detach \
icr.io/ibm-messaging/mq
ibmcom/mq
```
## Running with the default configuration and a volume
@@ -34,7 +34,7 @@ docker run \
--publish 9443:9443 \
--detach \
--volume qm1data:/mnt/mqm \
icr.io/ibm-messaging/mq
ibmcom/mq
```
The Docker image always uses `/mnt/mqm` for MQ data, which is correctly linked for you under `/var/mqm` at runtime. This is to handle problems with file permissions on some platforms.
@@ -51,7 +51,7 @@ docker run \
--publish 9443:9443 \
--publish 9157:9157 \
--detach \
icr.io/ibm-messaging/mq
ibmcom/mq
```
## Customizing the queue manager configuration
@@ -60,14 +60,14 @@ You can customize the configuration in several ways:
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
3. By using [remote MQ administration](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.3.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
3. By using [remote MQ administration](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.2.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file:
```dockerfile
FROM icr.io/ibm-messaging/mq
FROM ibmcom/mq
USER 1001
COPY 20-config.mqsc /etc/mqm/
```
@@ -112,5 +112,3 @@ For example, if you have an identity certificate you wish to add with the label
This can be achieved by either mounting the directories or files into the container when you run it or by baking the files into the correct location in the image.
If you supply multiple identity certificates then the first label alphabetically will be chosen as the certificate to be used by the MQ Console and the default certificate for the queue manager. If you wish to use a different certificate on the queue manager then you can change the certificate to use at runtime by executing the MQSC command `ALTER QMGR CERTLABL('<newlabel>')`
It must be noted that queue manager certificate with a Subject Distinguished Name (DN) same as it's Issuer certificate (CA) is not supported. Certificates must have a unique Subject Distinguished Name.

View File

@@ -1,4 +1,4 @@
* © Copyright IBM Corporation 2019, 2022
* © Copyright IBM Corporation 2019
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,5 +16,4 @@
* Set the keystore location for the queue manager
ALTER QMGR SSLKEYR('{{ .SSLKeyR }}')
ALTER QMGR CERTLABL('{{ .CertificateLabel }}')
ALTER QMGR SSLFIPS({{ .SSLFips }})
REFRESH SECURITY(*) TYPE(SSL)

27
go.mod
View File

@@ -1,24 +1,17 @@
module github.com/ibm-messaging/mq-container
go 1.19
go 1.15
require (
github.com/genuinetools/amicontained v0.4.3
github.com/genuinetools/amicontained v0.4.0
github.com/genuinetools/pkg v0.0.0-20181022210355-2fcf164d37cb // indirect
github.com/ibm-messaging/mq-golang v2.0.0+incompatible
github.com/prometheus/client_golang v1.19.1
github.com/prometheus/client_model v0.6.1
golang.org/x/crypto v0.24.0
golang.org/x/sys v0.21.0
software.sslmate.com/src/go-pkcs12 v0.4.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/prometheus/client_golang v1.7.1
github.com/prometheus/client_model v0.2.0
github.com/prometheus/common v0.14.0 // indirect
github.com/prometheus/procfs v0.2.0 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
google.golang.org/protobuf v1.33.0 // indirect
golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001
)

344
go.sum
View File

@@ -1,29 +1,84 @@
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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/genuinetools/amicontained v0.4.0 h1:J70LMWTebQqQJQaQx9uAW82A6QQqe5ux9GMFgo3NAGY=
github.com/genuinetools/amicontained v0.4.0/go.mod h1:PAMZkg9CcUTa6gNyULQ6tOMTMEb2HTKJufvKeFqDw+o=
github.com/genuinetools/amicontained v0.4.3 h1:cqq9XiAHfWWY3dk8VU8bSJFu9yh8Il5coEdeTAPq72o=
github.com/genuinetools/amicontained v0.4.3/go.mod h1:PAMZkg9CcUTa6gNyULQ6tOMTMEb2HTKJufvKeFqDw+o=
github.com/genuinetools/amicontained v0.4.9 h1:/LvLdgD7iO3IPk7neqfcwB7ufoH7tG77u1pERXBIj7w=
github.com/genuinetools/pkg v0.0.0-20181022210355-2fcf164d37cb h1:9MQ4N7zyYTtdjLGqE5McDbgjIjqR5TAPc6lytEOdndc=
github.com/genuinetools/pkg v0.0.0-20181022210355-2fcf164d37cb/go.mod h1:XTcrCYlXPxnxL2UpnwuRn7tcaTn9HAhxFoFJucootk8=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -32,74 +87,187 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
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.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ibm-messaging/mq-golang v1.0.0 h1:NZHBQlJzAuNsVv09sooYgxBWPvRUX4L6wZIuOSumiKE=
github.com/ibm-messaging/mq-golang v2.0.0+incompatible h1:xAufRPYSzoRGaME2+x7LcW5+uvy/G3xL/3Sn3u+G/lY=
github.com/ibm-messaging/mq-golang v2.0.0+incompatible/go.mod h1:qjsZDb7m1oKnbPeDma2JVJTKgyCA91I4bcJ1qHY+gcA=
github.com/ibm-messaging/mq-golang v3.0.0+incompatible h1:Yc3c8emAyveT54uNDRMkgvS+EBAHeLNWHkc3hk5x+IY=
github.com/ibm-messaging/mq-golang v3.0.0+incompatible/go.mod h1:qjsZDb7m1oKnbPeDma2JVJTKgyCA91I4bcJ1qHY+gcA=
github.com/ibm-messaging/mq-golang/v5 v5.0.0-alpha h1:Bw2c+k+o9VTMXpiVBmX6PKOm/vPuihx6dO2knPAhkKc=
github.com/ibm-messaging/mq-golang/v5 v5.0.0-alpha/go.mod h1:ywCwmYbJOU/E0rl+z4GiNoxVMty68O+LVO39a1VMXrE=
github.com/ibm-messaging/mq-golang/v5 v5.1.2 h1:u0e1Vce2TNqJpH088vF77rDMsnMRWnGaOIlxZo4DMZc=
github.com/ibm-messaging/mq-golang/v5 v5.1.2/go.mod h1:ywCwmYbJOU/E0rl+z4GiNoxVMty68O+LVO39a1VMXrE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -107,65 +275,153 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae h1:duLSQW+DZ5MsXKX7kc4rXlq6/mmxz4G6ewJuBPlhRe0=
golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae/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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190125091013-d26f9f9a57f3/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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/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-20190227155943-e225da77a7e6/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ=
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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
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=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001 h1:AVd6O+azYjVQYW1l55IqkbL8/JxjrLtO6q4FCmV8N5c=
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View File

@@ -6,9 +6,6 @@ NativeHALocalInstance:
{{ if .CipherSpec }}
CipherSpec={{ .CipherSpec }}
{{- end }}
{{ if .SSLFipsRequired }}
SSLFipsRequired={{ .SSLFipsRequired }}
{{- end }}
{{- end }}
NativeHAInstance:
Name={{ .NativeHAInstance0_Name }}

View File

@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM ubuntu:24.04
FROM ubuntu:16.04
# The URL to download the MQ installer from in tar.gz format
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev911_ubuntu_x86-64.tar.gz

View File

@@ -1,4 +1,4 @@
* © Copyright IBM Corporation 2018, 2022
* © Copyright IBM Corporation 2018, 2019
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,5 +14,5 @@
* limitations under the License.
* Set the cipherspec for dev channels
ALTER CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12_OR_HIGHER) SSLCAUTH(OPTIONAL)
ALTER CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12_OR_HIGHER) SSLCAUTH(OPTIONAL)
ALTER CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12) SSLCAUTH(OPTIONAL)
ALTER CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12) SSLCAUTH(OPTIONAL)

View File

@@ -36,7 +36,6 @@
</basicRegistry>
<variable name="httpHost" value="*"/>
<variable name="managementMode" value="externallyprovisioned"/>
<variable name="mqConsoleRemoteSupportEnabled" value="false"/>
<variable name="mqConsoleEnableUnsafeInline" value="true"/>
<jndiEntry jndiName="mqConsoleDefaultCCDTHostname" value="${env.MQ_CONSOLE_DEFAULT_CCDT_HOSTNAME}"/>
<jndiEntry jndiName="mqConsoleDefaultCCDTPort" value="${env.MQ_CONSOLE_DEFAULT_CCDT_PORT}"/>

View File

@@ -21,8 +21,6 @@ set -ex
sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.1/dep-linux-$ARCH
sudo chmod +x /usr/local/bin/dep
sudo apt-get update || :
sudo apt-get install -y jq
go install golang.org/x/lint/golint@latest
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin v2.14.0 || echo "Gosec not installed. Platform may not be supported."
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin 2.0.0 || echo "Gosec not installed. Platform may not be supported."

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2023
# © Copyright IBM Corporation 2015, 2021
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,6 @@ test -f /usr/bin/yum && YUM=true || YUM=false
test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false
test -f /usr/bin/rpm && RPM=true || RPM=false
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
CPU_ARCH=$(uname -m)
if ($UBUNTU); then
export DEBIAN_FRONTEND=noninteractive
@@ -30,7 +29,8 @@ if ($UBUNTU); then
# This ensures no unsupported code gets installed, and makes the build faster
source /etc/os-release
# Figure out the correct apt URL based on the CPU architecture
if [ "${CPU_ARCH}" == "x86_64" ]; then
CPU_ARCH=$(uname -p)
if [ ${CPU_ARCH} == "x86_64" ]; then
APT_URL="http://archive.ubuntu.com/ubuntu/"
else
APT_URL="http://ports.ubuntu.com/ubuntu-ports/"
@@ -41,9 +41,25 @@ if ($UBUNTU); then
echo "deb ${APT_URL} ${UBUNTU_CODENAME}-updates 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
EXTRA_DEBS="bash bc ca-certificates coreutils curl debianutils file findutils gawk grep libc-bin mount passwd procps sed tar util-linux"
apt-get update
apt-get install -y --no-install-recommends ${EXTRA_DEBS}
apt-get install -y --no-install-recommends \
bash \
bc \
ca-certificates \
coreutils \
curl \
debianutils \
file \
findutils \
gawk \
grep \
libc-bin \
mount \
passwd \
procps \
sed \
tar \
util-linux
fi
if ($RPM); then

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2023
# © Copyright IBM Corporation 2015, 2020
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,49 @@ set -ex
test -f /usr/bin/rpm && RPM=true || RPM=false
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
# Only install the SDK package as part of the build stage
INSTALL_SDK=${INSTALL_SDK:-0}
# Download and extract the MQ unzippable server
DIR_TMP=/tmp/mq
mkdir -p ${DIR_TMP}
cd ${DIR_TMP}
curl -LO $MQ_URL
tar -xzf ./*.tar.gz
rm -f ./*.tar.gz
ls -la ${DIR_TMP}
# Generate MQ package in INSTALLATION_DIR
export genmqpkg_inc32=0
export genmqpkg_incadm=1
export genmqpkg_incamqp=0
export genmqpkg_incams=1
export genmqpkg_inccbl=0
export genmqpkg_inccics=0
export genmqpkg_inccpp=0
export genmqpkg_incdnet=0
export genmqpkg_incjava=1
export genmqpkg_incjre=1
export genmqpkg_incman=0
export genmqpkg_incmqbc=0
export genmqpkg_incmqft=0
export genmqpkg_incmqsf=0
export genmqpkg_incmqxr=0
export genmqpkg_incnls=1
export genmqpkg_incras=1
export genmqpkg_incsamp=1
export genmqpkg_incsdk=$INSTALL_SDK
export genmqpkg_inctls=1
export genmqpkg_incunthrd=0
export genmqpkg_incweb=1
export INSTALLATION_DIR=/opt/mqm
${DIR_TMP}/bin/genmqpkg.sh -b ${INSTALLATION_DIR}
ls -la ${INSTALLATION_DIR}
rm -rf ${DIR_TMP}
# Accept the MQ license
/opt/mqm/bin/mqlicense -accept
${INSTALLATION_DIR}/bin/mqlicense -accept
# Optional: Update the command prompt with the MQ version
$UBUNTU && echo "mq:$(dspmqver -b -f 2)" > /etc/debian_chroot
@@ -56,8 +97,8 @@ $RPM && PAM_FILE=/etc/pam.d/password-auth
sed -i 's/password\t\[success=1 default=ignore\]\tpam_unix\.so obscure sha512/password\t[success=1 default=ignore]\tpam_unix.so obscure sha512 minlen=8/' $PAM_FILE
# List all the installed packages, for the build log
$RPM && (rpm -q --all | sort) || true
$UBUNTU && (dpkg --list | sort) || true
$RPM && rpm -q --all || true
$UBUNTU && dpkg --list || true
#Update the license file to include UBI 8 instead of UBI 7
sed -i 's/v7.0/v8.0/g' /opt/mqm/licenses/non_ibm_license.txt

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2022
© Copyright IBM Corporation 2017, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ limitations under the License.
package command
import (
"context"
"fmt"
"os/exec"
)
@@ -28,13 +27,9 @@ import (
// Do not use this function to run shell built-ins (like "cd"), because
// the error handling works differently
func Run(name string, arg ...string) (string, int, error) {
return RunContext(context.Background(), name, arg...)
}
func RunContext(ctx context.Context, name string, arg ...string) (string, int, error) {
// Run the command and wait for completion
// #nosec G204
cmd := exec.CommandContext(ctx, name, arg...)
cmd := exec.Command(name, arg...)
out, err := cmd.CombinedOutput()
rc := cmd.ProcessState.ExitCode()
if err != nil {

View File

@@ -36,15 +36,12 @@ func CopyFileMode(src, dest string, perm os.FileMode) error {
if err != nil {
return fmt.Errorf("failed to open %s for copy: %v", src, err)
}
// #nosec G307 - local to this function, pose no harm.
defer in.Close()
// #nosec G304 - this func creates based on the input filemode.
out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, perm)
if err != nil {
return fmt.Errorf("failed to open %s for copy: %v", dest, err)
}
// #nosec G307 - local to this function, pose no harm.
defer out.Close()
_, err = io.Copy(out, in)

View File

@@ -1,96 +0,0 @@
/*
© Copyright IBM Corporation 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 fips
import (
"os"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/pkg/logger"
)
var (
FIPSEnabledType int
)
// FIPS has been turned off either because OS is not FIPS enabled or
// MQ_ENABLE_FIPS environment variable is set to "false"
const FIPS_ENABLED_OFF = 0
// FIPS is turned ON
const FIPS_ENABLED_ON = 1
// FIPS enabled at operating system level
const FIPS_ENABLED_PLATFORM = 1
// FIPS enabled via environment variable
const FIPS_ENABLED_ENV_VAR = 2
// Get FIPS enabled type.
func ProcessFIPSType(logs *logger.Logger) {
// Run "sysctl crypto.fips_enabled" command to determine if FIPS has been enabled
// on OS.
FIPSEnabledType = FIPS_ENABLED_OFF
out, _, err := command.Run("sysctl", "crypto.fips_enabled")
if err == nil {
// Check the output of the command for expected output
if strings.Contains(out, "crypto.fips_enabled = 1") {
FIPSEnabledType = FIPS_ENABLED_PLATFORM
}
}
// Check if we have been asked to override FIPS cryptography
fipsOverride, fipsOverrideSet := os.LookupEnv("MQ_ENABLE_FIPS")
if fipsOverrideSet {
if strings.EqualFold(fipsOverride, "false") || strings.EqualFold(fipsOverride, "0") {
FIPSEnabledType = FIPS_ENABLED_OFF
} else if strings.EqualFold(fipsOverride, "true") || strings.EqualFold(fipsOverride, "1") {
// This is the case where OS may or may not be FIPS compliant but we have been asked
// to run MQ queue manager, web server and Native HA in FIPS mode. This case can also
// be used when running docker tests. If FIPS is enabled on host, then don't modify
// the original value.
if FIPSEnabledType != FIPS_ENABLED_PLATFORM {
FIPSEnabledType = FIPS_ENABLED_ENV_VAR
}
} else if strings.EqualFold(fipsOverride, "auto") {
// This is the default case. Leave it to the OS default as determined above.
} else {
// We don't recognise the value specified. Log a warning and carry on.
if logs != nil {
logs.Printf("Invalid value '%s' was specified for MQ_ENABLE_FIPS. The value has been ignored.\n", fipsOverride)
}
}
}
}
func IsFIPSEnabled() bool {
return FIPSEnabledType > FIPS_ENABLED_OFF
}
// Log a message on the console to indicate FIPS certified
// cryptography being used.
func PostInit(log *logger.Logger) {
message := "FIPS cryptography is not enabled."
if FIPSEnabledType == FIPS_ENABLED_PLATFORM {
message = "FIPS cryptography is enabled. FIPS cryptography setting on the host is 'true'."
} else if FIPSEnabledType == FIPS_ENABLED_ENV_VAR {
message = "FIPS cryptography is enabled. FIPS cryptography setting on the host is 'false'."
}
log.Println(message)
}

View File

@@ -1,65 +0,0 @@
/*
© Copyright IBM Corporation 2022
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 keystore contains code to create and update keystores
package fips
import (
"fmt"
"os"
"testing"
)
func TestEnableFIPSAuto(t *testing.T) {
ProcessFIPSType(nil)
// Test default "auto"
fipsType := IsFIPSEnabled()
if fipsType {
t.Errorf("Expected FIPS OFF but got %v\n", fipsType)
}
}
func TestEnableFIPSTrue(t *testing.T) {
// Test MQ_ENABLE_FIPS=true
os.Setenv("MQ_ENABLE_FIPS", "true")
fmt.Println(os.Getenv("MQ_ENABLE_FIPS"))
ProcessFIPSType(nil)
fipsType := IsFIPSEnabled()
if !fipsType {
t.Errorf("Expected FIPS ON but got %v\n", fipsType)
}
}
func TestEnableFIPSFalse(t *testing.T) {
// Test MQ_ENABLE_FIPS=false
os.Setenv("MQ_ENABLE_FIPS", "false")
ProcessFIPSType(nil)
fipsType := IsFIPSEnabled()
if fipsType {
t.Errorf("Expected FIPS OFF but got %v\n", fipsType)
}
}
func TestEnableFIPSInvalid(t *testing.T) {
// Test MQ_ENABLE_FIPS with invalid value
os.Setenv("MQ_ENABLE_FIPS", "falseOff")
ProcessFIPSType(nil)
fipsType := IsFIPSEnabled()
if fipsType {
t.Errorf("Expected FIPS OFF but got %v\n", fipsType)
}
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020, 2023
© Copyright IBM Corporation 2020, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@ package ha
import (
"os"
"github.com/ibm-messaging/mq-container/internal/fips"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
"github.com/ibm-messaging/mq-container/internal/tls"
"github.com/ibm-messaging/mq-container/pkg/logger"
@@ -58,13 +57,6 @@ func ConfigureNativeHA(log *logger.Logger) error {
if ok {
templateMap["CipherSpec"] = cipherSpec
}
// If FIPS is enabled, then set SSLFipsRequired to Yes
if fips.IsFIPSEnabled() {
templateMap["SSLFipsRequired"] = "Yes"
} else {
templateMap["SSLFipsRequired"] = "No"
}
}
err := mqtemplate.ProcessTemplateFile(templateFile, file, templateMap, log)

View File

@@ -108,6 +108,5 @@ func (htpfile mapHtPasswd) updateHtPasswordFile(isTest bool) error {
if isTest {
file = "my.htpasswd"
}
// #nosec G306 - its a read by owner/s group, and pose no harm.
return ioutil.WriteFile(file, htpfile.GetBytes(), 0660)
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@ import (
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/fips"
)
// KeyStore describes information about a keystore file
@@ -35,46 +34,36 @@ type KeyStore struct {
Password string
keyStoreType string
command string
fipsEnabled bool
}
// NewJKSKeyStore creates a new Java Key Store, managed by the runmqckm command
func NewJKSKeyStore(filename, password string) *KeyStore {
keyStore := &KeyStore{
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "jks",
command: "/opt/mqm/bin/runmqckm",
fipsEnabled: fips.IsFIPSEnabled(),
}
return keyStore
}
// NewCMSKeyStore creates a new MQ CMS Key Store, managed by the runmqakm command
func NewCMSKeyStore(filename, password string) *KeyStore {
keyStore := &KeyStore{
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "cms",
command: "/opt/mqm/bin/runmqakm",
fipsEnabled: fips.IsFIPSEnabled(),
}
return keyStore
}
// NewPKCS12KeyStore creates a new PKCS12 Key Store, managed by the runmqakm command
func NewPKCS12KeyStore(filename, password string) *KeyStore {
keyStore := &KeyStore{
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "p12",
command: "/opt/mqm/bin/runmqakm",
fipsEnabled: fips.IsFIPSEnabled(),
}
return keyStore
}
// Create a key store, if it doesn't already exist
@@ -111,7 +100,7 @@ func (ks *KeyStore) Create() error {
}
// Create the keystore now we're sure it doesn't exist
out, _, err := command.Run(ks.command, "-keydb", "-create", ks.getFipsEnabledFlag(), "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password, "-stash")
out, _, err := command.Run(ks.command, "-keydb", "-create", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password, "-stash")
if err != nil {
return fmt.Errorf("error running \"%v -keydb -create\": %v %s", ks.command, err, out)
}
@@ -126,7 +115,7 @@ func (ks *KeyStore) CreateStash() error {
_, err := os.Stat(stashFile)
if err != nil {
if os.IsNotExist(err) {
out, _, err := command.Run(ks.command, "-keydb", ks.getFipsEnabledFlag(), "-stashpw", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
out, _, err := command.Run(ks.command, "-keydb", "-stashpw", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return fmt.Errorf("error running \"%v -keydb -stashpw\": %v %s", ks.command, err, out)
}
@@ -138,7 +127,7 @@ func (ks *KeyStore) CreateStash() error {
// Import imports a certificate file in the keystore
func (ks *KeyStore) Import(inputFile, password string) error {
out, _, err := command.Run(ks.command, "-cert", "-import", ks.getFipsEnabledFlag(), "-file", inputFile, "-pw", password, "-target", ks.Filename, "-target_pw", ks.Password, "-target_type", ks.keyStoreType)
out, _, err := command.Run(ks.command, "-cert", "-import", "-file", inputFile, "-pw", password, "-target", ks.Filename, "-target_pw", ks.Password, "-target_type", ks.keyStoreType)
if err != nil {
return fmt.Errorf("error running \"%v -cert -import\": %v %s", ks.command, err, out)
}
@@ -147,7 +136,7 @@ func (ks *KeyStore) Import(inputFile, password string) error {
// CreateSelfSignedCertificate creates a self-signed certificate in the keystore
func (ks *KeyStore) CreateSelfSignedCertificate(label, dn, hostname string) error {
out, _, err := command.Run(ks.command, "-cert", "-create", ks.getFipsEnabledFlag(), "-db", ks.Filename, "-pw", ks.Password, "-label", label, "-dn", dn, "-san_dnsname", hostname, "-size 2048 -sig_alg sha256 -eku serverAuth")
out, _, err := command.Run(ks.command, "-cert", "-create", "-db", ks.Filename, "-pw", ks.Password, "-label", label, "-dn", dn, "-san_dnsname", hostname, "-size 2048 -sig_alg sha256 -eku serverAuth")
if err != nil {
return fmt.Errorf("error running \"%v -cert -create\": %v %s", ks.command, err, out)
}
@@ -156,7 +145,7 @@ func (ks *KeyStore) CreateSelfSignedCertificate(label, dn, hostname string) erro
// Add adds a CA certificate to the keystore
func (ks *KeyStore) Add(inputFile, label string) error {
out, _, err := command.Run(ks.command, "-cert", "-add", ks.getFipsEnabledFlag(), "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile, "-label", label)
out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile, "-label", label)
if err != nil {
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
}
@@ -165,7 +154,7 @@ func (ks *KeyStore) Add(inputFile, label string) error {
// Add adds a CA certificate to the keystore
func (ks *KeyStore) AddNoLabel(inputFile string) error {
out, _, err := command.Run(ks.command, "-cert", "-add", ks.getFipsEnabledFlag(), "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile)
out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile)
if err != nil {
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
}
@@ -174,7 +163,7 @@ func (ks *KeyStore) AddNoLabel(inputFile string) error {
// GetCertificateLabels returns the labels of all certificates in the key store
func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
out, _, err := command.Run(ks.command, "-cert", "-list", ks.getFipsEnabledFlag(), "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
}
@@ -218,7 +207,7 @@ func (ks *KeyStore) RenameCertificate(from, to string) error {
// ListAllCertificates Lists all certificates in the keystore
func (ks *KeyStore) ListAllCertificates() ([]string, error) {
out, _, err := command.Run(ks.command, "-cert", "-list", ks.getFipsEnabledFlag(), "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
}
@@ -226,8 +215,6 @@ func (ks *KeyStore) ListAllCertificates() ([]string, error) {
var labels []string
for scanner.Scan() {
s := scanner.Text()
// Check for trusted certficates as well here as this method can
// be called for trusted store as well.
if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") || strings.HasPrefix(s, "!") {
s := strings.TrimLeft(s, "-*!")
labels = append(labels, strings.TrimSpace(s))
@@ -239,22 +226,3 @@ func (ks *KeyStore) ListAllCertificates() ([]string, error) {
}
return labels, nil
}
// Returns the FIPS flag. True if enabled else false
func (ks *KeyStore) IsFIPSEnabled() bool {
return ks.fipsEnabled
}
// Returns -fips option if FIPS is enabled otherwise empty string. Return value is used
// when running runmqakm/runmqckm commands.
func (ks *KeyStore) getFipsEnabledFlag() string {
var fipsEnabled string
if ks.fipsEnabled {
fipsEnabled = "-fips"
} else {
fipsEnabled = ""
}
return fipsEnabled
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -35,8 +35,6 @@ const (
var (
metricsEnabled = false
// #nosec G112 - this code is changing soon to use https.
// for now we will ignore the gosec.
metricsServer = &http.Server{Addr: ":" + defaultPort}
)
@@ -45,8 +43,8 @@ func GatherMetrics(qmName string, log *logger.Logger) {
// If running in standby mode - wait until the queue manager becomes active
for {
status, _ := ready.Status(context.Background(), qmName)
if status.ActiveQM() {
active, _ := ready.IsRunningAsActiveQM(qmName)
if active {
break
}
time.Sleep(requestTimeout * time.Second)

View File

@@ -48,10 +48,8 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
return err
}
}
// #nosec G302 G304 G306 - its a read by owner/s group, and pose no harm.
// #nosec G302
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
// #nosec G307 - local to this function, pose no harm.
defer f.Close()
err = t.Execute(f, data)
if err != nil {

View File

@@ -18,7 +18,6 @@ package mqversion
import (
"fmt"
"strconv"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
@@ -39,59 +38,14 @@ func Compare(checkVersion string) (int, error) {
if err != nil {
return 0, err
}
currentVRMF, err := parseVRMF(currentVersion)
if err != nil {
return 0, err
// trim any suffix from MQ version x.x.x.x
currentVersion = currentVersion[0:7]
if currentVersion < checkVersion {
return -1, nil
} else if currentVersion == checkVersion {
return 0, nil
} else if currentVersion > checkVersion {
return 1, nil
}
compareVRMF, err := parseVRMF(checkVersion)
if err != nil {
return 0, fmt.Errorf("failed to parse compare version: %w", err)
}
return currentVRMF.compare(*compareVRMF), nil
}
type vrmf [4]int
func (v vrmf) String() string {
return fmt.Sprintf("%d.%d.%d.%d", v[0], v[1], v[2], v[3])
}
func (v vrmf) compare(to vrmf) int {
for idx := 0; idx < 4; idx++ {
if v[idx] < to[idx] {
return -1
}
if v[idx] > to[idx] {
return 1
}
}
return 0
}
func parseVRMF(vrmfString string) (*vrmf, error) {
versionParts := strings.Split(vrmfString, ".")
if len(versionParts) != 4 {
return nil, fmt.Errorf("incorrect number of parts to version string: expected 4, got %d", len(versionParts))
}
vmrfPartNames := []string{"version", "release", "minor", "fix"}
parsed := vrmf{}
for idx, value := range versionParts {
partName := vmrfPartNames[idx]
if value == "" {
return nil, fmt.Errorf("empty %s found in VRMF", partName)
}
val, err := strconv.Atoi(value)
if err != nil {
return nil, fmt.Errorf("non-numeric %s found in VRMF", partName)
}
if val < 0 {
return nil, fmt.Errorf("negative %s found in VRMF", partName)
}
if idx == 0 && val == 0 {
return nil, fmt.Errorf("zero value for version not allowed")
}
parsed[idx] = val
}
return &parsed, nil
return 0, fmt.Errorf("Failed to compare MQ versions")
}

View File

@@ -16,13 +16,10 @@ limitations under the License.
package mqversion
import (
"fmt"
"testing"
)
import "testing"
func TestCompareLower(t *testing.T) {
checkVersion := "99.99.99.99"
checkVersion := "9.9.9.9"
mqVersionCheck, err := Compare(checkVersion)
if err != nil {
t.Fatalf("Failed to compare MQ versions: %v", err)
@@ -56,92 +53,3 @@ func TestCompareEqual(t *testing.T) {
t.Errorf("MQ version compare result failed. Expected 0, Got %v", mqVersionCheck)
}
}
func TestVersionValid(t *testing.T) {
checkVersion, err := Get()
if err != nil {
t.Fatalf("Failed to get current MQ version: %v", err)
}
_, err = parseVRMF(checkVersion)
if err != nil {
t.Fatalf("Validation of MQ version failed: %v", err)
}
}
func TestValidVRMF(t *testing.T) {
validVRMFs := map[string]vrmf{
"1.0.0.0": {1, 0, 0, 0},
"10.0.0.0": {10, 0, 0, 0},
"1.10.0.0": {1, 10, 0, 0},
"1.0.10.0": {1, 0, 10, 0},
"1.0.0.10": {1, 0, 0, 10},
"999.998.997.996": {999, 998, 997, 996},
}
for test, expect := range validVRMFs {
t.Run(test, func(t *testing.T) {
parsed, err := parseVRMF(test)
if err != nil {
t.Fatalf("Unexpectedly failed to parse VRMF '%s': %s", test, err.Error())
}
if *parsed != expect {
t.Fatalf("VRMF not parsed as expected. Expected '%v', got '%v'", parsed, expect)
}
})
}
}
func TestInvalidVRMF(t *testing.T) {
invalidVRMFs := []string{
"not-a-number",
"9.8.7.string",
"0.1.2.3",
"1.0.0.-10",
}
for _, test := range invalidVRMFs {
t.Run(test, func(t *testing.T) {
parsed, err := parseVRMF(test)
if err == nil {
t.Fatalf("Expected error when parsing VRMF '%s', but got none. VRMF returned: %v", test, parsed)
}
})
}
}
func TestCompare(t *testing.T) {
tests := []struct {
current string
compare string
expect int
}{
{"1.0.0.1", "1.0.0.1", 0},
{"1.0.0.1", "1.0.0.0", 1},
{"1.0.0.1", "1.0.0.2", -1},
{"9.9.9.9", "10.0.0.0", -1},
{"9.9.9.9", "9.10.0.0", -1},
{"9.9.9.9", "9.9.10.0", -1},
{"9.9.9.9", "9.9.9.10", -1},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%s-%s", test.current, test.compare), func(t *testing.T) {
baseVRMF, err := parseVRMF(test.current)
if err != nil {
t.Fatalf("Could not parse base version '%s': %s", test.current, err.Error())
}
compareVRMF, err := parseVRMF(test.compare)
if err != nil {
t.Fatalf("Could not parse current version '%s': %s", test.current, err.Error())
}
result := baseVRMF.compare(*compareVRMF)
if result != test.expect {
t.Fatalf("Expected %d but got %d when comparing '%s' with '%s'", test.expect, result, test.current, test.compare)
}
if test.expect == 0 {
return
}
resultReversed := compareVRMF.compare(*baseVRMF)
if resultReversed != test.expect*-1 {
t.Fatalf("Expected %d but got %d when comparing '%s' with '%s'", test.expect*-1, resultReversed, test.compare, test.current)
}
})
}
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ limitations under the License.
package ready
import (
"context"
"io/ioutil"
"os"
"strings"
@@ -54,7 +53,6 @@ func Clear() error {
// Set lets any subsequent calls to `CheckReady` know that the queue
// manager has finished its configuration step
func Set() error {
// #nosec G306 - this gives permissions to owner/s group only.
return ioutil.WriteFile(fileName, []byte("1"), 0770)
}
@@ -68,38 +66,28 @@ func Check() (bool, error) {
return exists, nil
}
// Status returns an enum representing the current running status of the queue manager
func Status(ctx context.Context, name string) (QMStatus, error) {
out, _, err := command.RunContext(ctx, "dspmq", "-n", "-m", name)
if err != nil {
return StatusUnknown, err
}
if strings.Contains(string(out), "(RUNNING)") {
return StatusActiveQM, nil
}
if strings.Contains(string(out), "(RUNNING AS STANDBY)") {
return StatusStandbyQM, nil
}
if strings.Contains(string(out), "(REPLICA)") {
return StatusStandbyQM, nil
}
return StatusUnknown, nil
// IsRunningAsActiveQM returns true if the queue manager is running in active mode
func IsRunningAsActiveQM(name string) (bool, error) {
return isRunningQM(name, "(RUNNING)")
}
type QMStatus int
// IsRunningAsStandbyQM returns true if the queue manager is running in standby mode
func IsRunningAsStandbyQM(name string) (bool, error) {
return isRunningQM(name, "(RUNNING AS STANDBY)")
}
const (
StatusUnknown QMStatus = iota
StatusActiveQM
StatusStandbyQM
StatusReplicaQM
)
// IsRunningAsReplicaQM returns true if the queue manager is running in replica mode
func IsRunningAsReplicaQM(name string) (bool, error) {
return isRunningQM(name, "(REPLICA)")
}
// ActiveQM returns true if the queue manager is running in active mode
func (s QMStatus) ActiveQM() bool { return s == StatusActiveQM }
// StandbyQM returns true if the queue manager is running in standby mode
func (s QMStatus) StandbyQM() bool { return s == StatusStandbyQM }
// ReplicaQM returns true if the queue manager is running in replica mode
func (s QMStatus) ReplicaQM() bool { return s == StatusReplicaQM }
func isRunningQM(name string, status string) (bool, error) {
out, _, err := command.Run("dspmq", "-n", "-m", name)
if err != nil {
return false, err
}
if strings.Contains(string(out), status) {
return true, nil
}
return false, nil
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2019, 2023
© Copyright IBM Corporation 2019, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -76,20 +76,18 @@ type TLSStore struct {
Truststore KeyStoreData
}
func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool, nativeTLSHA bool) (string, KeyStoreData, KeyStoreData, error) {
var keyLabel string
func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool) (string, KeyStoreData, KeyStoreData, error) {
// Create the CMS Keystore & PKCS#12 Truststore (if required)
tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired, nativeTLSHA)
tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired)
if err != nil {
return "", tlsStore.Keystore, tlsStore.Truststore, err
}
if tlsStore.Keystore.Keystore != nil {
// Process all keys - add them to the CMS KeyStore
keyLabel, err = processKeys(&tlsStore, keystoreDir, keyDir)
if err != nil {
return "", tlsStore.Keystore, tlsStore.Truststore, err
}
// Process all keys - add them to the CMS KeyStore
keyLabel, err := processKeys(&tlsStore, keystoreDir, keyDir)
if err != nil {
return "", tlsStore.Keystore, tlsStore.Truststore, err
}
// Process all trust certificates - add them to the CMS KeyStore & PKCS#12 Truststore (if required)
@@ -103,13 +101,13 @@ func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRe
// ConfigureDefaultTLSKeystores configures the CMS Keystore & PKCS#12 Truststore
func ConfigureDefaultTLSKeystores() (string, KeyStoreData, KeyStoreData, error) {
return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true, false)
return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true)
}
// ConfigureHATLSKeystore configures the CMS Keystore & PKCS#12 Truststore
func ConfigureHATLSKeystore() (string, KeyStoreData, KeyStoreData, error) {
// *.crt files mounted to the HA TLS dir keyDirHA will be processed as trusted in the CMS keystore
return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false, true)
return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false)
}
// ConfigureTLS configures TLS for the queue manager
@@ -117,26 +115,10 @@ func ConfigureTLS(keyLabel string, cmsKeystore KeyStoreData, devMode bool, log *
const mqsc string = "/etc/mqm/15-tls.mqsc"
const mqscTemplate string = mqsc + ".tpl"
sslKeyRing := ""
var fipsEnabled = "NO"
// Don't set SSLKEYR if no keys or crts are not supplied
// Key label will be blank if no private keys were added during processing keys and certs.
if cmsKeystore.Keystore != nil && len(keyLabel) > 0 {
certList, _ := cmsKeystore.Keystore.ListAllCertificates()
if len(certList) > 0 {
sslKeyRing = strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb")
}
if cmsKeystore.Keystore.IsFIPSEnabled() {
fipsEnabled = "YES"
}
}
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
"SSLKeyR": sslKeyRing,
"SSLKeyR": strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb"),
"CertificateLabel": keyLabel,
"SSLFips": fipsEnabled,
}, log)
if err != nil {
return err
@@ -177,7 +159,7 @@ func configureTLSDev(log *logger.Logger) error {
}
// generateAllKeystores creates the CMS Keystore & PKCS#12 Truststore (if required)
func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool, nativeTLSHA bool) (TLSStore, error) {
func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool) (TLSStore, error) {
var cmsKeystore, p12Truststore KeyStoreData
@@ -193,19 +175,11 @@ func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool, native
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create Keystore directory: %v", err)
}
// Search the default keys directory for any keys/certs.
keysDirectory := keyDirDefault
// Change to default native HA TLS directory if we are configuring nativeHA
if nativeTLSHA {
keysDirectory = keyDirHA
}
// Create the CMS Keystore if we have been provided keys and certificates
if haveKeysAndCerts(keysDirectory) || haveKeysAndCerts(trustDirDefault) {
cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password)
err = cmsKeystore.Keystore.Create()
if err != nil {
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err)
}
// Create the CMS Keystore
cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password)
err = cmsKeystore.Keystore.Create()
if err != nil {
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err)
}
// Create the PKCS#12 Truststore (if required)
@@ -229,6 +203,7 @@ func processKeys(tlsStore *TLSStore, keystoreDir string, keyDir string) (string,
// Process all keys
keyList, err := ioutil.ReadDir(keyDir)
if err == nil && len(keyList) > 0 {
// Process each set of keys - each set should contain files: *.key & *.crt
for _, keySet := range keyList {
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, keySet.Name()))
@@ -255,19 +230,11 @@ func processKeys(tlsStore *TLSStore, keystoreDir string, keyDir string) (string,
return "", err
}
// Validate certificates for duplicate Subject DNs
if len(caCertificate) > 0 {
errCertValid := validateCertificates(publicCertificate, caCertificate)
if errCertValid != nil {
return "", errCertValid
}
}
// Create a new PKCS#12 Keystore - containing private key, public certificate & optional CA certificate
file, err := pkcs.Encode(rand.Reader, privateKey, publicCertificate, caCertificate, tlsStore.Keystore.Password)
if err != nil {
return "", fmt.Errorf("Failed to encode PKCS#12 Keystore %s: %v", keySet.Name()+".p12", err)
}
// #nosec G306 - this gives permissions to owner/s group only.
err = ioutil.WriteFile(filepath.Join(keystoreDir, keySet.Name()+".p12"), file, 0644)
if err != nil {
return "", fmt.Errorf("Failed to write PKCS#12 Keystore %s: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
@@ -571,7 +538,6 @@ func generateRandomPassword() string {
validcharArray := []byte(validChars)
password := ""
for i := 0; i < 12; i++ {
// #nosec G404 - this is only for internal keystore and using math/rand pose no harm.
password = password + string(validcharArray[pwr.Intn(len(validcharArray))])
}
@@ -616,13 +582,10 @@ func getCertificateFingerprint(block *pem.Block) (string, error) {
// writeCertificatesToFile writes a list of certificates to a file
func writeCertificatesToFile(file string, certificates []*pem.Block) error {
// #nosec G304 - this is a temporary pem file to write certs.
f, err := os.Create(file)
if err != nil {
return fmt.Errorf("Failed to create file %s: %v", file, err)
}
// #nosec G307 - local to this function, pose no harm.
defer f.Close()
w := bufio.NewWriter(f)
@@ -639,39 +602,3 @@ func writeCertificatesToFile(file string, certificates []*pem.Block) error {
}
return nil
}
// Search the specified directory for .key and .crt files.
// Return true if at least one .key or .crt file is found else false
func haveKeysAndCerts(keyDir string) bool {
fileList, err := os.ReadDir(keyDir)
if err == nil && len(fileList) > 0 {
for _, fileInfo := range fileList {
// Keys and certs will be supplied in an user defined subdirectory.
// Do a listing of the subdirectory and then search for .key and .cert files
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, fileInfo.Name()))
for _, key := range keys {
if strings.HasSuffix(key.Name(), ".key") || strings.HasSuffix(key.Name(), ".crt") {
// We found at least one key/crt file.
return true
}
}
}
}
return false
}
// Iterate through the certificates to ensure there are no two certificates with same Subject DN.
// GSKit does not allow two certificates with same Subject DN/Friendly Names
func validateCertificates(personalCert *x509.Certificate, caCertificates []*x509.Certificate) error {
// Check if we have been asked to override certificate validation by setting
// MQ_ENABLE_CERT_VALIDATION to false
enableValidation, enableValidationSet := os.LookupEnv("MQ_ENABLE_CERT_VALIDATION")
if !enableValidationSet || (enableValidationSet && !strings.EqualFold(strings.Trim(enableValidation, ""), "false")) {
for _, caCert := range caCertificates {
if strings.EqualFold(personalCert.Subject.String(), caCert.Subject.String()) {
return fmt.Errorf("Error: The Subject DN of the Issuer Certificate and the Queue Manager are same")
}
}
}
return nil
}

View File

@@ -65,6 +65,7 @@ func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (strin
// Check if a new self-signed certificate should be generated
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
if genHostName != "" {
// Create the Web Keystore
newWebKeystore := keystore.NewPKCS12KeyStore(webKeystoreFile, p12Truststore.Password)
err := newWebKeystore.Create()
@@ -77,6 +78,7 @@ func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (strin
if err != nil {
return "", fmt.Errorf("Failed to generate certificate in Web Keystore %s with DN of 'CN=%s': %v", webKeystoreFile, genHostName, err)
}
} else {
// Check Web Keystore already exists
_, err := os.Stat(webKeystoreFile)

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2023
© Copyright IBM Corporation 2017, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -102,10 +102,5 @@ func LogContainerDetails(log *logger.Logger) error {
}
}
}
if os.Getenv("MQ_LOGGING_CONSOLE_FORMAT") == "" && os.Getenv("LOG_FORMAT") != "" {
log.Println("Environment variable LOG_FORMAT is deprecated. Use MQ_LOGGING_CONSOLE_FORMAT instead.")
}
return nil
}

View File

@@ -1,3 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

View File

@@ -1,7 +0,0 @@
###########################################################################################################################################################
# SOURCE_BRANCH is the repository branch name for this release stream.
# It should be updated when a new release fork is created but not for testing of personal builds or pre-fork updates.
SOURCE_BRANCH ?= private-master
###########################################################################################################################################################

View File

@@ -1,669 +0,0 @@
/*
© 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
}

View File

@@ -1,760 +0,0 @@
//go:build mqdev
// +build mqdev
/*
© Copyright IBM Corporation 2018, 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 main
import (
"crypto/tls"
"fmt"
"path/filepath"
"strings"
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
)
// 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.
func TestDevGoldenPath(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
qm := "qm1"
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + qm,
"DEBUG=true",
},
}
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443, 1414})
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
waitForWebReady(t, cli, id, insecureTLSConfig)
t.Run("JMS", func(t *testing.T) {
// Run the JMS tests, with no password specified.
// Use OpenJDK JRE for running testing, pass false for 7th parameter.
// Last parameter is blank as the test doesn't use TLS.
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS, "false", "")
})
t.Run("REST admin", func(t *testing.T) {
testRESTAdmin(t, cli, id, insecureTLSConfig, "")
})
t.Run("REST messaging", func(t *testing.T) {
testRESTMessaging(t, cli, id, insecureTLSConfig, qm, "app", defaultAppPasswordWeb, "")
})
// Stop the container cleanly
stopContainer(t, cli, id)
}
// TestDevSecure tests the default developer config using the a custom TLS key store and password.
// Note: This test requires a separate container image to be available for the JMS tests
func TestDevSecure(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
const tlsPassPhrase string = "passw0rd"
qm := "qm1"
appPassword := "differentPassw0rd"
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + qm,
"MQ_APP_PASSWORD=" + appPassword,
"DEBUG=1",
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
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
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 {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
cert := filepath.Join(tlsDir(t, true), "server.crt")
waitForWebReady(t, cli, ID, createTLSConfig(t, cert, tlsPassPhrase))
t.Run("JMS", func(t *testing.T) {
// OpenJDK is used for running tests, hence pass "false" for 7th parameter.
// Cipher name specified is compliant with non-IBM JRE naming.
runJMSTests(t, cli, ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
})
t.Run("REST admin", func(t *testing.T) {
testRESTAdmin(t, cli, ID, insecureTLSConfig, "")
})
t.Run("REST messaging", func(t *testing.T) {
testRESTMessaging(t, cli, ID, insecureTLSConfig, qm, "app", appPassword, "")
})
// Stop the container cleanly
stopContainer(t, cli, ID)
}
func TestDevWebDisabled(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=qm1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
},
}
id := runContainerWithPorts(t, cli, &containerConfig, []int{1414})
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
t.Run("Web", func(t *testing.T) {
_, dspmqweb := cli.ExecContainer(id, "", []string{"dspmqweb"})
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.Run("JMS", func(t *testing.T) {
// Run the JMS tests, with no password specified
// OpenJDK is used for running tests, hence pass "false" for 7th parameter.
// Last parameter is blank as the test doesn't use TLS.
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS, "false", "")
})
// Stop the container cleanly
stopContainer(t, cli, id)
}
func TestDevConfigDisabled(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=qm1",
"MQ_DEV=false",
},
}
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
waitForWebReady(t, cli, id, insecureTLSConfig)
rc, _ := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"})
if rc == 0 {
t.Errorf("Expected DEV queues to be missing")
}
// Stop the container cleanly
stopContainer(t, cli, id)
}
// Test if SSLKEYR and CERTLABL attributes are not set when key and certificate
// are not supplied.
func TestSSLKEYRBlank(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
},
}
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
// Search the console output for exepcted values
_, sslkeyROutput := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
if !strings.Contains(sslkeyROutput, "SSLKEYR( )") || !strings.Contains(sslkeyROutput, "CERTLABL( )") {
// 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.
waitCount := 30
var i int
for i = 0; i < waitCount; i++ {
time.Sleep(1 * time.Second)
_, sslkeyROutput = execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
if strings.Contains(sslkeyROutput, "SSLKEYR( )") && strings.Contains(sslkeyROutput, "CERTLABL( )") {
break
}
}
// Failed to get expected output? dump the contents of mqsc files.
if i == waitCount {
_, tls15mqsc := execContainer(t, cli, id, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
_, autoMQSC := execContainer(t, cli, id, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
t.Errorf("Expected SSLKEYR to be blank but it is not; got \"%v\"\n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
}
}
// Stop the container cleanly
stopContainer(t, cli, id)
}
// Test if SSLKEYR and CERTLABL attributes are set when key and certificate
// are supplied.
func TestSSLKEYRWithSuppliedKeyAndCert(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
},
}
networkingConfig := ce.ContainerNetworkSettings{}
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
// Search the console output for exepcted values
_, 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)") {
// 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.
waitCount := 30
var i int
for i = 0; i < waitCount; i++ {
time.Sleep(1 * time.Second)
_, 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)") {
break
}
}
// Failed to get expected output? dump the contents of mqsc files.
if i == waitCount {
_, tls15mqsc := execContainer(t, cli, ID, "", []string{"cat", "/etc/mqm/15-tls.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)
}
}
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// Test with CA cert
func TestSSLKEYRWithCACert(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDirWithCA(t, false) + ":/etc/mqm/pki/keys/QM1CA",
},
}
// Assign a random port for the web server on the host
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 {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
// Search the console output for exepcted values
_, sslkeyROutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
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.
// Hence wait for a second and retry few times before giving up.
waitCount := 30
var i int
for i = 0; i < waitCount; i++ {
time.Sleep(1 * time.Second)
_, sslkeyROutput = execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
if strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
break
}
}
// Failed to get expected output? dump the contents of mqsc files.
if i == waitCount {
_, tls15mqsc := execContainer(t, cli, ID, "", []string{"cat", "/etc/mqm/15-tls.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)
}
}
if !strings.Contains(sslkeyROutput, "CERTLABL(QM1CA)") {
_, 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)
}
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=false
func TestSSLFIPSNO(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
"MQ_ENABLE_FIPS=false",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
},
}
networkingConfig := ce.ContainerNetworkSettings{}
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
// Search the console output for exepcted values
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
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)
}
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
}
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
}
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// Verifies SSLFIPS is set to YES if certificates for queue manager
// are supplied and MQ_ENABLE_FIPS=true
func TestSSLFIPSYES(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
appPassword := "differentPassw0rd"
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_APP_PASSWORD=" + appPassword,
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
"MQ_ENABLE_FIPS=true",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
},
}
var binding ce.PortBinding
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 {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
// Check for expected message on container log
logs := inspectLogs(t, cli, ID)
if !strings.Contains(logs, "FIPS cryptography is enabled.") {
t.Errorf("Expected 'FIPS cryptography is enabled.' but got %v\n", logs)
}
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
// Search the console output for exepcted values
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
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)
}
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
}
if !strings.Contains(sslFIPSOutput, "SSLFIPS(YES)") {
t.Errorf("Expected SSLFIPS to be 'YES' but it is not; got \"%v\"", sslFIPSOutput)
}
t.Run("JMS", func(t *testing.T) {
// Run the JMS tests, with no password specified
runJMSTests(t, cli, ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
})
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// TestDevSecureFIPSYESWeb verifies if the MQ Web Server is running in FIPS mode
func TestDevSecureFIPSTrueWeb(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
const tlsPassPhrase string = "passw0rd"
qm := "qm1"
appPassword := "differentPassw0rd"
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + qm,
"MQ_APP_PASSWORD=" + appPassword,
"DEBUG=1",
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
"MQ_ENABLE_FIPS=true",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t, false) + ":/etc/mqm/pki/keys/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
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 {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
cert := filepath.Join(tlsDir(t, true), "server.crt")
waitForWebReady(t, cli, ID, createTLSConfig(t, cert, tlsPassPhrase))
// 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})
// Put a message to queue
t.Run("REST messaging", func(t *testing.T) {
testRESTMessaging(t, cli, ID, secureTLSConfig, qm, "app", appPassword, "")
})
// 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})
// 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) {
testRESTMessaging(t, cli, ID, secureNonFIPSCipherConfig, qm, "app", appPassword, "EOF")
})
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// TestDevSecureNOFIPSWeb verifies if the MQ Web Server is not running in FIPS mode
func TestDevSecureFalseFIPSWeb(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
const tlsPassPhrase string = "passw0rd"
qm := "qm1"
appPassword := "differentPassw0rd"
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + qm,
"MQ_APP_PASSWORD=" + appPassword,
"DEBUG=1",
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
"MQ_ENABLE_FIPS=false",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
},
}
// Assign a random port for the web server on the host
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 {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
cert := filepath.Join(tlsDir(t, true), "server.crt")
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
// 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
// -Dcom.ibm.jsse2.usefipsprovider line.
_, 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") {
t.Errorf("Did not expect -Dcom.ibm.jsse2.usefipsprovider but it is not; got \"%v\"", jvmOptionsOutput)
}
// 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})
t.Run("REST admin", func(t *testing.T) {
testRESTAdmin(t, cli, ID, secureTLSConfig, "")
})
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// Verify SSLFIPS is set to NO if no certificates were supplied
func TestSSLFIPSTrueNoCerts(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
appPassword := "differentPassw0rd"
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_APP_PASSWORD=" + appPassword,
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
"MQ_ENABLE_FIPS=true",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
},
}
networkingConfig := ce.ContainerNetworkSettings{}
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
// Search the console output for exepcted values
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
if !strings.Contains(sslFIPSOutput, "SSLKEYR( )") {
t.Errorf("Expected SSLKEYR to be ' ' but it is not; got \"%v\"", sslFIPSOutput)
}
if !strings.Contains(sslFIPSOutput, "CERTLABL( )") {
t.Errorf("Expected CERTLABL to be blank but it is not; got \"%v\"", sslFIPSOutput)
}
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
}
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=tru (invalid value)
func TestSSLFIPSInvalidValue(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
"MQ_ENABLE_FIPS=tru",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
},
}
networkingConfig := ce.ContainerNetworkSettings{}
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
waitForReady(t, cli, ID)
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
// Search the console output for exepcted values
_, sslFIPSOutput := execContainer(t, cli, ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
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)
}
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
}
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
}
// Stop the container cleanly
stopContainer(t, cli, ID)
}
// Container creation fails when invalid certs are passed and MQ_ENABLE_FIPS set true
func TestSSLFIPSBadCerts(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
containerConfig := ce.ContainerConfig{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=QM1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
"MQ_ENABLE_FIPS=true",
},
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
Binds: []string{
coverageBind(t),
tlsDirInvalid(t, false) + ":/etc/mqm/pki/keys/default",
},
}
networkingConfig := ce.ContainerNetworkSettings{}
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ID)
startContainer(t, cli, ID)
rc := waitForContainer(t, cli, ID, 20*time.Second)
// Expect return code 1 if container failed to create.
if rc == 1 {
// Get container logs and search for specific message.
logs := inspectLogs(t, cli, ID)
if strings.Contains(logs, "Failed to parse private key") {
t.Logf("Container creating failed because of invalid certifates")
}
} else {
// Some other error occurred.
t.Errorf("Expected rc=0, got rc=%v", rc)
}
// Stop the container cleanly
stopContainer(t, cli, ID)
}

View File

@@ -1,3 +0,0 @@
module github.com/ibm-messaging/mq-container/test/container
go 1.19

View File

@@ -1,285 +0,0 @@
/*
© Copyright IBM Corporation 2021, 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 main
import (
"strings"
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
)
// TestNativeHABasic creates 3 containers in a Native HA queue manager configuration
// and ensures the queue manger and replicas start as expected
func TestNativeHABasic(t *testing.T) {
cli := ce.NewContainerClient()
version, err := cli.GetMQVersion(imageName())
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
qmVolumes := []string{}
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
basePort := 14551
for i := 0; i <= 2; i++ {
nhaPort := basePort + i
vol := createVolume(t, cli, containerNames[i])
defer removeVolume(t, cli, vol)
qmVolumes = append(qmVolumes, vol)
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, basePort)
hostConfig := getHostConfig(t, 1, "", "", vol)
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
networkingConfig := getNativeHANetworkConfig("host")
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// TestNativeHAFailover creates 3 containers in a Native HA queue manager configuration,
// stops the active queue manager, checks a replica becomes active, and ensures the stopped
// queue manager comes back as a replica
func TestNativeHAFailover(t *testing.T) {
cli := ce.NewContainerClient()
version, err := cli.GetMQVersion(imageName())
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
qmVolumes := []string{}
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
basePort := 14551
for i := 0; i <= 2; i++ {
nhaPort := basePort + i
vol := createVolume(t, cli, containerNames[i])
defer removeVolume(t, cli, vol)
qmVolumes = append(qmVolumes, vol)
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, basePort)
hostConfig := getHostConfig(t, 1, "", "", vol)
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
networkingConfig := getNativeHANetworkConfig("host")
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
haStatus, err := getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
stopContainer(t, cli, haStatus.Active)
waitForFailoverHA(t, cli, haStatus.Replica)
startContainer(t, cli, haStatus.Active)
waitForReady(t, cli, haStatus.Active)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// 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
func TestNativeHASecure(t *testing.T) {
cli := ce.NewContainerClient()
version, err := cli.GetMQVersion(imageName())
if err != nil {
t.Fatal(err)
}
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)
}
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"}
qmReplicaIDs := [3]string{}
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
basePort := 14551
for i := 0; i <= 2; i++ {
nhaPort := basePort + i
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true")
hostConfig := getNativeHASecureHostConfig(t)
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
networkingConfig := getNativeHANetworkConfig("host")
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
// with HA TLS enabled, overrides the default CipherSpec, and ensures the queue manger
// and replicas start as expected
func TestNativeHASecureCipherSpec(t *testing.T) {
cli := ce.NewContainerClient()
version, err := cli.GetMQVersion(imageName())
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
basePort := 14551
for i := 0; i <= 2; i++ {
nhaPort := basePort + i
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")
hostConfig := getNativeHASecureHostConfig(t)
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
networkingConfig := getNativeHANetworkConfig("host")
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
// 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.
func TestNativeHASecureCipherSpecFIPS(t *testing.T) {
cli := ce.NewContainerClient()
version, err := cli.GetMQVersion(imageName())
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
basePort := 14551
for i := 0; i <= 2; i++ {
nhaPort := basePort + i
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
// 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")
hostConfig := getNativeHASecureHostConfig(t)
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
networkingConfig := getNativeHANetworkConfig("host")
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
// Display the contents of qm.ini
_, qmini := execContainer(t, cli, qmReplicaIDs[0], "", []string{"cat", "/var/mqm/qmgrs/QM1/qm.ini"})
if !strings.Contains(qmini, "SSLFipsRequired=Yes") {
t.Errorf("Expected SSLFipsRequired=Yes but it is not; got \"%v\"", qmini)
}
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
// 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
func TestNativeHASecureCipherSpecNonFIPSCipher(t *testing.T) {
cli := ce.NewContainerClient()
version, err := cli.GetMQVersion(imageName())
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
//Each native HA qmgr instance is exposed on subsequent ports on the host starting with basePort
//If the qmgr exposes more than one port (tests do not do this currently) then they are offset by +50
basePort := 14551
for i := 0; i <= 2; i++ {
nhaPort := basePort + i
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
// 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=SSL_ECDHE_ECDSA_WITH_RC4_128_SHA", "MQ_ENABLE_FIPS=true")
hostConfig := getNativeHASecureHostConfig(t)
hostConfig = populateNativeHAPortBindings([]int{9414}, nhaPort, hostConfig)
networkingConfig := getNativeHANetworkConfig("host")
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
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
// by setting MQ_ENABLE_FIPS=true
qmReplicaIDs[i] = ctr
}
for i := 0; i <= 2; i++ {
waitForTerminationMessage(t, cli, qmReplicaIDs[i], "/opt/mqm/bin/strmqm: exit status 23", 60*time.Second)
}
}

View File

@@ -0,0 +1,186 @@
// +build mqdev
/*
© Copyright IBM Corporation 2018, 2021
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 main
import (
"context"
"path/filepath"
"strings"
"testing"
"github.com/docker/docker/api/types/container"
"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.
// Note: This test requires a separate container image to be available for the JMS tests.
func TestDevGoldenPath(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
qm := "qm1"
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + qm,
"DEBUG=true",
},
}
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
waitForWebReady(t, cli, id, insecureTLSConfig)
t.Run("JMS", func(t *testing.T) {
// Run the JMS tests, with no password specified
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS)
})
t.Run("REST admin", func(t *testing.T) {
testRESTAdmin(t, cli, id, insecureTLSConfig)
})
t.Run("REST messaging", func(t *testing.T) {
testRESTMessaging(t, cli, id, insecureTLSConfig, qm, "app", defaultAppPasswordWeb)
})
// Stop the container cleanly
stopContainer(t, cli, id)
}
// TestDevSecure tests the default developer config using the a custom TLS key store and password.
// Note: This test requires a separate container image to be available for the JMS tests
func TestDevSecure(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
const tlsPassPhrase string = "passw0rd"
qm := "qm1"
appPassword := "differentPassw0rd"
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + qm,
"MQ_APP_PASSWORD=" + appPassword,
"DEBUG=1",
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
},
Image: imageName(),
}
hostConfig := container.HostConfig{
Binds: []string{
coverageBind(t),
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{}
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ctr.ID)
startContainer(t, cli, ctr.ID)
waitForReady(t, cli, ctr.ID)
cert := filepath.Join(tlsDir(t, true), "server.crt")
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
t.Run("JMS", func(t *testing.T) {
runJMSTests(t, cli, ctr.ID, true, "app", appPassword)
})
t.Run("REST admin", func(t *testing.T) {
testRESTAdmin(t, cli, ctr.ID, insecureTLSConfig)
})
t.Run("REST messaging", func(t *testing.T) {
testRESTMessaging(t, cli, ctr.ID, insecureTLSConfig, qm, "app", appPassword)
})
// Stop the container cleanly
stopContainer(t, cli, ctr.ID)
}
func TestDevWebDisabled(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=qm1",
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
t.Run("Web", func(t *testing.T) {
_, dspmqweb := execContainer(t, cli, id, "", []string{"dspmqweb"})
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.Run("JMS", func(t *testing.T) {
// Run the JMS tests, with no password specified
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS)
})
// Stop the container cleanly
stopContainer(t, cli, id)
}
func TestDevConfigDisabled(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=qm1",
"MQ_DEV=false",
},
}
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
waitForWebReady(t, cli, id, insecureTLSConfig)
rc, _ := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"})
if rc == 0 {
t.Errorf("Expected DEV queues to be missing")
}
// Stop the container cleanly
stopContainer(t, cli, id)
}

View File

@@ -1,8 +1,7 @@
//go:build mqdev
// +build mqdev
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,7 +18,6 @@ limitations under the License.
package main
import (
"bufio"
"bytes"
"context"
"crypto/tls"
@@ -28,13 +26,15 @@ import (
"io/ioutil"
"net/http"
"net/http/httputil"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
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 defaultAdminPassword string = "passw0rd"
@@ -47,7 +47,7 @@ var insecureTLSConfig *tls.Config = &tls.Config{
InsecureSkipVerify: true,
}
func waitForWebReady(t *testing.T, cli ce.ContainerInterface, ID string, tlsConfig *tls.Config) {
func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
t.Logf("%s Waiting for web server to be ready", time.Now().Format(time.RFC3339))
httpClient := http.Client{
Timeout: time.Duration(10 * time.Second),
@@ -55,11 +55,7 @@ func waitForWebReady(t *testing.T, cli ce.ContainerInterface, ID string, tlsConf
TLSClientConfig: tlsConfig,
},
}
port, err := cli.GetContainerPort(ID, 9443)
if err != nil {
t.Fatal(err)
}
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", port)
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
@@ -84,28 +80,15 @@ func tlsDir(t *testing.T, unixPath bool) string {
return filepath.Join(getCwd(t, unixPath), "../tls")
}
func tlsDirWithCA(t *testing.T, unixPath bool) string {
return filepath.Join(getCwd(t, unixPath), "../tlscacert")
}
func tlsDirInvalid(t *testing.T, unixPath bool) string {
return filepath.Join(getCwd(t, unixPath), "../tlsinvalidcert")
}
// 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 ce.ContainerInterface, ID string, tls bool, user, password string, ibmjre string, cipherName string) {
port, err := cli.GetContainerPort(ID, 1414)
if err != nil {
t.Error(err)
}
containerConfig := ce.ContainerConfig{
func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string) {
containerConfig := container.Config{
// -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{
"MQ_PORT_1414_TCP_ADDR=127.0.0.1",
"MQ_PORT_1414_OVERRIDE=" + port,
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
"MQ_USERNAME=" + user,
"MQ_CHANNEL=DEV.APP.SVRCONN",
"IBMJRE=" + ibmjre,
"IBMJRE=" + os.Getenv("IBMJRE"),
},
Image: imageNameDevJMS(),
}
@@ -118,76 +101,25 @@ func runJMSTests(t *testing.T, cli ce.ContainerInterface, ID string, tls bool, u
containerConfig.Env = append(containerConfig.Env, []string{
"MQ_TLS_TRUSTSTORE=/var/tls/client-trust.jks",
"MQ_TLS_PASSPHRASE=passw0rd",
"MQ_TLS_CIPHER=" + cipherName,
}...)
}
hostConfig := ce.ContainerHostConfig{
hostConfig := container.HostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t, false) + ":/var/tls",
},
}
networkingConfig := ce.ContainerNetworkSettings{
Networks: []string{"host"},
}
jmsID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, strings.Replace(t.Name()+"JMS", "/", "", -1))
networkingConfig := network.NetworkingConfig{}
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, strings.Replace(t.Name()+"JMS", "/", "", -1))
if err != nil {
t.Fatal(err)
}
startContainer(t, cli, jmsID)
rc := waitForContainer(t, cli, jmsID, 2*time.Minute)
startContainer(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 2*time.Minute)
if rc != 0 {
t.Errorf("JUnit container failed with rc=%v", rc)
}
// Get console output of the container and process the lines
// to see if we have any failures
scanner := bufio.NewScanner(strings.NewReader(inspectLogs(t, cli, jmsID)))
for scanner.Scan() {
s := scanner.Text()
if processJunitLogLine(s) {
t.Errorf("JUnit container tests failed. Reason: %s", s)
}
}
defer cleanContainer(t, cli, jmsID)
}
// Parse JUnit log line and return true if line contains failed or aborted tests
func processJunitLogLine(outputLine string) bool {
var failedLine bool
// Sample JUnit test run output
//[ 2 containers found ]
//[ 0 containers skipped ]
//[ 2 containers started ]
//[ 0 containers aborted ]
//[ 2 containers successful ]
//[ 0 containers failed ]
//[ 0 tests found ]
//[ 0 tests skipped ]
//[ 0 tests started ]
//[ 0 tests aborted ]
//[ 0 tests successful ]
//[ 0 tests failed ]
// Consider only those lines that begin with '[' and with ']'
if strings.HasPrefix(outputLine, "[") && strings.HasSuffix(outputLine, "]") {
// Strip off [] and whitespaces
trimmed := strings.Trim(outputLine, "[] ")
if strings.Contains(trimmed, "aborted") || strings.Contains(trimmed, "failed") {
// Tokenize on whitespace
tokens := strings.Split(trimmed, " ")
// Determine the count of aborted or failed tests
count, err := strconv.Atoi(tokens[0])
if err == nil {
if count > 0 {
failedLine = true
}
}
}
}
return failedLine
defer cleanContainer(t, cli, ctr.ID)
}
// createTLSConfig creates a tls.Config which trusts the specified certificate
@@ -214,31 +146,21 @@ func createTLSConfig(t *testing.T, certFile, password string) *tls.Config {
}
}
func testRESTAdmin(t *testing.T, cli ce.ContainerInterface, ID string, tlsConfig *tls.Config, errorExpected string) {
func testRESTAdmin(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
httpClient := http.Client{
Timeout: time.Duration(30 * time.Second),
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
}
port, err := cli.GetContainerPort(ID, 9443)
if err != nil {
t.Fatal(err)
}
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", port)
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
req, err := http.NewRequest("GET", url, nil)
req.SetBasicAuth("admin", defaultAdminPassword)
resp, err := httpClient.Do(req)
if err != nil {
if len(errorExpected) > 0 {
if !strings.Contains(err.Error(), errorExpected) {
t.Fatal(err)
}
} else {
t.Fatal(err)
}
t.Fatal(err)
}
if resp != nil && resp.StatusCode != http.StatusOK {
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode)
}
}
@@ -261,7 +183,7 @@ func logHTTPResponse(t *testing.T, resp *http.Response) {
t.Logf("HTTP response: %v", string(d))
}
func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsConfig *tls.Config, qmName string, user string, password string, errorExpected string) {
func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config, qmName string, user string, password string) {
httpClient := http.Client{
Timeout: time.Duration(30 * time.Second),
Transport: &http.Transport{
@@ -269,11 +191,7 @@ func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsCo
},
}
q := "DEV.QUEUE.1"
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)
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/messaging/qmgr/%s/queue/%s/message", getPort(t, cli, ID, 9443), qmName, q)
putMessage := []byte("Hello")
req, err := http.NewRequest("POST", url, bytes.NewBuffer(putMessage))
req.SetBasicAuth(user, password)
@@ -282,19 +200,10 @@ func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsCo
logHTTPRequest(t, req)
resp, err := httpClient.Do(req)
if err != nil {
if len(errorExpected) > 0 {
if strings.Contains(err.Error(), errorExpected) {
t.Logf("Error contains expected '%s' value", errorExpected)
return
} else {
t.Fatal(err)
}
} else {
t.Fatal(err)
}
t.Fatal(err)
}
logHTTPResponse(t, resp)
if resp != nil && resp.StatusCode != http.StatusCreated {
if resp.StatusCode != http.StatusCreated {
t.Errorf("Expected HTTP status code %v from 'POST to queue'; got %v", http.StatusOK, resp.StatusCode)
t.Logf("HTTP response: %+v", resp)
t.Fail()
@@ -322,28 +231,3 @@ func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsCo
t.Errorf("Expected payload to be \"%s\"; got \"%s\"", putMessage, gotMessage)
}
}
// createTLSConfig creates a tls.Config which trusts the specified certificate
func createTLSConfigWithCipher(t *testing.T, certFile, password string, ciphers []uint16) *tls.Config {
// Get the SystemCertPool, continue with an empty pool on error
certs, err := x509.SystemCertPool()
if err != nil {
t.Fatal(err)
}
// Read in the cert file
cert, err := ioutil.ReadFile(certFile)
if err != nil {
t.Fatal(err)
}
// Append our cert to the system pool
ok := certs.AppendCertsFromPEM(cert)
if !ok {
t.Fatal("No certs appended")
}
// Trust the augmented cert pool in our client
return &tls.Config{
InsecureSkipVerify: false,
RootCAs: certs,
CipherSuites: ciphers,
}
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2017, 2023
© Copyright IBM Corporation 2017, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -34,9 +34,28 @@ import (
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
"github.com/docker/docker/api/types"
"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 {
image, ok := os.LookupEnv("TEST_IMAGE")
if !ok {
@@ -54,7 +73,7 @@ func imageNameDevJMS() string {
}
// baseImage returns the ID of the underlying base image (e.g. "ubuntu" or "rhel")
func baseImage(t *testing.T, cli ce.ContainerInterface) string {
func baseImage(t *testing.T, cli *client.Client) string {
rc, out := runContainerOneShot(t, cli, "grep", "^ID=", "/etc/os-release")
if rc != 0 {
t.Fatal("Couldn't determine base image")
@@ -68,7 +87,7 @@ func baseImage(t *testing.T, cli ce.ContainerInterface) string {
// devImage returns true if the image under test is a developer image,
// determined by use of the MQ_ADMIN_PASSWORD environment variable
func devImage(t *testing.T, cli ce.ContainerInterface) bool {
func devImage(t *testing.T, cli *client.Client) bool {
rc, _ := runContainerOneShot(t, cli, "printenv", "MQ_ADMIN_PASSWORD")
if rc == 0 {
return true
@@ -88,11 +107,6 @@ func isWSL(t *testing.T) bool {
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
func getCwd(t *testing.T, unixPath bool) string {
dir, err := os.Getwd()
@@ -147,17 +161,29 @@ func getTempDir(t *testing.T, unixStylePath bool) string {
}
// terminationMessage return the termination message, or an empty string if not set
func terminationMessage(t *testing.T, cli ce.ContainerInterface, ID string) string {
r, err := cli.CopyFromContainer(ID, "/run/termination-log")
func terminationMessage(t *testing.T, cli *client.Client, ID string) string {
r, _, err := cli.CopyFromContainer(context.Background(), ID, "/run/termination-log")
if err != nil {
t.Log(err)
t.Log(string(r))
return ""
}
return string(r)
b, err := ioutil.ReadAll(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 ce.ContainerInterface, ID string) {
func expectTerminationMessage(t *testing.T, cli *client.Client, ID string) {
m := terminationMessage(t, cli, ID)
if m == "" {
t.Error("Expected termination message to be set")
@@ -165,10 +191,10 @@ func expectTerminationMessage(t *testing.T, cli ce.ContainerInterface, ID string
}
// logContainerDetails logs selected details about the container
func logContainerDetails(t *testing.T, cli ce.ContainerInterface, ID string) {
i, err := cli.ContainerInspect(ID)
func logContainerDetails(t *testing.T, cli *client.Client, ID string) {
i, err := cli.ContainerInspect(context.Background(), ID)
if err == nil {
d := ce.ContainerDetailsLogging{
d := containerDetails{
ID: ID,
Name: i.Name,
Image: i.Image,
@@ -184,29 +210,29 @@ func logContainerDetails(t *testing.T, cli ce.ContainerInterface, ID string) {
}
}
func cleanContainerQuiet(t *testing.T, cli ce.ContainerInterface, ID string) {
func cleanContainerQuiet(t *testing.T, cli *client.Client, ID string) {
timeout := 10 * time.Second
err := cli.ContainerStop(ID, &timeout)
err := cli.ContainerStop(context.Background(), ID, &timeout)
if err != nil {
// Just log the error and continue
t.Log(err)
}
opts := ce.ContainerRemoveOptions{
opts := types.ContainerRemoveOptions{
RemoveVolumes: true,
Force: true,
}
err = cli.ContainerRemove(ID, opts)
err = cli.ContainerRemove(context.Background(), ID, opts)
if err != nil {
t.Error(err)
}
}
func cleanContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
func cleanContainer(t *testing.T, cli *client.Client, ID string) {
logContainerDetails(t, cli, ID)
t.Logf("Stopping container: %v", ID)
timeout := 10 * time.Second
// Stop the container. This allows the coverage output to be generated.
err := cli.ContainerStop(ID, &timeout)
err := cli.ContainerStop(context.Background(), ID, &timeout)
if err != nil {
// Just log the error and continue
t.Log(err)
@@ -224,11 +250,11 @@ func cleanContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
}
t.Logf("Removing container: %s", ID)
opts := ce.ContainerRemoveOptions{
opts := types.ContainerRemoveOptions{
RemoveVolumes: true,
Force: true,
}
err = cli.ContainerRemove(ID, opts)
err = cli.ContainerRemove(context.Background(), ID, opts)
if err != nil {
t.Error(err)
}
@@ -242,17 +268,17 @@ func generateRandomUID() string {
}
// getDefaultHostConfig creates a HostConfig and populates it with the defaults used in testing
func getDefaultHostConfig(t *testing.T, cli ce.ContainerInterface) *ce.ContainerHostConfig {
hostConfig := ce.ContainerHostConfig{
PortBindings: []ce.PortBinding{},
func getDefaultHostConfig(t *testing.T, cli *client.Client) *container.HostConfig {
hostConfig := container.HostConfig{
Binds: []string{
coverageBind(t),
},
PortBindings: nat.PortMap{},
CapDrop: []string{
"ALL",
},
Privileged: false,
}
if coverage() {
hostConfig.Binds = append(hostConfig.Binds, coverageBind(t))
}
if devImage(t, cli) {
// Only needed for a RHEL-based image
if baseImage(t, cli) != "ubuntu" {
@@ -266,7 +292,7 @@ func getDefaultHostConfig(t *testing.T, cli ce.ContainerInterface) *ce.Container
// runContainerWithHostConfig creates and starts a container, using the supplied HostConfig.
// Note that a default HostConfig can be created using getDefaultHostConfig.
func runContainerWithHostConfig(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, hostConfig *ce.ContainerHostConfig) string {
func runContainerWithHostConfig(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig) string {
if containerConfig.Image == "" {
containerConfig.Image = imageName()
}
@@ -274,23 +300,22 @@ func runContainerWithHostConfig(t *testing.T, cli ce.ContainerInterface, contain
if containerConfig.User == "" {
containerConfig.User = generateRandomUID()
}
if coverage() {
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
}
networkingConfig := ce.ContainerNetworkSettings{}
// if coverage
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
networkingConfig := network.NetworkingConfig{}
t.Logf("Running container (%s)", containerConfig.Image)
ID, err := cli.ContainerCreate(containerConfig, hostConfig, &networkingConfig, t.Name())
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
startContainer(t, cli, ID)
return ID
startContainer(t, cli, ctr.ID)
return ctr.ID
}
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
func runContainerWithAllConfig(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, hostConfig *ce.ContainerHostConfig, networkingConfig *ce.ContainerNetworkSettings, containerName string) string {
func runContainerWithAllConfig(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) string {
if containerName == "" {
containerName = t.Name()
}
@@ -301,32 +326,30 @@ func runContainerWithAllConfig(t *testing.T, cli ce.ContainerInterface, containe
if containerConfig.User == "" {
containerConfig.User = generateRandomUID()
}
if coverage() {
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
}
// if coverage
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
t.Logf("Running container (%s)", containerConfig.Image)
ID, err := cli.ContainerCreate(containerConfig, hostConfig, networkingConfig, containerName)
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkingConfig, containerName)
if err != nil {
t.Fatal(err)
}
startContainer(t, cli, ID)
return ID
startContainer(t, cli, ctr.ID)
return ctr.ID
}
// 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
// environment variable.
func runContainerWithPorts(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, ports []int) string {
func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *container.Config, ports []int) string {
hostConfig := getDefaultHostConfig(t, cli)
var binding ce.PortBinding
for _, p := range ports {
port := fmt.Sprintf("%v/tcp", p)
binding = ce.PortBinding{
ContainerPort: port,
HostIP: "0.0.0.0",
port := nat.Port(fmt.Sprintf("%v/tcp", p))
hostConfig.PortBindings[port] = []nat.PortBinding{
{
HostIP: "0.0.0.0",
},
}
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
}
return runContainerWithHostConfig(t, cli, containerConfig, hostConfig)
}
@@ -334,160 +357,161 @@ func runContainerWithPorts(t *testing.T, cli ce.ContainerInterface, containerCon
// 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
// environment variable.
func runContainer(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig) string {
func runContainer(t *testing.T, cli *client.Client, containerConfig *container.Config) string {
return runContainerWithPorts(t, cli, containerConfig, nil)
}
// runContainerOneShot runs a container with a custom entrypoint, as the root
// user and with default capabilities
func runContainerOneShot(t *testing.T, cli ce.ContainerInterface, command ...string) (int64, string) {
containerConfig := ce.ContainerConfig{
func runContainerOneShot(t *testing.T, cli *client.Client, command ...string) (int64, string) {
containerConfig := container.Config{
Entrypoint: command,
User: "root",
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{}
networkingConfig := ce.ContainerNetworkSettings{}
hostConfig := container.HostConfig{}
networkingConfig := network.NetworkingConfig{}
t.Logf("Running one shot container (%s): %v", containerConfig.Image, command)
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShot")
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShot")
if err != nil {
t.Fatal(err)
}
startOptions := ce.ContainerStartOptions{}
err = cli.ContainerStart(ID, startOptions)
startOptions := types.ContainerStartOptions{}
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
if err != nil {
t.Fatal(err)
}
defer cleanContainerQuiet(t, cli, ID)
rc := waitForContainer(t, cli, ID, 20*time.Second)
out := inspectLogs(t, cli, ID)
defer cleanContainerQuiet(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
out := inspectLogs(t, cli, ctr.ID)
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
return rc, out
}
// runContainerOneShot runs a container with a custom entrypoint, as the root
// user, with default capabilities, and a volume mounted
func runContainerOneShotWithVolume(t *testing.T, cli ce.ContainerInterface, bind string, command ...string) (int64, string) {
containerConfig := ce.ContainerConfig{
func runContainerOneShotWithVolume(t *testing.T, cli *client.Client, bind string, command ...string) (int64, string) {
containerConfig := container.Config{
Entrypoint: command,
User: "root",
Image: imageName(),
}
hostConfig := ce.ContainerHostConfig{
hostConfig := container.HostConfig{
Binds: []string{
bind,
},
}
networkingConfig := ce.ContainerNetworkSettings{}
networkingConfig := network.NetworkingConfig{}
t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command)
ID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShotVolume")
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShotVolume")
if err != nil {
t.Fatal(err)
}
startOptions := ce.ContainerStartOptions{}
err = cli.ContainerStart(ID, startOptions)
startOptions := types.ContainerStartOptions{}
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
if err != nil {
t.Fatal(err)
}
defer cleanContainerQuiet(t, cli, ID)
rc := waitForContainer(t, cli, ID, 20*time.Second)
out := inspectLogs(t, cli, ID)
defer cleanContainerQuiet(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
out := inspectLogs(t, cli, ctr.ID)
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
return rc, out
}
func startMultiVolumeQueueManager(t *testing.T, cli ce.ContainerInterface, dataVol bool, qmsharedlogs string, qmshareddata string, env []string) (error, string, string) {
func startMultiVolumeQueueManager(t *testing.T, cli *client.Client, dataVol bool, qmsharedlogs string, qmshareddata string, env []string) (error, string, string) {
id := strconv.FormatInt(time.Now().UnixNano(), 10)
volume := createVolume(t, cli, id)
containerConfig := ce.ContainerConfig{
qmdata := createVolume(t, cli, id)
containerConfig := container.Config{
Image: imageName(),
Env: env,
}
var hostConfig ce.ContainerHostConfig
var hostConfig container.HostConfig
if !dataVol {
hostConfig = ce.ContainerHostConfig{}
hostConfig = container.HostConfig{}
} else if qmsharedlogs == "" && qmshareddata == "" {
hostConfig = getHostConfig(t, 1, "", "", volume)
hostConfig = getHostConfig(t, 1, "", "", qmdata.Name)
} else if qmsharedlogs == "" {
hostConfig = getHostConfig(t, 2, "", qmshareddata, volume)
hostConfig = getHostConfig(t, 2, "", qmshareddata, qmdata.Name)
} else if qmshareddata == "" {
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", volume)
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", qmdata.Name)
} else {
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, volume)
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, qmdata.Name)
}
networkingConfig := ce.ContainerNetworkSettings{}
qmID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
networkingConfig := network.NetworkingConfig{}
qm, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
if err != nil {
return err, "", ""
}
startContainer(t, cli, qmID)
startContainer(t, cli, qm.ID)
return nil, qmID, volume
return nil, qm.ID, qmdata.Name
}
func getHostConfig(t *testing.T, mounts int, qmsharedlogs string, qmshareddata string, qmdata string) ce.ContainerHostConfig {
func getHostConfig(t *testing.T, mounts int, qmsharedlogs string, qmshareddata string, qmdata string) container.HostConfig {
var hostConfig ce.ContainerHostConfig
var hostConfig container.HostConfig
switch mounts {
case 1:
hostConfig = ce.ContainerHostConfig{
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
},
}
case 2:
hostConfig = ce.ContainerHostConfig{
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmshareddata + ":/mnt/mqm-data",
},
}
case 3:
hostConfig = ce.ContainerHostConfig{
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmsharedlogs + ":/mnt/mqm-log",
},
}
case 4:
hostConfig = ce.ContainerHostConfig{
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmsharedlogs + ":/mnt/mqm-log",
qmshareddata + ":/mnt/mqm-data",
},
}
}
if coverage() {
hostConfig.Binds = append(hostConfig.Binds, coverageBind(t))
}
return hostConfig
}
func startContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
func startContainer(t *testing.T, cli *client.Client, ID string) {
t.Logf("Starting container: %v", ID)
startOptions := ce.ContainerStartOptions{}
err := cli.ContainerStart(ID, startOptions)
startOptions := types.ContainerStartOptions{}
err := cli.ContainerStart(context.Background(), ID, startOptions)
if err != nil {
t.Fatal(err)
}
}
func stopContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
func stopContainer(t *testing.T, cli *client.Client, ID string) {
t.Logf("Stopping container: %v", ID)
timeout := 10 * time.Second
err := cli.ContainerStop(ID, &timeout) //Duration(20)*time.Second)
err := cli.ContainerStop(context.Background(), ID, &timeout) //Duration(20)*time.Second)
if err != nil {
// Just log the error and continue
t.Log(err)
t.Fatal(err)
}
}
func killContainer(t *testing.T, cli ce.ContainerInterface, ID string, signal string) {
func killContainer(t *testing.T, cli *client.Client, ID string, signal string) {
t.Logf("Killing container: %v", ID)
err := cli.ContainerKill(ID, signal)
err := cli.ContainerKill(context.Background(), ID, signal)
if err != nil {
t.Fatal(err)
}
@@ -521,17 +545,12 @@ func getCoverageExitCode(t *testing.T, orig int64) int64 {
}
// waitForContainer waits until a container has exited
func waitForContainer(t *testing.T, cli ce.ContainerInterface, ID string, timeout time.Duration) int64 {
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.Duration) int64 {
c, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
t.Logf("Waiting for container for %s", timeout)
okC, errC := cli.ContainerWait(c, ID, ce.ContainerStateNotRunning)
var rc int64
select {
case err := <-errC:
rc, err := cli.ContainerWait(c, ID)
if err != nil {
t.Fatal(err)
case ok := <-okC:
rc = ok
}
if coverage() {
// COVERAGE: When running coverage, the exit code is written to a file,
@@ -543,15 +562,78 @@ func waitForContainer(t *testing.T, cli ce.ContainerInterface, ID string, timeou
}
// execContainer runs a command in a running container, and returns the exit code and output
func execContainer(t *testing.T, cli ce.ContainerInterface, ID string, user string, cmd []string) (int, string) {
func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd []string) (int, string) {
t.Logf("Running command: %v", cmd)
exitcode, outputStr := cli.ExecContainer(ID, user, cmd)
config := types.ExecConfig{
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, config)
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
}
func waitForReady(t *testing.T, cli ce.ContainerInterface, ID string) {
func waitForReady(t *testing.T, cli *client.Client, ID string) {
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
for {
@@ -575,47 +657,57 @@ func waitForReady(t *testing.T, cli ce.ContainerInterface, ID string) {
}
}
func createNetwork(t *testing.T, cli ce.ContainerInterface) string {
func getIPAddress(t *testing.T, cli *client.Client, ID string) 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"
t.Logf("Creating network: %v", name)
opts := ce.NetworkCreateOptions{}
netID, err := cli.NetworkCreate(name, opts)
opts := types.NetworkCreate{}
net, err := cli.NetworkCreate(context.Background(), name, opts)
if err != nil {
t.Fatal(err)
}
t.Logf("Created network %v with ID %v", name, netID)
return netID
t.Logf("Created network %v with ID %v", name, net.ID)
return net.ID
}
func removeNetwork(t *testing.T, cli ce.ContainerInterface, ID string) {
func removeNetwork(t *testing.T, cli *client.Client, ID string) {
t.Logf("Removing network ID: %v", ID)
err := cli.NetworkRemove(ID)
err := cli.NetworkRemove(context.Background(), ID)
if err != nil {
t.Fatal(err)
}
}
func createVolume(t *testing.T, cli ce.ContainerInterface, name string) string {
v, err := cli.VolumeCreate(ce.VolumeCreateOptions{
Driver: "local",
Name: name,
func createVolume(t *testing.T, cli *client.Client, name string) types.Volume {
v, err := cli.VolumeCreate(context.Background(), volume.VolumesCreateBody{
Driver: "local",
DriverOpts: map[string]string{},
Labels: map[string]string{},
Name: name,
})
if err != nil {
t.Fatal(err)
}
t.Logf("Created volume %v", v)
t.Logf("Created volume %v", v.Name)
return v
}
func removeVolume(t *testing.T, cli ce.ContainerInterface, name string) {
func removeVolume(t *testing.T, cli *client.Client, name string) {
t.Logf("Removing volume %v", name)
err := cli.VolumeRemove(name, true)
err := cli.VolumeRemove(context.Background(), name, true)
if err != nil {
t.Fatal(err)
}
}
func inspectTextLogs(t *testing.T, cli ce.ContainerInterface, ID string) string {
func inspectTextLogs(t *testing.T, cli *client.Client, ID string) string {
jsonLogs := inspectLogs(t, cli, ID)
scanner := bufio.NewScanner(strings.NewReader(jsonLogs))
b := make([]byte, 64*1024)
@@ -623,11 +715,9 @@ func inspectTextLogs(t *testing.T, cli ce.ContainerInterface, ID string) string
for scanner.Scan() {
text := scanner.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{}
json.Unmarshal([]byte(text), &e)
fmt.Fprintf(buf, "{\"ibm_datetime\": \"%v\", \"message\": \"%v\", ...}\n", e["ibm_datetime"], e["message"])
fmt.Fprintf(buf, "{\"message\": \"%v\"}\n", e["message"])
} else {
fmt.Fprintln(buf, text)
}
@@ -639,14 +729,23 @@ func inspectTextLogs(t *testing.T, cli ce.ContainerInterface, ID string) string
return buf.String()
}
func inspectLogs(t *testing.T, cli ce.ContainerInterface, ID string) string {
func inspectLogs(t *testing.T, cli *client.Client, ID string) string {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
logs, err := cli.GetContainerLogs(ctx, ID, ce.ContainerLogsOptions{})
reader, err := cli.ContainerLogs(ctx, ID, types.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
})
if err != nil {
t.Fatal(err)
}
return logs
buf := new(bytes.Buffer)
// 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.
@@ -676,54 +775,76 @@ func generateTAR(t *testing.T, files []struct{ Name, Body string }) []byte {
}
// createImage creates a new Docker image with the specified files included.
func createImage(t *testing.T, cli ce.ContainerInterface, files []struct{ Name, Body string }) string {
func createImage(t *testing.T, cli *client.Client, files []struct{ Name, Body string }) string {
r := bytes.NewReader(generateTAR(t, files))
tag := strings.ToLower(t.Name())
tmpDir, err := os.MkdirTemp("", "tmp")
buildOptions := types.ImageBuildOptions{
Context: r,
Tags: []string{tag},
}
resp, err := cli.ImageBuild(context.Background(), r, buildOptions)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
//Write files to temp directory
for _, file := range files {
//Add tag to file name to allow parallel testing
f, err := os.Create(filepath.Join(tmpDir, file.Name))
// resp (ImageBuildResponse) contains a series of JSON messages
dec := json.NewDecoder(resp.Body)
for {
m := jsonmessage.JSONMessage{}
err := dec.Decode(&m)
if m.Error != nil {
t.Fatal(m.ErrorMessage)
}
t.Log(strings.TrimSpace(m.Stream))
if err == io.EOF {
break
}
if err != nil {
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
}
// deleteImage deletes a Docker image
func deleteImage(t *testing.T, cli ce.ContainerInterface, id string) {
cli.ImageRemove(id, ce.ImageRemoveOptions{
func deleteImage(t *testing.T, cli *client.Client, id string) {
cli.ImageRemove(context.Background(), id, types.ImageRemoveOptions{
Force: true,
})
}
func copyFromContainer(t *testing.T, cli ce.ContainerInterface, id string, file string) []byte {
b, err := cli.CopyFromContainer(id, file)
func copyFromContainer(t *testing.T, cli *client.Client, id string, file string) []byte {
reader, _, err := cli.CopyFromContainer(context.Background(), id, file)
if err != nil {
t.Fatal(err)
}
defer reader.Close()
b, err := ioutil.ReadAll(reader)
if err != nil {
t.Fatal(err)
}
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 {
scanner := bufio.NewScanner(r)
count := 0
@@ -755,117 +876,11 @@ func countTarLines(t *testing.T, b []byte) int {
return total
}
// scanForExcludedEntries scans for default excluded messages
func scanForExcludedEntries(msg string) bool {
if strings.Contains(msg, "AMQ5041I") || strings.Contains(msg, "AMQ5052I") ||
strings.Contains(msg, "AMQ5051I") || strings.Contains(msg, "AMQ5037I") ||
strings.Contains(msg, "AMQ5975I") {
return true
}
return false
}
// checkLogForValidJSON checks if the message is in Json format
func checkLogForValidJSON(jsonLogs string) bool {
scanner := bufio.NewScanner(strings.NewReader(jsonLogs))
for scanner.Scan() {
var obj map[string]interface{}
s := scanner.Text()
err := json.Unmarshal([]byte(s), &obj)
if err != nil {
return false
}
}
return true
}
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
func runContainerWithAllConfigError(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig, hostConfig *ce.ContainerHostConfig, networkingConfig *ce.ContainerNetworkSettings, containerName string) (string, error) {
if containerName == "" {
containerName = t.Name()
}
if containerConfig.Image == "" {
containerConfig.Image = imageName()
}
// Always run as a random user, unless the test has specified otherwise
if containerConfig.User == "" {
containerConfig.User = generateRandomUID()
}
if coverage() {
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
}
t.Logf("Running container (%s)", containerConfig.Image)
ID, err := cli.ContainerCreate(containerConfig, hostConfig, networkingConfig, containerName)
func getMQVersion(t *testing.T, cli *client.Client) (string, error) {
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
if err != nil {
return "", err
}
err = startContainerError(t, cli, ID)
if err != nil {
return "", err
}
return ID, nil
}
func startContainerError(t *testing.T, cli ce.ContainerInterface, ID string) error {
t.Logf("Starting container: %v", ID)
startOptions := ce.ContainerStartOptions{}
err := cli.ContainerStart(ID, startOptions)
if err != nil {
return err
}
return nil
}
// testLogFilePages validates that the specified number of logFilePages is present in the qm.ini file.
func testLogFilePages(t *testing.T, cli ce.ContainerInterface, id string, qmName string, expectedLogFilePages string) {
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/" + qmName + "/qm.ini")
_, iniContent := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand})
if !strings.Contains(iniContent, "LogFilePages="+expectedLogFilePages) {
t.Errorf("Expected qm.ini to contain LogFilePages="+expectedLogFilePages+"; got qm.ini \"%v\"", iniContent)
}
}
// waitForMessageInLog will check for a particular message with wait
func waitForMessageInLog(t *testing.T, cli ce.ContainerInterface, id string, expectedMessageId string) (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) {
return jsonLogs, nil
}
case <-ctx.Done():
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)
}
}
}
// Returns fully qualified path
func tlsDirDN(t *testing.T, unixPath bool, certPath string) string {
return filepath.Join(getCwd(t, unixPath), certPath)
version := inspect.ContainerConfig.Labels["version"]
return version, nil
}

20
test/docker/go.mod Normal file
View File

@@ -0,0 +1,20 @@
module github.com/ibm-messaging/mq-container/test/docker
go 1.15
require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/Sirupsen/logrus v1.0.5 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v1.13.2-0.20170601211448-f5ec1e2936dc
github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.4.0 // indirect
github.com/onsi/ginkgo v1.14.1 // indirect
github.com/onsi/gomega v1.10.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/cobra v1.1.1 // indirect
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
)

366
test/docker/go.sum Normal file
View File

@@ -0,0 +1,366 @@
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=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Sirupsen/logrus v1.0.5 h1:447dy9LxSj+Iaa2uN3yoFHOzU9yJcJYiQPtNz8OXtv0=
github.com/Sirupsen/logrus v1.0.5/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.13.2-0.20170601211448-f5ec1e2936dc h1:y4nIGNQUH6JtUV3pd6HjnzdnHq+96wMDVXhkfZ6jc4E=
github.com/docker/docker v1.13.2-0.20170601211448-f5ec1e2936dc/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.2+incompatible h1:vFgEHPqWBTp4pTjdLwjAA4bSo3gvIGOYwuJTlEjVBCw=
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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
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/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
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/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
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.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2019, 2023
© Copyright IBM Corporation 2019, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,12 +16,11 @@ limitations under the License.
package main
import (
"context"
"strings"
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
"github.com/docker/docker/client"
)
var miEnv = []string{
@@ -34,7 +33,10 @@ var miEnv = []string{
// and starts/stop them checking we always have an active and standby
func TestMultiInstanceStartStop(t *testing.T) {
t.Skipf("Skipping %v until test defect fixed", t.Name())
cli := ce.NewContainerClient()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
if err != nil {
t.Fatal(err)
@@ -73,7 +75,10 @@ func TestMultiInstanceStartStop(t *testing.T) {
// 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
func TestMultiInstanceContainerStop(t *testing.T) {
cli := ce.NewContainerClient()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
if err != nil {
t.Fatal(err)
@@ -87,28 +92,15 @@ func TestMultiInstanceContainerStop(t *testing.T) {
waitForReady(t, cli, qm1aId)
waitForReady(t, cli, qm1bId)
err, originalActive, originalStandby := getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
err, active, standby := getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
stopContainer(t, cli, originalActive)
stopContainer(t, cli, active)
for {
status := getQueueManagerStatus(t, cli, originalStandby, "QM1")
select {
case <-time.After(1 * time.Second):
if status == "Running" {
t.Logf("Original standby is now the active")
return
} else if status == "Starting" {
t.Logf("Original standby is starting")
}
case <-ctx.Done():
t.Fatalf("%s Timed out waiting for standby to become the active. Status=%v", time.Now().Format(time.RFC3339), status)
}
if status := getQueueManagerStatus(t, cli, standby, "QM1"); strings.Compare(status, "Running") != 0 {
t.Fatalf("Expected QM1 to be running as active queue manager, dspmq returned status of %v", status)
}
}
@@ -116,16 +108,21 @@ func TestMultiInstanceContainerStop(t *testing.T) {
// configuration, then checks to ensure that both an active and standby queue manager have been started
func TestMultiInstanceRace(t *testing.T) {
t.Skipf("Skipping %v until file lock is implemented", t.Name())
cli := ce.NewContainerClient()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
defer removeVolume(t, cli, qmsharedlogs)
defer removeVolume(t, cli, qmsharedlogs.Name)
qmshareddata := createVolume(t, cli, "qmshareddata")
defer removeVolume(t, cli, qmshareddata)
defer removeVolume(t, cli, qmshareddata.Name)
qmsChannel := make(chan QMChan)
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs, qmshareddata, qmsChannel)
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs, qmshareddata, qmsChannel)
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs.Name, qmshareddata.Name, qmsChannel)
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs.Name, qmshareddata.Name, qmsChannel)
qm1a := <-qmsChannel
if qm1a.Error != nil {
@@ -148,7 +145,7 @@ func TestMultiInstanceRace(t *testing.T) {
waitForReady(t, cli, qm1aId)
waitForReady(t, cli, qm1bId)
err, _, _ := getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
err, _, _ = getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
if err != nil {
t.Fatal(err)
}
@@ -158,7 +155,10 @@ func TestMultiInstanceRace(t *testing.T) {
// mounts, then checks to ensure that the container terminates with the expected message
func TestMultiInstanceNoSharedMounts(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", "", miEnv)
if err != nil {
@@ -174,12 +174,15 @@ func TestMultiInstanceNoSharedMounts(t *testing.T) {
// 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
func TestMultiInstanceNoSharedLogs(t *testing.T) {
cli := ce.NewContainerClient()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
qmshareddata := createVolume(t, cli, "qmshareddata")
defer removeVolume(t, cli, qmshareddata)
defer removeVolume(t, cli, qmshareddata.Name)
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", qmshareddata, miEnv)
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", qmshareddata.Name, miEnv)
if err != nil {
t.Fatal(err)
}
@@ -193,12 +196,15 @@ func TestMultiInstanceNoSharedLogs(t *testing.T) {
// 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
func TestMultiInstanceNoSharedData(t *testing.T) {
cli := ce.NewContainerClient()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
defer removeVolume(t, cli, qmsharedlogs)
defer removeVolume(t, cli, qmsharedlogs.Name)
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, "", miEnv)
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, "", miEnv)
if err != nil {
t.Fatal(err)
}
@@ -212,7 +218,10 @@ func TestMultiInstanceNoSharedData(t *testing.T) {
// 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
func TestMultiInstanceNoMounts(t *testing.T) {
cli := ce.NewContainerClient()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, false, "", "", miEnv)
if err != nil {

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2019, 2023
© Copyright IBM Corporation 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ import (
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
"github.com/docker/docker/client"
)
type QMChan struct {
@@ -34,27 +34,27 @@ type QMChan struct {
// 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
func configureMultiInstance(t *testing.T, cli ce.ContainerInterface) (error, string, string, []string) {
func configureMultiInstance(t *testing.T, cli *client.Client) (error, string, string, []string) {
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
qmshareddata := createVolume(t, cli, "qmshareddata")
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, qmshareddata.Name, miEnv)
if err != nil {
return err, "", "", []string{}
}
time.Sleep(10 * time.Second)
err, qm1bId, qm1bData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
err, qm1bId, qm1bData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, qmshareddata.Name, miEnv)
if err != nil {
return err, "", "", []string{}
}
volumes := []string{qmsharedlogs, qmshareddata, qm1aData, qm1bData}
volumes := []string{qmsharedlogs.Name, qmshareddata.Name, qm1aData, qm1bData}
return nil, qm1aId, qm1bId, volumes
}
func singleMultiInstanceQueueManager(t *testing.T, cli ce.ContainerInterface, qmsharedlogs string, qmshareddata string, qmsChannel chan QMChan) {
func singleMultiInstanceQueueManager(t *testing.T, cli *client.Client, qmsharedlogs string, qmshareddata string, qmsChannel chan QMChan) {
err, qmId, qmData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
if err != nil {
qmsChannel <- QMChan{Error: err}
@@ -62,7 +62,7 @@ func singleMultiInstanceQueueManager(t *testing.T, cli ce.ContainerInterface, qm
qmsChannel <- QMChan{QMId: qmId, QMData: qmData}
}
func getActiveStandbyQueueManager(t *testing.T, cli ce.ContainerInterface, qm1aId string, qm1bId string) (error, string, string) {
func getActiveStandbyQueueManager(t *testing.T, cli *client.Client, qm1aId string, qm1bId string) (error, string, string) {
qm1aStatus := getQueueManagerStatus(t, cli, qm1aId, "QM1")
qm1bStatus := getQueueManagerStatus(t, cli, qm1bId, "QM1")
@@ -75,16 +75,15 @@ func getActiveStandbyQueueManager(t *testing.T, cli ce.ContainerInterface, qm1aI
return err, "", ""
}
func getQueueManagerStatus(t *testing.T, cli ce.ContainerInterface, containerID string, queueManagerName string) string {
func getQueueManagerStatus(t *testing.T, cli *client.Client, containerID string, queueManagerName string) string {
_, dspmqOut := execContainer(t, cli, containerID, "", []string{"bash", "-c", "dspmq", "-m", queueManagerName})
t.Logf("dspmq for %v (%v) returned: %v", containerID, queueManagerName, dspmqOut)
regex := regexp.MustCompile(`STATUS\(.*\)`)
status := regex.FindString(dspmqOut)
status = strings.TrimSuffix(strings.TrimPrefix(status, "STATUS("), ")")
return status
}
func waitForTerminationMessage(t *testing.T, cli ce.ContainerInterface, qmId string, terminationString string, timeout time.Duration) {
func waitForTerminationMessage(t *testing.T, cli *client.Client, qmId string, terminationString string, timeout time.Duration) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
for {
@@ -93,7 +92,7 @@ func waitForTerminationMessage(t *testing.T, cli ce.ContainerInterface, qmId str
m := terminationMessage(t, cli, qmId)
if m != "" {
if !strings.Contains(m, terminationString) {
t.Fatalf("Expected container to fail with termination message %v. Got termination message: %v", terminationString, m)
t.Fatalf("Expected container to fail on missing required mount. Got termination message: %v", m)
}
return
}

View File

@@ -0,0 +1,219 @@
/*
© Copyright IBM Corporation 2021
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 main
import (
"testing"
"github.com/docker/docker/client"
)
// TestNativeHABasic creates 3 containers in a Native HA queue manager configuration
// and ensures the queue manger and replicas start as expected
func TestNativeHABasic(t *testing.T) {
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
version, err := getMQVersion(t, cli)
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
qmVolumes := []string{}
qmNetwork, err := createBridgeNetwork(cli, t)
if err != nil {
t.Fatal(err)
}
defer removeBridgeNetwork(cli, qmNetwork.ID)
for i := 0; i <= 2; i++ {
vol := createVolume(t, cli, containerNames[i])
defer removeVolume(t, cli, vol.Name)
qmVolumes = append(qmVolumes, vol.Name)
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
hostConfig := getHostConfig(t, 1, "", "", vol.Name)
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// TestNativeHAFailover creates 3 containers in a Native HA queue manager configuration,
// stops the active queue manager, checks a replica becomes active, and ensures the stopped
// queue manager comes back as a replica
func TestNativeHAFailover(t *testing.T) {
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
version, err := getMQVersion(t, cli)
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
qmVolumes := []string{}
qmNetwork, err := createBridgeNetwork(cli, t)
if err != nil {
t.Fatal(err)
}
defer removeBridgeNetwork(cli, qmNetwork.ID)
for i := 0; i <= 2; i++ {
vol := createVolume(t, cli, containerNames[i])
defer removeVolume(t, cli, vol.Name)
qmVolumes = append(qmVolumes, vol.Name)
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
hostConfig := getHostConfig(t, 1, "", "", vol.Name)
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
haStatus, err := getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
stopContainer(t, cli, haStatus.Active)
waitForFailoverHA(t, cli, haStatus.Replica)
startContainer(t, cli, haStatus.Active)
waitForReady(t, cli, haStatus.Active)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// 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
func TestNativeHASecure(t *testing.T) {
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
version, err := getMQVersion(t, cli)
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
qmNetwork, err := createBridgeNetwork(cli, t)
if err != nil {
t.Fatal(err)
}
defer removeBridgeNetwork(cli, qmNetwork.ID)
for i := 0; i <= 2; i++ {
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true")
hostConfig := getNativeHASecureHostConfig(t)
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
// with HA TLS enabled, overrides the default CipherSpec, and ensures the queue manger
// and replicas start as expected
func TestNativeHASecureCipherSpec(t *testing.T) {
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
version, err := getMQVersion(t, cli)
if err != nil {
t.Fatal(err)
}
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)
}
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
qmReplicaIDs := [3]string{}
qmNetwork, err := createBridgeNetwork(cli, t)
if err != nil {
t.Fatal(err)
}
defer removeBridgeNetwork(cli, qmNetwork.ID)
for i := 0; i <= 2; i++ {
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")
hostConfig := getNativeHASecureHostConfig(t)
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
defer cleanContainer(t, cli, ctr)
qmReplicaIDs[i] = ctr
}
waitForReadyHA(t, cli, qmReplicaIDs)
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2021, 2023
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,11 +19,13 @@ import (
"context"
"fmt"
"path/filepath"
"strconv"
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
)
const defaultHAPort = 9414
@@ -34,8 +36,16 @@ type HAReplicaStatus struct {
Replica [2]string
}
func getNativeHAContainerConfig(containerName string, replicaNames [3]string, haPort int) ce.ContainerConfig {
return ce.ContainerConfig{
func createBridgeNetwork(cli *client.Client, t *testing.T) (types.NetworkCreateResponse, error) {
return cli.NetworkCreate(context.Background(), t.Name(), types.NetworkCreate{})
}
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{
"LICENSE=accept",
"MQ_QMGR_NAME=QM1",
@@ -45,18 +55,15 @@ 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_1_NAME=%s", replicaNames[1]),
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_NAME=%s", replicaNames[2]),
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)", "127.0.0.1", haPort+1),
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_REPLICATION_ADDRESS=%s(%d)", "127.0.0.1", haPort+2),
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_REPLICATION_ADDRESS=%s(%d)", replicaNames[0], haPort),
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_REPLICATION_ADDRESS=%s(%d)", replicaNames[1], haPort),
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_REPLICATION_ADDRESS=%s(%d)", replicaNames[2], haPort),
},
//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) ce.ContainerHostConfig {
return ce.ContainerHostConfig{
func getNativeHASecureHostConfig(t *testing.T) container.HostConfig {
return container.HostConfig{
Binds: []string{
coverageBind(t),
filepath.Join(getCwd(t, true), "../tls") + ":/etc/mqm/ha/pki/keys/ha",
@@ -64,30 +71,15 @@ func getNativeHASecureHostConfig(t *testing.T) ce.ContainerHostConfig {
}
}
func getNativeHANetworkConfig(networkID string) ce.ContainerNetworkSettings {
return ce.ContainerNetworkSettings{
Networks: []string{networkID},
func getNativeHANetworkConfig(networkID string) network.NetworkingConfig {
return network.NetworkingConfig{
EndpointsConfig: map[string]*network.EndpointSettings{
networkID: &network.EndpointSettings{},
},
}
}
// 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) {
func getActiveReplicaInstances(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) (HAReplicaStatus, error) {
var actives []string
var replicas []string
@@ -112,9 +104,9 @@ func getActiveReplicaInstances(t *testing.T, cli ce.ContainerInterface, qmReplic
return HAReplicaStatus{actives[0], [2]string{replicas[0], replicas[1]}}, nil
}
func waitForReadyHA(t *testing.T, cli ce.ContainerInterface, qmReplicaIDs [3]string) {
func waitForReadyHA(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) {
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
for {
@@ -137,7 +129,7 @@ func waitForReadyHA(t *testing.T, cli ce.ContainerInterface, qmReplicaIDs [3]str
}
}
func waitForFailoverHA(t *testing.T, cli ce.ContainerInterface, replicas [2]string) {
func waitForFailoverHA(t *testing.T, cli *client.Client, replicas [2]string) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -22,20 +22,20 @@ import (
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
"github.com/docker/docker/client"
)
func TestGoldenPathMetric(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
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.
waitForMetricReady(t, port)
@@ -55,14 +55,14 @@ func TestGoldenPathMetric(t *testing.T) {
func TestMetricNames(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
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.
waitForMetricReady(t, port)
@@ -99,14 +99,14 @@ func TestMetricNames(t *testing.T) {
func TestMetricLabels(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
requiredLabels := []string{"qmgr"}
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
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.
waitForMetricReady(t, port)
@@ -148,13 +148,13 @@ func TestMetricLabels(t *testing.T) {
func TestRapidFirePrometheus(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
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.
waitForMetricReady(t, port)
@@ -182,13 +182,13 @@ func TestRapidFirePrometheus(t *testing.T) {
func TestSlowPrometheus(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
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.
waitForMetricReady(t, port)
@@ -213,14 +213,15 @@ func TestSlowPrometheus(t *testing.T) {
func TestContainerRestart(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
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.
waitForMetricReady(t, port)
@@ -238,10 +239,7 @@ func TestContainerRestart(t *testing.T) {
stopContainer(t, cli, id)
// Start the container cleanly
startContainer(t, cli, id)
port, err = cli.GetContainerPort(id, defaultMetricPort)
if err != nil {
t.Fatal(err)
}
port = getPort(t, cli, id, defaultMetricPort)
// Now the container is ready we prod the prometheus endpoint until it's up.
waitForMetricReady(t, port)
@@ -263,15 +261,16 @@ func TestContainerRestart(t *testing.T) {
func TestQMRestart(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
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.
waitForMetricReady(t, port)
@@ -320,14 +319,14 @@ func TestQMRestart(t *testing.T) {
func TestValidValues(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
// hostname := getIPAddress(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
defer cleanContainer(t, cli, id)
// hostname := getIPAddress(t, cli, id)
port := getPort(t, cli, id, defaultMetricPort)
// Now the container is ready we prod the prometheus endpoint until it's up.
waitForMetricReady(t, port)
@@ -344,7 +343,7 @@ func TestValidValues(t *testing.T) {
// 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
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)
}
}
@@ -356,14 +355,14 @@ func TestValidValues(t *testing.T) {
func TestChangingValues(t *testing.T) {
t.Parallel()
cli := ce.NewContainerClient()
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{1414, defaultMetricPort})
defer cleanContainer(t, cli, id)
// hostname := getIPAddress(t, cli, id)
port, err := cli.GetContainerPort(id, defaultMetricPort)
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{1414, defaultMetricPort})
defer cleanContainer(t, cli, id)
// hostname := getIPAddress(t, cli, id)
port := getPort(t, cli, id, defaultMetricPort)
// Now the container is ready we prod the prometheus endpoint until it's up.
waitForMetricReady(t, port)
@@ -387,11 +386,7 @@ func TestChangingValues(t *testing.T) {
}
// Send invalid data to the MQ listener to generate a FDC
noport, err := cli.GetContainerPort(id, 1414)
if err != nil {
t.Fatal(err)
}
listener := fmt.Sprintf("localhost:%s", noport)
listener := fmt.Sprintf("localhost:%s", getPort(t, cli, id, 1414))
conn, err := net.Dial("tcp", listener)
if err != nil {
t.Fatalf("Could not connect to the listener - %v", err)

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import (
"testing"
"time"
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
"github.com/docker/docker/api/types/container"
)
type mqmetric struct {
@@ -146,8 +146,8 @@ func waitForMetricReady(t *testing.T, port string) {
t.Fatalf("Metric endpoint failed to startup in timely manner")
}
func metricsContainerConfig() *ce.ContainerConfig {
return &ce.ContainerConfig{
func metricsContainerConfig() *container.Config {
return &container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + defaultMetricQMName,

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2022
# © Copyright IBM Corporation 2018, 2021
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,24 +15,24 @@
###############################################################################
# Application build environment (Maven)
###############################################################################
FROM registry.access.redhat.com/ubi8/openjdk-8 as builder
COPY pom.xml ./
FROM registry.redhat.io/ubi8/openjdk-8 as builder
COPY pom.xml .
#WORKDIR /usr/src/mymaven
# Download dependencies separately, so Docker caches them
RUN mvn dependency:go-offline install
# Copy source
COPY src ./src
COPY src .
# Run the main build
RUN mvn --offline install
# Print a list of all the files (useful for debugging)
RUN find ./
RUN find .
###############################################################################
# Application runtime (JRE only, no build environment)
###############################################################################
# OpenJDK is not technically supported with the MQ client, but is good enough for these tests
FROM registry.access.redhat.com/ubi8/openjdk-8-runtime
FROM registry.redhat.io/ubi8/openjdk-8-runtime
COPY --from=builder /home/jboss/target/*.jar /opt/app/
COPY --from=builder /home/jboss/target/lib/*.jar /opt/app/
USER 1001
ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "--fail-if-no-tests", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]
ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]

View File

@@ -1,5 +1,5 @@
<!--
© Copyright IBM Corporation 2018, 2022
© Copyright IBM Corporation 2018, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -26,25 +26,25 @@ limitations under the License.
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId>
<version>9.3.0.0</version>
<version>9.2.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
<version>5.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<version>5.5.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-console-standalone</artifactId>
<version>1.8.2</version>
<version>1.5.2</version>
<scope>runtime</scope>
</dependency>
</dependencies>

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2018, 2023
© Copyright IBM Corporation 2018, 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -51,7 +51,6 @@ class JMSTests {
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 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 CHANNEL = System.getenv("MQ_CHANNEL");
protected static final String TRUSTSTORE = System.getenv("MQ_TLS_TRUSTSTORE");
@@ -68,11 +67,11 @@ class JMSTests {
return ctx.getSocketFactory();
}
static MQConnectionFactory createMQConnectionFactory(String channel, String addr, String port) throws JMSException, IOException, GeneralSecurityException {
static MQConnectionFactory createMQConnectionFactory(String channel, String addr) throws JMSException, IOException, GeneralSecurityException {
MQConnectionFactory factory = new MQConnectionFactory();
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
factory.setChannel(channel);
factory.setConnectionNameList(String.format("%s(%s)", addr, port));
factory.setConnectionNameList(String.format("%s(1414)", addr));
if (TRUSTSTORE == null) {
LOGGER.info("Not using TLS");
}
@@ -83,10 +82,11 @@ class JMSTests {
boolean ibmjre = System.getenv("IBMJRE").equals("true");
if (ibmjre){
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
factory.setSSLCipherSuite("SSL_RSA_WITH_AES_128_CBC_SHA256");
} else {
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
factory.setSSLCipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA256");
}
factory.setSSLCipherSuite(System.getenv("MQ_TLS_CIPHER"));
}
return factory;
}
@@ -94,9 +94,9 @@ class JMSTests {
/**
* Create a JMSContext with the supplied user and password.
*/
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(%s) as %s", channel, addr, port, user));
MQConnectionFactory factory = createMQConnectionFactory(channel, addr, port);
static JMSContext create(String channel, String addr, String user, String password) throws JMSException, IOException, GeneralSecurityException {
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as %s", channel, addr, user));
MQConnectionFactory factory = createMQConnectionFactory(channel, addr);
// If a password is set, make sure it gets sent to the queue manager for authentication
if (password != null) {
factory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
@@ -108,9 +108,9 @@ class JMSTests {
/**
* Create a JMSContext with the default user identity (from the OS)
*/
static JMSContext create(String channel, String addr, String port) throws JMSException, IOException, GeneralSecurityException {
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, port);
static JMSContext create(String channel, String addr) throws JMSException, IOException, GeneralSecurityException {
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as OS user '%s'", channel, addr, System.getProperty("user.name")));
MQConnectionFactory factory = createMQConnectionFactory(channel, addr);
LOGGER.info(String.format("CSP authentication: %s", factory.getBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP)));
return factory.createContext();
}
@@ -119,7 +119,7 @@ class JMSTests {
private static void waitForQueueManager() {
for (int i = 0; i < 20; i++) {
try {
Socket s = new Socket(ADDR, Integer.parseInt(PORT));
Socket s = new Socket(ADDR, 1414);
s.close();
return;
} catch (IOException e) {
@@ -133,7 +133,7 @@ class JMSTests {
@Test
void putGetTest(TestInfo t) throws Exception {
context = create(CHANNEL, ADDR, PORT, USER, PASSWORD);
context = create(CHANNEL, ADDR, USER, PASSWORD);
Queue queue = new MQQueue("DEV.QUEUE.1");
context.createProducer().send(queue, t.getDisplayName());
Message m = context.createConsumer(queue).receive();
@@ -145,7 +145,7 @@ class JMSTests {
LOGGER.info(String.format("Password='%s'", PASSWORD));
try {
// Don't pass a user/password, which should cause the default identity to be used
context = create(CHANNEL, ADDR, PORT);
context = create(CHANNEL, ADDR);
} catch (DetailedJMSSecurityRuntimeException ex) {
Throwable cause = ex.getCause();
assertNotNull(cause);

View File

@@ -1,23 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIUc5EKoPi8cg2M2n+SqCPn44LFjoAwDQYJKoZIhvcNAQEL
BQAwcjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9y
azEMMAoGA1UECgwDSUJNMQwwCgYDVQQLDANJQk0xDDAKBgNVBAMMA0lCTTEZMBcG
CSqGSIb3DQEJARYKbXFAaWJtLmNvbTAeFw0yMjEwMDYxMzA2NTVaFw0zMjEwMDMx
MzA2NTVaMHIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTERMA8GA1UEBwwITmV3
IFlvcmsxDDAKBgNVBAoMA0lCTTEMMAoGA1UECwwDSUJNMQwwCgYDVQQDDANJQk0x
GTAXBgkqhkiG9w0BCQEWCm1xQGlibS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCls3oNIDxzKct0NXVsoz1Hng3BcaDPcBRYCNgAEwDOVe3rEEbZ
d2KFliDgCG3hCHMM1Yaabx3iTVsKklubBxr1JFmyDtgb4z9mJpMVYXS+gsKsZOs/
vNSmzpt5VlbEadHKJ/aFf/EWxvoOP80UiEeUJt36aWFUTyjjyArd2xS8fD1DATFB
U2bteaWfkpuLeFiTtwftZhsLv1s5T35+Ex087eX1tkm/TArxZsNl/9RrSWsbJh/t
bjiRKn+fCZdirFsurP3Si5Jd9laCW0RBKAKYEh40XYDgjLhvcazDPTBueTHXQPG5
S0hCOhCJiCWpPCsh8rIOCz0D9YIByZADR1WvAgMBAAGjUzBRMB0GA1UdDgQWBBS5
OsiPqZXlMwpMqGKczUg3qVvy0zAfBgNVHSMEGDAWgBS5OsiPqZXlMwpMqGKczUg3
qVvy0zAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBfwYRcckke
/NzDHlFb8TBlUDqERmlT/qTWamVZO2Zuo4Y0BFOYFEA23F5sQU2s2MFSEZcAKe5v
mJroFE2rr4aY4bJ4Z0UXlOAYyqNxVOTI4MIxwbg3GVr8c8oWBnAmgqI9W9OpgZ52
/bN24XL9s6I3TeOTtYI9z5O70Kl/E3nG8GcfMw0EtNIy0UPUWvJH8FgEsotsRO9v
tPtlZklEK/D+Keozbs2shdNhKgVnDatpdTBqvwLztb1+te5AckuOnJsnG+iIrG2D
Ehoq2O3gktIVdAk4sv2BoONzegLWB+GSxGVZsemfYF4PkN9/w+znz0LK/ATAtabK
rikk0yC+Xg8z
-----END CERTIFICATE-----

View File

@@ -1,34 +0,0 @@
#!/bin/bash -ex
# -*- mode: sh -*-
# © Copyright IBM Corporation 2018, 2022
#
# 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.
KEY=server.key
CERT=server.crt
CACERT=cacert.crt
CAPEM=rootcakey.pem
# Create a private key and certificate in PEM format, for the server to use
openssl req \
-newkey rsa:2048 -nodes -keyout ${KEY} \
-subj "/CN=localhost" \
-addext "subjectAltName = DNS:localhost" \
-x509 -days 3650 -out ${CERT}
# Generate the private key of the root CA
openssl genrsa -out ${CAPEM} 2048
#Generate the self-signed root CA certificate. Manual input is required when prompted
openssl req -x509 -sha256 -new -nodes -key ${CAPEM} -days 3650 -out ${CACERT}

View File

@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApbN6DSA8cynLdDV1bKM9R54NwXGgz3AUWAjYABMAzlXt6xBG
2XdihZYg4Aht4QhzDNWGmm8d4k1bCpJbmwca9SRZsg7YG+M/ZiaTFWF0voLCrGTr
P7zUps6beVZWxGnRyif2hX/xFsb6Dj/NFIhHlCbd+mlhVE8o48gK3dsUvHw9QwEx
QVNm7Xmln5Kbi3hYk7cH7WYbC79bOU9+fhMdPO3l9bZJv0wK8WbDZf/Ua0lrGyYf
7W44kSp/nwmXYqxbLqz90ouSXfZWgltEQSgCmBIeNF2A4Iy4b3Gswz0wbnkx10Dx
uUtIQjoQiYglqTwrIfKyDgs9A/WCAcmQA0dVrwIDAQABAoIBAQCcL9ZltPMF4mlh
+lnasuu6K+LvafmYTh7+9CcVutPRqfF+1nLR3NRC8sW+JnPb36kCeepMe1yByUR9
bINoV4QzebYKPi+56bQCx21wg9IVGRACi4WrKISRTsIB1z4mGVCj6pNWNsi7HYbq
E31tUx+VKCWoOdiCLbNvMUn84Npk5npK9P9F86qypSJqJv3HORgOa58x7qZiD2fk
TroLuGHKFWGtSiK1vvgax8gBwMi9JvWoPhwHagINh0WwT820+3/4KbqcsvRNSIu8
qA+ltk/Vt0ftwPMpxPYnvRFrSvzYIRE04fbWqA3mxhPr/oP3xXrwyd1hnX6GzPIR
KXeX1i7BAoGBANGV6XtL8cq8tu/4emOYDn4tncMRICQ8uMWZqnIQAvX8PBx1w9E2
Wbkl0oBHJ/gDtU+feDvbHI0JBvXerce2cxj4+793TGLUl980dgq776x2fcxHjvYZ
uZjJd4M95Lh+IhtWGZQ1FviiylDg62w+mrNydX8WiFjLGYPydQqCIAAxAoGBAMpl
m/MDqpgPxiDU1O9DAq8C/0MQUOc/p+67aGsYxmPDdCouBLA/zckQh6Cp9Wo3n7MF
X5UHOqn72q/4ahNEx+3YQoaLqRKTjUHl3r3zj+MsM0hIDp1uOxVzbANxazuLuqqA
C+yJTmRU7uvNPH1AMFJBKRSmhd3MJwoHF/KZAhvfAoGAFaGPU3ZnIjGP//x5RUYw
WL2EhtmBo7vQpjRR7yvP4muCGL3e0/z0DbPloe+2JFbdo7Ylxqe6rqO74Cx3ayFd
h7pK4VwCukCO3C6h8EGtXvNr0GWiT6wgB7DjcNw2ewQpqQCd6zn/gPHsR6SvJ6De
fp7VmaRNtjxgCcpAYjFD9EECgYAhEPaofjnZvAH/jSX4rPb8Rr4TY9AD58d03lNR
4+tNkzogRgJoFRR2u+ecnQfGQa4qnj8eZt7ztHzm8OvLmBodxo4f0yNdMJQMZxS7
7dXdJHSAY51XpRGsEH5eFaKSSOLHRkIsc8ZF6AZcqdwvDlSWq6SdhhMqyFa8cao8
7TiF+wKBgADNZ4HoZDfnuH5jUvf7y+YlxDX3jxWR+BUTLCJmt082uT+8Xg5SALec
B8GP5s6VKglD5Wzj8IhxvpQ5yzH9DRHwEeu3vFLBinIUlWdBiXwtnbmY0E9r3PSb
pZQH5RZ5PyrJicIVBJSqdFu2HDl4heeLJE0LGh7SQnFaexxXn397
-----END RSA PRIVATE KEY-----

View File

@@ -1,19 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDHzCCAgegAwIBAgIUUFCo8fUglrbfDY8ZUDnzAfWeq54wDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMTAwNjEzMDYwMloXDTMyMTAw
MzEzMDYwMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAxcja4TbshPj4tWgbRP73eDs2382j6Km5TNej6To13PJq
Wyezg081ctmgFEMlgbRiowZmecpYOKjDKuVDtfLE6nZMmN+PjXXuOMGIPu67fx/4
tnaMDYw96WIBEFNVZ7dC/pceaTIRbnjma89o1/mTudTAYPLAvKpeBqpJJFWPMDhz
nK3NKeydTdUYc9jmEJWiFCI4bUdyvyUjp+7QrDbdODXo27/nVAV0Ih+OuU4ZnxT5
cf1fzVV1ZqHd8jbLm25ZoAmkk+9DSXFNA2hbSepf70mRVD/Qyn8U6b5A2v+mWIfs
B1+iAlPl7IX88W1Q9q1yu0uT8YWGWpeTbeOnJ4WJ8wIDAQABo2kwZzAdBgNVHQ4E
FgQUEjp6AtPmpuLQyBPeiW4pW+VGb2wwHwYDVR0jBBgwFoAUEjp6AtPmpuLQyBPe
iW4pW+VGb2wwDwYDVR0TAQH/BAUwAwEB/zAUBgNVHREEDTALgglsb2NhbGhvc3Qw
DQYJKoZIhvcNAQELBQADggEBAL2bTWfTqxfN0YbBPjG05sR4nO8mhbNSGHDuGeiO
OP0wPxkgAueScTpyhHWEAJmMQOMUM9KhByZj7LnqW8XY9BBS3zPAyzAdia8/o6Vl
7El+M2JCfqz7hSupRK8M+r+XUq3hyEFjPLt+KO6D5VNzXiTM+36UueeQD3aaxxyo
LpHSPeXFBkOrT/wt6FHi4NHvWls95PllncWZVYjxPMUUF/o30tOxSmgXwjUknrI8
29ADKM1IbFuXd4vKYG9V+ukI6n5F86PYrN2ajPBKIidvTqU8tPzMHuJZ3YiIiv8p
TARE2b5YLWuu+aF2z/V71MmIWr0uyOk6pZVGOCw7fwHx/wg=
-----END CERTIFICATE-----

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyNrhNuyE+Pi1
aBtE/vd4OzbfzaPoqblM16PpOjXc8mpbJ7ODTzVy2aAUQyWBtGKjBmZ5ylg4qMMq
5UO18sTqdkyY34+Nde44wYg+7rt/H/i2dowNjD3pYgEQU1Vnt0L+lx5pMhFueOZr
z2jX+ZO51MBg8sC8ql4GqkkkVY8wOHOcrc0p7J1N1Rhz2OYQlaIUIjhtR3K/JSOn
7tCsNt04Nejbv+dUBXQiH465ThmfFPlx/V/NVXVmod3yNsubblmgCaST70NJcU0D
aFtJ6l/vSZFUP9DKfxTpvkDa/6ZYh+wHX6ICU+XshfzxbVD2rXK7S5PxhYZal5Nt
46cnhYnzAgMBAAECggEBAKLRsZZbf6QLzbqRBHntJ04b+RWOlVOQfRHMJ4x1Nig4
i+OUsEv1pftxOj3T9QlstRKdzziNociq7VffurkLLJ4TWwUybVu37K9easncABAs
ArQ6rRruC32YB2YoJBOoowcw4oEZDY6TCqVP7nB1be46PVDSJmZqHdOA1YuKv8Ci
FbzLZEKYy6QGmHp9xMzc3usQ+KRNIFcR3NJb0eCbfAXb0tP3F12i4ygnxifkOVQS
hukTJlZVbAO3W9uUEzLh5bkLoPfob6Vrwv1tGQ48uFgzgPXc4bWOUDFXHW5+vQLD
1MKFboozrNhRR+Q5xvbRnaWEv4hMHlUNggc5ErRj6CkCgYEA5m5f1VfhfqSvEF2c
XcIfUDiCzREpllY2ZdBSfUlz/GA6f0QUyFJBCdd4ypipQcggn60de9DoKDcNcq32
rfVfANpsciJq9s4+xLL8MGtUuoi4HK8LHP3tc8aJaAcCVjBFbz0orKXDUOcue6A5
Z5riDjiXOE56XSLSSNSRjWh4psUCgYEA27sfaM4J0YkdFuth/Qu+X9PeroUZyC0T
3glMN/7PU4jZg+2v4Psfe61gj8qOt0catuWvsD0wQTy3jt+svY/KfkbspK6/7CEG
fKx1AB1xeMr4JuQp9POFVhKRn4sBUMbHOkbjzlNpGmUI2arlLRTwT8YpuMDjCK4l
ZuUYB/IHOVcCgYAqexqryCHIKTAlAjz7g/gl3+UtTQavsoEg0AEFG++IDW17XN+/
9noLCHA6WV6KxAxPo6iV1POXxl5yT+P0OhIjpCDuAa5ahbdIp/6aJo9ePCpFD3gr
Bh0qhOV8Ch7CKPAEC/Bds8mINrZ5EBbFJOab3I70UHN6jBrcVmPm/+WOSQKBgQCW
AbBWt1qCnu2qCPWzcAH+n8DFOf645vVKPuS20ZEuwR1l8K2ClU4P+/QRFkLKIpO9
Sx7e3VcFInNZ6Z+fJfwiqz7AysAhbwZjtMSHWJJv2XkB7AAsxtc/RJv/5ED4qUu3
oE/DOrRlHZamKwIb/dB1VZ6ED8Ku2VyVW09FlViTLwKBgEU21xqvP1+TXzsrZNGm
/Hj/RAaA8B6tyo5Dj9glV80oakMSaxBsLP9xHkoZjkHaJnoFosKBQSnCcPnEY4gP
22WEyGshu8sujLibLKWhARqjeubatXv+XBxiDdMbgcd/XTwbI4HTjXy5LF0o47UI
W6itMOg9uCfBJM/i2jrAkmQR
-----END PRIVATE KEY-----

View File

@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDiTCCAnECFClOtyvBoQXVAGMcX0ObUawZJuYAMA0GCSqGSIb3DQEBCwUAMH0x
CzAJBgNVBAYTAklOMQswCQYDVQQIDAJLQTEMMAoGA1UEBwwDQkxSMQwwCgYDVQQK
DANJQk0xDDAKBgNVBAsMA0lTTDEQMA4GA1UEAwwHTVFNRlRRTTElMCMGCSqGSIb3
DQEJARYWc2hhc2hpa2FudGhAaW4uaWJtLmNvbTAeFw0yMzAxMjUwNjQzMTBaFw0y
NTA0MjkwNjQzMTBaMIGEMQswCQYDVQQGEwJVUzELMAkGA1UECAwCSUwxEDAOBgNV
BAcMB0NISUNBR08xEDAOBgNVBAoMB0J1cnJhZ28xCzAJBgNVBAsMAkJHMRAwDgYD
VQQDDAdNUVFNQ05UMSUwIwYJKoZIhvcNAQkBFhZzaGFzaGlrYW50aEBpbi5pYm0u
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAys3CaU4vXdZuKyw5
AMkM4onEiJk3/TulWZIrXvFMgYLzAPX5eVUzs+eKfSBVIRiDGtsbmhcztT1GiAU6
l8G9jHSegItJpKjiBEfFEuMmV6Fhx7ZjQdpyGdV+0bcE2IJHmeiaNxouvsV5gBJT
vEamVsw9zU7GGOhhMyBQUUQDNy7yoHn8CBhDdoBskwJtpqPcxzohUDDt5wqSqOUl
jo8yS375k4Q18hWzWIxJIAHoAFk+YyJqLq3mqq438Z9WSgjv9V+eLpNtKlge2IzW
d1uH/siXE8Pp6p3WleG7cw2dzQZap+ekbx+3rRVLs8WYBHeTx08980sv6bBUKwHw
aXXXSQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAMrE0nDBw8wfPR8w7hrUPyG1Ib
/k72yAv9wqaso1pL4IpXE3DFbuoIOQLjNCr+C7h2IzegRZ1z4kZbWh7LeES7M0io
yDgM16Vikr9ek+NCLmF5QAtn/smhfhSEOjJoGkTPUTdWR4VdLeMFGQ9D8LHc0DFP
EyPZy0JZQpRiXAs0ZEDhlFOCxI1aZzJhwGBJd9wOlG/SZKI8izC74mNPU1eE7Js6
1sdU+4zs2wm/QtZ1MLlkKspSQqdNis/wpSSyjTEr9TkfzxVr4f3bALjQydkrcAyv
BkATBYqvJYSHA3PS8VxNTDVef5EgKEWXlCmP/jfMcYNsUxBjaUcqiJJcmI9e
-----END CERTIFICATE-----

Some files were not shown because too many files have changed in this diff Show More