Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcdd76cb55 | ||
|
|
b234eb33c8 | ||
|
|
a5f4bb624c | ||
|
|
a2f2c1fe3b | ||
|
|
ba59442c1c | ||
|
|
e0c3b36b61 | ||
|
|
4dbdc42ca5 |
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
downloads
|
||||||
|
.git
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,3 @@
|
|||||||
.dockerignore
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.vscode
|
.vscode
|
||||||
test/docker/coverage
|
test/docker/coverage
|
||||||
@@ -6,7 +5,7 @@ test/docker/vendor
|
|||||||
test/kubernetes/vendor
|
test/kubernetes/vendor
|
||||||
build
|
build
|
||||||
coverage
|
coverage
|
||||||
#downloads
|
downloads
|
||||||
incubating/mqipt/ms81*
|
incubating/mqipt/ms81*
|
||||||
vendor/github.com/prometheus/client_model/bin/
|
vendor/github.com/prometheus/client_model/bin/
|
||||||
vendor/github.com/prometheus/client_model/.classpath
|
vendor/github.com/prometheus/client_model/.classpath
|
||||||
|
|||||||
32
.travis.yml
32
.travis.yml
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018, 2023
|
# © Copyright IBM Corporation 2018, 2020
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -18,14 +18,14 @@ sudo: required
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- "1.19.9"
|
- "1.17.12"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- MAIN_BRANCH=private-master
|
- MAIN_BRANCH=v9.3.1
|
||||||
- TAGCACHE_FILE=tagcache
|
- TAGCACHE_FILE=tagcache
|
||||||
- RELEASE=r1
|
- RELEASE=r1
|
||||||
|
|
||||||
@@ -38,51 +38,51 @@ go_import_path: "github.com/ibm-messaging/mq-container"
|
|||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- stage: basic-build
|
- stage: basic-build
|
||||||
if: branch != private-master AND tag IS blank
|
if: branch != v9.3.1 AND tag IS blank
|
||||||
name: "Basic AMD64 build"
|
name: "Basic AMD64 build"
|
||||||
os: linux
|
os: linux
|
||||||
env:
|
env:
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_931_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
|
|
||||||
# CD Build
|
# CD Build
|
||||||
|
|
||||||
- stage: global-tag
|
- stage: global-tag
|
||||||
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
|
if: branch = v9.3.1 AND type != pull_request OR tag =~ ^release-candidate*
|
||||||
name: "Generate Global Tag"
|
name: "Generate Global Tag"
|
||||||
os: linux
|
os: linux
|
||||||
script: bash -e travis-build-scripts/global-tag.sh
|
script: bash -e travis-build-scripts/global-tag.sh
|
||||||
- stage: build
|
- stage: build
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = v9.3.1 OR tag =~ ^release-candidate*
|
||||||
name: "Multi-Arch AMD64 build"
|
name: "Multi-Arch AMD64 build"
|
||||||
os: linux
|
os: linux
|
||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_AMD64
|
- MQ_ARCHIVE_REPOSITORY=$MQ_931_ARCHIVE_REPOSITORY_AMD64
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_931_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
- stage: build
|
- stage: build
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = v9.3.1 OR tag =~ ^release-candidate*
|
||||||
name: "Multi-Arch S390X build"
|
name: "Multi-Arch S390X build"
|
||||||
os: linux-s390
|
os: linux-s390
|
||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_S390X
|
- MQ_ARCHIVE_REPOSITORY=$MQ_931_ARCHIVE_REPOSITORY_S390X
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_S390X
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_931_ARCHIVE_REPOSITORY_DEV_S390X
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
- stage: build
|
- stage: build
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = v9.3.1 OR tag =~ ^release-candidate*
|
||||||
name: "Multi-Arch PPC64LE build"
|
name: "Multi-Arch PPC64LE build"
|
||||||
os: linux-ppc64le
|
os: linux-ppc64le
|
||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_PPC64LE
|
- MQ_ARCHIVE_REPOSITORY=$MQ_931_ARCHIVE_REPOSITORY_PPC64LE
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_PPC64LE
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_931_ARCHIVE_REPOSITORY_DEV_PPC64LE
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
- stage: push-manifest
|
- stage: push-manifest
|
||||||
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
|
if: branch = v9.3.1 AND type != pull_request OR tag =~ ^release-candidate*
|
||||||
name: "Push Manifest-list to registry"
|
name: "Push Manifest-list to registry"
|
||||||
env:
|
env:
|
||||||
- PUSH_MANIFEST_ONLY=true
|
- PUSH_MANIFEST_ONLY=true
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"settingsInheritedFrom": "whitesource-config/whitesource-config@master",
|
"settingsInheritedFrom": "whitesource-config/whitesource-config@master",
|
||||||
"scanSettings": {
|
"scanSettings": {
|
||||||
"configMode": "LOCAL",
|
|
||||||
"baseBranches": ["private-master", "v9.2.0.x-eus", "v9.3.0.x"]
|
"baseBranches": ["private-master", "v9.2.0.x-eus", "v9.3.0.x"]
|
||||||
},
|
},
|
||||||
"issueSettings": {
|
"issueSettings": {
|
||||||
|
|||||||
39
CBO.md
39
CBO.md
@@ -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
|
|
||||||
```
|
|
||||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,15 +1,8 @@
|
|||||||
# Change log
|
# Change log
|
||||||
|
|
||||||
## 9.3.3.0 (2023-06)
|
## 9.3.1.1 (2023-01)
|
||||||
|
|
||||||
* Updated to MQ version 9.3.3.0
|
* Updated to MQ version 9.3.1.1
|
||||||
|
|
||||||
## 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)
|
## 9.3.1.0-r2 (2022-11)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2015, 2023
|
# © Copyright IBM Corporation 2015, 2022
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -12,40 +12,38 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# 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_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal
|
||||||
ARG BASE_TAG=8.10-896.1716497715
|
ARG BASE_TAG=8.7-1031
|
||||||
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
|
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
|
||||||
ARG BUILDER_TAG=1.21.9-3.1716505664
|
ARG BUILDER_TAG=1.17.12-11
|
||||||
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
|
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
|
||||||
ARG MQ_ARCHIVE="downloads/9.3.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.3.1.1-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build stage to build Go code
|
# Build stage to build Go code
|
||||||
###############################################################################
|
###############################################################################
|
||||||
FROM $BUILDER_IMAGE:$BUILDER_TAG as builder
|
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_REVISION="Not specified"
|
||||||
ARG IMAGE_SOURCE="Not specified"
|
ARG IMAGE_SOURCE="Not specified"
|
||||||
ARG IMAGE_TAG="Not specified"
|
ARG IMAGE_TAG="Not specified"
|
||||||
ARG GO_WORKDIR
|
ARG GO_WORKDIR
|
||||||
ARG MQ_ARCHIVE
|
|
||||||
USER 0
|
USER 0
|
||||||
|
WORKDIR /opt/mqm
|
||||||
|
# Download and extract MQ files, to get the MQ client needed to compile.
|
||||||
|
# Only extract certain MQ files to make the build quicker
|
||||||
|
RUN curl --fail --location $MQ_URL | tar --extract --gunzip \
|
||||||
|
&& chown -R 1001:root /opt/mqm/*
|
||||||
WORKDIR $GO_WORKDIR/
|
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 go.mod go.sum ./
|
||||||
COPY cmd/ ./cmd
|
COPY cmd/ ./cmd
|
||||||
COPY internal/ ./internal
|
COPY internal/ ./internal
|
||||||
COPY pkg/ ./pkg
|
COPY pkg/ ./pkg
|
||||||
COPY vendor/ ./vendor
|
COPY vendor/ ./vendor
|
||||||
|
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \
|
||||||
|
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
|
||||||
|
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 -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/chkmqready/ \
|
||||||
&& go build ./cmd/chkmqhealthy/ \
|
&& go build ./cmd/chkmqhealthy/ \
|
||||||
@@ -60,44 +58,11 @@ RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"
|
|||||||
&& go test -v ./internal/... \
|
&& go test -v ./internal/... \
|
||||||
&& go vet ./cmd/... ./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
|
# Main build stage, to build MQ image
|
||||||
###############################################################################
|
###############################################################################
|
||||||
FROM $BASE_IMAGE:$BASE_TAG AS mq-server
|
FROM $BASE_IMAGE:$BASE_TAG AS mq-server
|
||||||
|
# The MQ packages to install - see install-mq.sh for default value
|
||||||
ARG MQ_URL
|
ARG MQ_URL
|
||||||
ARG BASE_IMAGE
|
ARG BASE_IMAGE
|
||||||
ARG BASE_TAG
|
ARG BASE_TAG
|
||||||
@@ -114,14 +79,15 @@ LABEL summary="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 world’s most successful enterprises" \
|
io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises" \
|
||||||
base-image=$BASE_IMAGE \
|
base-image=$BASE_IMAGE \
|
||||||
base-image-release=$BASE_TAG
|
base-image-release=$BASE_TAG
|
||||||
COPY --from=mq-redux /opt/mqm-redux/ /opt/mqm/
|
COPY install-mq.sh /usr/local/bin/
|
||||||
COPY setup-image.sh /usr/local/bin/
|
|
||||||
COPY install-mq-server-prereqs.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 \
|
RUN env \
|
||||||
|
&& mkdir /opt/mqm \
|
||||||
&& chmod u+x /usr/local/bin/install-*.sh \
|
&& chmod u+x /usr/local/bin/install-*.sh \
|
||||||
&& chmod u+x /usr/local/bin/setup-image.sh \
|
&& sleep 1 \
|
||||||
&& install-mq-server-prereqs.sh \
|
&& install-mq-server-prereqs.sh \
|
||||||
&& setup-image.sh \
|
&& install-mq.sh \
|
||||||
&& /opt/mqm/bin/security/amqpamcf \
|
&& /opt/mqm/bin/security/amqpamcf \
|
||||||
&& chown -R 1001:root /opt/mqm/*
|
&& chown -R 1001:root /opt/mqm/*
|
||||||
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/
|
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/
|
||||||
@@ -144,9 +110,7 @@ RUN chmod ug+x /usr/local/bin/runmqserver \
|
|||||||
EXPOSE 1414 9157 9443
|
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_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 MQ_GRACE_PERIOD=30
|
||||||
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1
|
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic
|
||||||
ENV MQ_LOGGING_CONSOLE_EXCLUDE_ID=AMQ5041I,AMQ5052I,AMQ5051I,AMQ5037I,AMQ5975I
|
|
||||||
ENV WLP_LOGGING_MESSAGE_FORMAT=json
|
|
||||||
# We can run as any UID
|
# We can run as any UID
|
||||||
USER 1001
|
USER 1001
|
||||||
ENV MQ_CONNAUTH_USE_HTP=false
|
ENV MQ_CONNAUTH_USE_HTP=false
|
||||||
@@ -157,6 +121,9 @@ ENTRYPOINT ["runmqserver"]
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Use the Go toolset image, which already includes gcc and the MQ SDK
|
# Use the Go toolset image, which already includes gcc and the MQ SDK
|
||||||
FROM builder as cbuilder
|
FROM builder 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
|
USER 0
|
||||||
# Install the Apache Portable Runtime code (used for htpasswd hash checking)
|
# 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 --assumeyes --disableplugin=subscription-manager install apr-devel apr-util-openssl apr-util-devel
|
||||||
@@ -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 world’s 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 world’s 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 world’s 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 world’s 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"]
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
ARG BASE_IMAGE
|
ARG BASE_IMAGE
|
||||||
|
|
||||||
# Build stage to build Go code
|
# 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/
|
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
|
||||||
COPY cmd/ ./cmd
|
COPY cmd/ ./cmd
|
||||||
COPY internal/ ./internal
|
COPY internal/ ./internal
|
||||||
|
|||||||
136
Makefile
136
Makefile
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2017, 2023
|
# © Copyright IBM Corporation 2017, 2022
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -45,10 +45,10 @@ MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH)_NOI
|
|||||||
MQ_ARCHIVE_DEV ?= $(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-$(MQ_ARCHIVE_DEV_TYPE)$(MQ_ARCHIVE_DEV_ARCH).tar.gz
|
MQ_ARCHIVE_DEV ?= $(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-$(MQ_ARCHIVE_DEV_TYPE)$(MQ_ARCHIVE_DEV_ARCH).tar.gz
|
||||||
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
||||||
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
# Options to `go test` for the Container tests
|
# Options to `go test` for the Docker tests
|
||||||
TEST_OPTS_CONTAINER ?=
|
TEST_OPTS_DOCKER ?=
|
||||||
# Timeout for the tests
|
# Timeout for the Docker tests
|
||||||
TEST_TIMEOUT_CONTAINER ?= 45m
|
TEST_TIMEOUT_DOCKER ?= 30m
|
||||||
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
||||||
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
||||||
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
||||||
@@ -75,6 +75,8 @@ VOLUME_MOUNT_OPTIONS ?= :Z
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Other variables
|
# Other variables
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
# Build doesn't work if BuildKit is enabled
|
||||||
|
DOCKER_BUILDKIT=0
|
||||||
# Lock Docker API version for compatibility with Podman and with the Docker version in Travis' Ubuntu Bionic
|
# Lock Docker API version for compatibility with Podman and with the Docker version in Travis' Ubuntu Bionic
|
||||||
DOCKER_API_VERSION=1.40
|
DOCKER_API_VERSION=1.40
|
||||||
GO_PKG_DIRS = ./cmd ./internal ./test
|
GO_PKG_DIRS = ./cmd ./internal ./test
|
||||||
@@ -278,9 +280,9 @@ cache-mq-tag:
|
|||||||
# Test targets
|
# Test targets
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# Vendor Go dependencies for the Container tests
|
# Vendor Go dependencies for the Docker tests
|
||||||
test/container/vendor:
|
test/docker/vendor:
|
||||||
cd test/container && go mod vendor
|
cd test/docker && go mod vendor
|
||||||
|
|
||||||
# Shortcut to just run the unit tests
|
# Shortcut to just run the unit tests
|
||||||
.PHONY: test-unit
|
.PHONY: test-unit
|
||||||
@@ -288,28 +290,28 @@ test-unit:
|
|||||||
$(COMMAND) build --target builder --file Dockerfile-server .
|
$(COMMAND) build --target builder --file Dockerfile-server .
|
||||||
|
|
||||||
.PHONY: test-advancedserver
|
.PHONY: test-advancedserver
|
||||||
test-advancedserver: test/container/vendor
|
test-advancedserver: test/docker/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||||
$(COMMAND) inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
$(COMMAND) inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
||||||
cd test/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)
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
.PHONY: build-devjmstest
|
.PHONY: build-devjmstest
|
||||||
build-devjmstest:
|
build-devjmstest:
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
||||||
cd test/messaging && $(COMMAND) build --tag $(DEV_JMS_IMAGE) .
|
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
|
||||||
|
|
||||||
.PHONY: test-devserver
|
.PHONY: test-devserver
|
||||||
test-devserver: test/container/vendor
|
test-devserver: test/docker/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||||
$(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
$(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
||||||
cd test/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)
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=false DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
coverage:
|
coverage:
|
||||||
mkdir coverage
|
mkdir coverage
|
||||||
|
|
||||||
.PHONY: test-advancedserver-cover
|
.PHONY: test-advancedserver-cover
|
||||||
test-advancedserver-cover: test/container/vendor coverage
|
test-advancedserver-cover: test/docker/vendor coverage
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell $(COMMAND) --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell $(COMMAND) --version)"$(END)))
|
||||||
rm -f ./coverage/unit*.cov
|
rm -f ./coverage/unit*.cov
|
||||||
# Run unit tests with coverage, for each package under 'internal'
|
# Run unit tests with coverage, for each package under 'internal'
|
||||||
@@ -319,16 +321,16 @@ test-advancedserver-cover: test/container/vendor coverage
|
|||||||
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
|
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
|
||||||
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
|
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
|
||||||
|
|
||||||
rm -f ./test/container/coverage/*.cov
|
rm -f ./test/docker/coverage/*.cov
|
||||||
rm -f ./coverage/container.*
|
rm -f ./coverage/docker.*
|
||||||
mkdir -p ./test/container/coverage/
|
mkdir -p ./test/docker/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)
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test $(TEST_OPTS_DOCKER)
|
||||||
echo 'mode: count' > ./coverage/container.cov
|
echo 'mode: count' > ./coverage/docker.cov
|
||||||
tail -q -n +2 ./test/container/coverage/*.cov >> ./coverage/container.cov
|
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
|
||||||
go tool cover -html=./coverage/container.cov -o ./coverage/container.html
|
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
|
||||||
|
|
||||||
echo 'mode: count' > ./coverage/combined.cov
|
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
|
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -338,16 +340,14 @@ test-advancedserver-cover: test/container/vendor coverage
|
|||||||
# Command to build the image
|
# Command to build the image
|
||||||
# Args: imageName, imageTag, dockerfile, extraArgs, dockerfileTarget
|
# 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
|
# 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
|
define build-mq-command
|
||||||
define build-mq
|
|
||||||
rm -f .dockerignore && echo ".git\ndownloads\n!downloads/$4" > .dockerignore
|
|
||||||
$(COMMAND) build \
|
$(COMMAND) build \
|
||||||
--tag $1:$2 \
|
--tag $1:$2 \
|
||||||
--file $3 \
|
--file $3 \
|
||||||
|
$4 \
|
||||||
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
||||||
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
||||||
--build-arg IMAGE_TAG="$1:$2" \
|
--build-arg IMAGE_TAG="$1:$2" \
|
||||||
--build-arg MQ_ARCHIVE="downloads/$4" \
|
|
||||||
--label version=$(MQ_VERSION) \
|
--label version=$(MQ_VERSION) \
|
||||||
--label name=$1 \
|
--label name=$1 \
|
||||||
--label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \
|
--label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \
|
||||||
@@ -362,6 +362,57 @@ define build-mq
|
|||||||
.
|
.
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
# Build using a separate container to host the MQ download files.
|
||||||
|
# To minimize the layers in the resulting image, the download files can't be part of the build context.
|
||||||
|
# The "docker build" command (and "podman build" on macOS) don't allow you to mount a directory into the build, so a
|
||||||
|
# separate container is used to host a web server.
|
||||||
|
# Note that for Podman, this means that you need to be using the "rootful" mode, because the rootless mode doesn't allow
|
||||||
|
# much control of networking, so the containers can't talk to each other.
|
||||||
|
define build-mq-using-web-server
|
||||||
|
$(COMMAND) network create $(BUILD_SERVER_NETWORK)
|
||||||
|
$(COMMAND) run \
|
||||||
|
--rm \
|
||||||
|
--name $(BUILD_SERVER_CONTAINER) \
|
||||||
|
--network $(BUILD_SERVER_NETWORK) \
|
||||||
|
--volume $(DOWNLOADS_DIR):/opt/app-root/src$(VOLUME_MOUNT_OPTIONS) \
|
||||||
|
--detach \
|
||||||
|
registry.access.redhat.com/ubi8/nginx-120 nginx -g "daemon off;" || ($(COMMAND) network rm $(BUILD_SERVER_NETWORK) && exit 1)
|
||||||
|
BUILD_SERVER_IP=$$($(COMMAND) inspect -f '{{ .NetworkSettings.Networks.$(BUILD_SERVER_NETWORK).IPAddress }}' $(BUILD_SERVER_CONTAINER)); \
|
||||||
|
$(call build-mq-command,$1,$2,$3,--network build --build-arg MQ_URL=http://$$BUILD_SERVER_IP:8080/$4,$5) || ($(COMMAND) rm -f $(BUILD_SERVER_CONTAINER) && $(COMMAND) network rm $(BUILD_SERVER_NETWORK) && exit 1)
|
||||||
|
$(COMMAND) rm -f $(BUILD_SERVER_CONTAINER)
|
||||||
|
$(COMMAND) network rm $(BUILD_SERVER_NETWORK)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# When building with Docker, always use the web server build because you can't use bind-mounted volumes.
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-docker
|
||||||
|
$(call build-mq-using-web-server,$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# When building with Podman on macOS (Darwin), use the web server build because you can't use bind-mounted volumes with `podman build` on macOS
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-podman-Darwin
|
||||||
|
$(call build-mq-using-web-server,$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# When building with Podman on Linux, just pass the downloads directory as a volume
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-podman-Linux
|
||||||
|
$(call build-mq-command,$1,$2,$3,--volume $(DOWNLOADS_DIR):/var/downloads$(VOLUME_MOUNT_OPTIONS) --build-arg MQ_URL=file:///var/downloads/$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# When building with Podman, just pass the downloads directory as a volume
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-podman
|
||||||
|
$(call build-mq-podman-$(shell uname -s),$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Build an MQ image. The commands used are slightly different between Docker and Podman
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq
|
||||||
|
$(call build-mq-$(COMMAND),$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build targets
|
# Build targets
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -533,20 +584,33 @@ lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
|||||||
.PHONY: gosec
|
.PHONY: gosec
|
||||||
gosec:
|
gosec:
|
||||||
$(info $(SPACER)$(shell printf "Running gosec test"$(END)))
|
$(info $(SPACER)$(shell printf "Running gosec test"$(END)))
|
||||||
@gosecrc=0; gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null || gosecrc=$$?; \
|
@gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\
|
||||||
cat gosec_results.json | jq '{"GolangErrors": (.["Golang errors"]|length>0),"Issues":(.Issues|length>0)}' | grep 'true' >/dev/null ;\
|
cat "gosec_results.json" ;\
|
||||||
if [ $$? -eq 0 ] || [ $$gosecrc -ne 0 ]; then \
|
cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\
|
||||||
printf "FAILURE: Issues found running gosec - see gosec_results.json\n" ;\
|
if [ $$? -eq 0 ]; then \
|
||||||
cat "gosec_results.json" ;\
|
printf "\nFAILURE: gosec found files containing HIGH severity issues - see results.json\n" ;\
|
||||||
exit 1 ;\
|
exit 1 ;\
|
||||||
else \
|
else \
|
||||||
printf "gosec found no issues\n" ;\
|
printf "\ngosec found no HIGH severity issues\n" ;\
|
||||||
cat "gosec_results.json" ;\
|
fi ;\
|
||||||
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 ;\
|
||||||
|
|
||||||
.PHONY: update-release-information
|
.PHONY: update-release-information
|
||||||
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))
|
$(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_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
|
sed -i.bak 's/ibm-mqadvanced-server:.*-amd64/ibm-mqadvanced-server:$(MQ_VERSION)-amd64/g' docs/security.md
|
||||||
@@ -569,4 +633,4 @@ ifneq (,$(findstring docker,$(COMMAND)))
|
|||||||
endif
|
endif
|
||||||
ifneq (,$(findstring podman,$(COMMAND)))
|
ifneq (,$(findstring podman,$(COMMAND)))
|
||||||
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
|
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
|
||||||
endif
|
endif
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -27,10 +27,7 @@ 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`.
|
- **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.
|
- **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_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.
|
- **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_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".
|
|
||||||
- **MQ_ENABLE_METRICS** - Set this to `true` to generate Prometheus metrics for your Queue Manager.
|
- **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.
|
See the [default developer configuration docs](docs/developer-config.md) for the extra environment variables supported by the MQ Advanced for Developers image.
|
||||||
@@ -41,19 +38,19 @@ If you want to use IBM MQ on [Kubernetes](https://kubernetes.io), you can find a
|
|||||||
|
|
||||||
## Issues and contributions
|
## 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
|
## 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).
|
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
||||||
Licenses for the products installed within the images are as follows:
|
Licenses for the products installed within the images are as follows:
|
||||||
|
|
||||||
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-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 for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-CAUEQC) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||||
- [IBM MQ Advanced](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](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-CAUEBE) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||||
|
|
||||||
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine.
|
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine.
|
||||||
|
|
||||||
|
|
||||||
## Copyright
|
## Copyright
|
||||||
|
|
||||||
© Copyright IBM Corporation 2015, 2023
|
© Copyright IBM Corporation 2015, 2022
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2023
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -44,12 +44,7 @@ func doMain() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the queue manager has a running listener
|
// Check if the queue manager has a running listener
|
||||||
status, err := ready.Status(ctx, name)
|
if active, _ := ready.IsRunningAsActiveQM(ctx, name); active {
|
||||||
if err != nil {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
switch status {
|
|
||||||
case ready.StatusActiveQM:
|
|
||||||
conn, err := net.Dial("tcp", "127.0.0.1:1414")
|
conn, err := net.Dial("tcp", "127.0.0.1:1414")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -59,16 +54,16 @@ func doMain() int {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
return 0
|
} else if standby, _ := ready.IsRunningAsStandbyQM(ctx, name); standby {
|
||||||
case ready.StatusStandbyQM:
|
|
||||||
fmt.Printf("Detected queue manager running in standby mode")
|
fmt.Printf("Detected queue manager running in standby mode")
|
||||||
return 10
|
return 10
|
||||||
case ready.StatusReplicaQM:
|
} else if replica, _ := ready.IsRunningAsReplicaQM(ctx, name); replica {
|
||||||
fmt.Printf("Detected queue manager running in replica mode")
|
fmt.Printf("Detected queue manager running in replica mode")
|
||||||
return 20
|
return 20
|
||||||
default:
|
} else {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2021
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/htpasswd"
|
"github.com/ibm-messaging/mq-container/internal/htpasswd"
|
||||||
@@ -31,20 +30,7 @@ import (
|
|||||||
var log *logger.Logger
|
var log *logger.Logger
|
||||||
|
|
||||||
func getLogFormat() string {
|
func getLogFormat() string {
|
||||||
logFormat := strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_FORMAT")))
|
return os.Getenv("LOG_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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDebug() bool {
|
func getDebug() bool {
|
||||||
@@ -91,7 +77,6 @@ func logTermination(args ...interface{}) {
|
|||||||
// Write the message to the termination log. This is not the default place
|
// Write the message to the termination log. This is not the default place
|
||||||
// that Kubernetes will look for termination information.
|
// that Kubernetes will look for termination information.
|
||||||
log.Debugf("Writing termination message: %v", msg)
|
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)
|
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2023
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -46,7 +46,6 @@ func logTermination(args ...interface{}) {
|
|||||||
// Write the message to the termination log. This is not the default place
|
// Write the message to the termination log. This is not the default place
|
||||||
// that Kubernetes will look for termination information.
|
// that Kubernetes will look for termination information.
|
||||||
log.Debugf("Writing termination message: %v", msg)
|
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)
|
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
@@ -59,20 +58,7 @@ func logTermination(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getLogFormat() string {
|
func getLogFormat() string {
|
||||||
logFormat := strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_FORMAT")))
|
return os.Getenv("LOG_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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatBasic formats a log message parsed from JSON, as "basic" text
|
// 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
|
// Convert time zone information from some logs (e.g. Liberty) for consistency
|
||||||
obj["ibm_datetime"] = strings.Replace(obj["ibm_datetime"].(string), "+0000", "Z", 1)
|
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"])
|
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
|
// mirrorWebServerLogs starts a goroutine to mirror the contents of the Liberty web server messages.log
|
||||||
func mirrorWebServerLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
func mirrorWebServerLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
||||||
return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", fromStart, mf, true)
|
return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", false, mf, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDebug() bool {
|
func getDebug() bool {
|
||||||
@@ -233,11 +131,6 @@ func configureLogger(name string) (mirrorFunc, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func(msg string, isQMLog bool) bool {
|
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
|
// Check if the message is JSON
|
||||||
if len(msg) > 0 && msg[0] == '{' {
|
if len(msg) > 0 && msg[0] == '{' {
|
||||||
obj, err := processLogMessage(msg)
|
obj, err := processLogMessage(msg)
|
||||||
@@ -262,11 +155,6 @@ func configureLogger(name string) (mirrorFunc, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func(msg string, isQMLog bool) bool {
|
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
|
// Check if the message is JSON
|
||||||
if len(msg) > 0 && msg[0] == '{' {
|
if len(msg) > 0 && msg[0] == '{' {
|
||||||
// Parse the JSON message, and print a simplified version
|
// Parse the JSON message, and print a simplified version
|
||||||
@@ -309,16 +197,6 @@ func filterQMLogMessage(obj map[string]interface{}) bool {
|
|||||||
return false
|
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() {
|
func logDiagnostics() {
|
||||||
if getDebug() {
|
if getDebug() {
|
||||||
log.Debug("--- Start Diagnostics ---")
|
log.Debug("--- Start Diagnostics ---")
|
||||||
@@ -360,73 +238,3 @@ func logDiagnostics() {
|
|||||||
log.Debug("--- End Diagnostics ---")
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2020, 2023
|
© Copyright IBM Corporation 2020
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -18,7 +18,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2023
|
© Copyright IBM Corporation 2017, 2021
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -24,7 +24,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/fips"
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/ha"
|
"github.com/ibm-messaging/mq-container/internal/ha"
|
||||||
"github.com/ibm-messaging/mq-container/internal/metrics"
|
"github.com/ibm-messaging/mq-container/internal/metrics"
|
||||||
"github.com/ibm-messaging/mq-container/internal/ready"
|
"github.com/ibm-messaging/mq-container/internal/ready"
|
||||||
@@ -145,9 +144,6 @@ func doMain() error {
|
|||||||
// Print out versioning information
|
// Print out versioning information
|
||||||
logVersionInfo()
|
logVersionInfo()
|
||||||
|
|
||||||
// Determine FIPS compliance level
|
|
||||||
fips.ProcessFIPSType(log)
|
|
||||||
|
|
||||||
keyLabel, defaultCmsKeystore, defaultP12Truststore, err := tls.ConfigureDefaultTLSKeystores()
|
keyLabel, defaultCmsKeystore, defaultP12Truststore, err := tls.ConfigureDefaultTLSKeystores()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
@@ -160,32 +156,6 @@ func doMain() error {
|
|||||||
return err
|
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)
|
err = postInit(name, keyLabel, defaultP12Truststore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
@@ -200,9 +170,6 @@ func doMain() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post FIPS initialization processing
|
|
||||||
fips.PostInit(log)
|
|
||||||
|
|
||||||
enableTraceCrtmqm := os.Getenv("MQ_ENABLE_TRACE_CRTMQM")
|
enableTraceCrtmqm := os.Getenv("MQ_ENABLE_TRACE_CRTMQM")
|
||||||
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
||||||
err = startMQTrace()
|
err = startMQTrace()
|
||||||
@@ -226,25 +193,38 @@ func doMain() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//For mirroring mq system logs and qm logs, if environment variable is set
|
var wg sync.WaitGroup
|
||||||
if checkLogSourceForMirroring("qmgr") {
|
defer func() {
|
||||||
//Mirror MQ system logs
|
log.Debug("Waiting for log mirroring to complete")
|
||||||
_, err = mirrorSystemErrorLogs(ctx, &wg, mf)
|
wg.Wait()
|
||||||
if err != nil {
|
}()
|
||||||
logTermination(err)
|
ctx, cancelMirror := context.WithCancel(context.Background())
|
||||||
return err
|
defer func() {
|
||||||
}
|
log.Debug("Cancel log mirroring")
|
||||||
|
cancelMirror()
|
||||||
//Mirror queue manager logs
|
}()
|
||||||
_, err = mirrorQueueManagerErrorLogs(ctx, &wg, name, newQM, mf)
|
// 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 {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Recommended to use this option in conjunction with setting WLP_LOGGING_MESSAGE_FORMAT=JSON
|
||||||
if *devFlag {
|
mirrorWebLog := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG")
|
||||||
_, err = mirrorHTPasswdLogs(ctx, &wg, name, newQM, mf)
|
if mirrorWebLog == "true" || mirrorWebLog == "1" {
|
||||||
|
_, err = mirrorWebServerLogs(ctx, &wg, name, newQM, mf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -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.
|
// the file is open before the queue manager is created or started.
|
||||||
// Otherwise, there would be the potential for a nearly-full file to
|
// Otherwise, there would be the potential for a nearly-full file to
|
||||||
// rotate before the goroutine had a chance to open it.
|
// 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)
|
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -123,7 +122,6 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("File exists: %v, %v", path, fi.Size())
|
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)
|
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -171,7 +169,6 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
}
|
}
|
||||||
// Re-open file
|
// Re-open file
|
||||||
log.Debugf("Re-opening error log file %v", path)
|
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)
|
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -18,7 +18,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/fips"
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/tls"
|
"github.com/ibm-messaging/mq-container/internal/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,15 +25,6 @@ import (
|
|||||||
func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error {
|
func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error {
|
||||||
enableWebServer := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER")
|
enableWebServer := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER")
|
||||||
if enableWebServer == "true" || enableWebServer == "1" {
|
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)
|
// Configure the web server (if enabled)
|
||||||
webKeystore, err := configureWebServer(keyLabel, p12Truststore)
|
webKeystore, err := configureWebServer(keyLabel, p12Truststore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,7 +35,6 @@ func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error {
|
|||||||
if len(p12Truststore.TrustedCerts) == 0 {
|
if len(p12Truststore.TrustedCerts) == 0 {
|
||||||
webTruststoreRef = "MQWebKeyStore"
|
webTruststoreRef = "MQWebKeyStore"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the web server, in the background (if installed)
|
// Start the web server, in the background (if installed)
|
||||||
// WARNING: No error handling or health checking available for the web server
|
// WARNING: No error handling or health checking available for the web server
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2023
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -55,36 +55,23 @@ func createDirStructure() error {
|
|||||||
func createQueueManager(name string, devMode bool) (bool, error) {
|
func createQueueManager(name string, devMode bool) (bool, error) {
|
||||||
log.Printf("Creating queue manager %v", name)
|
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()
|
mounts, err := containerruntime.GetMounts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error getting mounts for queue manager")
|
log.Printf("Error getting mounts for queue manager")
|
||||||
return false, err
|
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
|
// Check if 'qm.ini' configuration file exists for the queue manager
|
||||||
// TODO : handle possible race condition - use a file lock?
|
// TODO : handle possible race condition - use a file lock?
|
||||||
|
dataDir := getQueueManagerDataDir(mounts, name)
|
||||||
_, err = os.Stat(filepath.Join(dataDir, "qm.ini"))
|
_, err = os.Stat(filepath.Join(dataDir, "qm.ini"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If 'qm.ini' is not found - run 'crtmqm' to create a new queue manager
|
// If 'qm.ini' is not found - run 'crtmqm' to create a new queue manager
|
||||||
@@ -109,25 +96,6 @@ func createQueueManager(name string, devMode bool) (bool, error) {
|
|||||||
return true, nil
|
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 {
|
func updateCommandLevel() error {
|
||||||
level, ok := os.LookupEnv("MQ_CMDLEVEL")
|
level, ok := os.LookupEnv("MQ_CMDLEVEL")
|
||||||
if ok && level != "" {
|
if ok && level != "" {
|
||||||
@@ -164,12 +132,11 @@ func startQueueManager(name string) error {
|
|||||||
func stopQueueManager(name string) error {
|
func stopQueueManager(name string) error {
|
||||||
log.Println("Stopping queue manager")
|
log.Println("Stopping queue manager")
|
||||||
qmGracePeriod := os.Getenv("MQ_GRACE_PERIOD")
|
qmGracePeriod := os.Getenv("MQ_GRACE_PERIOD")
|
||||||
status, err := ready.Status(context.Background(), name)
|
isStandby, err := ready.IsRunningAsStandbyQM(context.Background(), name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error getting status for queue manager %v: %v", name, err.Error())
|
log.Printf("Error getting status for queue manager %v: %v", name, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
isStandby := status.StandbyQM()
|
|
||||||
args := []string{"-w", "-r", "-tp", qmGracePeriod, name}
|
args := []string{"-w", "-r", "-tp", qmGracePeriod, name}
|
||||||
if os.Getenv("MQ_MULTI_INSTANCE") == "true" {
|
if os.Getenv("MQ_MULTI_INSTANCE") == "true" {
|
||||||
if isStandby {
|
if isStandby {
|
||||||
@@ -271,14 +238,6 @@ func getCreateQueueManagerArgs(mounts map[string]string, name string, devMode bo
|
|||||||
if _, ok := mounts["/mnt/mqm-data"]; ok {
|
if _, ok := mounts["/mnt/mqm-data"]; ok {
|
||||||
args = append(args, "-md", "/mnt/mqm-data/qmgrs")
|
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)
|
args = append(args, name)
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
@@ -328,8 +287,7 @@ func updateQMini(qmname string) error {
|
|||||||
if strings.Contains(qminiConfigStr, "ServiceComponent:") {
|
if strings.Contains(qminiConfigStr, "ServiceComponent:") {
|
||||||
var re = regexp.MustCompile(`(?m)^.*ServiceComponent.*$\s^.*Service.*$\s^.*Name.*$\s^.*Module.*$\s^.*ComponentDataSize.*$`)
|
var re = regexp.MustCompile(`(?m)^.*ServiceComponent.*$\s^.*Service.*$\s^.*Name.*$\s^.*Module.*$\s^.*ComponentDataSize.*$`)
|
||||||
curFile := re.ReplaceAllString(qminiConfigStr, "")
|
curFile := re.ReplaceAllString(qminiConfigStr, "")
|
||||||
// #nosec G304 G306 - qmgrDir filepath is derived from dspmqinf and
|
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
|
||||||
// its a read by owner/s group, and pose no harm.
|
|
||||||
err := ioutil.WriteFile(qmgrDir, []byte(curFile), 0660)
|
err := ioutil.WriteFile(qmgrDir, []byte(curFile), 0660)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
ExitPath:
|
|
||||||
ExitsDefaultPath=/mnt/mqm/data/exits
|
|
||||||
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
|
||||||
Log:
|
|
||||||
LogPrimaryFiles=3
|
|
||||||
LogSecondaryFiles=2
|
|
||||||
LogBufferPages=0
|
|
||||||
LogWriteIntegrity=TripleWrite
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
ExitPath:
|
|
||||||
ExitsDefaultPath=/mnt/mqm/data/exits
|
|
||||||
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
|
||||||
Log:
|
|
||||||
LogPrimaryFiles=3
|
|
||||||
LogSecondaryFiles=2
|
|
||||||
LogBufferPages=1235
|
|
||||||
LogWriteIntegrity=TripleWrite
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2022
|
© Copyright IBM Corporation 2018, 2020
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -197,25 +197,3 @@ func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string
|
|||||||
|
|
||||||
return webKeystore, err
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
###########################################################################################################################################################
|
###########################################################################################################################################################
|
||||||
|
|
||||||
# MQ_VERSION is the fully qualified MQ version number to build
|
# MQ_VERSION is the fully qualified MQ version number to build
|
||||||
MQ_VERSION ?= 9.3.3.0
|
MQ_VERSION ?= 9.3.1.1
|
||||||
|
|
||||||
###########################################################################################################################################################
|
###########################################################################################################################################################
|
||||||
|
|||||||
@@ -12,6 +12,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM fedora:41
|
FROM fedora:32
|
||||||
RUN yum install skopeo -y -qq
|
RUN yum install skopeo -y -qq
|
||||||
ENTRYPOINT [ "skopeo" ]
|
ENTRYPOINT [ "skopeo" ]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
You need to have the following tools installed:
|
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/) 17.06.1 or later, or [Podman](https://podman.io) 1.0 or later (Podman 4.1 on macOS). If using Podman on macOS, the you need to be in "rootful" mode to allow the use of a network during builds. Run `podman machine init --rootful`.
|
||||||
* [GNU make](https://www.gnu.org/software/make/)
|
* [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.
|
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.
|
||||||
@@ -38,10 +38,10 @@ However, if you wish to build the previous MQ LTS, use the [instructions](https:
|
|||||||
|
|
||||||
## Building a developer image
|
## 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.
|
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).
|
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
|
## 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.
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ docker run \
|
|||||||
--env LICENSE=accept \
|
--env LICENSE=accept \
|
||||||
--env MQ_QMGR_NAME=QM1 \
|
--env MQ_QMGR_NAME=QM1 \
|
||||||
--detach \
|
--detach \
|
||||||
ibm-mqadvanced-server:9.3.3.0-amd64
|
ibm-mqadvanced-server:9.3.1.1-amd64
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ make test-advancedserver
|
|||||||
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
||||||
|
|
||||||
```
|
```
|
||||||
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.3.3.0-amd64 make test-advancedserver
|
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.3.1.1-amd64 make test-advancedserver
|
||||||
```
|
```
|
||||||
|
|
||||||
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command:
|
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command:
|
||||||
|
|||||||
@@ -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.
|
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>')`
|
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.
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
* © Copyright IBM Corporation 2019, 2022
|
* © Copyright IBM Corporation 2019
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -16,5 +16,4 @@
|
|||||||
* Set the keystore location for the queue manager
|
* Set the keystore location for the queue manager
|
||||||
ALTER QMGR SSLKEYR('{{ .SSLKeyR }}')
|
ALTER QMGR SSLKEYR('{{ .SSLKeyR }}')
|
||||||
ALTER QMGR CERTLABL('{{ .CertificateLabel }}')
|
ALTER QMGR CERTLABL('{{ .CertificateLabel }}')
|
||||||
ALTER QMGR SSLFIPS({{ .SSLFips }})
|
|
||||||
REFRESH SECURITY(*) TYPE(SSL)
|
REFRESH SECURITY(*) TYPE(SSL)
|
||||||
|
|||||||
22
go.mod
22
go.mod
@@ -1,24 +1,14 @@
|
|||||||
module github.com/ibm-messaging/mq-container
|
module github.com/ibm-messaging/mq-container
|
||||||
|
|
||||||
go 1.19
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/genuinetools/amicontained v0.4.3
|
github.com/genuinetools/amicontained v0.4.3
|
||||||
github.com/ibm-messaging/mq-golang v2.0.0+incompatible
|
github.com/ibm-messaging/mq-golang v2.0.0+incompatible
|
||||||
github.com/prometheus/client_golang v1.19.1
|
github.com/prometheus/client_golang v1.11.1
|
||||||
github.com/prometheus/client_model v0.6.1
|
github.com/prometheus/client_model v0.2.0
|
||||||
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/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // 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-20220622213112-05595931fe9d
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1
|
||||||
|
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001
|
||||||
)
|
)
|
||||||
|
|||||||
27
go.sum
27
go.sum
@@ -10,8 +10,6 @@ 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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
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.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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/genuinetools/amicontained v0.4.3 h1:cqq9XiAHfWWY3dk8VU8bSJFu9yh8Il5coEdeTAPq72o=
|
github.com/genuinetools/amicontained v0.4.3 h1:cqq9XiAHfWWY3dk8VU8bSJFu9yh8Il5coEdeTAPq72o=
|
||||||
@@ -35,9 +33,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
|
|||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
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 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
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/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
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.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
@@ -76,27 +71,19 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
|
|||||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
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 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
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-20180712105110-5c3871d89910/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-20190129233127-fd36f4220a90/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 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
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.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
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 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
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/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
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 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
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/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
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/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
@@ -112,14 +99,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
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 h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
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/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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-20181114220301-adae6a3d119a/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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -134,14 +120,16 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-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-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-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 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.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
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=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -154,9 +142,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
|||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ=
|
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-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/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 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -167,5 +152,3 @@ 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=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
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 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.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=
|
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ NativeHALocalInstance:
|
|||||||
{{ if .CipherSpec }}
|
{{ if .CipherSpec }}
|
||||||
CipherSpec={{ .CipherSpec }}
|
CipherSpec={{ .CipherSpec }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{ if .SSLFipsRequired }}
|
|
||||||
SSLFipsRequired={{ .SSLFipsRequired }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
NativeHAInstance:
|
NativeHAInstance:
|
||||||
Name={{ .NativeHAInstance0_Name }}
|
Name={{ .NativeHAInstance0_Name }}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM ubuntu:24.04
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
# The URL to download the MQ installer from in tar.gz format
|
# 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
|
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev911_ubuntu_x86-64.tar.gz
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ sudo apt-get update || :
|
|||||||
sudo apt-get install -y jq
|
sudo apt-get install -y jq
|
||||||
|
|
||||||
go install golang.org/x/lint/golint@latest
|
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."
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2015, 2023
|
# © Copyright IBM Corporation 2015, 2022
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -42,12 +42,21 @@ if ($UBUNTU); then
|
|||||||
echo "deb ${APT_URL} ${UBUNTU_CODENAME}-security main restricted" >> /etc/apt/sources.list
|
echo "deb ${APT_URL} ${UBUNTU_CODENAME}-security main restricted" >> /etc/apt/sources.list
|
||||||
# Install additional packages required by MQ, this install process and the runtime scripts
|
# Install additional packages required by MQ, this install process and the runtime scripts
|
||||||
EXTRA_DEBS="bash bc ca-certificates coreutils curl debianutils file findutils gawk grep libc-bin mount passwd procps sed tar util-linux"
|
EXTRA_DEBS="bash bc ca-certificates coreutils curl debianutils file findutils gawk grep libc-bin mount passwd procps sed tar util-linux"
|
||||||
|
# On ARM CPUs, there is no IBM JRE, so install another one
|
||||||
|
if [ "${CPU_ARCH}" == "aarch64" ]; then
|
||||||
|
EXTRA_DEBS="${EXTRA_DEBS} openjdk-8-jre"
|
||||||
|
fi
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y --no-install-recommends ${EXTRA_DEBS}
|
apt-get install -y --no-install-recommends ${EXTRA_DEBS}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ($RPM); then
|
if ($RPM); then
|
||||||
EXTRA_RPMS="bash bc ca-certificates file findutils gawk glibc-common grep ncurses-compat-libs passwd procps-ng sed shadow-utils tar util-linux which"
|
EXTRA_RPMS="bash bc ca-certificates file findutils gawk glibc-common grep ncurses-compat-libs passwd procps-ng sed shadow-utils tar util-linux which"
|
||||||
|
# On ARM CPUs, there is no IBM JRE, so install another one
|
||||||
|
if [ "${CPU_ARCH}" == "aarch64" ]; then
|
||||||
|
EXTRA_RPMS="${EXTRA_RPMS} java-1.8.0-openjdk-headless"
|
||||||
|
fi
|
||||||
|
|
||||||
# Install additional packages required by MQ, this install process and the runtime scripts
|
# Install additional packages required by MQ, this install process and the runtime scripts
|
||||||
$YUM && yum -y install --setopt install_weak_deps=false ${EXTRA_RPMS}
|
$YUM && yum -y install --setopt install_weak_deps=false ${EXTRA_RPMS}
|
||||||
$MICRODNF && microdnf --disableplugin=subscription-manager install ${EXTRA_RPMS}
|
$MICRODNF && microdnf --disableplugin=subscription-manager install ${EXTRA_RPMS}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2015, 2023
|
# © Copyright IBM Corporation 2015, 2022
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -21,8 +21,43 @@ set -ex
|
|||||||
test -f /usr/bin/rpm && RPM=true || RPM=false
|
test -f /usr/bin/rpm && RPM=true || RPM=false
|
||||||
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
|
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
|
||||||
|
|
||||||
|
# Download and extract the MQ unzippable server
|
||||||
|
DIR_TMP=/tmp/mq
|
||||||
|
mkdir -p ${DIR_TMP}
|
||||||
|
cd ${DIR_TMP}
|
||||||
|
curl --fail --location $MQ_URL | tar --extract --gunzip
|
||||||
|
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=0
|
||||||
|
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
|
# Accept the MQ license
|
||||||
/opt/mqm/bin/mqlicense -accept
|
${INSTALLATION_DIR}/bin/mqlicense -accept
|
||||||
|
|
||||||
# Optional: Update the command prompt with the MQ version
|
# Optional: Update the command prompt with the MQ version
|
||||||
$UBUNTU && echo "mq:$(dspmqver -b -f 2)" > /etc/debian_chroot
|
$UBUNTU && echo "mq:$(dspmqver -b -f 2)" > /etc/debian_chroot
|
||||||
@@ -36,15 +36,12 @@ func CopyFileMode(src, dest string, perm os.FileMode) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open %s for copy: %v", src, err)
|
return fmt.Errorf("failed to open %s for copy: %v", src, err)
|
||||||
}
|
}
|
||||||
// #nosec G307 - local to this function, pose no harm.
|
|
||||||
defer in.Close()
|
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)
|
out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open %s for copy: %v", dest, err)
|
return fmt.Errorf("failed to open %s for copy: %v", dest, err)
|
||||||
}
|
}
|
||||||
// #nosec G307 - local to this function, pose no harm.
|
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
|
|
||||||
_, err = io.Copy(out, in)
|
_, err = io.Copy(out, in)
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2020, 2023
|
© Copyright IBM Corporation 2020, 2021
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -20,7 +20,6 @@ package ha
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/fips"
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
|
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
|
||||||
"github.com/ibm-messaging/mq-container/internal/tls"
|
"github.com/ibm-messaging/mq-container/internal/tls"
|
||||||
"github.com/ibm-messaging/mq-container/pkg/logger"
|
"github.com/ibm-messaging/mq-container/pkg/logger"
|
||||||
@@ -58,13 +57,6 @@ func ConfigureNativeHA(log *logger.Logger) error {
|
|||||||
if ok {
|
if ok {
|
||||||
templateMap["CipherSpec"] = cipherSpec
|
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)
|
err := mqtemplate.ProcessTemplateFile(templateFile, file, templateMap, log)
|
||||||
|
|||||||
@@ -108,6 +108,5 @@ func (htpfile mapHtPasswd) updateHtPasswordFile(isTest bool) error {
|
|||||||
if isTest {
|
if isTest {
|
||||||
file = "my.htpasswd"
|
file = "my.htpasswd"
|
||||||
}
|
}
|
||||||
// #nosec G306 - its a read by owner/s group, and pose no harm.
|
|
||||||
return ioutil.WriteFile(file, htpfile.GetBytes(), 0660)
|
return ioutil.WriteFile(file, htpfile.GetBytes(), 0660)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -26,7 +26,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
"github.com/ibm-messaging/mq-container/internal/fips"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// KeyStore describes information about a keystore file
|
// KeyStore describes information about a keystore file
|
||||||
@@ -35,46 +34,36 @@ type KeyStore struct {
|
|||||||
Password string
|
Password string
|
||||||
keyStoreType string
|
keyStoreType string
|
||||||
command string
|
command string
|
||||||
fipsEnabled bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewJKSKeyStore creates a new Java Key Store, managed by the runmqckm command
|
// NewJKSKeyStore creates a new Java Key Store, managed by the runmqckm command
|
||||||
func NewJKSKeyStore(filename, password string) *KeyStore {
|
func NewJKSKeyStore(filename, password string) *KeyStore {
|
||||||
keyStore := &KeyStore{
|
return &KeyStore{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Password: password,
|
Password: password,
|
||||||
keyStoreType: "jks",
|
keyStoreType: "jks",
|
||||||
command: "/opt/mqm/bin/runmqckm",
|
command: "/opt/mqm/bin/runmqckm",
|
||||||
fipsEnabled: fips.IsFIPSEnabled(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyStore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCMSKeyStore creates a new MQ CMS Key Store, managed by the runmqakm command
|
// NewCMSKeyStore creates a new MQ CMS Key Store, managed by the runmqakm command
|
||||||
func NewCMSKeyStore(filename, password string) *KeyStore {
|
func NewCMSKeyStore(filename, password string) *KeyStore {
|
||||||
keyStore := &KeyStore{
|
return &KeyStore{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Password: password,
|
Password: password,
|
||||||
keyStoreType: "cms",
|
keyStoreType: "cms",
|
||||||
command: "/opt/mqm/bin/runmqakm",
|
command: "/opt/mqm/bin/runmqakm",
|
||||||
fipsEnabled: fips.IsFIPSEnabled(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyStore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPKCS12KeyStore creates a new PKCS12 Key Store, managed by the runmqakm command
|
// NewPKCS12KeyStore creates a new PKCS12 Key Store, managed by the runmqakm command
|
||||||
func NewPKCS12KeyStore(filename, password string) *KeyStore {
|
func NewPKCS12KeyStore(filename, password string) *KeyStore {
|
||||||
keyStore := &KeyStore{
|
return &KeyStore{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Password: password,
|
Password: password,
|
||||||
keyStoreType: "p12",
|
keyStoreType: "p12",
|
||||||
command: "/opt/mqm/bin/runmqakm",
|
command: "/opt/mqm/bin/runmqakm",
|
||||||
fipsEnabled: fips.IsFIPSEnabled(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyStore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a key store, if it doesn't already exist
|
// 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
|
// 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -keydb -create\": %v %s", ks.command, err, out)
|
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)
|
_, err := os.Stat(stashFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -keydb -stashpw\": %v %s", ks.command, err, out)
|
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
|
// Import imports a certificate file in the keystore
|
||||||
func (ks *KeyStore) Import(inputFile, password string) error {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -import\": %v %s", ks.command, err, out)
|
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
|
// CreateSelfSignedCertificate creates a self-signed certificate in the keystore
|
||||||
func (ks *KeyStore) CreateSelfSignedCertificate(label, dn, hostname string) error {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -create\": %v %s", ks.command, err, out)
|
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
|
// Add adds a CA certificate to the keystore
|
||||||
func (ks *KeyStore) Add(inputFile, label string) error {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
|
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
|
// Add adds a CA certificate to the keystore
|
||||||
func (ks *KeyStore) AddNoLabel(inputFile string) error {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
|
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
|
// GetCertificateLabels returns the labels of all certificates in the key store
|
||||||
func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
|
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -182,8 +171,8 @@ func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
|
|||||||
var labels []string
|
var labels []string
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
s := scanner.Text()
|
s := scanner.Text()
|
||||||
if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") {
|
if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") || strings.HasPrefix(s, "!") {
|
||||||
s := strings.TrimLeft(s, "-*")
|
s := strings.TrimLeft(s, "-*!")
|
||||||
labels = append(labels, strings.TrimSpace(s))
|
labels = append(labels, strings.TrimSpace(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,7 +207,7 @@ func (ks *KeyStore) RenameCertificate(from, to string) error {
|
|||||||
|
|
||||||
// ListAllCertificates Lists all certificates in the keystore
|
// ListAllCertificates Lists all certificates in the keystore
|
||||||
func (ks *KeyStore) ListAllCertificates() ([]string, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
|
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
|
var labels []string
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
s := scanner.Text()
|
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, "!") {
|
if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") || strings.HasPrefix(s, "!") {
|
||||||
s := strings.TrimLeft(s, "-*!")
|
s := strings.TrimLeft(s, "-*!")
|
||||||
labels = append(labels, strings.TrimSpace(s))
|
labels = append(labels, strings.TrimSpace(s))
|
||||||
@@ -239,22 +226,3 @@ func (ks *KeyStore) ListAllCertificates() ([]string, error) {
|
|||||||
}
|
}
|
||||||
return labels, nil
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -35,8 +35,6 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
metricsEnabled = false
|
metricsEnabled = false
|
||||||
// #nosec G112 - this code is changing soon to use https.
|
|
||||||
// for now we will ignore the gosec.
|
|
||||||
metricsServer = &http.Server{Addr: ":" + defaultPort}
|
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
|
// If running in standby mode - wait until the queue manager becomes active
|
||||||
for {
|
for {
|
||||||
status, _ := ready.Status(context.Background(), qmName)
|
active, _ := ready.IsRunningAsActiveQM(context.Background(), qmName)
|
||||||
if status.ActiveQM() {
|
if active {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(requestTimeout * time.Second)
|
time.Sleep(requestTimeout * time.Second)
|
||||||
|
|||||||
@@ -48,10 +48,8 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// #nosec G302
|
||||||
// #nosec G302 G304 G306 - its a read by owner/s group, and pose no harm.
|
|
||||||
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
|
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
|
||||||
// #nosec G307 - local to this function, pose no harm.
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
err = t.Execute(f, data)
|
err = t.Execute(f, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package mqversion
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
@@ -39,59 +38,14 @@ func Compare(checkVersion string) (int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
// trim any suffix from MQ version x.x.x.x
|
||||||
currentVRMF, err := parseVRMF(currentVersion)
|
currentVersion = currentVersion[0:7]
|
||||||
if err != nil {
|
if currentVersion < checkVersion {
|
||||||
return 0, err
|
return -1, nil
|
||||||
|
} else if currentVersion == checkVersion {
|
||||||
|
return 0, nil
|
||||||
|
} else if currentVersion > checkVersion {
|
||||||
|
return 1, nil
|
||||||
}
|
}
|
||||||
compareVRMF, err := parseVRMF(checkVersion)
|
return 0, fmt.Errorf("Failed to compare MQ versions")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,10 @@ limitations under the License.
|
|||||||
|
|
||||||
package mqversion
|
package mqversion
|
||||||
|
|
||||||
import (
|
import "testing"
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCompareLower(t *testing.T) {
|
func TestCompareLower(t *testing.T) {
|
||||||
checkVersion := "99.99.99.99"
|
checkVersion := "9.9.9.9"
|
||||||
mqVersionCheck, err := Compare(checkVersion)
|
mqVersionCheck, err := Compare(checkVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to compare MQ versions: %v", err)
|
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)
|
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -54,7 +54,6 @@ func Clear() error {
|
|||||||
// Set lets any subsequent calls to `CheckReady` know that the queue
|
// Set lets any subsequent calls to `CheckReady` know that the queue
|
||||||
// manager has finished its configuration step
|
// manager has finished its configuration step
|
||||||
func Set() error {
|
func Set() error {
|
||||||
// #nosec G306 - this gives permissions to owner/s group only.
|
|
||||||
return ioutil.WriteFile(fileName, []byte("1"), 0770)
|
return ioutil.WriteFile(fileName, []byte("1"), 0770)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,38 +67,28 @@ func Check() (bool, error) {
|
|||||||
return exists, nil
|
return exists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status returns an enum representing the current running status of the queue manager
|
// IsRunningAsActiveQM returns true if the queue manager is running in active mode
|
||||||
func Status(ctx context.Context, name string) (QMStatus, error) {
|
func IsRunningAsActiveQM(ctx context.Context, name string) (bool, error) {
|
||||||
out, _, err := command.RunContext(ctx, "dspmq", "-n", "-m", name)
|
return isRunningQM(ctx, name, "(RUNNING)")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type QMStatus int
|
// IsRunningAsStandbyQM returns true if the queue manager is running in standby mode
|
||||||
|
func IsRunningAsStandbyQM(ctx context.Context, name string) (bool, error) {
|
||||||
|
return isRunningQM(ctx, name, "(RUNNING AS STANDBY)")
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
// IsRunningAsReplicaQM returns true if the queue manager is running in replica mode
|
||||||
StatusUnknown QMStatus = iota
|
func IsRunningAsReplicaQM(ctx context.Context, name string) (bool, error) {
|
||||||
StatusActiveQM
|
return isRunningQM(ctx, name, "(REPLICA)")
|
||||||
StatusStandbyQM
|
}
|
||||||
StatusReplicaQM
|
|
||||||
)
|
|
||||||
|
|
||||||
// ActiveQM returns true if the queue manager is running in active mode
|
func isRunningQM(ctx context.Context, name string, status string) (bool, error) {
|
||||||
func (s QMStatus) ActiveQM() bool { return s == StatusActiveQM }
|
out, _, err := command.RunContext(ctx, "dspmq", "-n", "-m", name)
|
||||||
|
if err != nil {
|
||||||
// StandbyQM returns true if the queue manager is running in standby mode
|
return false, err
|
||||||
func (s QMStatus) StandbyQM() bool { return s == StatusStandbyQM }
|
}
|
||||||
|
if strings.Contains(string(out), status) {
|
||||||
// ReplicaQM returns true if the queue manager is running in replica mode
|
return true, nil
|
||||||
func (s QMStatus) ReplicaQM() bool { return s == StatusReplicaQM }
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019, 2023
|
© Copyright IBM Corporation 2019, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -118,25 +118,18 @@ func ConfigureTLS(keyLabel string, cmsKeystore KeyStoreData, devMode bool, log *
|
|||||||
const mqsc string = "/etc/mqm/15-tls.mqsc"
|
const mqsc string = "/etc/mqm/15-tls.mqsc"
|
||||||
const mqscTemplate string = mqsc + ".tpl"
|
const mqscTemplate string = mqsc + ".tpl"
|
||||||
sslKeyRing := ""
|
sslKeyRing := ""
|
||||||
var fipsEnabled = "NO"
|
|
||||||
|
|
||||||
// Don't set SSLKEYR if no keys or crts are not supplied
|
// 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.
|
// Key label will be blank if no certs were added during processing keys and certs.
|
||||||
if cmsKeystore.Keystore != nil && len(keyLabel) > 0 {
|
if cmsKeystore.Keystore != nil {
|
||||||
certList, _ := cmsKeystore.Keystore.ListAllCertificates()
|
certList, _ := cmsKeystore.Keystore.ListAllCertificates()
|
||||||
if len(certList) > 0 {
|
if len(certList) > 0 {
|
||||||
sslKeyRing = strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb")
|
sslKeyRing = strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmsKeystore.Keystore.IsFIPSEnabled() {
|
|
||||||
fipsEnabled = "YES"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
|
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
|
||||||
"SSLKeyR": sslKeyRing,
|
"SSLKeyR": sslKeyRing,
|
||||||
"CertificateLabel": keyLabel,
|
"CertificateLabel": keyLabel,
|
||||||
"SSLFips": fipsEnabled,
|
|
||||||
}, log)
|
}, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -255,19 +248,11 @@ func processKeys(tlsStore *TLSStore, keystoreDir string, keyDir string) (string,
|
|||||||
return "", err
|
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
|
// 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)
|
file, err := pkcs.Encode(rand.Reader, privateKey, publicCertificate, caCertificate, tlsStore.Keystore.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to encode PKCS#12 Keystore %s: %v", keySet.Name()+".p12", err)
|
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)
|
err = ioutil.WriteFile(filepath.Join(keystoreDir, keySet.Name()+".p12"), file, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to write PKCS#12 Keystore %s: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
|
return "", fmt.Errorf("Failed to write PKCS#12 Keystore %s: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
|
||||||
@@ -571,7 +556,6 @@ func generateRandomPassword() string {
|
|||||||
validcharArray := []byte(validChars)
|
validcharArray := []byte(validChars)
|
||||||
password := ""
|
password := ""
|
||||||
for i := 0; i < 12; i++ {
|
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))])
|
password = password + string(validcharArray[pwr.Intn(len(validcharArray))])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,13 +600,10 @@ func getCertificateFingerprint(block *pem.Block) (string, error) {
|
|||||||
|
|
||||||
// writeCertificatesToFile writes a list of certificates to a file
|
// writeCertificatesToFile writes a list of certificates to a file
|
||||||
func writeCertificatesToFile(file string, certificates []*pem.Block) error {
|
func writeCertificatesToFile(file string, certificates []*pem.Block) error {
|
||||||
|
|
||||||
// #nosec G304 - this is a temporary pem file to write certs.
|
|
||||||
f, err := os.Create(file)
|
f, err := os.Create(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to create file %s: %v", file, err)
|
return fmt.Errorf("Failed to create file %s: %v", file, err)
|
||||||
}
|
}
|
||||||
// #nosec G307 - local to this function, pose no harm.
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
w := bufio.NewWriter(f)
|
w := bufio.NewWriter(f)
|
||||||
@@ -650,7 +631,7 @@ func haveKeysAndCerts(keyDir string) bool {
|
|||||||
// Do a listing of the subdirectory and then search for .key and .cert files
|
// Do a listing of the subdirectory and then search for .key and .cert files
|
||||||
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, fileInfo.Name()))
|
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, fileInfo.Name()))
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
if strings.HasSuffix(key.Name(), ".key") || strings.HasSuffix(key.Name(), ".crt") {
|
if strings.Contains(key.Name(), ".key") || strings.Contains(key.Name(), ".crt") {
|
||||||
// We found at least one key/crt file.
|
// We found at least one key/crt file.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -659,19 +640,3 @@ func haveKeysAndCerts(keyDir string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to generate certificate in Web Keystore %s with DN of 'CN=%s': %v", webKeystoreFile, genHostName, err)
|
return "", fmt.Errorf("Failed to generate certificate in Web Keystore %s with DN of 'CN=%s': %v", webKeystoreFile, genHostName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Check Web Keystore already exists
|
// Check Web Keystore already exists
|
||||||
_, err := os.Stat(webKeystoreFile)
|
_, err := os.Stat(webKeystoreFile)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2023
|
© Copyright IBM Corporation 2017, 2020
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
# SOURCE_BRANCH is the repository branch name for this release stream.
|
# 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.
|
# 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
|
SOURCE_BRANCH ?= v9.3.1
|
||||||
|
|
||||||
###########################################################################################################################################################
|
###########################################################################################################################################################
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module github.com/ibm-messaging/mq-container/test/container
|
|
||||||
|
|
||||||
go 1.19
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
321
test/docker/devconfig_test.go
Normal file
321
test/docker/devconfig_test.go
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
//go:build mqdev
|
||||||
|
// +build mqdev
|
||||||
|
|
||||||
|
/*
|
||||||
|
© 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.
|
||||||
|
*/
|
||||||
|
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.NewClientWithOpts(client.FromEnv)
|
||||||
|
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.
|
||||||
|
// 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, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
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) {
|
||||||
|
// 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, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
||||||
|
})
|
||||||
|
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.NewClientWithOpts(client.FromEnv)
|
||||||
|
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
|
||||||
|
// 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, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if SSLKEYR and CERTLABL attributes are not set when key and certificate
|
||||||
|
// are not supplied.
|
||||||
|
func TestSSLKEYRBlank(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
containerConfig := container.Config{
|
||||||
|
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( )") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be blank but it is not; got \"%v\"", sslkeyROutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
|
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") && !strings.Contains(sslkeyROutput, "CERTLABL(default)") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslkeyROutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with CA cert
|
||||||
|
func TestSSLKEYRWithCACert(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDirWithCA(t, false) + ":/etc/mqm/pki/keys/QM1CA",
|
||||||
|
},
|
||||||
|
// Assign a random port for the web server on the host
|
||||||
|
PortBindings: nat.PortMap{
|
||||||
|
"9443/tcp": []nat.PortBinding{
|
||||||
|
{
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
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)
|
||||||
|
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
|
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslkeyROutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(sslkeyROutput, "CERTLABL(QM1CA)") {
|
||||||
|
t.Errorf("Expected CERTLABL to be 'QM1CA' but it is not; got \"%v\"", sslkeyROutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -34,7 +34,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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"
|
const defaultAdminPassword string = "passw0rd"
|
||||||
@@ -47,7 +49,7 @@ var insecureTLSConfig *tls.Config = &tls.Config{
|
|||||||
InsecureSkipVerify: true,
|
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))
|
t.Logf("%s Waiting for web server to be ready", time.Now().Format(time.RFC3339))
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(10 * time.Second),
|
Timeout: time.Duration(10 * time.Second),
|
||||||
@@ -55,11 +57,7 @@ func waitForWebReady(t *testing.T, cli ce.ContainerInterface, ID string, tlsConf
|
|||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
port, err := cli.GetContainerPort(ID, 9443)
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", port)
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -88,21 +86,12 @@ func tlsDirWithCA(t *testing.T, unixPath bool) string {
|
|||||||
return filepath.Join(getCwd(t, unixPath), "../tlscacert")
|
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
|
// 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) {
|
func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string, ibmjre string, cipherName string) {
|
||||||
port, err := cli.GetContainerPort(ID, 1414)
|
containerConfig := container.Config{
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
containerConfig := ce.ContainerConfig{
|
|
||||||
// -e MQ_PORT_1414_TCP_ADDR=9.145.14.173 -e MQ_USERNAME=app -e MQ_PASSWORD=passw0rd -e MQ_CHANNEL=DEV.APP.SVRCONN -e MQ_TLS_TRUSTSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest
|
// -e MQ_PORT_1414_TCP_ADDR=9.145.14.173 -e MQ_USERNAME=app -e MQ_PASSWORD=passw0rd -e MQ_CHANNEL=DEV.APP.SVRCONN -e MQ_TLS_TRUSTSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"MQ_PORT_1414_TCP_ADDR=127.0.0.1",
|
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
|
||||||
"MQ_PORT_1414_OVERRIDE=" + port,
|
|
||||||
"MQ_USERNAME=" + user,
|
"MQ_USERNAME=" + user,
|
||||||
"MQ_CHANNEL=DEV.APP.SVRCONN",
|
"MQ_CHANNEL=DEV.APP.SVRCONN",
|
||||||
"IBMJRE=" + ibmjre,
|
"IBMJRE=" + ibmjre,
|
||||||
@@ -121,28 +110,26 @@ func runJMSTests(t *testing.T, cli ce.ContainerInterface, ID string, tls bool, u
|
|||||||
"MQ_TLS_CIPHER=" + cipherName,
|
"MQ_TLS_CIPHER=" + cipherName,
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
hostConfig := ce.ContainerHostConfig{
|
hostConfig := container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
tlsDir(t, false) + ":/var/tls",
|
tlsDir(t, false) + ":/var/tls",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := ce.ContainerNetworkSettings{
|
networkingConfig := network.NetworkingConfig{}
|
||||||
Networks: []string{"host"},
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, strings.Replace(t.Name()+"JMS", "/", "", -1))
|
||||||
}
|
|
||||||
jmsID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, strings.Replace(t.Name()+"JMS", "/", "", -1))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startContainer(t, cli, jmsID)
|
startContainer(t, cli, ctr.ID)
|
||||||
rc := waitForContainer(t, cli, jmsID, 2*time.Minute)
|
rc := waitForContainer(t, cli, ctr.ID, 2*time.Minute)
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
t.Errorf("JUnit container failed with rc=%v", rc)
|
t.Errorf("JUnit container failed with rc=%v", rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get console output of the container and process the lines
|
// Get console output of the container and process the lines
|
||||||
// to see if we have any failures
|
// to see if we have any failures
|
||||||
scanner := bufio.NewScanner(strings.NewReader(inspectLogs(t, cli, jmsID)))
|
scanner := bufio.NewScanner(strings.NewReader(inspectLogs(t, cli, ctr.ID)))
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
s := scanner.Text()
|
s := scanner.Text()
|
||||||
if processJunitLogLine(s) {
|
if processJunitLogLine(s) {
|
||||||
@@ -150,7 +137,7 @@ func runJMSTests(t *testing.T, cli ce.ContainerInterface, ID string, tls bool, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defer cleanContainer(t, cli, jmsID)
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse JUnit log line and return true if line contains failed or aborted tests
|
// Parse JUnit log line and return true if line contains failed or aborted tests
|
||||||
@@ -214,31 +201,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{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(30 * time.Second),
|
Timeout: time.Duration(30 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
port, err := cli.GetContainerPort(ID, 9443)
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", port)
|
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
req.SetBasicAuth("admin", defaultAdminPassword)
|
req.SetBasicAuth("admin", defaultAdminPassword)
|
||||||
resp, err := httpClient.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if len(errorExpected) > 0 {
|
t.Fatal(err)
|
||||||
if !strings.Contains(err.Error(), errorExpected) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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)
|
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,7 +238,7 @@ func logHTTPResponse(t *testing.T, resp *http.Response) {
|
|||||||
t.Logf("HTTP response: %v", string(d))
|
t.Logf("HTTP response: %v", string(d))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRESTMessaging(t *testing.T, cli 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{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(30 * time.Second),
|
Timeout: time.Duration(30 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
@@ -269,11 +246,7 @@ func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsCo
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
q := "DEV.QUEUE.1"
|
q := "DEV.QUEUE.1"
|
||||||
port, err := cli.GetContainerPort(ID, 9443)
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/messaging/qmgr/%s/queue/%s/message", getPort(t, cli, ID, 9443), qmName, q)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/messaging/qmgr/%s/queue/%s/message", port, qmName, q)
|
|
||||||
putMessage := []byte("Hello")
|
putMessage := []byte("Hello")
|
||||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(putMessage))
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(putMessage))
|
||||||
req.SetBasicAuth(user, password)
|
req.SetBasicAuth(user, password)
|
||||||
@@ -282,19 +255,10 @@ func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsCo
|
|||||||
logHTTPRequest(t, req)
|
logHTTPRequest(t, req)
|
||||||
resp, err := httpClient.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if len(errorExpected) > 0 {
|
t.Fatal(err)
|
||||||
if strings.Contains(err.Error(), errorExpected) {
|
|
||||||
t.Logf("Error contains expected '%s' value", errorExpected)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
logHTTPResponse(t, resp)
|
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.Errorf("Expected HTTP status code %v from 'POST to queue'; got %v", http.StatusOK, resp.StatusCode)
|
||||||
t.Logf("HTTP response: %+v", resp)
|
t.Logf("HTTP response: %+v", resp)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -322,28 +286,3 @@ func testRESTMessaging(t *testing.T, cli ce.ContainerInterface, ID string, tlsCo
|
|||||||
t.Errorf("Expected payload to be \"%s\"; got \"%s\"", putMessage, gotMessage)
|
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2023
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -34,9 +34,28 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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 {
|
func imageName() string {
|
||||||
image, ok := os.LookupEnv("TEST_IMAGE")
|
image, ok := os.LookupEnv("TEST_IMAGE")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -54,7 +73,7 @@ func imageNameDevJMS() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// baseImage returns the ID of the underlying base image (e.g. "ubuntu" or "rhel")
|
// baseImage returns the ID of the underlying base image (e.g. "ubuntu" or "rhel")
|
||||||
func baseImage(t *testing.T, cli ce.ContainerInterface) string {
|
func baseImage(t *testing.T, cli *client.Client) string {
|
||||||
rc, out := runContainerOneShot(t, cli, "grep", "^ID=", "/etc/os-release")
|
rc, out := runContainerOneShot(t, cli, "grep", "^ID=", "/etc/os-release")
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
t.Fatal("Couldn't determine base image")
|
t.Fatal("Couldn't determine base image")
|
||||||
@@ -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,
|
// devImage returns true if the image under test is a developer image,
|
||||||
// determined by use of the MQ_ADMIN_PASSWORD environment variable
|
// determined by use of the MQ_ADMIN_PASSWORD environment variable
|
||||||
func devImage(t *testing.T, cli ce.ContainerInterface) bool {
|
func devImage(t *testing.T, cli *client.Client) bool {
|
||||||
rc, _ := runContainerOneShot(t, cli, "printenv", "MQ_ADMIN_PASSWORD")
|
rc, _ := runContainerOneShot(t, cli, "printenv", "MQ_ADMIN_PASSWORD")
|
||||||
if rc == 0 {
|
if rc == 0 {
|
||||||
return true
|
return true
|
||||||
@@ -88,11 +107,6 @@ func isWSL(t *testing.T) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// isARM returns whether we are running an arm64 MacOS machine
|
|
||||||
func isARM(t *testing.T) bool {
|
|
||||||
return runtime.GOARCH == "arm64"
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCwd returns the working directory, in an os-specific or UNIX form
|
// getCwd returns the working directory, in an os-specific or UNIX form
|
||||||
func getCwd(t *testing.T, unixPath bool) string {
|
func getCwd(t *testing.T, unixPath bool) string {
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
@@ -147,17 +161,29 @@ func getTempDir(t *testing.T, unixStylePath bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// terminationMessage return the termination message, or an empty string if not set
|
// terminationMessage return the termination message, or an empty string if not set
|
||||||
func terminationMessage(t *testing.T, cli ce.ContainerInterface, ID string) string {
|
func terminationMessage(t *testing.T, cli *client.Client, ID string) string {
|
||||||
r, err := cli.CopyFromContainer(ID, "/run/termination-log")
|
r, _, err := cli.CopyFromContainer(context.Background(), ID, "/run/termination-log")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
t.Log(string(r))
|
|
||||||
return ""
|
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)
|
m := terminationMessage(t, cli, ID)
|
||||||
if m == "" {
|
if m == "" {
|
||||||
t.Error("Expected termination message to be set")
|
t.Error("Expected termination message to be set")
|
||||||
@@ -165,10 +191,10 @@ func expectTerminationMessage(t *testing.T, cli ce.ContainerInterface, ID string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// logContainerDetails logs selected details about the container
|
// logContainerDetails logs selected details about the container
|
||||||
func logContainerDetails(t *testing.T, cli ce.ContainerInterface, ID string) {
|
func logContainerDetails(t *testing.T, cli *client.Client, ID string) {
|
||||||
i, err := cli.ContainerInspect(ID)
|
i, err := cli.ContainerInspect(context.Background(), ID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
d := ce.ContainerDetailsLogging{
|
d := containerDetails{
|
||||||
ID: ID,
|
ID: ID,
|
||||||
Name: i.Name,
|
Name: i.Name,
|
||||||
Image: i.Image,
|
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
|
timeout := 10 * time.Second
|
||||||
err := cli.ContainerStop(ID, &timeout)
|
err := cli.ContainerStop(context.Background(), ID, &timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Just log the error and continue
|
// Just log the error and continue
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
opts := ce.ContainerRemoveOptions{
|
opts := types.ContainerRemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
Force: true,
|
Force: true,
|
||||||
}
|
}
|
||||||
err = cli.ContainerRemove(ID, opts)
|
err = cli.ContainerRemove(context.Background(), ID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
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)
|
logContainerDetails(t, cli, ID)
|
||||||
t.Logf("Stopping container: %v", ID)
|
t.Logf("Stopping container: %v", ID)
|
||||||
timeout := 10 * time.Second
|
timeout := 10 * time.Second
|
||||||
// Stop the container. This allows the coverage output to be generated.
|
// Stop the container. This allows the coverage output to be generated.
|
||||||
err := cli.ContainerStop(ID, &timeout)
|
err := cli.ContainerStop(context.Background(), ID, &timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Just log the error and continue
|
// Just log the error and continue
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@@ -224,11 +250,11 @@ func cleanContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Removing container: %s", ID)
|
t.Logf("Removing container: %s", ID)
|
||||||
opts := ce.ContainerRemoveOptions{
|
opts := types.ContainerRemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
Force: true,
|
Force: true,
|
||||||
}
|
}
|
||||||
err = cli.ContainerRemove(ID, opts)
|
err = cli.ContainerRemove(context.Background(), ID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -242,17 +268,17 @@ func generateRandomUID() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getDefaultHostConfig creates a HostConfig and populates it with the defaults used in testing
|
// getDefaultHostConfig creates a HostConfig and populates it with the defaults used in testing
|
||||||
func getDefaultHostConfig(t *testing.T, cli ce.ContainerInterface) *ce.ContainerHostConfig {
|
func getDefaultHostConfig(t *testing.T, cli *client.Client) *container.HostConfig {
|
||||||
hostConfig := ce.ContainerHostConfig{
|
hostConfig := container.HostConfig{
|
||||||
PortBindings: []ce.PortBinding{},
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
},
|
||||||
|
PortBindings: nat.PortMap{},
|
||||||
CapDrop: []string{
|
CapDrop: []string{
|
||||||
"ALL",
|
"ALL",
|
||||||
},
|
},
|
||||||
Privileged: false,
|
Privileged: false,
|
||||||
}
|
}
|
||||||
if coverage() {
|
|
||||||
hostConfig.Binds = append(hostConfig.Binds, coverageBind(t))
|
|
||||||
}
|
|
||||||
if devImage(t, cli) {
|
if devImage(t, cli) {
|
||||||
// Only needed for a RHEL-based image
|
// Only needed for a RHEL-based image
|
||||||
if baseImage(t, cli) != "ubuntu" {
|
if baseImage(t, cli) != "ubuntu" {
|
||||||
@@ -266,7 +292,7 @@ func getDefaultHostConfig(t *testing.T, cli ce.ContainerInterface) *ce.Container
|
|||||||
|
|
||||||
// runContainerWithHostConfig creates and starts a container, using the supplied HostConfig.
|
// runContainerWithHostConfig creates and starts a container, using the supplied HostConfig.
|
||||||
// Note that a default HostConfig can be created using getDefaultHostConfig.
|
// Note that a default HostConfig can be created using getDefaultHostConfig.
|
||||||
func runContainerWithHostConfig(t *testing.T, cli 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 == "" {
|
if containerConfig.Image == "" {
|
||||||
containerConfig.Image = imageName()
|
containerConfig.Image = imageName()
|
||||||
}
|
}
|
||||||
@@ -274,23 +300,22 @@ func runContainerWithHostConfig(t *testing.T, cli ce.ContainerInterface, contain
|
|||||||
if containerConfig.User == "" {
|
if containerConfig.User == "" {
|
||||||
containerConfig.User = generateRandomUID()
|
containerConfig.User = generateRandomUID()
|
||||||
}
|
}
|
||||||
if coverage() {
|
// if coverage
|
||||||
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
}
|
networkingConfig := network.NetworkingConfig{}
|
||||||
networkingConfig := ce.ContainerNetworkSettings{}
|
|
||||||
t.Logf("Running container (%s)", containerConfig.Image)
|
t.Logf("Running container (%s)", containerConfig.Image)
|
||||||
ID, err := cli.ContainerCreate(containerConfig, hostConfig, &networkingConfig, t.Name())
|
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, &networkingConfig, t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startContainer(t, cli, ID)
|
startContainer(t, cli, ctr.ID)
|
||||||
return ID
|
return ctr.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
||||||
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
||||||
func runContainerWithAllConfig(t *testing.T, cli 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 == "" {
|
if containerName == "" {
|
||||||
containerName = t.Name()
|
containerName = t.Name()
|
||||||
}
|
}
|
||||||
@@ -301,32 +326,30 @@ func runContainerWithAllConfig(t *testing.T, cli ce.ContainerInterface, containe
|
|||||||
if containerConfig.User == "" {
|
if containerConfig.User == "" {
|
||||||
containerConfig.User = generateRandomUID()
|
containerConfig.User = generateRandomUID()
|
||||||
}
|
}
|
||||||
if coverage() {
|
// if coverage
|
||||||
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
}
|
|
||||||
t.Logf("Running container (%s)", containerConfig.Image)
|
t.Logf("Running container (%s)", containerConfig.Image)
|
||||||
ID, err := cli.ContainerCreate(containerConfig, hostConfig, networkingConfig, containerName)
|
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkingConfig, containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startContainer(t, cli, ID)
|
startContainer(t, cli, ctr.ID)
|
||||||
return ID
|
return ctr.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
|
// runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
|
||||||
// If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
|
// If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
|
||||||
// environment variable.
|
// environment variable.
|
||||||
func runContainerWithPorts(t *testing.T, cli 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)
|
hostConfig := getDefaultHostConfig(t, cli)
|
||||||
var binding ce.PortBinding
|
|
||||||
for _, p := range ports {
|
for _, p := range ports {
|
||||||
port := fmt.Sprintf("%v/tcp", p)
|
port := nat.Port(fmt.Sprintf("%v/tcp", p))
|
||||||
binding = ce.PortBinding{
|
hostConfig.PortBindings[port] = []nat.PortBinding{
|
||||||
ContainerPort: port,
|
{
|
||||||
HostIP: "0.0.0.0",
|
HostIP: "0.0.0.0",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
|
||||||
}
|
}
|
||||||
return runContainerWithHostConfig(t, cli, containerConfig, hostConfig)
|
return runContainerWithHostConfig(t, cli, containerConfig, hostConfig)
|
||||||
}
|
}
|
||||||
@@ -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
|
// runContainer creates and starts a container. If no image is specified in
|
||||||
// the container config, then the image name is retrieved from the TEST_IMAGE
|
// the container config, then the image name is retrieved from the TEST_IMAGE
|
||||||
// environment variable.
|
// environment variable.
|
||||||
func runContainer(t *testing.T, cli ce.ContainerInterface, containerConfig *ce.ContainerConfig) string {
|
func runContainer(t *testing.T, cli *client.Client, containerConfig *container.Config) string {
|
||||||
return runContainerWithPorts(t, cli, containerConfig, nil)
|
return runContainerWithPorts(t, cli, containerConfig, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
||||||
// user and with default capabilities
|
// user and with default capabilities
|
||||||
func runContainerOneShot(t *testing.T, cli ce.ContainerInterface, command ...string) (int64, string) {
|
func runContainerOneShot(t *testing.T, cli *client.Client, command ...string) (int64, string) {
|
||||||
containerConfig := ce.ContainerConfig{
|
containerConfig := container.Config{
|
||||||
Entrypoint: command,
|
Entrypoint: command,
|
||||||
User: "root",
|
User: "root",
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := ce.ContainerHostConfig{}
|
hostConfig := container.HostConfig{}
|
||||||
networkingConfig := ce.ContainerNetworkSettings{}
|
networkingConfig := network.NetworkingConfig{}
|
||||||
t.Logf("Running one shot container (%s): %v", containerConfig.Image, command)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startOptions := ce.ContainerStartOptions{}
|
startOptions := types.ContainerStartOptions{}
|
||||||
err = cli.ContainerStart(ID, startOptions)
|
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainerQuiet(t, cli, ID)
|
defer cleanContainerQuiet(t, cli, ctr.ID)
|
||||||
rc := waitForContainer(t, cli, ID, 20*time.Second)
|
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
|
||||||
out := inspectLogs(t, cli, ID)
|
out := inspectLogs(t, cli, ctr.ID)
|
||||||
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
||||||
return rc, out
|
return rc, out
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
// runContainerOneShot runs a container with a custom entrypoint, as the root
|
||||||
// user, with default capabilities, and a volume mounted
|
// user, with default capabilities, and a volume mounted
|
||||||
func runContainerOneShotWithVolume(t *testing.T, cli ce.ContainerInterface, bind string, command ...string) (int64, string) {
|
func runContainerOneShotWithVolume(t *testing.T, cli *client.Client, bind string, command ...string) (int64, string) {
|
||||||
containerConfig := ce.ContainerConfig{
|
containerConfig := container.Config{
|
||||||
Entrypoint: command,
|
Entrypoint: command,
|
||||||
User: "root",
|
User: "root",
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
hostConfig := ce.ContainerHostConfig{
|
hostConfig := container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
bind,
|
bind,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
networkingConfig := ce.ContainerNetworkSettings{}
|
networkingConfig := network.NetworkingConfig{}
|
||||||
t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command)
|
t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command)
|
||||||
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startOptions := ce.ContainerStartOptions{}
|
startOptions := types.ContainerStartOptions{}
|
||||||
err = cli.ContainerStart(ID, startOptions)
|
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer cleanContainerQuiet(t, cli, ID)
|
defer cleanContainerQuiet(t, cli, ctr.ID)
|
||||||
rc := waitForContainer(t, cli, ID, 20*time.Second)
|
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
|
||||||
out := inspectLogs(t, cli, ID)
|
out := inspectLogs(t, cli, ctr.ID)
|
||||||
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
|
||||||
return rc, out
|
return rc, out
|
||||||
}
|
}
|
||||||
|
|
||||||
func startMultiVolumeQueueManager(t *testing.T, cli 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)
|
id := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||||
volume := createVolume(t, cli, id)
|
qmdata := createVolume(t, cli, id)
|
||||||
containerConfig := ce.ContainerConfig{
|
containerConfig := container.Config{
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
Env: env,
|
Env: env,
|
||||||
}
|
}
|
||||||
var hostConfig ce.ContainerHostConfig
|
var hostConfig container.HostConfig
|
||||||
|
|
||||||
if !dataVol {
|
if !dataVol {
|
||||||
hostConfig = ce.ContainerHostConfig{}
|
hostConfig = container.HostConfig{}
|
||||||
} else if qmsharedlogs == "" && qmshareddata == "" {
|
} else if qmsharedlogs == "" && qmshareddata == "" {
|
||||||
hostConfig = getHostConfig(t, 1, "", "", volume)
|
hostConfig = getHostConfig(t, 1, "", "", qmdata.Name)
|
||||||
} else if qmsharedlogs == "" {
|
} else if qmsharedlogs == "" {
|
||||||
hostConfig = getHostConfig(t, 2, "", qmshareddata, volume)
|
hostConfig = getHostConfig(t, 2, "", qmshareddata, qmdata.Name)
|
||||||
} else if qmshareddata == "" {
|
} else if qmshareddata == "" {
|
||||||
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", volume)
|
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", qmdata.Name)
|
||||||
} else {
|
} else {
|
||||||
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, volume)
|
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, qmdata.Name)
|
||||||
}
|
}
|
||||||
networkingConfig := ce.ContainerNetworkSettings{}
|
networkingConfig := network.NetworkingConfig{}
|
||||||
qmID, err := cli.ContainerCreate(&containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
|
qm, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, "", ""
|
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 {
|
switch mounts {
|
||||||
case 1:
|
case 1:
|
||||||
hostConfig = ce.ContainerHostConfig{
|
hostConfig = container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
hostConfig = ce.ContainerHostConfig{
|
hostConfig = container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
qmshareddata + ":/mnt/mqm-data",
|
qmshareddata + ":/mnt/mqm-data",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
hostConfig = ce.ContainerHostConfig{
|
hostConfig = container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
qmsharedlogs + ":/mnt/mqm-log",
|
qmsharedlogs + ":/mnt/mqm-log",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
hostConfig = ce.ContainerHostConfig{
|
hostConfig = container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
qmdata + ":/mnt/mqm",
|
qmdata + ":/mnt/mqm",
|
||||||
qmsharedlogs + ":/mnt/mqm-log",
|
qmsharedlogs + ":/mnt/mqm-log",
|
||||||
qmshareddata + ":/mnt/mqm-data",
|
qmshareddata + ":/mnt/mqm-data",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if coverage() {
|
|
||||||
hostConfig.Binds = append(hostConfig.Binds, coverageBind(t))
|
|
||||||
}
|
|
||||||
return hostConfig
|
return hostConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func startContainer(t *testing.T, cli ce.ContainerInterface, ID string) {
|
func startContainer(t *testing.T, cli *client.Client, ID string) {
|
||||||
t.Logf("Starting container: %v", ID)
|
t.Logf("Starting container: %v", ID)
|
||||||
startOptions := ce.ContainerStartOptions{}
|
startOptions := types.ContainerStartOptions{}
|
||||||
err := cli.ContainerStart(ID, startOptions)
|
err := cli.ContainerStart(context.Background(), ID, startOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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)
|
t.Logf("Stopping container: %v", ID)
|
||||||
timeout := 10 * time.Second
|
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 {
|
if err != nil {
|
||||||
// Just log the error and continue
|
t.Fatal(err)
|
||||||
t.Log(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)
|
t.Logf("Killing container: %v", ID)
|
||||||
err := cli.ContainerKill(ID, signal)
|
err := cli.ContainerKill(context.Background(), ID, signal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -521,17 +545,17 @@ func getCoverageExitCode(t *testing.T, orig int64) int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// waitForContainer waits until a container has exited
|
// waitForContainer waits until a container has exited
|
||||||
func waitForContainer(t *testing.T, cli 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)
|
c, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
t.Logf("Waiting for container for %s", timeout)
|
t.Logf("Waiting for container for %s", timeout)
|
||||||
okC, errC := cli.ContainerWait(c, ID, ce.ContainerStateNotRunning)
|
okC, errC := cli.ContainerWait(c, ID, container.WaitConditionNotRunning)
|
||||||
var rc int64
|
var rc int64
|
||||||
select {
|
select {
|
||||||
case err := <-errC:
|
case err := <-errC:
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
case ok := <-okC:
|
case ok := <-okC:
|
||||||
rc = ok
|
rc = ok.StatusCode
|
||||||
}
|
}
|
||||||
if coverage() {
|
if coverage() {
|
||||||
// COVERAGE: When running coverage, the exit code is written to a file,
|
// COVERAGE: When running coverage, the exit code is written to a file,
|
||||||
@@ -543,15 +567,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
|
// 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)
|
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, types.ExecStartCheck{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer hijack.Close()
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
err = cli.ContainerExecStart(context.Background(), resp.ID, types.ExecStartCheck{
|
||||||
|
Detach: false,
|
||||||
|
Tty: false,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Wait for the command to finish
|
||||||
|
var exitcode int
|
||||||
|
var outputStr string
|
||||||
|
for {
|
||||||
|
inspect, err := cli.ContainerExecInspect(context.Background(), resp.ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if inspect.Running {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
exitcode = inspect.ExitCode
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
// Each output line has a header, which needs to be removed
|
||||||
|
_, err = stdcopy.StdCopy(buf, buf, hijack.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStr = strings.TrimSpace(buf.String())
|
||||||
|
|
||||||
|
/* Commented out on 14/06/2018 as it might not be needed after adding
|
||||||
|
* pause between ContainerExecAttach and ContainerExecStart.
|
||||||
|
* TODO If intermittent failures do not occur, remove and refactor.
|
||||||
|
*
|
||||||
|
* // Before we go let's just double check it did actually finish running
|
||||||
|
* // because sometimes we get a "Exec command already running error"
|
||||||
|
* alreadyRunningErr := regexp.MustCompile("Error: Exec command .* is already running")
|
||||||
|
* if alreadyRunningErr.MatchString(outputStr) {
|
||||||
|
* continue
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
return exitcode, outputStr
|
return exitcode, outputStr
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForReady(t *testing.T, cli 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()
|
defer cancel()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -575,47 +662,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"
|
name := "test"
|
||||||
t.Logf("Creating network: %v", name)
|
t.Logf("Creating network: %v", name)
|
||||||
opts := ce.NetworkCreateOptions{}
|
opts := types.NetworkCreate{}
|
||||||
netID, err := cli.NetworkCreate(name, opts)
|
net, err := cli.NetworkCreate(context.Background(), name, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Logf("Created network %v with ID %v", name, netID)
|
t.Logf("Created network %v with ID %v", name, net.ID)
|
||||||
return netID
|
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)
|
t.Logf("Removing network ID: %v", ID)
|
||||||
err := cli.NetworkRemove(ID)
|
err := cli.NetworkRemove(context.Background(), ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVolume(t *testing.T, cli ce.ContainerInterface, name string) string {
|
func createVolume(t *testing.T, cli *client.Client, name string) types.Volume {
|
||||||
v, err := cli.VolumeCreate(ce.VolumeCreateOptions{
|
v, err := cli.VolumeCreate(context.Background(), volume.VolumeCreateBody{
|
||||||
Driver: "local",
|
Driver: "local",
|
||||||
Name: name,
|
DriverOpts: map[string]string{},
|
||||||
|
Labels: map[string]string{},
|
||||||
|
Name: name,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Logf("Created volume %v", v)
|
t.Logf("Created volume %v", v.Name)
|
||||||
return v
|
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)
|
t.Logf("Removing volume %v", name)
|
||||||
err := cli.VolumeRemove(name, true)
|
err := cli.VolumeRemove(context.Background(), name, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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)
|
jsonLogs := inspectLogs(t, cli, ID)
|
||||||
scanner := bufio.NewScanner(strings.NewReader(jsonLogs))
|
scanner := bufio.NewScanner(strings.NewReader(jsonLogs))
|
||||||
b := make([]byte, 64*1024)
|
b := make([]byte, 64*1024)
|
||||||
@@ -623,11 +720,9 @@ func inspectTextLogs(t *testing.T, cli ce.ContainerInterface, ID string) string
|
|||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
text := scanner.Text()
|
text := scanner.Text()
|
||||||
if strings.HasPrefix(text, "{") {
|
if strings.HasPrefix(text, "{") {
|
||||||
// If it's a JSON log message, it makes it hard to debug the test, as the JSON
|
|
||||||
// is embedded in the long test output. So just summarize the JSON instead.
|
|
||||||
var e map[string]interface{}
|
var e map[string]interface{}
|
||||||
json.Unmarshal([]byte(text), &e)
|
json.Unmarshal([]byte(text), &e)
|
||||||
fmt.Fprintf(buf, "{\"ibm_datetime\": \"%v\", \"message\": \"%v\", ...}\n", e["ibm_datetime"], e["message"])
|
fmt.Fprintf(buf, "{\"message\": \"%v\"}\n", e["message"])
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(buf, text)
|
fmt.Fprintln(buf, text)
|
||||||
}
|
}
|
||||||
@@ -639,14 +734,23 @@ func inspectTextLogs(t *testing.T, cli ce.ContainerInterface, ID string) string
|
|||||||
return buf.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)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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.
|
// generateTAR creates a TAR-formatted []byte, with the specified files included.
|
||||||
@@ -676,54 +780,76 @@ func generateTAR(t *testing.T, files []struct{ Name, Body string }) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createImage creates a new Docker image with the specified files included.
|
// createImage creates a new Docker image with the specified files included.
|
||||||
func createImage(t *testing.T, cli 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))
|
r := bytes.NewReader(generateTAR(t, files))
|
||||||
tag := strings.ToLower(t.Name())
|
tag := strings.ToLower(t.Name())
|
||||||
|
buildOptions := types.ImageBuildOptions{
|
||||||
tmpDir, err := os.MkdirTemp("", "tmp")
|
Context: r,
|
||||||
|
Tags: []string{tag},
|
||||||
|
}
|
||||||
|
resp, err := cli.ImageBuild(context.Background(), r, buildOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
// resp (ImageBuildResponse) contains a series of JSON messages
|
||||||
defer os.RemoveAll(tmpDir)
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
for {
|
||||||
//Write files to temp directory
|
m := jsonmessage.JSONMessage{}
|
||||||
for _, file := range files {
|
err := dec.Decode(&m)
|
||||||
//Add tag to file name to allow parallel testing
|
if m.Error != nil {
|
||||||
f, err := os.Create(filepath.Join(tmpDir, file.Name))
|
t.Fatal(m.ErrorMessage)
|
||||||
|
}
|
||||||
|
t.Log(strings.TrimSpace(m.Stream))
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
body := []byte(file.Body)
|
|
||||||
_, err = f.Write(body)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, err = cli.ImageBuild(r, tag, filepath.Join(tmpDir, files[0].Name))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteImage deletes a Docker image
|
// deleteImage deletes a Docker image
|
||||||
func deleteImage(t *testing.T, cli ce.ContainerInterface, id string) {
|
func deleteImage(t *testing.T, cli *client.Client, id string) {
|
||||||
cli.ImageRemove(id, ce.ImageRemoveOptions{
|
cli.ImageRemove(context.Background(), id, types.ImageRemoveOptions{
|
||||||
Force: true,
|
Force: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFromContainer(t *testing.T, cli ce.ContainerInterface, id string, file string) []byte {
|
func copyFromContainer(t *testing.T, cli *client.Client, id string, file string) []byte {
|
||||||
b, err := cli.CopyFromContainer(id, file)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPort(t *testing.T, cli *client.Client, ID string, port int) string {
|
||||||
|
var inspectInfo types.ContainerJSON
|
||||||
|
var err error
|
||||||
|
for attemptsRemaining := 3; attemptsRemaining > 0; attemptsRemaining-- {
|
||||||
|
inspectInfo, err = cli.ContainerInspect(context.Background(), ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
portNat := nat.Port(fmt.Sprintf("%d/tcp", port))
|
||||||
|
if inspectInfo.NetworkSettings.Ports[portNat] == nil || len(inspectInfo.NetworkSettings.Ports[portNat]) == 0 {
|
||||||
|
t.Log("Container port not yet bound")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return inspectInfo.NetworkSettings.Ports[portNat][0].HostPort
|
||||||
|
}
|
||||||
|
t.Fatal("Failed to get port")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func countLines(t *testing.T, r io.Reader) int {
|
func countLines(t *testing.T, r io.Reader) int {
|
||||||
scanner := bufio.NewScanner(r)
|
scanner := bufio.NewScanner(r)
|
||||||
count := 0
|
count := 0
|
||||||
@@ -755,117 +881,11 @@ func countTarLines(t *testing.T, b []byte) int {
|
|||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanForExcludedEntries scans for default excluded messages
|
func getMQVersion(t *testing.T, cli *client.Client) (string, error) {
|
||||||
func scanForExcludedEntries(msg string) bool {
|
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
err = startContainerError(t, cli, ID)
|
version := inspect.ContainerConfig.Labels["version"]
|
||||||
if err != nil {
|
return version, 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)
|
|
||||||
}
|
}
|
||||||
22
test/docker/go.mod
Normal file
22
test/docker/go.mod
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
module github.com/ibm-messaging/mq-container/test/docker
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/containerd/containerd v1.6.6 // indirect
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||||
|
// Note: This is not actually Docker v17.12!
|
||||||
|
// Go modules require the use of semver, but Docker does not use semver and has not
|
||||||
|
// [opted-in to use Go modules](https://github.com/golang/go/wiki/Modules#can-a-module-consume-a-package-that-has-not-opted-in-to-modules)
|
||||||
|
// This means that when you `go get` Docker, you need to do so based on a commit,
|
||||||
|
// e.g. `go get -v github.com/docker/docker@420b1d36250f9cfdc561f086f25a213ecb669b6f`,
|
||||||
|
// which uses the commit for [Docker v19.03.15](https://github.com/moby/moby/releases/tag/v19.03.15)
|
||||||
|
// Go will then find the latest tag with a semver-compatible tag. In Docker's case,
|
||||||
|
// v17.12.0 is valid semver, but v18.09 and v19.03 are not.
|
||||||
|
// Also note: Docker v20.10 is valid semver, but the v20.10 client API requires use of Docker API
|
||||||
|
// version 1.41 on the server, which is currently too new for the version of Docker in Travis (Ubuntu Bionic)
|
||||||
|
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible
|
||||||
|
github.com/docker/go-connections v0.4.0
|
||||||
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
|
||||||
|
google.golang.org/grpc v1.46.0 // indirect
|
||||||
|
)
|
||||||
1421
test/docker/go.sum
Normal file
1421
test/docker/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019, 2023
|
© Copyright IBM Corporation 2019, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
"github.com/docker/docker/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
var miEnv = []string{
|
var miEnv = []string{
|
||||||
@@ -34,7 +34,10 @@ var miEnv = []string{
|
|||||||
// and starts/stop them checking we always have an active and standby
|
// and starts/stop them checking we always have an active and standby
|
||||||
func TestMultiInstanceStartStop(t *testing.T) {
|
func TestMultiInstanceStartStop(t *testing.T) {
|
||||||
t.Skipf("Skipping %v until test defect fixed", t.Name())
|
t.Skipf("Skipping %v until test defect fixed", t.Name())
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -73,7 +76,10 @@ func TestMultiInstanceStartStop(t *testing.T) {
|
|||||||
// TestMultiInstanceContainerStop starts 2 containers in a multi instance queue manager configuration,
|
// TestMultiInstanceContainerStop starts 2 containers in a multi instance queue manager configuration,
|
||||||
// stops the active queue manager, then checks to ensure the backup queue manager becomes active
|
// stops the active queue manager, then checks to ensure the backup queue manager becomes active
|
||||||
func TestMultiInstanceContainerStop(t *testing.T) {
|
func TestMultiInstanceContainerStop(t *testing.T) {
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
err, qm1aId, qm1bId, volumes := configureMultiInstance(t, cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -116,16 +122,21 @@ func TestMultiInstanceContainerStop(t *testing.T) {
|
|||||||
// configuration, then checks to ensure that both an active and standby queue manager have been started
|
// configuration, then checks to ensure that both an active and standby queue manager have been started
|
||||||
func TestMultiInstanceRace(t *testing.T) {
|
func TestMultiInstanceRace(t *testing.T) {
|
||||||
t.Skipf("Skipping %v until file lock is implemented", t.Name())
|
t.Skipf("Skipping %v until file lock is implemented", t.Name())
|
||||||
cli := ce.NewContainerClient()
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
||||||
defer removeVolume(t, cli, qmsharedlogs)
|
defer removeVolume(t, cli, qmsharedlogs.Name)
|
||||||
qmshareddata := createVolume(t, cli, "qmshareddata")
|
qmshareddata := createVolume(t, cli, "qmshareddata")
|
||||||
defer removeVolume(t, cli, qmshareddata)
|
defer removeVolume(t, cli, qmshareddata.Name)
|
||||||
|
|
||||||
qmsChannel := make(chan QMChan)
|
qmsChannel := make(chan QMChan)
|
||||||
|
|
||||||
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs, qmshareddata, qmsChannel)
|
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs.Name, qmshareddata.Name, qmsChannel)
|
||||||
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs, qmshareddata, qmsChannel)
|
go singleMultiInstanceQueueManager(t, cli, qmsharedlogs.Name, qmshareddata.Name, qmsChannel)
|
||||||
|
|
||||||
qm1a := <-qmsChannel
|
qm1a := <-qmsChannel
|
||||||
if qm1a.Error != nil {
|
if qm1a.Error != nil {
|
||||||
@@ -148,7 +159,7 @@ func TestMultiInstanceRace(t *testing.T) {
|
|||||||
waitForReady(t, cli, qm1aId)
|
waitForReady(t, cli, qm1aId)
|
||||||
waitForReady(t, cli, qm1bId)
|
waitForReady(t, cli, qm1bId)
|
||||||
|
|
||||||
err, _, _ := getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
|
err, _, _ = getActiveStandbyQueueManager(t, cli, qm1aId, qm1bId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -158,7 +169,10 @@ func TestMultiInstanceRace(t *testing.T) {
|
|||||||
// mounts, then checks to ensure that the container terminates with the expected message
|
// mounts, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", "", miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, "", "", miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -174,12 +188,15 @@ func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
|||||||
// TestMultiInstanceNoSharedLogs starts 2 multi instance queue managers without providing a shared log
|
// TestMultiInstanceNoSharedLogs starts 2 multi instance queue managers without providing a shared log
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
qmshareddata := createVolume(t, cli, "qmshareddata")
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -193,12 +210,15 @@ func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
|||||||
// TestMultiInstanceNoSharedData starts 2 multi instance queue managers without providing a shared data
|
// TestMultiInstanceNoSharedData starts 2 multi instance queue managers without providing a shared data
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedData(t *testing.T) {
|
func TestMultiInstanceNoSharedData(t *testing.T) {
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
||||||
defer removeVolume(t, cli, qmsharedlogs)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -212,7 +232,10 @@ func TestMultiInstanceNoSharedData(t *testing.T) {
|
|||||||
// TestMultiInstanceNoMounts starts 2 multi instance queue managers without providing a shared data
|
// TestMultiInstanceNoMounts starts 2 multi instance queue managers without providing a shared data
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoMounts(t *testing.T) {
|
func TestMultiInstanceNoMounts(t *testing.T) {
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, false, "", "", miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, false, "", "", miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019, 2023
|
© Copyright IBM Corporation 2019, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
"github.com/docker/docker/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
type QMChan struct {
|
type QMChan struct {
|
||||||
@@ -34,27 +34,27 @@ type QMChan struct {
|
|||||||
|
|
||||||
// configureMultiInstance creates the volumes and containers required for basic testing
|
// configureMultiInstance creates the volumes and containers required for basic testing
|
||||||
// of multi instance queue managers. Returns error, qm1a ID, qm1b ID, slice of volume names
|
// of multi instance queue managers. Returns error, qm1a ID, qm1b ID, slice of volume names
|
||||||
func configureMultiInstance(t *testing.T, cli ce.ContainerInterface) (error, string, string, []string) {
|
func configureMultiInstance(t *testing.T, cli *client.Client) (error, string, string, []string) {
|
||||||
|
|
||||||
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
qmsharedlogs := createVolume(t, cli, "qmsharedlogs")
|
||||||
qmshareddata := createVolume(t, cli, "qmshareddata")
|
qmshareddata := createVolume(t, cli, "qmshareddata")
|
||||||
|
|
||||||
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
|
err, qm1aId, qm1aData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, qmshareddata.Name, miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, "", "", []string{}
|
return err, "", "", []string{}
|
||||||
}
|
}
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
err, qm1bId, qm1bData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
|
err, qm1bId, qm1bData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs.Name, qmshareddata.Name, miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, "", "", []string{}
|
return err, "", "", []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
volumes := []string{qmsharedlogs, qmshareddata, qm1aData, qm1bData}
|
volumes := []string{qmsharedlogs.Name, qmshareddata.Name, qm1aData, qm1bData}
|
||||||
|
|
||||||
return nil, qm1aId, qm1bId, volumes
|
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)
|
err, qmId, qmData := startMultiVolumeQueueManager(t, cli, true, qmsharedlogs, qmshareddata, miEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
qmsChannel <- QMChan{Error: err}
|
qmsChannel <- QMChan{Error: err}
|
||||||
@@ -62,7 +62,7 @@ func singleMultiInstanceQueueManager(t *testing.T, cli ce.ContainerInterface, qm
|
|||||||
qmsChannel <- QMChan{QMId: qmId, QMData: qmData}
|
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")
|
qm1aStatus := getQueueManagerStatus(t, cli, qm1aId, "QM1")
|
||||||
qm1bStatus := getQueueManagerStatus(t, cli, qm1bId, "QM1")
|
qm1bStatus := getQueueManagerStatus(t, cli, qm1bId, "QM1")
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ func getActiveStandbyQueueManager(t *testing.T, cli ce.ContainerInterface, qm1aI
|
|||||||
return err, "", ""
|
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})
|
_, dspmqOut := execContainer(t, cli, containerID, "", []string{"bash", "-c", "dspmq", "-m", queueManagerName})
|
||||||
t.Logf("dspmq for %v (%v) returned: %v", containerID, queueManagerName, dspmqOut)
|
t.Logf("dspmq for %v (%v) returned: %v", containerID, queueManagerName, dspmqOut)
|
||||||
regex := regexp.MustCompile(`STATUS\(.*\)`)
|
regex := regexp.MustCompile(`STATUS\(.*\)`)
|
||||||
@@ -84,7 +84,7 @@ func getQueueManagerStatus(t *testing.T, cli ce.ContainerInterface, containerID
|
|||||||
return 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)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
for {
|
for {
|
||||||
@@ -93,7 +93,7 @@ func waitForTerminationMessage(t *testing.T, cli ce.ContainerInterface, qmId str
|
|||||||
m := terminationMessage(t, cli, qmId)
|
m := terminationMessage(t, cli, qmId)
|
||||||
if m != "" {
|
if m != "" {
|
||||||
if !strings.Contains(m, terminationString) {
|
if !strings.Contains(m, terminationString) {
|
||||||
t.Fatalf("Expected container to fail 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
|
return
|
||||||
}
|
}
|
||||||
219
test/docker/mq_native_ha_test.go
Normal file
219
test/docker/mq_native_ha_test.go
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021, 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 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.NewClientWithOpts(client.FromEnv)
|
||||||
|
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.NewClientWithOpts(client.FromEnv)
|
||||||
|
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.NewClientWithOpts(client.FromEnv)
|
||||||
|
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.NewClientWithOpts(client.FromEnv)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2021, 2023
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -19,11 +19,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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
|
const defaultHAPort = 9414
|
||||||
@@ -34,8 +36,16 @@ type HAReplicaStatus struct {
|
|||||||
Replica [2]string
|
Replica [2]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNativeHAContainerConfig(containerName string, replicaNames [3]string, haPort int) ce.ContainerConfig {
|
func createBridgeNetwork(cli *client.Client, t *testing.T) (types.NetworkCreateResponse, error) {
|
||||||
return ce.ContainerConfig{
|
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{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=QM1",
|
"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_0_NAME=%s", replicaNames[0]),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_NAME=%s", replicaNames[1]),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_NAME=%s", replicaNames[1]),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_NAME=%s", replicaNames[2]),
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_NAME=%s", replicaNames[2]),
|
||||||
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_REPLICATION_ADDRESS=%s(%d)", "127.0.0.1", haPort+0),
|
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)", "127.0.0.1", haPort+1),
|
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)", "127.0.0.1", haPort+2),
|
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 {
|
func getNativeHASecureHostConfig(t *testing.T) container.HostConfig {
|
||||||
return ce.ContainerHostConfig{
|
return container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
filepath.Join(getCwd(t, true), "../tls") + ":/etc/mqm/ha/pki/keys/ha",
|
filepath.Join(getCwd(t, true), "../tls") + ":/etc/mqm/ha/pki/keys/ha",
|
||||||
@@ -64,30 +71,15 @@ func getNativeHASecureHostConfig(t *testing.T) ce.ContainerHostConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNativeHANetworkConfig(networkID string) ce.ContainerNetworkSettings {
|
func getNativeHANetworkConfig(networkID string) network.NetworkingConfig {
|
||||||
return ce.ContainerNetworkSettings{
|
return network.NetworkingConfig{
|
||||||
Networks: []string{networkID},
|
EndpointsConfig: map[string]*network.EndpointSettings{
|
||||||
|
networkID: &network.EndpointSettings{},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// populatePortBindings writes port bindings to the host config
|
func getActiveReplicaInstances(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) (HAReplicaStatus, error) {
|
||||||
func populateNativeHAPortBindings(ports []int, nativeHaPort int, hostConfig ce.ContainerHostConfig) ce.ContainerHostConfig {
|
|
||||||
hostConfig.PortBindings = []ce.PortBinding{}
|
|
||||||
var binding ce.PortBinding
|
|
||||||
for i, p := range ports {
|
|
||||||
port := fmt.Sprintf("%v/tcp", p)
|
|
||||||
binding = ce.PortBinding{
|
|
||||||
ContainerPort: port,
|
|
||||||
HostIP: "0.0.0.0",
|
|
||||||
//Offset the ports by 50 if there are multiple
|
|
||||||
HostPort: strconv.Itoa(nativeHaPort + 50*i),
|
|
||||||
}
|
|
||||||
hostConfig.PortBindings = append(hostConfig.PortBindings, binding)
|
|
||||||
}
|
|
||||||
return hostConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func getActiveReplicaInstances(t *testing.T, cli ce.ContainerInterface, qmReplicaIDs [3]string) (HAReplicaStatus, error) {
|
|
||||||
|
|
||||||
var actives []string
|
var actives []string
|
||||||
var replicas []string
|
var replicas []string
|
||||||
@@ -112,9 +104,9 @@ func getActiveReplicaInstances(t *testing.T, cli ce.ContainerInterface, qmReplic
|
|||||||
return HAReplicaStatus{actives[0], [2]string{replicas[0], replicas[1]}}, nil
|
return HAReplicaStatus{actives[0], [2]string{replicas[0], replicas[1]}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForReadyHA(t *testing.T, cli 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()
|
defer cancel()
|
||||||
|
|
||||||
for {
|
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)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -22,20 +22,20 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
"github.com/docker/docker/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGoldenPathMetric(t *testing.T) {
|
func TestGoldenPathMetric(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
|
||||||
|
port := getPort(t, cli, id, defaultMetricPort)
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -55,14 +55,14 @@ func TestGoldenPathMetric(t *testing.T) {
|
|||||||
func TestMetricNames(t *testing.T) {
|
func TestMetricNames(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
|
||||||
|
port := getPort(t, cli, id, defaultMetricPort)
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -99,14 +99,14 @@ func TestMetricNames(t *testing.T) {
|
|||||||
func TestMetricLabels(t *testing.T) {
|
func TestMetricLabels(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
|
||||||
requiredLabels := []string{"qmgr"}
|
requiredLabels := []string{"qmgr"}
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port := getPort(t, cli, id, defaultMetricPort)
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -148,13 +148,13 @@ func TestMetricLabels(t *testing.T) {
|
|||||||
func TestRapidFirePrometheus(t *testing.T) {
|
func TestRapidFirePrometheus(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port := getPort(t, cli, id, defaultMetricPort)
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -182,13 +182,13 @@ func TestRapidFirePrometheus(t *testing.T) {
|
|||||||
func TestSlowPrometheus(t *testing.T) {
|
func TestSlowPrometheus(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port := getPort(t, cli, id, defaultMetricPort)
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -213,14 +213,15 @@ func TestSlowPrometheus(t *testing.T) {
|
|||||||
func TestContainerRestart(t *testing.T) {
|
func TestContainerRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
port := getPort(t, cli, id, defaultMetricPort)
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -238,10 +239,7 @@ func TestContainerRestart(t *testing.T) {
|
|||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
// Start the container cleanly
|
// Start the container cleanly
|
||||||
startContainer(t, cli, id)
|
startContainer(t, cli, id)
|
||||||
port, err = cli.GetContainerPort(id, defaultMetricPort)
|
port = getPort(t, cli, id, defaultMetricPort)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
@@ -263,15 +261,16 @@ func TestContainerRestart(t *testing.T) {
|
|||||||
func TestQMRestart(t *testing.T) {
|
func TestQMRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
|
||||||
|
port := getPort(t, cli, id, defaultMetricPort)
|
||||||
|
|
||||||
// Now the container is ready we prod the prometheus endpoint until it's up.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -320,14 +319,14 @@ func TestQMRestart(t *testing.T) {
|
|||||||
func TestValidValues(t *testing.T) {
|
func TestValidValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
// hostname := getIPAddress(t, cli, id)
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{defaultMetricPort})
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
// 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.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -344,7 +343,7 @@ func TestValidValues(t *testing.T) {
|
|||||||
// Check that the values for each metric are valid numbers
|
// Check that the values for each metric are valid numbers
|
||||||
// can be either int, float or exponential - all these can be parsed by ParseFloat function
|
// can be either int, float or exponential - all these can be parsed by ParseFloat function
|
||||||
for _, e := range metrics {
|
for _, e := range metrics {
|
||||||
if _, err := strconv.ParseFloat(e.Value, 64); err != nil {
|
if _, err = strconv.ParseFloat(e.Value, 64); err != nil {
|
||||||
t.Errorf("Value (%s) for key (%s) is not a valid number", e.Value, e.Key)
|
t.Errorf("Value (%s) for key (%s) is not a valid number", e.Value, e.Key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,14 +355,14 @@ func TestValidValues(t *testing.T) {
|
|||||||
func TestChangingValues(t *testing.T) {
|
func TestChangingValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli := ce.NewContainerClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{1414, defaultMetricPort})
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
// hostname := getIPAddress(t, cli, id)
|
|
||||||
port, err := cli.GetContainerPort(id, defaultMetricPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
id := runContainerWithPorts(t, cli, metricsContainerConfig(), []int{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.
|
// Now the container is ready we prod the prometheus endpoint until it's up.
|
||||||
waitForMetricReady(t, port)
|
waitForMetricReady(t, port)
|
||||||
|
|
||||||
@@ -387,11 +386,7 @@ func TestChangingValues(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send invalid data to the MQ listener to generate a FDC
|
// Send invalid data to the MQ listener to generate a FDC
|
||||||
noport, err := cli.GetContainerPort(id, 1414)
|
listener := fmt.Sprintf("localhost:%s", getPort(t, cli, id, 1414))
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
listener := fmt.Sprintf("localhost:%s", noport)
|
|
||||||
conn, err := net.Dial("tcp", listener)
|
conn, err := net.Dial("tcp", listener)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Could not connect to the listener - %v", err)
|
t.Fatalf("Could not connect to the listener - %v", err)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ce "github.com/ibm-messaging/mq-container/test/container/containerengine"
|
"github.com/docker/docker/api/types/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mqmetric struct {
|
type mqmetric struct {
|
||||||
@@ -146,8 +146,8 @@ func waitForMetricReady(t *testing.T, port string) {
|
|||||||
t.Fatalf("Metric endpoint failed to startup in timely manner")
|
t.Fatalf("Metric endpoint failed to startup in timely manner")
|
||||||
}
|
}
|
||||||
|
|
||||||
func metricsContainerConfig() *ce.ContainerConfig {
|
func metricsContainerConfig() *container.Config {
|
||||||
return &ce.ContainerConfig{
|
return &container.Config{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + defaultMetricQMName,
|
"MQ_QMGR_NAME=" + defaultMetricQMName,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2023
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -51,7 +51,6 @@ class JMSTests {
|
|||||||
private static final Logger LOGGER = Logger.getLogger(JMSTests.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(JMSTests.class.getName());
|
||||||
protected static final String ADDR = System.getenv("MQ_PORT_1414_TCP_ADDR");
|
protected static final String ADDR = System.getenv("MQ_PORT_1414_TCP_ADDR");
|
||||||
protected static final String USER = System.getenv("MQ_USERNAME");
|
protected static final String USER = System.getenv("MQ_USERNAME");
|
||||||
protected static final String PORT = System.getenv().getOrDefault("MQ_PORT_1414_OVERRIDE", "1414");
|
|
||||||
protected static final String PASSWORD = System.getenv("MQ_PASSWORD");
|
protected static final String PASSWORD = System.getenv("MQ_PASSWORD");
|
||||||
protected static final String CHANNEL = System.getenv("MQ_CHANNEL");
|
protected static final String CHANNEL = System.getenv("MQ_CHANNEL");
|
||||||
protected static final String TRUSTSTORE = System.getenv("MQ_TLS_TRUSTSTORE");
|
protected static final String TRUSTSTORE = System.getenv("MQ_TLS_TRUSTSTORE");
|
||||||
@@ -68,11 +67,11 @@ class JMSTests {
|
|||||||
return ctx.getSocketFactory();
|
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();
|
MQConnectionFactory factory = new MQConnectionFactory();
|
||||||
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
|
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
|
||||||
factory.setChannel(channel);
|
factory.setChannel(channel);
|
||||||
factory.setConnectionNameList(String.format("%s(%s)", addr, port));
|
factory.setConnectionNameList(String.format("%s(1414)", addr));
|
||||||
if (TRUSTSTORE == null) {
|
if (TRUSTSTORE == null) {
|
||||||
LOGGER.info("Not using TLS");
|
LOGGER.info("Not using TLS");
|
||||||
}
|
}
|
||||||
@@ -84,7 +83,7 @@ class JMSTests {
|
|||||||
if (ibmjre){
|
if (ibmjre){
|
||||||
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
|
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
|
||||||
} else {
|
} else {
|
||||||
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
|
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
|
||||||
}
|
}
|
||||||
factory.setSSLCipherSuite(System.getenv("MQ_TLS_CIPHER"));
|
factory.setSSLCipherSuite(System.getenv("MQ_TLS_CIPHER"));
|
||||||
}
|
}
|
||||||
@@ -94,9 +93,9 @@ class JMSTests {
|
|||||||
/**
|
/**
|
||||||
* Create a JMSContext with the supplied user and password.
|
* Create a JMSContext with the supplied user and password.
|
||||||
*/
|
*/
|
||||||
static JMSContext create(String channel, String addr, String port, String user, String password) throws JMSException, IOException, GeneralSecurityException {
|
static JMSContext create(String channel, String addr, String user, String password) throws JMSException, IOException, GeneralSecurityException {
|
||||||
LOGGER.info(String.format("Connecting to %s/TCP/%s(%s) as %s", channel, addr, port, user));
|
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as %s", channel, addr, user));
|
||||||
MQConnectionFactory factory = createMQConnectionFactory(channel, addr, port);
|
MQConnectionFactory factory = createMQConnectionFactory(channel, addr);
|
||||||
// If a password is set, make sure it gets sent to the queue manager for authentication
|
// If a password is set, make sure it gets sent to the queue manager for authentication
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
factory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
|
factory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
|
||||||
@@ -108,9 +107,9 @@ class JMSTests {
|
|||||||
/**
|
/**
|
||||||
* Create a JMSContext with the default user identity (from the OS)
|
* Create a JMSContext with the default user identity (from the OS)
|
||||||
*/
|
*/
|
||||||
static JMSContext create(String channel, String addr, String port) throws JMSException, IOException, GeneralSecurityException {
|
static JMSContext create(String channel, String addr) 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")));
|
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, port);
|
MQConnectionFactory factory = createMQConnectionFactory(channel, addr);
|
||||||
LOGGER.info(String.format("CSP authentication: %s", factory.getBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP)));
|
LOGGER.info(String.format("CSP authentication: %s", factory.getBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP)));
|
||||||
return factory.createContext();
|
return factory.createContext();
|
||||||
}
|
}
|
||||||
@@ -119,7 +118,7 @@ class JMSTests {
|
|||||||
private static void waitForQueueManager() {
|
private static void waitForQueueManager() {
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
try {
|
try {
|
||||||
Socket s = new Socket(ADDR, Integer.parseInt(PORT));
|
Socket s = new Socket(ADDR, 1414);
|
||||||
s.close();
|
s.close();
|
||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -133,7 +132,7 @@ class JMSTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void putGetTest(TestInfo t) throws Exception {
|
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");
|
Queue queue = new MQQueue("DEV.QUEUE.1");
|
||||||
context.createProducer().send(queue, t.getDisplayName());
|
context.createProducer().send(queue, t.getDisplayName());
|
||||||
Message m = context.createConsumer(queue).receive();
|
Message m = context.createConsumer(queue).receive();
|
||||||
@@ -145,7 +144,7 @@ class JMSTests {
|
|||||||
LOGGER.info(String.format("Password='%s'", PASSWORD));
|
LOGGER.info(String.format("Password='%s'", PASSWORD));
|
||||||
try {
|
try {
|
||||||
// Don't pass a user/password, which should cause the default identity to be used
|
// Don't pass a user/password, which should cause the default identity to be used
|
||||||
context = create(CHANNEL, ADDR, PORT);
|
context = create(CHANNEL, ADDR);
|
||||||
} catch (DetailedJMSSecurityRuntimeException ex) {
|
} catch (DetailedJMSSecurityRuntimeException ex) {
|
||||||
Throwable cause = ex.getCause();
|
Throwable cause = ex.getCause();
|
||||||
assertNotNull(cause);
|
assertNotNull(cause);
|
||||||
|
|||||||
@@ -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-----
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpAIBAAKCAQEAys3CaU4vXdZuKyw5AMkM4onEiJk3/TulWZIrXvFMgYLzAPX5
|
|
||||||
eVUzs+eKfSBVIRiDGtsbmhcztT1GiAU6l8G9jHSegItJpKjiBEfFEuMmV6Fhx7Zj
|
|
||||||
QdpyGdV+0bcE2IJHmeiaNxouvsV5gBJTvEamVsw9zU7GGOhhMyBQUUQDNy7yoHn8
|
|
||||||
CBhDdoBskwJtpqPcxzohUDDt5wqSqOUljo8yS375k4Q18hWzWIxJIAHoAFk+YyJq
|
|
||||||
Lq3mqq438Z9WSgjv9V+eLpNtKlge2IzWd1uH/siXE8Pp6p3WleG7cw2dzQZap+ek
|
|
||||||
bx+3rRVLs8WYBHeTx08980sv6bBUKwHwaXXXSQIDAQABAoIBAQCdbqs7yij1BG/T
|
|
||||||
ben2VRx+g4ogrCiNmY7bgJ/QfSrx4vC3TztR2DVhtB2K0t2i6n9kCrFbpiVKzX2C
|
|
||||||
O+TnR8vYS/N7QCV0AHIr9nbjGZh7MFlSiqB0z5oBuf1P2W6WkFP7A1kr61RcXbnb
|
|
||||||
FN8R6hpYiQZ06XDYhxRldvFClLSWUaZOhM6DoEcfNV5djDWPv4tSlw0ILvgIDfeu
|
|
||||||
DfW5d6ih51CT+NqtXUZNgWB4WCFrqxLz2H197QtFNbeEnT2kqU81LiSR6ZLU2LAc
|
|
||||||
SEhWD9xpldPvm6CsYDy9LQazG+F4KA45OGgiHUfB43EvGnDHJEeX4HFMFWYKmefa
|
|
||||||
VQRD5GKBAoGBAPEQXruYnfYk3B+arl4GWCZd37TQd4ik2HybkhxPK/LXLJhuImun
|
|
||||||
6gYu0Y5dSpBv0B6LjhTencAjgfZRSiCplxbnnPMg2Tuu1FAjG7W5UlKsT8IlmHR3
|
|
||||||
3LqublsCQDaww/pBlXMsT7TUe89uH05v5Fn4pwp5Hy6IArhJLecDoYk5AoGBANde
|
|
||||||
hrLVn0XhFwQWe11vbhclF9KtJHqspXhKX6mRcQ4VSzoGuaji+ISyfoCaU6kVQrq8
|
|
||||||
WCZIOcTJTDScrk3BYQbY0+I6hBIug3SXhR8pGshQHvGOC/pAUInzWO3xc3lbJAwR
|
|
||||||
aK70zN8wXFJjc1rOivMY/mRvdJSYlPmr2e5fJg6RAoGAEj97/FVsN7LImvfZlTKD
|
|
||||||
v7vBcG2LbuOTo7MfF1eC6yoQrSVBI8cdNwSaRl2XhGGCbp1/zuKfLGlDsEKtCtXr
|
|
||||||
owc7YUguSY9NcReHRHVX3vw+OWMhLEfahKMppWgBNmKhIzONvZ8wFW80RBqA8i4U
|
|
||||||
Kh9hfbB3hM0074BSojcrJjkCgYEApavzVjJ6WRjzyZM5xwBm4asJDmlefHe+ujAM
|
|
||||||
MrbNDxZWTgbKXx5qKjnckjUlUhYmxNsJvDknJzfqRTaZ5vpxFwFIzOhSnGHngZLl
|
|
||||||
Nrk5/wmTJCIvGIzM57GooTFxsNLpgdcKfjuWNcJP4pjaLepgfOynFL+gIIbXYtBN
|
|
||||||
zs6myeECgYBp2shsVXAo0G2Iw5qSrPmsC0WurVYv5jZSAcnbV468vgGKP+L65nou
|
|
||||||
c7iuLWFJdsvgZUXWyijsQNmkOpNDkfYxcimFtNWMzt2IcoAEQzk5VO0Ok6EfrVCr
|
|
||||||
S1Kj0bo7oOyy0eZfQKVs39gE+ZKc8Fn2s4w4l6ZayhTKcfW6lwrJJA==
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIID2zCCAsOgAwIBAgIUdbPSj6WWhFu2amL9voKbyCMKiB4wDQYJKoZIhvcNAQEL
|
|
||||||
BQAwfTELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAktBMQwwCgYDVQQHDANCTFIxDDAK
|
|
||||||
BgNVBAoMA0lCTTEMMAoGA1UECwwDSVNMMRAwDgYDVQQDDAdNUU1GVFFNMSUwIwYJ
|
|
||||||
KoZIhvcNAQkBFhZzaGFzaGlrYW50aEBpbi5pYm0uY29tMB4XDTIzMDEyNTA1MjEz
|
|
||||||
NloXDTI4MDEyNDA1MjEzNlowfTELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAktBMQww
|
|
||||||
CgYDVQQHDANCTFIxDDAKBgNVBAoMA0lCTTEMMAoGA1UECwwDSVNMMRAwDgYDVQQD
|
|
||||||
DAdNUU1GVFFNMSUwIwYJKoZIhvcNAQkBFhZzaGFzaGlrYW50aEBpbi5pYm0uY29t
|
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwl9MlmCNG7kzk7qKGuBX
|
|
||||||
jTONcn2OcifKfwgJlvzTqHcf8X/BIiyOOiwoeznke///LLtt9ygF0iyBMQYM/CG/
|
|
||||||
rzOR6tbzI4y4Bmx6VqY02CkXi/p66ywQ7B5N2Fdp9Bop3SnthTcT4NoXBSEUhI1O
|
|
||||||
ob8lDFv1KMRkCULD2sA0FUYCrHtw0M/vEOqsA9VVjyzOXsIlbbR1BSXtlWNneGeL
|
|
||||||
OAdmQWO3QYCku/YrCyJlscvIisjp4s7guGnQh0Ws8h50R5sqag8RvdHUwExVLUfZ
|
|
||||||
L1Od0+hCiO5mNfKekT0cs9owplcwgNHw88b8q4/aHDBtQRgsukkMxTpo00ftPJxI
|
|
||||||
nwIDAQABo1MwUTAdBgNVHQ4EFgQUOyw89AeB0jXb5WCZv/5oDY8oWxkwHwYDVR0j
|
|
||||||
BBgwFoAUOyw89AeB0jXb5WCZv/5oDY8oWxkwDwYDVR0TAQH/BAUwAwEB/zANBgkq
|
|
||||||
hkiG9w0BAQsFAAOCAQEAtbybQQ9GpY5gH7xz4EWOUZ7XMmBYtuGXVrqUd+76hvCA
|
|
||||||
H/SB0nl2bGp7tAKBttmXhfKVac6wFCbXvYe49B+Q9+iL7H9st9VZUPKLQ6K3Uet6
|
|
||||||
L1ggMm2BhecpuYbwkG7ZidVFo/SuUCbCTnXBgHjvq4IkVCaJe7aKZmejSCh7gsIR
|
|
||||||
BQkZvz/22Vx/WPTEYp0x/riIvSViBjLCuD25Y+nCtS8c2xGVBjs9Q4GWCOAvEfAr
|
|
||||||
Tqs42brH1Vs92xS143p2h/wv52tmhfJI6X9QVQBBUoIjPR/VDFqZU5EYhAvuQPBi
|
|
||||||
UADz9hNYGQ9wBzZGvzbrorpoT+7aW9nGtmUsvvupBA==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
This directory contains private key and a certificate that signed by CA.
|
|
||||||
The directory also contains the CA certificate. The certificate and it's
|
|
||||||
CA certificate have different Subject DNs.
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIF5DCCA8ygAwIBAgICEAAwDQYJKoZIhvcNAQENBQAwgYsxCzAJBgNVBAYTAkdC
|
|
||||||
MQ4wDAYDVQQIDAVIQU5UUzETMBEGA1UEBwwKV2luY2hlc3RlcjEMMAoGA1UECgwD
|
|
||||||
SUJNMQ8wDQYDVQQLDAZIVVJJQk0xETAPBgNVBAMMCEhVUklCTUdCMSUwIwYJKoZI
|
|
||||||
hvcNAQkBFhZzaGFzaGlrYW50aEBpbi5pYm0uY29tMB4XDTIzMDEyODAyMjEyNFoX
|
|
||||||
DTMzMDEyNTAyMjEyNFowdjELMAkGA1UEBhMCR0IxDjAMBgNVBAgMBUhBTlRTMQww
|
|
||||||
CgYDVQQKDANJQk0xDzANBgNVBAsMBkhVUklCTTERMA8GA1UEAwwISFVSSUJNR0Ix
|
|
||||||
JTAjBgkqhkiG9w0BCQEWFnNoYXNoaWthbnRoQGluLmlibS5jb20wggIiMA0GCSqG
|
|
||||||
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDyTaomebXQXMGAs3ux3SSJnJseozpUIWS2
|
|
||||||
eUMG8U3YK81raVpFsGPcjDi4RdCo72SqwD3LKKJmyfz4NOlKpZJq5rhqaHkECRj/
|
|
||||||
GUKihl6Fr4OWlcJui/x4xeJmgFHvgnQEH/r8mvVVE8GqKHX9mRVOMaJtG14hm1qI
|
|
||||||
DoK+x9IwOut/H5FMeici/C11xIDK65/54vztb4wEfyRNK5e8dFwuD9yJo2gYM0GB
|
|
||||||
csQTq5WbKr0/uMF9rfFEx0lybHEASqgLCUA5lAGFtexefCFNxOxLnP4U2c5J+bcR
|
|
||||||
rGQ/hpfw02m0UU+fuNba8GPJbXJ6zT+FP0kme0180OKmH1zcNDRJuGY6OQ1nICHc
|
|
||||||
hf9QF95XQcwkf4MIltxZiNHbhSLuHrNFImv/AxiFchQJ+KPMLHV23x1uVKvRK3Mg
|
|
||||||
ZOEZmtCZVTRbOF6AWSTMGblu1tuxjSohO9ycqk8yQk/YkHW3zuEiIV+AAZW6qMKI
|
|
||||||
UZK64AoFb+E79gRpamz3ZOFfzNn/nKT4eMovDUUa8W4sVOVjBP2lT87xt7WBsE2f
|
|
||||||
mK4vE19hQGMzI3jZcMjIwNp4HjKIAeZb8o21ywogGF0qHctoINnEu7nG2trH02ug
|
|
||||||
0d+hwCfPRQHB7dicwTZm8ute4cHrwXed5tt1Bwv4Rq45GbwaOCAeZWa9S9GUaY/t
|
|
||||||
9xeS66HLPQIDAQABo2YwZDAdBgNVHQ4EFgQUMIuRPon0lwjMxi5tLwJYRcagTN0w
|
|
||||||
HwYDVR0jBBgwFoAUMjCCvlMnTcsiRvpiGPgBUGAA0EwwEgYDVR0TAQH/BAgwBgEB
|
|
||||||
/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQENBQADggIBACPpl2Im9El6
|
|
||||||
m7T8cmtgXEW+rcQH/AA3px3+J/RnSWyRUi5fb0lc1RkfxQvuG7/sH3ywOc+uuB2b
|
|
||||||
3lg6zkNaP4tZYTEjrrkj5qFycoQcvem/5nBKuQ18+ZGulHqE+YzcPTmbNO2VzD5e
|
|
||||||
RJJpboiJa5TtM4wBeIuWbicWN+2wPeOkiQHxHEWtXOEVmbKzuREI6JHg2CDYMpWb
|
|
||||||
GWqS3hn9hfQoNhtSdtDFGChlsTpgKB/gRpYEfrlLKYKekJafD+xhEl/ZC2JDOtUr
|
|
||||||
/dZW4JicC++rUrMt89aFzEAOtcaR4dbL4NQhMRAlF9MdjZvHdcJqYEd3wqOymEnV
|
|
||||||
4ce1VpraZIh3qywqoOqf54vjd5DugpFoxjye+5ynzfMGX6RjwWnVRiY36kjFiMFR
|
|
||||||
iGhFT74lbRmw86RUQFjiXWAG9R0cR5s0EyOM3Egp/qRkWxbG6z7JeCdUd7Z/aaR3
|
|
||||||
iT081PUcQsl+jzCw2J6SDkemzZn/spkViodfzGJ5xEXB0fldIDarbDqOeWjSoKaz
|
|
||||||
LA7qIfPJptJkwybK/hBqvfR5fXx1VuubJdMfbo5jmP4OVCkNV5I6D5EMkYCxPrOl
|
|
||||||
9eVjYbndAVAXRF8vopJRqe067c+IwKPTnG4iIoXcR28efCBQ0Tv8DXYmHjSlVLdt
|
|
||||||
UCqYhFBxgGOUJLmqe7O9TWVk/aIM3Q3M
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIF9jCCA96gAwIBAgIBADANBgkqhkiG9w0BAQ0FADCBizELMAkGA1UEBhMCR0Ix
|
|
||||||
DjAMBgNVBAgMBUhBTlRTMRMwEQYDVQQHDApXaW5jaGVzdGVyMQwwCgYDVQQKDANJ
|
|
||||||
Qk0xDzANBgNVBAsMBkhVUklCTTERMA8GA1UEAwwISFVSSUJNR0IxJTAjBgkqhkiG
|
|
||||||
9w0BCQEWFnNoYXNoaWthbnRoQGluLmlibS5jb20wHhcNMjMwMTI4MDIxNjIzWhcN
|
|
||||||
MzMwMTI1MDIxNjIzWjCBizELMAkGA1UEBhMCR0IxDjAMBgNVBAgMBUhBTlRTMRMw
|
|
||||||
EQYDVQQHDApXaW5jaGVzdGVyMQwwCgYDVQQKDANJQk0xDzANBgNVBAsMBkhVUklC
|
|
||||||
TTERMA8GA1UEAwwISFVSSUJNR0IxJTAjBgkqhkiG9w0BCQEWFnNoYXNoaWthbnRo
|
|
||||||
QGluLmlibS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDjTlg8
|
|
||||||
0bZ3vzeYLJ1Z4zp/HplJSDzAn22EROJtHNb1pyfWfaO7UyUy5jNt1UJ6hTXy1xOS
|
|
||||||
r9eGaSu3kAm/R/METYgsMM56ALQ458VlLpZUEJBMgu63W6/FTckl5iUno7n9y3qL
|
|
||||||
2CKkHuEXG9jd/jPhBX+GLc+h1iwe1URaJSe1CLdSc8SMsGZUC3wMO3EAAqEOHh9j
|
|
||||||
BQy2qeWpR6oAF8HST5JX6lW+k/4NeNthdse8/Oqv1otPzseXE9jz09tz+4Qd5fdt
|
|
||||||
J8UcCWPcpAFb/TM6S2Hpr8xSqZr5+Em4JimdNDtEbJZKjzSwvmZ4S3qsUP0xb9ad
|
|
||||||
NgDjxYjBqNStgjrSzKGebazD6U4EDa8dXS6UxqgnxmtcSQLXIPcwfH9FniKnR7Tu
|
|
||||||
/cmSDOdWCedyxeDjrLlGuFUtJiSXCqRHU8c5KxTVkyDV1YZPjISktVJQS1/n39Lf
|
|
||||||
2TtHNTH3qTDfPzcgBqqczF+vlIKspE4YcTFBynOlL4biWZEsddOjpoqzamycMBqj
|
|
||||||
sEMlvydggS+Z8oZqDFVTU9/BCC2mth9HZr7hjO950IQcgVKexXOqxgPP4rmzEl2k
|
|
||||||
jEp9PKdDqBv7lOYjYO4taegfCZs5FPwaKtCStmzQLERMwSifqXe0TGV5obA8asRY
|
|
||||||
pOiZf6d9nVBvIYKotB1mNJTMqBke5hom8uarPQIDAQABo2MwYTAdBgNVHQ4EFgQU
|
|
||||||
MjCCvlMnTcsiRvpiGPgBUGAA0EwwHwYDVR0jBBgwFoAUMjCCvlMnTcsiRvpiGPgB
|
|
||||||
UGAA0EwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcN
|
|
||||||
AQENBQADggIBADYAHeWqQEg+oIC5qy8obEul4Zuk5J9HignrP8ef0+wdJf+Zx9/j
|
|
||||||
3nZKBrUrgZiBP+RJgNYLRByO9QT/q+P5dLfuLikyP377oLlVUcXQIXbJU60Yxdl5
|
|
||||||
wrpS9O8nfbwMUdi+1foGmA17zYNiTfBZ0/vem6yrhKdP6pS4h1+291tF3+mac0Q1
|
|
||||||
sx7RhssZT22YclH9u3U4q7Ef3q5ilqV5fb/Rm2z/iGtOLF2swm/jS1CEpJbyb0EE
|
|
||||||
yF8hoX8oliJdunmUqGV8bK5D7GFx47tyS5lU4B/Q14xBYUUc4hs83xAs667h0fym
|
|
||||||
0fbyQGh92bASPEDw6ep8eI6Iv+DSniwEFPG0ayDtnSEM/HkRVML497Rhqks/cP/9
|
|
||||||
rMJe9hUoetKO+p390R22EQLqGT6nvWV1jsGMHIMjJB7kfBLbgvFz8pQQdo7IxK4N
|
|
||||||
IirFdEn/atri2Z6baT6eqKt2tnjodQs1F+14rK1cj0QbH/tkHF8S411MclmufthB
|
|
||||||
U+VlEcjr4pnpVzvE4B78kXtlRH1N7Pj+vIgwpiC+hnWcQdqVF58E+7ERz9U1JqaQ
|
|
||||||
tX9c6aZW4m1pMcxR3c76NnYJi6rmhoL8xUNDq7HXrkK3DM0/rUvxl5HwfgGC0FGS
|
|
||||||
QmFgXgNddo2pj/TjnssE9XxFjsU+gEbGudGe0p5HR5qlKzTLc44WxcmW
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIF7jCCA9agAwIBAgICEjQwDQYJKoZIhvcNAQENBQAwdjELMAkGA1UEBhMCR0Ix
|
|
||||||
DjAMBgNVBAgMBUhBTlRTMQwwCgYDVQQKDANJQk0xDzANBgNVBAsMBkhVUklCTTER
|
|
||||||
MA8GA1UEAwwISFVSSUJNR0IxJTAjBgkqhkiG9w0BCQEWFnNoYXNoaWthbnRoQGlu
|
|
||||||
LmlibS5jb20wHhcNMjMwMTI4MDM1NTAxWhcNMzMwNTA1MDM1NTAxWjBHMQswCQYD
|
|
||||||
VQQGEwJJTjELMAkGA1UECAwCS0ExDDAKBgNVBAcMA0JMUjEMMAoGA1UECgwDSUJN
|
|
||||||
MQ8wDQYDVQQDDAZJQk1JU0wwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
|
||||||
AQCvn7rGrAzGr1BI688hirHC+P1xcI2dUAc1EZx9bQ1mzSAP+9F5hBzT0Ty6ay0Q
|
|
||||||
zs8qKOs9YpHy1qCrETlrFJxWmd8IYVhT2QoKPxF6jhfYMf6anabtYSRZe1c3v/zi
|
|
||||||
DyuLuS2XuDeHnfuJl732YTtteYcG4nAx2Y2GcKLnEfNyrB49+ZGbjnNTqIBsR1tD
|
|
||||||
U96C1h1z4PGtZDxDGbdjGlaB1AJXH9r2tocaS2WyBKo8w9ogTI5d63NYdVvsPKm8
|
|
||||||
AKwnVLu1kE/xk8/5fraW3tyX4JmCFk4Tt/rf+Oy0dbFfoC9m6JmHPeEopqE9f/qy
|
|
||||||
m0WpqM3PHuz2Kke7RQ3GNYFDAgMBAAGjggGzMIIBrzAJBgNVHRMEAjAAMBEGCWCG
|
|
||||||
SAGG+EIBAQQEAwIGQDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQg
|
|
||||||
U2VydmVyIENlcnRpZmljYXRlMB0GA1UdDgQWBBTaihsw+XFiyTZXn27Y7qpTFQSD
|
|
||||||
2DCBuQYDVR0jBIGxMIGugBQwi5E+ifSXCMzGLm0vAlhFxqBM3aGBkaSBjjCBizEL
|
|
||||||
MAkGA1UEBhMCR0IxDjAMBgNVBAgMBUhBTlRTMRMwEQYDVQQHDApXaW5jaGVzdGVy
|
|
||||||
MQwwCgYDVQQKDANJQk0xDzANBgNVBAsMBkhVUklCTTERMA8GA1UEAwwISFVSSUJN
|
|
||||||
R0IxJTAjBgkqhkiG9w0BCQEWFnNoYXNoaWthbnRoQGluLmlibS5jb22CAhAAMA4G
|
|
||||||
A1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBaBgNVHREEUzBRgh1b
|
|
||||||
RnVsbHkgUXVhbGlmaWVkIERvbWFpbiBOYW1lXYIXW0FueSB2YXJpYXRpb24gb2Yg
|
|
||||||
RlFETl2CF1tBbnkgdmFyaWF0aW9uIG9mIEZRRE5dMA0GCSqGSIb3DQEBDQUAA4IC
|
|
||||||
AQCD3iROwkBiSfJ1jCzUdblYawclZE3kX7remHR77sAuGYHEsHhU4PmXUs+A70JJ
|
|
||||||
jF8gzc1cqMqy4Kwd1BGbNLp9cdtre4TigQ9UqbqxCENyoq0aTIhHmJ5GP3RKMwC1
|
|
||||||
jaNmH/MUlFhOKZsTLKymkBGCA9GLhD+quU4AIQHMLGoxMIbRZwZzyuGpa7/Gl2Om
|
|
||||||
f6taMfBsnmFFC+O+saGvu8TG+Q28bGA7wJQM5WMxyVbVY2Lkbb4u2/gDEY1/6T7g
|
|
||||||
ZkGuCxVlyQ2+dy5teKe7I2AGkgTbwl39i4YMGdj9ZC7ydRIANnNgCuygUTZ3c+w3
|
|
||||||
PvA33cX7ICWrmrk0y8Ulox7uj1jNi/npdwPkfjyuh9fJpdV4J/BcsQyZ/j4F5Z4B
|
|
||||||
5MrQeJ7wEELYDv1OOTntyQoqH1HH3TrZ3PFS0whA6gTT76ci2ra85vLVW4SJrbKj
|
|
||||||
VvDr5VcHE+IsJBedscbP2fO6imkAB74xdkBx9uy7x4aXJi399DHvw6b7mMsbR0om
|
|
||||||
6CpI0akjprfhdyv4Ri3vvWpWrzHMUMjzLuj6HYopBlFLErMe6WTY1BAh4ljUFKZ0
|
|
||||||
141/BCkGzNpH/5g1O1QwdQXzEIgUjG16Dm7gM2WKAeJFBttogX2ygTRnVRCZs/fY
|
|
||||||
JE3CwtxKczC0XteonH/ylGTQQR/0J8Y/ozLAWQxDyzi2Og==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCvn7rGrAzGr1BI
|
|
||||||
688hirHC+P1xcI2dUAc1EZx9bQ1mzSAP+9F5hBzT0Ty6ay0Qzs8qKOs9YpHy1qCr
|
|
||||||
ETlrFJxWmd8IYVhT2QoKPxF6jhfYMf6anabtYSRZe1c3v/ziDyuLuS2XuDeHnfuJ
|
|
||||||
l732YTtteYcG4nAx2Y2GcKLnEfNyrB49+ZGbjnNTqIBsR1tDU96C1h1z4PGtZDxD
|
|
||||||
GbdjGlaB1AJXH9r2tocaS2WyBKo8w9ogTI5d63NYdVvsPKm8AKwnVLu1kE/xk8/5
|
|
||||||
fraW3tyX4JmCFk4Tt/rf+Oy0dbFfoC9m6JmHPeEopqE9f/qym0WpqM3PHuz2Kke7
|
|
||||||
RQ3GNYFDAgMBAAECggEAPeL1eEjsf58LlYazCMjM9z2yYaUd4g9vWr4H/RLOpCko
|
|
||||||
YTmFiWKKngGfermFueSGj/63VnxDneUP3PhG2Xr71HCIbXWQIIvcw9uRlzQ3JtIH
|
|
||||||
PAjN59xRaM7T3ytiO27JE4V/kXUy7DE5kDTOleGRhXRLpptomchl3LgYT4C93uw+
|
|
||||||
Pul/KS4PZrGvTD+QnKNd4aOmlEaVLDRcwMqvg96bofE4Qk8LniQB1xEuYUpJFtPm
|
|
||||||
dBaGmtkTg8M6ghqOYMMqx8qNjqcv/HxIUFbV6F6fmhDOAAvt0gRzhHsmJieYiWFv
|
|
||||||
Igj/pmJbo/sfcgiiV4g3lEfqP4i9WpMmpVtEbOrvUQKBgQDio+YfKOwO4Pv0soi6
|
|
||||||
4qPpAZyYvDeQNFYfm0GP/FBuFHUR7dMA88snPZUY8mSgtfG/zoQdcyI3G7HEsugD
|
|
||||||
redwGoVvp0s9435xW7KCB3tMP3PhmeMjXihQw5cXyJx+LrHjorme5zQ4OkcB23lF
|
|
||||||
cjN/Yv0ZxRp2wWpOp3F08CvntQKBgQDGX/h3DTx4IHRjfL6jnL8vKJIsxNFhy/Rz
|
|
||||||
SMMnwAXLmYv29O+rupqsx/MNbM/VA99HqGQt8p2fVEGafYlolaFjICZM6DH5j30B
|
|
||||||
t1M4LsPZf+fI5vWI9KHwHT1JxCqfqM5GwwHMrEw8pdicr/+FS6O16Kymln/aAILb
|
|
||||||
sjvpFyLwFwKBgQCO1m06RjhASFuDJOI3po9XUsS3HiiGofWFhfwUGxk1x37hBdpu
|
|
||||||
RzhKSu2lA1+YShNKp4VsahuuT64CIh9H8lpitNRUQkORhccy+m/Os5hpvbPzA2G7
|
|
||||||
8KPIAv0+6Bh5DkTfCreiBmVK6q/F4+TSd98s8d5CV48OOWgemjlPUe7Z4QKBgQCu
|
|
||||||
MiYP/NqFrhImLquFJqantZuunmIy25NcDJ/6bt9n6vyCLpGrniAm6yneNxfFuTG/
|
|
||||||
TfoycuLAv48gJ26bHRHr5pZbYGZJ/BtMf3wfUMmAW5Xg0Bb6Xb86B6MC/LRlISmJ
|
|
||||||
78HLxdzoQMYWyWG63jHzEk9RtcStXVeLrlZ3l26BnwKBgHxMtBHvcaXWzRdm1PZ0
|
|
||||||
2DVFOP5lm/5t5WC8re8L9oeVLt0+yMBEKXUwX66Z1s5iO24CWsHFN8zDjQhVKfZM
|
|
||||||
/YOxbfjQWYO1LsgJweAEeEauYI+ncMnQEZf1Ei1P8g2X1GTS+n0r4YANawWczp71
|
|
||||||
tZURwKJSJwKpGMChxucQDJc9
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
This directory contains private key and a certificate that signed by intermediate CA.
|
|
||||||
The directory also contains the intermediate CA certificate and it's root certificate.
|
|
||||||
The certificate and it's CA certificate have different Subject DNs.
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
|
||||||
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIxuHuzG+WcZACAggA
|
|
||||||
MBQGCCqGSIb3DQMHBAgMKyhajZd/ewSCBMiCL57/BUvVwtxmhaIqQBSjHLnx+AvG
|
|
||||||
f+frFkwM52KuAg0Q+vF/1iQXMbZRrHpxNz/1t3cIdwzlc9S3FB+L42q0CEH0c1FW
|
|
||||||
6gB6csmb1AyhGYffwkeT8bPkELJhpO2taIFTynwDhHaeKeDce3EwQ5xQd4ydq1Ku
|
|
||||||
t4oJZun51J5qvNs91BiHHVB3/q1Lnh4VK4TTDgXTGfu8qcuOexHQcOgko4oemorv
|
|
||||||
E1Woy6Lf99bePxedSuMIxPAXysSCBqcrZDbY9K3yaxV6Gr7S9FBVvOx9r8PTaFEY
|
|
||||||
sXxdtB22qM1PqZIIjK6nzwXb5iu8wcaZFatD6y7RQaS0kz5EcS5kExrEocFV7D1T
|
|
||||||
dtTf6tt31PbtKfEauRjz3fBXMw+r3Pu/hWRXd3og9hfzFQz49v9RdvgkHy57uCY+
|
|
||||||
F/fN3BKyTcTqJWKpBDMx/xtD1kXWHf81SFmckuShbgKjDvZraR4RmzO/9upIDCFF
|
|
||||||
rJ85takmPvZyAdfvZp6RqVja+cphI4nmxVvmOmUiFMmUJ0lv9MhqpxdVFfleWz0w
|
|
||||||
9XxeL4l+cd/Kbl2ihHwF4oOzWlamyRZjoWiq5s/ika9I1iQ40rGTThqnphonlhUz
|
|
||||||
HX4NvA+fbugwqyOjqEkg5AqyP5ucUN3Hl0qd7wqAJprDkB938unKo/1sr82PfdO/
|
|
||||||
5UvzsKz2ieVavEzi/NxYyR+Xjm3YHG1akcftvElcpYepvemt/PtXJH8fX29b1X6C
|
|
||||||
TYxV03MeA1sJXeM9iqIf/wGQJ657U5ciXUyUtU8s0dDY+jqpZVjxekgCove9FNXz
|
|
||||||
Mja15yiAy/F8xKX20ZRisg+Ly60UQYbX6Wu6Uy6NMjWkxZOYebCVYLMag6UjS0CS
|
|
||||||
8n3/DNvuVooGWbgBFs0tyabtlz/Fz5jGktkMBQeEK4PZKZdMt9aXnDfPFGJWrsme
|
|
||||||
bUzEZLZSWD2Zwr/ujzfBgVeg56AyHJzHuOOLaofZ90ecv69Udl7sYZBelFXxgN8R
|
|
||||||
JVXyV0kNZYj9LaqRTi54H8YToAIV7GXIcasH3jP54dOba3px2NXbaiMf7Oe8apyW
|
|
||||||
E7/vKQNoIbWaglRHXVPGoATTUzYNdBO4jca1rTOXjmzsiZl1JGPwQsS03PuTfa8C
|
|
||||||
F7Uqxj8P9m71G1KuLYA1es55aNXzXSx6uqrRYeu0iug/jE+voGfjbRW3BUY/qxtl
|
|
||||||
OjR8pCDPLN6/rt//ejvBdA4gPDgjRNH4fO9DULQDqIVHmYlysZqhbPbhzmiBXZVP
|
|
||||||
zw1/z9amWR00OeN7xUvm9n+65dosoIn2v1dOz8JBh6Uooj63D2cOghBwEXoPg53B
|
|
||||||
3vLgqy3NKyNZQ/gGfBjXTTeoWzAy8U8hKecNKcsTBquBeBUfS55WwkbD7Mz0Deho
|
|
||||||
EcMZPZUwAPyJ2kHL74etpoBXuH7Jzo8SVedhE+C5J6F+oUP/JcoXdehdGLI89CHU
|
|
||||||
cUARt91OiF3WQo51xT21GlGL8RMHVpjTnYZinnQ/fE1y7JfWtYshBya+YLlAk5vb
|
|
||||||
9jt0tZ9I/KhJ579ZwWBH8V179kBr5Vn+uWlEBBaJu0abdbRSDjt6fAaxi3Q8XK+c
|
|
||||||
isuVuzN/8JAeRgRpm7hRfIoG6XOsrY72ktz0JiHflZ+90xaPRvpCA9/mFC5qp1zh
|
|
||||||
yBs=
|
|
||||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
||||||
Binary file not shown.
@@ -1,26 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEaTCCAlECAQEwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMREwDwYD
|
|
||||||
VQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMTQwMgYDVQQKDCtJbnRlcm5h
|
|
||||||
dGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTYwNAYDVQQDDC1N
|
|
||||||
USBMaWdodCBFeHBpcmVkIENBIChmb3IgZXhwaXJlZCBzaWduZWQgY2VydCkwHhcN
|
|
||||||
MTUwMzI4MTMwNDI2WhcNMTUwMzI5MTMwNDI2WjBVMQswCQYDVQQGEwJHQjESMBAG
|
|
||||||
A1UECAwJSGFtcHNoaXJlMRAwDgYDVQQHDAdIdXJzbGV5MQwwCgYDVQQKDANJQk0x
|
|
||||||
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
|
||||||
ggEBAMeNfSaC0XZoi9CHXLUHz7BA8frIlz+gnl1sjaGimsofiMjd8a0c4pOhlusR
|
|
||||||
kvB4qAQDxmDYhh9QTuqiJZvQxzTI3sNt4W3kcm/bEVawg8HvsWBY40fKkWJYlypV
|
|
||||||
K4Oizcri7CLaeUwgpJlrSlYiJSzjaaytTDeC1F+RSTrdDg0CxI+pfhxIkc9+HPMC
|
|
||||||
oSv1ynxktcJPnCLGRIIHYCE4jm1ZsYxAkSV1crja5OQdd3czEMz6wfHdYzTJUEa1
|
|
||||||
pmnTOa9lhuxlYb8ykt7G2CK66tXaoN0SsAsy6sT2SblI16RDkyOL5XJk56ThhHrn
|
|
||||||
XjjWr3Zo4/tE/pgn5fd+91oi2+ECAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAZNZn
|
|
||||||
OJVQ54NLCzCyTiTauG2jJU+3aYEG4hRhpLM6N11vrukIFTeVfbrr1uKp7sLHYB0E
|
|
||||||
6xLgTxhKF2lDHzCPjA3bOO0tDsxwkOZNP//jmMi+9VKd6Voh/UENOVnBHaXLb5G2
|
|
||||||
9OXi70W/K8eQU7Qi+tu+snWNLYHb5nsYKnPed3+h/zLV3iNB7cz2DCNCas2cKekx
|
|
||||||
6hJo+tWoC+jXcpM97pnqY6saYNmKmugIdZ1W77jueoEIIkSMAZvd8sgXzE6Ad8mD
|
|
||||||
bTMimX9ri0APgxZewaF51YzR2yKqgkpvLVBef0nCbjCDK5zgJVSQHtVJswE4mIcL
|
|
||||||
J3PbSxtmt3BcIr9jmYZZjmoXSjK0+YQkDYT9/uiE5h+6KXrk4AOTkcO9kuxQcBAD
|
|
||||||
QYJB8Hr7h9OcWmpOOJDjOz4BspBwQ7Vs2swHBQgWu9mS9I187JFSFm46dp9CnqSV
|
|
||||||
K5i5amsrJUcRtqlBs4JzqsLivUaet+BtQwlWDfl52TgWpWeIs2EiPFERZxiEggVr
|
|
||||||
pIhjZ9F2d0pL1Oj5jCWMRGWrz1px5W4r92uzfYvTrT/eyGNGGNdDeAgidJ4SftXu
|
|
||||||
XMcqgVjAy0kKvQEK9bCqfoOxTllFqLcneaPI6O0hLREph6sti6eDvJeMsUGoYm/7
|
|
||||||
MxfCaqBU1HStl0HHPaaqHnPP+FW+/xuXhHij1hY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
Binary file not shown.
@@ -1,35 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIGEzCCA/ugAwIBAgIJAI+sAC+/ups4MA0GCSqGSIb3DQEBBQUAMIGfMQswCQYD
|
|
||||||
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxDzANBgNVBAcMBkFybW9uazE0MDIG
|
|
||||||
A1UECgwrSW50ZXJuYXRpb25hbCBCdXNpbmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlv
|
|
||||||
bjE2MDQGA1UEAwwtTVEgTGlnaHQgRXhwaXJlZCBDQSAoZm9yIGV4cGlyZWQgc2ln
|
|
||||||
bmVkIGNlcnQpMB4XDTE1MDQwMTExNTkxNloXDTQyMDgxNjExNTkxNlowgZ8xCzAJ
|
|
||||||
BgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMTQw
|
|
||||||
MgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0
|
|
||||||
aW9uMTYwNAYDVQQDDC1NUSBMaWdodCBFeHBpcmVkIENBIChmb3IgZXhwaXJlZCBz
|
|
||||||
aWduZWQgY2VydCkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLGn4P
|
|
||||||
97BZteNO/5zIlGH4F067TPlOjFiLI1TFI/bKp3bx1fHpsQdMX5C9y1s6BqoOzMJV
|
|
||||||
VHDJH4NlxvnMUGNzYvluynjujejhyDryDrb4uY3JMcewvnHmrWArzbfZw4eBzANr
|
|
||||||
feBkro4xr6m5HWMxM4GJZeFaEGqbXNE5vAYhZ270qUKqrkSHv4g/LqapITaBPJDC
|
|
||||||
3tAtV0UD4/HmwB2ogZlXy4DkbBsgcc2rS4xPxx3Qki78DeA9oT6aeLP7KZnoEgo9
|
|
||||||
Xqb/UfRuZ5MYR17u8yTuJz/JdAs6Saf80t5PLDO/SRKj7Uu1lt+HbkpEghdEdB/V
|
|
||||||
pPdmlIfo7uNe7rFG/OWif2qwVm2t9o02oIUqlAHggS4WYeOmcB8L9EtmlfZHaoDA
|
|
||||||
H0a0xlbZ+XlE/EMpphgrzSE5g9h9Vw7vvH5Ygzks8lSXKd5VS8C9y8tWqaMCynAy
|
|
||||||
5MTIZdXMvouG8vy5Ip+iWck4QSo6eJBryLNt/vzljxo6XntveXRZVvywyjh3NuVu
|
|
||||||
nVLPe0CFkmRHXK5/zA6H8rZeGb3eK8Y4VcLKj7x4Lnluo47BeGnKH7UcKBA2AREC
|
|
||||||
VGFVsHcr0HwKgCCSsyv4qRefY/mJWO59BL38shHuzydLxlKHf/uPGdsZ3DU0rb6i
|
|
||||||
QXMCHC6lzAjJHVCDJ2witiPSjmW2LRZzRqdTqwIDAQABo1AwTjAdBgNVHQ4EFgQU
|
|
||||||
dv3XdSdsOkZJDWgusfuZqBx/jpMwHwYDVR0jBBgwFoAUdv3XdSdsOkZJDWgusfuZ
|
|
||||||
qBx/jpMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAR9o32FR4AjTZ
|
|
||||||
LV5nH5rsQ9OVon1TCv9yemAI4coh08RHWVf7cDyIp8XKy3gTM/lq70wzsXUHwaAS
|
|
||||||
4xSOjc/fBLP0UTEwCrdyy1guRs9ZjKIhqth1AkB92sF9HV4P811vUNppVfA/BDmb
|
|
||||||
Ttl6i1Joyl6nhnDxn1HzjcSBB4ZVt/1MRwIaEfRXrqAklYbMOtw8D6Onth6IQ7dS
|
|
||||||
27ulUPD+AA8H5Ilm2XhPI6ttnR+822+mgB1K9WAjmuIbDJwQJl32UmTUiXPwdlWm
|
|
||||||
KqyKZGST8wV6Jylha84ETL99IlJsxoAMGmNshMe4t773n0LousAvnbVt9uZcBNUH
|
|
||||||
d/53EWP7kw1PPhY6jo0gLVK/ZQt8MHBJuT3f5IM9dmkLJmyM9t8tEmvjNEoC2xSW
|
|
||||||
JHxoWfbMOxxFx+S5CwwcvySpKltio7s5bf/dYexE+Dv/+zMDeMb8GXv811TCqsD2
|
|
||||||
lm4kTsHjwd+zSGCuvH+R4vWbkSrd65CATmFsVpVPLsIVXDa3DrgFQBmUI/q9UFaG
|
|
||||||
K25HztaHk8GJkBZdBA7xXxzSJxW37yqPGKqQ/ZoqSz6XFnsgy5AsW0fDM+cPUl7l
|
|
||||||
tftOlLeSqkaBq9O++76yY2asb0AyqjNs0tajluzxGFZ38DOqA1xkltV/c+KYnEv3
|
|
||||||
q+K4agMHIKMr7lGJfSBevz3mG+NJ7AU=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIID2zCCAsOgAwIBAgIUdbPSj6WWhFu2amL9voKbyCMKiB4wDQYJKoZIhvcNAQEL
|
|
||||||
BQAwfTELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAktBMQwwCgYDVQQHDANCTFIxDDAK
|
|
||||||
BgNVBAoMA0lCTTEMMAoGA1UECwwDSVNMMRAwDgYDVQQDDAdNUU1GVFFNMSUwIwYJ
|
|
||||||
KoZIhvcNAQkBFhZzaGFzaGlrYW50aEBpbi5pYm0uY29tMB4XDTIzMDEyNTA1MjEz
|
|
||||||
NloXDTI4MDEyNDA1MjEzNlowfTELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAktBMQww
|
|
||||||
CgYDVQQHDANCTFIxDDAKBgNVBAoMA0lCTTEMMAoGA1UECwwDSVNMMRAwDgYDVQQD
|
|
||||||
DAdNUU1GVFFNMSUwIwYJKoZIhvcNAQkBFhZzaGFzaGlrYW50aEBpbi5pYm0uY29t
|
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwl9MlmCNG7kzk7qKGuBX
|
|
||||||
jTONcn2OcifKfwgJlvzTqHcf8X/BIiyOOiwoeznke///LLtt9ygF0iyBMQYM/CG/
|
|
||||||
rzOR6tbzI4y4Bmx6VqY02CkXi/p66ywQ7B5N2Fdp9Bop3SnthTcT4NoXBSEUhI1O
|
|
||||||
ob8lDFv1KMRkCULD2sA0FUYCrHtw0M/vEOqsA9VVjyzOXsIlbbR1BSXtlWNneGeL
|
|
||||||
OAdmQWO3QYCku/YrCyJlscvIisjp4s7guGnQh0Ws8h50R5sqag8RvdHUwExVLUfZ
|
|
||||||
L1Od0+hCiO5mNfKekT0cs9owplcwgNHw88b8q4/aHDBtQRgsukkMxTpo00ftPJxI
|
|
||||||
nwIDAQABo1MwUTAdBgNVHQ4EFgQUOyw89AeB0jXb5WCZv/5oDY8oWxkwHwYDVR0j
|
|
||||||
BBgwFoAUOyw89AeB0jXb5WCZv/5oDY8oWxkwDwYDVR0TAQH/BAUwAwEB/zANBgkq
|
|
||||||
hkiG9w0BAQsFAAOCAQEAtbybQQ9GpY5gH7xz4EWOUZ7XMmBYtuGXVrqUd+76hvCA
|
|
||||||
H/SB0nl2bGp7tAKBttmXhfKVac6wFCbXvYe49B+Q9+iL7H9st9VZUPKLQ6K3Uet6
|
|
||||||
L1ggMm2BhecpuYbwkG7ZidVFo/SuUCbCTnXBgHjvq4IkVCaJe7aKZmejSCh7gsIR
|
|
||||||
BQkZvz/22Vx/WPTEYp0x/riIvSViBjLCuD25Y+nCtS8c2xGVBjs9Q4GWCOAvEfAr
|
|
||||||
Tqs42brH1Vs92xS143p2h/wv52tmhfJI6X9QVQBBUoIjPR/VDFqZU5EYhAvuQPBi
|
|
||||||
UADz9hNYGQ9wBzZGvzbrorpoT+7aW9nGtmUsvvupBA==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
This directory contains private key and a certificate that signed by CA.
|
|
||||||
The directory also contains the CA certificate. The certificate and it's
|
|
||||||
CA certificate have same Subject DNs.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDgTCCAmkCFClOtyvBoQXVAGMcX0ObUawZJuX/MA0GCSqGSIb3DQEBCwUAMH0x
|
|
||||||
CzAJBgNVBAYTAklOMQswCQYDVQQIDAJLQTEMMAoGA1UEBwwDQkxSMQwwCgYDVQQK
|
|
||||||
DANJQk0xDDAKBgNVBAsMA0lTTDEQMA4GA1UEAwwHTVFNRlRRTTElMCMGCSqGSIb3
|
|
||||||
DQEJARYWc2hhc2hpa2FudGhAaW4uaWJtLmNvbTAeFw0yMzAxMjUwNTM4MzBaFw0y
|
|
||||||
NTA0MjkwNTM4MzBaMH0xCzAJBgNVBAYTAklOMQswCQYDVQQIDAJLQTEMMAoGA1UE
|
|
||||||
BwwDQkxSMQwwCgYDVQQKDANJQk0xDDAKBgNVBAsMA0lTTDEQMA4GA1UEAwwHTVFN
|
|
||||||
RlRRTTElMCMGCSqGSIb3DQEJARYWc2hhc2hpa2FudGhAaW4uaWJtLmNvbTCCASIw
|
|
||||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJNAGirCyLzsHpV2cyso8pc2BOP
|
|
||||||
4j6lu2ZTsdSE+WVZsqX3YWmV8TCYpJQRD4jmlrYIEdYAGmKPZvbvWjhzZWOJIxfI
|
|
||||||
MGRwQ4dl8bSDZpcc7OAcHgLaW1OnMy2/1NgVyyXOKTaG4PmzZCzSKnhDF8/+FhUm
|
|
||||||
rIYi5EU6bn1MuY34HOswAau0G7YVeroBUPs+LUjUpQx4vp5Baz9sWBzWcvsZsoSo
|
|
||||||
LTMWEqCocqYOhj1ALrwN61NzdRwVtoS41dcjHAiFKEVTKIbqE0ib57Of1sohO9dr
|
|
||||||
JgjegBNi18lsVUqDnYvydbe1hTEZfoXyN3QHm6QZLYtKB0RqR4HlcufnFWkCAwEA
|
|
||||||
ATANBgkqhkiG9w0BAQsFAAOCAQEAtgG/2/7q2xPJG+Z0xJIyS9O7h6Igus2LhrAw
|
|
||||||
tkudX5FZtJclBmDx3KvtJMPzpoGFRF48nXaqNcDSI3+8MiMk+JfpfGtmFbYuaa+l
|
|
||||||
seqk/3byv/y1ofd8JMk0olY219tI1/BK4AU+fPP1obYV0tFcwIDOqQaS6f/N4RP1
|
|
||||||
MO0PE+j9dDO6GQjIEUHZVVis70WvGaTc6DfGPVehZzDbNW9nTdkuacZf+XtlLVXq
|
|
||||||
LzJpGeMxvX7SRRkdyegNigiWHJzOchVcoNnO+rUm9JDjY8pukDC08uZEQVqNpOXD
|
|
||||||
tO1t4rpBT9HWxPRCLt8IwOhoYAGb5DWwUeIaiY637CSPTJVjCQ==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEogIBAAKCAQEAsk0AaKsLIvOwelXZzKyjylzYE4/iPqW7ZlOx1IT5ZVmypfdh
|
|
||||||
aZXxMJiklBEPiOaWtggR1gAaYo9m9u9aOHNlY4kjF8gwZHBDh2XxtINmlxzs4Bwe
|
|
||||||
AtpbU6czLb/U2BXLJc4pNobg+bNkLNIqeEMXz/4WFSashiLkRTpufUy5jfgc6zAB
|
|
||||||
q7QbthV6ugFQ+z4tSNSlDHi+nkFrP2xYHNZy+xmyhKgtMxYSoKhypg6GPUAuvA3r
|
|
||||||
U3N1HBW2hLjV1yMcCIUoRVMohuoTSJvns5/WyiE712smCN6AE2LXyWxVSoOdi/J1
|
|
||||||
t7WFMRl+hfI3dAebpBkti0oHRGpHgeVy5+cVaQIDAQABAoIBAGlAmVAwQBe24OOm
|
|
||||||
kDaJZvrLSeZqVnUC4pgqKdy5Tnusso/Uc5WfpMw6H1UkqRX4gNkd9GFumCS8YFy+
|
|
||||||
uHSAckaKqsOcMizoNITWAhO8SbBEq/QzxOeMPMMp/UUxa5TPcKd1htCgWGgupKDs
|
|
||||||
w5NQj9sBM8nylX9tU3EmaBjhVNvfsZSeA76s0z+JDDwJLUlH33dwvgidw+baRxYM
|
|
||||||
U6Tr3Z7YCFZ7+iZbOTHZjkKVtS2EqHtU5OW/pQltbBSovhYQMXjBsCHpTK78+jbV
|
|
||||||
jKjtDUYWplcAYoN/O8ljYHU6lKQlTfo8KQInLtek/Ycen7uOCT6kFAreWFg08g4x
|
|
||||||
5IH/pXECgYEA4ivLQjKR1BHiO+6rDZIfQxvbTa2RgT3Yr9W923OpGY1LiuapGFfJ
|
|
||||||
97PjVKQf6HromQuzveYZR9YFKR4u8YTUn5PCB16v9MEc7nxnwIfE1kH5aEMvMSq9
|
|
||||||
MvxvYObs3dJu4dx+AF8q8REuviBkQ2br34ukbl8ssaB/7zHPXyNJDt0CgYEAydD3
|
|
||||||
BNtPRwKorQKOC1VXQxAFtlu/iiia4LEocAODDUX8N0iGxRBpQcfY/OuqV2j8Alfx
|
|
||||||
n7+Zv/NGEah+WLaApc6wZVvOOuJevam/3ZJReawUtpCcG5em388WSQDuIj3AKhVV
|
|
||||||
IzRRRFlGrTuHENdsqG5rBzbYWvans4lpVkB6Kf0CgYA0YUQfvqp7XPDyRGIlMHRB
|
|
||||||
DJCLuuj576LhhjUEQBMnscuPDcCXvK0vyt+ZWLFzHBQGbelgz4uHUY+8aBsjIEpF
|
|
||||||
8uh64HkLzDWxHerBcjAqFvl2Jiklz+olhsUcwh6VeQjpEjG0UFYXoo0ax1GxMoLq
|
|
||||||
MOMSFMS7FprKgNSwCfH/mQKBgBLA8lNnNcS5gIcjN6Ph+EvpDz7U48Wo5EuA6usN
|
|
||||||
yH3RRRC2Ep/5WG6ebZGDLL8WqGRnW7KmkVj++EHn0GXZ/7ZosIeasl1Sb89cGNI0
|
|
||||||
KJIP5ZTZd0gxHXaqvb1m8roH1vWSKektkWeyjBjI8VIlUpmMOTHgbNZ3GTpbyIgV
|
|
||||||
UcTZAoGAJp5AX+5u6OhLcCI56dpKYGiIS+8fXd2+oz7uZYf2yNTZONulehh2earM
|
|
||||||
4soiUF5ArPgc3KbZhorvIXjOUSb5wc7I2nQKxXQt9j2fyZMD8qsyI1kBqLQ53Z0r
|
|
||||||
agAkX1xMvhvHMQFKmPMXt3pUfXEx/oa32f3ciyPAhyyQNpv5gx4=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2020, 2023
|
# © Copyright IBM Corporation 2020
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -35,12 +35,10 @@ go_minor="${go_version_parts[1]}"
|
|||||||
if [[ "$go_major" -eq 1 && "$go_minor" -lt 18 ]]; then
|
if [[ "$go_major" -eq 1 && "$go_minor" -lt 18 ]]; then
|
||||||
echo "Go version ${go_major}.${go_minor} < 1.18... Pinning credential-helper commit"
|
echo "Go version ${go_major}.${go_minor} < 1.18... Pinning credential-helper commit"
|
||||||
git checkout ab7fd12c67d83193072fa91e5648b036547f6323
|
git checkout ab7fd12c67d83193072fa91e5648b036547f6323
|
||||||
make pass
|
|
||||||
cp bin/docker-credential-pass $GOPATH/bin/docker-credential-pass
|
|
||||||
else
|
|
||||||
make pass
|
|
||||||
cp bin/build/docker-credential-pass $GOPATH/bin/docker-credential-pass
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
make pass
|
||||||
|
cp bin/docker-credential-pass $GOPATH/bin/docker-credential-pass
|
||||||
mkdir -p /home/travis/.docker
|
mkdir -p /home/travis/.docker
|
||||||
echo '{ "credsStore": "pass" }' | tee /home/travis/.docker/config.json
|
echo '{ "credsStore": "pass" }' | tee /home/travis/.docker/config.json
|
||||||
gpg2 --batch --gen-key <<-EOF
|
gpg2 --batch --gen-key <<-EOF
|
||||||
|
|||||||
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.x"
|
||||||
|
- master
|
||||||
|
env:
|
||||||
|
- TAGS=""
|
||||||
|
- TAGS="-tags purego"
|
||||||
|
script: go test $TAGS -v ./...
|
||||||
37
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
37
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
@@ -1,9 +1,10 @@
|
|||||||
# xxhash
|
# xxhash
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
|
[](https://godoc.org/github.com/cespare/xxhash)
|
||||||
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)
|
[](https://travis-ci.org/cespare/xxhash)
|
||||||
|
|
||||||
xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
|
xxhash is a Go implementation of the 64-bit
|
||||||
|
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
||||||
high-quality hashing algorithm that is much faster than anything in the Go
|
high-quality hashing algorithm that is much faster than anything in the Go
|
||||||
standard library.
|
standard library.
|
||||||
|
|
||||||
@@ -24,11 +25,8 @@ func (*Digest) WriteString(string) (int, error)
|
|||||||
func (*Digest) Sum64() uint64
|
func (*Digest) Sum64() uint64
|
||||||
```
|
```
|
||||||
|
|
||||||
The package is written with optimized pure Go and also contains even faster
|
This implementation provides a fast pure-Go implementation and an even faster
|
||||||
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
|
assembly implementation for amd64.
|
||||||
opts into using the Go code even on those architectures.
|
|
||||||
|
|
||||||
[xxHash]: http://cyan4973.github.io/xxHash/
|
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
@@ -47,26 +45,23 @@ I recommend using the latest release of Go.
|
|||||||
Here are some quick benchmarks comparing the pure-Go and assembly
|
Here are some quick benchmarks comparing the pure-Go and assembly
|
||||||
implementations of Sum64.
|
implementations of Sum64.
|
||||||
|
|
||||||
| input size | purego | asm |
|
| input size | purego | asm |
|
||||||
| ---------- | --------- | --------- |
|
| --- | --- | --- |
|
||||||
| 4 B | 1.3 GB/s | 1.2 GB/s |
|
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
||||||
| 16 B | 2.9 GB/s | 3.5 GB/s |
|
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
||||||
| 100 B | 6.9 GB/s | 8.1 GB/s |
|
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
||||||
| 4 KB | 11.7 GB/s | 16.7 GB/s |
|
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
||||||
| 10 MB | 12.0 GB/s | 17.3 GB/s |
|
|
||||||
|
|
||||||
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
|
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
||||||
CPU using the following commands under Go 1.19.2:
|
the following commands under Go 1.11.2:
|
||||||
|
|
||||||
```
|
```
|
||||||
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
|
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||||
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
|
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Projects using this package
|
## Projects using this package
|
||||||
|
|
||||||
- [InfluxDB](https://github.com/influxdata/influxdb)
|
- [InfluxDB](https://github.com/influxdata/influxdb)
|
||||||
- [Prometheus](https://github.com/prometheus/prometheus)
|
- [Prometheus](https://github.com/prometheus/prometheus)
|
||||||
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
|
||||||
- [FreeCache](https://github.com/coocood/freecache)
|
- [FreeCache](https://github.com/coocood/freecache)
|
||||||
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user