Compare commits

..

5 Commits

Author SHA1 Message Date
Rob Parker
1aab07c6ed set CipherSpec to ANY_TLS12 and refresh security (#362) 2019-08-28 17:01:15 +01:00
Luke Powlett
556ac6aec2 Update to UBI 7.7-98 2019-08-28 15:10:14 +01:00
Arthur Barr
950aecf300 Temporarily remove Docker 1.12 test in Travis 2019-08-28 14:21:40 +01:00
Arthur Barr
492c6876ca Use podman build if available 2019-08-28 14:21:40 +01:00
Luke Powlett
9896e53cba increment release in makefile 2019-08-07 16:02:46 +01:00
1112 changed files with 177773 additions and 151394 deletions

2
.gitignore vendored
View File

@@ -12,5 +12,3 @@ vendor/github.com/prometheus/client_model/.classpath
vendor/github.com/prometheus/client_model/.project vendor/github.com/prometheus/client_model/.project
vendor/github.com/prometheus/client_model/.settings* vendor/github.com/prometheus/client_model/.settings*
gosec_results.json gosec_results.json
internal/qmgrauth/qmgroam/patch
.tagcache

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2020 # © 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.
@@ -12,94 +12,66 @@
# 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.
dist: bionic dist: xenial
group: beta
sudo: required sudo: required
language: go language: go
go: go:
- "1.17.12" - "1.10"
services: services:
- docker - docker
env:
global:
- MAIN_BRANCH=v9.2.0.x-eus
- MQ_LTS_VERSION=9.2.0.6
- TAGCACHE_FILE=tagcache
- RELEASE=r2
- RELEASE_LTS=r3
go_import_path: "github.com/ibm-messaging/mq-container" go_import_path: "github.com/ibm-messaging/mq-container"
# cache: cache:
# directories: directories:
# - downloads - downloads
jobs: jobs:
include: include:
- stage: basic-build - stage: build and test
if: branch != v9.2.0.x-eus AND tag IS blank
name: "Basic AMD64 build"
os: linux
env: env:
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_920_ARCHIVE_REPOSITORY_DEV_AMD64 - BASE_IMAGE=ubuntu:16.04
script: bash -e travis-build-scripts/run.sh - DOCKER_DOWNGRADE="echo nothing to be done"
# TEMPORARY removal of Docker 1.12 test, due to errors from apt repository
# LTS Build # - if: type IN (pull_request) OR tag IS present
- stage: global-tag # env:
if: branch = v9.2.0.x-eus AND type != pull_request OR tag =~ ^release-candidate* # - BASE_IMAGE=ubuntu:16.04
name: "Generate Global Tag" # - DOCKER_DOWNGRADE="docker save -o images.tar mqadvanced-server-dev mq-dev-jms-test &&
os: linux # sudo apt-get autoremove -y docker-ce &&
env: # curl -fsSL \"https://apt.dockerproject.org/gpg\" | sudo apt-key add - &&
- LTS=true # sudo apt-add-repository \"deb https://apt.dockerproject.org/repo ubuntu-$(lsb_release -cs) main\" &&
- TAGCACHE_FILE=tagcache-lts # sudo apt-get update &&
- MQ_VERSION=$MQ_LTS_VERSION # sudo apt-get install docker-engine=1.12.6-0~ubuntu-$(lsb_release -cs) &&
- RELEASE=$RELEASE_LTS # docker load -q -i images.tar &&
script: bash -e travis-build-scripts/global-tag.sh # export DOCKER_API_VERSION=\"1.24\""
- stage: build
if: branch = v9.2.0.x-eus OR tag =~ ^release-candidate*
name: "Multi-Arch AMD64 build"
os: linux
env:
- LTS=true
- TAGCACHE_FILE=tagcache-lts
- MQ_VERSION=$MQ_LTS_VERSION
- MQ_ARCHIVE_REPOSITORY=$MQ_9206_EUS_ARCHIVE_REPOSITORY_AMD64
- RELEASE=$RELEASE_LTS
script: bash -e travis-build-scripts/run.sh
- stage: build
if: branch = v9.2.0.x-eus OR tag =~ ^release-candidate*
name: "Multi-Arch S390X build"
os: linux-s390
env:
- LTS=true
- TAGCACHE_FILE=tagcache-lts
- MQ_VERSION=$MQ_LTS_VERSION
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
- MQ_ARCHIVE_REPOSITORY=$MQ_9206_EUS_ARCHIVE_REPOSITORY_S390X
- RELEASE=$RELEASE_LTS
script: bash -e travis-build-scripts/run.sh
- stage: push-manifest
if: branch = v9.2.0.x-eus AND type != pull_request OR tag =~ ^release-candidate*
name: "Push Manifest-list to registry"
env:
- LTS=true
- TAGCACHE_FILE=tagcache-lts
- MQ_VERSION=$MQ_LTS_VERSION
- PUSH_MANIFEST_ONLY=true
- RELEASE=$RELEASE_LTS
script: bash -e travis-build-scripts/run.sh
before_install: before_install:
- make install-build-deps - ./install-build-deps-ubuntu.sh
- make install-credential-helper
install: install:
- echo nothing - echo nothing
before_script: echo nothing before_script:
- echo 'Downloading Go dependencies...' && echo -en 'travis_fold:start:deps\\r'
- make deps
- echo -en 'travis_fold:end:deps\\r'
- echo 'Building Developer image...' && echo -en 'travis_fold:start:build-devserver\\r'
- make build-devserver
- echo -en 'travis_fold:end:build-devserver\\r'
- echo 'Building Developer JMS test image...' && echo -en 'travis_fold:start:build-devjmstest\\r'
- make build-devjmstest
- echo -en 'travis_fold:end:build-devjmstest\\r'
script:
- echo 'Downgrading Docker (if necessary)...' && echo -en 'travis_fold:start:docker-downgrade\\r'
- eval "$DOCKER_DOWNGRADE"
- echo -en 'travis_fold:end:docker-downgrade\\r'
- echo 'Testing Developer image...' && echo -en 'travis_fold:start:test-devserver\\r'
- make test-devserver
- echo -en 'travis_fold:end:test-devserver\\r'
after_success: after_success:
- make lint - make lint

View File

@@ -1,38 +1,5 @@
# Change log # Change log
## 9.2.0.6-LTS (2022-07-20)
* Updated to MQ version 9.2.0.6
* Updated to Go version 1.17
## 9.2.0.5-LTS (2022-01-25)
* Updated to MQ version 9.2.0.5
## 9.2.0.4-LTS (2021-10-05)
* Updated to MQ version 9.2.0.4
## 9.2.0.1-LTS (2020-12-04)
* Added support for MQ Long Term Support (production licensed only) in the mq-container
## 9.2.0.0 (2020-07-23)
* Updated to [MQ version 9.2.0.0](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.2.0/com.ibm.mq.pro.doc/q113110_.htm)
* Use `-ic` arguments with `crtmqm` to process MQSC files in `/etc/mqm`. Replaces previous use of "runmqsc" commands
## 9.1.5.0 (2020-04-02)
* Updated to MQ version 9.1.5.0
* Can now run as a random user, instead of the "mqm" user, which has now been removed. This adds compatability for the [Red Hat OpenShift restricted SCC](https://docs.openshift.com/container-platform/4.3/authentication/managing-security-context-constraints.html#security-context-constraints-about_configuring-internal-oauth). The default image UID is `1001`.
## 9.1.4.0 (2019-12-06)
* Updated to MQ version 9.1.4.0
* Updated to use UBI8 as base image
* Added required security settings to self signed certificates to align with macOS Catalina requirements
## 9.1.3.0 (2019-07-19) ## 9.1.3.0 (2019-07-19)
* Updated to MQ version 9.1.3.0 * Updated to MQ version 9.1.3.0
@@ -53,7 +20,7 @@
* Security fixes * Security fixes
* Web console added to production image * Web console added to production image
* Container built on RedHat host * Container built on RedHat host
## 9.1.2.0 (2019-03-21) ## 9.1.2.0 (2019-03-21)
* Updated to MQ version 9.1.2.0 * Updated to MQ version 9.1.2.0

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2022 # © Copyright IBM Corporation 2015, 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.
@@ -12,66 +12,57 @@
# 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.
ARG BASE_IMAGE=registry.redhat.io/ubi8/ubi-minimal ARG BASE_IMAGE=registry.access.redhat.com/ubi7/ubi-minimal
ARG BASE_TAG=8.6-902.1661794353 ARG BASE_TAG=7.7-98
ARG BUILDER_IMAGE=registry.redhat.io/ubi8/go-toolset
ARG BUILDER_TAG=1.17.12-3.1661377020
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/9.2.0.6-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 registry.access.redhat.com/devtools/go-toolset-7-rhel7 as builder
# FROM docker.io/centos/go-toolset-7-centos7 as builder
# The URL to download the MQ installer from in tar.gz format # The URL to download the MQ installer from in tar.gz format
# This assumes an archive containing the MQ Non-Install packages # This assumes an archive containing the MQ RPM install packages
ARG MQ_URL ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev912_linux_x86-64.tar.gz"
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 MQM_UID=888
USER 0 USER 0
COPY install-mq.sh /usr/local/bin/ COPY install-mq.sh /usr/local/bin/
RUN mkdir /opt/mqm \ RUN chmod a+x /usr/local/bin/install-mq.sh \
&& chmod a+x /usr/local/bin/install-mq.sh \
&& sleep 1 \ && sleep 1 \
&& INSTALL_SDK=1 install-mq.sh \ && MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm" install-mq.sh $MQM_UID
&& chown -R 1001:root /opt/mqm/* WORKDIR /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/
WORKDIR $GO_WORKDIR/
COPY go.mod go.sum ./
COPY cmd/ ./cmd COPY cmd/ ./cmd
COPY internal/ ./internal COPY internal/ ./internal
COPY pkg/ ./pkg
COPY vendor/ ./vendor COPY vendor/ ./vendor
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \ ENV PATH="${PATH}:/opt/rh/go-toolset-7/root/usr/bin" \
CGO_CFLAGS="-I/opt/mqm/inc/" \
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" CGO_LDFLAGS_ALLOW="-Wl,-rpath.*"
ENV PATH="${PATH}:/opt/mqm/bin"
RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\" -X \"main.ImageTag=$IMAGE_TAG\"" ./cmd/runmqserver/ RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\" -X \"main.ImageTag=$IMAGE_TAG\"" ./cmd/runmqserver/
RUN go build ./cmd/chkmqready/ RUN go build ./cmd/chkmqready/
RUN go build ./cmd/chkmqhealthy/ RUN go build ./cmd/chkmqhealthy/
RUN go build ./cmd/runmqdevserver/ RUN go build ./cmd/runmqdevserver/
RUN go build -buildmode=c-shared -o amqpasdev.so ./internal/qmgrauth/pas.go
RUN go test -v ./cmd/runmqdevserver/... RUN go test -v ./cmd/runmqdevserver/...
RUN go test -v ./cmd/runmqserver/ RUN go test -v ./cmd/runmqserver/
RUN go test -v ./cmd/chkmqready/ RUN go test -v ./cmd/chkmqready/
RUN go test -v ./cmd/chkmqhealthy/ RUN go test -v ./cmd/chkmqhealthy/
RUN go test -v ./pkg/...
RUN go test -v ./internal/... RUN go test -v ./internal/...
# go 1.17 sigchanyzer check disabled for EUS stream as fix would introduce change of behaviour RUN go vet ./cmd/... ./internal/...
RUN go vet -sigchanyzer=FALSE ./cmd/... ./internal/...
############################################################################### ###############################################################################
# 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 # The MQ packages to install - see install-mq.sh for default value
ARG MQ_URL ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev912_linux_x86-64.tar.gz"
ARG MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesWeb*.rpm MQSeriesAMS-*.rpm"
#ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-web ibmmq-ams"
ARG MQM_UID=888
ARG BASE_IMAGE ARG BASE_IMAGE
ARG BASE_TAG ARG BASE_TAG
ARG GO_WORKDIR
LABEL summary="IBM MQ Advanced Server" LABEL summary="IBM MQ Advanced Server"
LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL vendor="IBM" LABEL vendor="IBM"
LABEL maintainer="IBM"
LABEL distribution-scope="private" LABEL distribution-scope="private"
LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/" LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/"
LABEL url="https://www.ibm.com/products/mq/advanced" LABEL url="https://www.ibm.com/products/mq/advanced"
@@ -83,51 +74,44 @@ LABEL base-image-release=$BASE_TAG
COPY install-mq.sh /usr/local/bin/ COPY install-mq.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. # Install MQ. To avoid a "text file busy" error here, we sleep before installing.
RUN env \ RUN env && chmod u+x /usr/local/bin/install-*.sh \
&& mkdir /opt/mqm \
&& chmod u+x /usr/local/bin/install-*.sh \
&& sleep 1 \ && sleep 1 \
&& install-mq-server-prereqs.sh \ && install-mq-server-prereqs.sh $MQM_UID \
&& install-mq.sh \ && install-mq.sh $MQM_UID
&& /opt/mqm/bin/security/amqpamcf \
&& chown -R 1001:root /opt/mqm/*
# Create a directory for runtime data from runmqserver # Create a directory for runtime data from runmqserver
RUN mkdir -p /run/runmqserver \ RUN mkdir -p /run/runmqserver \
&& chown 1001:root /run/runmqserver && chown mqm:mqm /run/runmqserver
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/ COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/runmqserver /usr/local/bin/
COPY --from=builder $GO_WORKDIR/chkmq* /usr/local/bin/ COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/chkmq* /usr/local/bin/
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
# Copy web XML files # Copy web XML files
COPY web /etc/mqm/web COPY web /etc/mqm/web
COPY etc/mqm/*.tpl /etc/mqm/ COPY etc/mqm/*.tpl /etc/mqm/
RUN chmod ug+x /usr/local/bin/runmqserver \ RUN chmod ug+x /usr/local/bin/runmqserver \
&& chown 1001:root /usr/local/bin/*mq* \ && chown mqm:mqm /usr/local/bin/*mq* \
&& chmod ug+x /usr/local/bin/chkmq* \ && chmod ug+xs /usr/local/bin/chkmq* \
&& chown -R 1001:root /etc/mqm/* \ && chown -R mqm:mqm /etc/mqm/* \
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqserver \ && install --directory --mode 0775 --owner mqm --group root /run/runmqserver \
&& touch /run/termination-log \ && touch /run/termination-log \
&& chown 1001:root /run/termination-log \ && chown mqm:root /run/termination-log \
&& chmod 0660 /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 # Always use port 1414 for MQ & 9157 for the metrics
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_GRACE_PERIOD=30
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic
# We can run as any UID USER $MQM_UID
USER 1001
ENV MQ_CONNAUTH_USE_HTP=false
ENTRYPOINT ["runmqserver"] ENTRYPOINT ["runmqserver"]
############################################################################### ###############################################################################
# Add default developer config # Add default developer config
############################################################################### ###############################################################################
FROM mq-server AS mq-dev-server FROM mq-server AS mq-dev-server
ARG MQM_UID=888
ARG BASE_IMAGE ARG BASE_IMAGE
ARG BASE_TAG ARG BASE_TAG
ARG GO_WORKDIR
# Enable MQ developer default configuration # Enable MQ developer default configuration
ENV MQ_DEV=true ENV MQ_DEV=true
# Default administrator password
ENV MQ_ADMIN_PASSWORD=passw0rd
LABEL summary="IBM MQ Advanced for Developers Server" LABEL summary="IBM MQ Advanced for Developers Server"
LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises" LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL vendor="IBM" LABEL vendor="IBM"
@@ -140,29 +124,29 @@ LABEL io.k8s.description="Simplify, accelerate and facilitate the reliable excha
LABEL base-image=$BASE_IMAGE LABEL base-image=$BASE_IMAGE
LABEL base-image-release=$BASE_TAG LABEL base-image-release=$BASE_TAG
USER 0 USER 0
COPY --from=builder $GO_WORKDIR/amqpas* /opt/mqm/lib64/
COPY etc/mqm/*.ini /etc/mqm/
COPY etc/mqm/mq.htpasswd /etc/mqm/
RUN chmod 0660 /etc/mqm/mq.htpasswd
COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/ COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/install-extra-packages.sh \ RUN chmod u+x /usr/local/bin/install-extra-packages.sh \
&& sleep 1 \ && sleep 1 \
&& install-extra-packages.sh && install-extra-packages.sh
# WARNING: This is what allows the mqm user to change the password of any other user
# It's used by runmqdevserver to change the admin/app passwords.
RUN echo "mqm ALL = NOPASSWD: /usr/sbin/chpasswd" > /etc/sudoers.d/mq-dev-config
## Add admin and app users, and set a default password for admin
RUN useradd admin -G mqm \
&& groupadd mqclient \
&& useradd app -G mqclient \
&& echo admin:$MQ_ADMIN_PASSWORD | chpasswd
# Create a directory for runtime data from runmqserver # Create a directory for runtime data from runmqserver
RUN mkdir -p /run/runmqdevserver \ RUN mkdir -p /run/runmqdevserver \
&& chown 1001:root /run/runmqdevserver && chown mqm:mqm /run/runmqdevserver
COPY --from=builder $GO_WORKDIR/runmqdevserver /usr/local/bin/ COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/
# Copy template files # Copy template files
COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/ COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/
# Copy web XML files for default developer configuration # Copy web XML files for default developer configuration
COPY incubating/mqadvanced-server-dev/web /etc/mqm/web COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
RUN chown -R 1001:root /etc/mqm/* \ RUN chown -R mqm:mqm /etc/mqm/* \
&& chmod -R g+w /etc/mqm/web \
&& chmod +x /usr/local/bin/runmq* \ && chmod +x /usr/local/bin/runmq* \
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqdevserver && install --directory --mode 0775 --owner mqm --group root /run/runmqdevserver
ENV MQ_ENABLE_EMBEDDED_WEB_SERVER=1 MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost ENV MQ_ENABLE_EMBEDDED_WEB_SERVER=1
ENV LD_LIBRARY_PATH=/opt/mqm/lib64 USER $MQM_UID
ENV MQS_PERMIT_UNKNOWN_ID=true
ENV MQ_CONNAUTH_USE_HTP=true
USER 1001
ENTRYPOINT ["runmqdevserver"] ENTRYPOINT ["runmqdevserver"]

333
Makefile
View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2017, 2020 # © Copyright IBM Corporation 2017, 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.
@@ -16,74 +16,47 @@
# Conditional variables - you can override the values of these variables from # Conditional variables - you can override the values of these variables from
# the command line # the command line
############################################################################### ###############################################################################
# MQ_VERSION is the fully qualified MQ version number to build
include config.env MQ_VERSION ?= 9.1.3.0
include source-branch.env
# RELEASE shows what release of the container code has been built # RELEASE shows what release of the container code has been built
RELEASE ?= RELEASE ?= 2
# MQ_ARCHIVE_REPOSITORY is a remote repository from which to pull the MQ_ARCHIVE (if required)
MQ_ARCHIVE_REPOSITORY ?=
# MQ_ARCHIVE_REPOSITORY_DEV is a remote repository from which to pull the MQ_ARCHIVE_DEV (if required)
MQ_ARCHIVE_REPOSITORY_DEV ?=
# MQ_ARCHIVE_REPOSITORY_USER is the user for the remote repository (if required)
MQ_ARCHIVE_REPOSITORY_USER ?=
# MQ_ARCHIVE_REPOSITORY_CREDENTIAL is the password/API key for the remote repository (if required)
MQ_ARCHIVE_REPOSITORY_CREDENTIAL ?=
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can # MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
# be installed. Does not apply to MQ Advanced for Developers # be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH)_NOINST.tar.gz # Does not apply to MQ Advanced for Developers.
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH).tar.gz
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced # MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
# for Developers can be installed # for Developers can be installed
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_ARCHIVE_DEV_$(MQ_VERSION))
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced. # MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION)) MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
# Options to `go test` for the Docker tests # Options to `go test` for the Docker tests
TEST_OPTS_DOCKER ?= TEST_OPTS_DOCKER ?=
# Timeout for the Docker tests
TEST_TIMEOUT_DOCKER ?= 30m
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image # MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server MQ_IMAGE_ADVANCEDSERVER ?=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
MQ_IMAGE_DEVSERVER ?=ibm-mqadvanced-server-dev MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev
# MQ_MANIFEST_TAG is the tag to use for fat-manifest
MQ_MANIFEST_TAG ?= $(MQ_VERSION)$(RELEASE_TAG)$(LTS_TAG)$(MQ_MANIFEST_TAG_SUFFIX)
# MQ_TAG is the tag of the built MQ Advanced image & MQ Advanced for Developers image # MQ_TAG is the tag of the built MQ Advanced image & MQ Advanced for Developers image
MQ_TAG ?= $(MQ_MANIFEST_TAG)-$(ARCH) MQ_TAG ?=$(MQ_VERSION)-$(ARCH)
# MQ_PACKAGES specifies the MQ packages (.deb or .rpm) to install. Defaults vary on base image.
MQ_PACKAGES ?=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesWeb*.rpm MQSeriesAMS-*.rpm
# MQM_UID is the UID to use for the "mqm" user
MQM_UID ?= 888
# COMMAND is the container command to run. "podman" or "docker" # COMMAND is the container command to run. "podman" or "docker"
COMMAND ?=$(shell type -p podman 2>&1 >/dev/null && echo podman || echo docker) COMMAND ?=$(shell type -p podman 2>&1 >/dev/null && echo podman || echo docker)
# MQ_DELIVERY_REGISTRY_HOSTNAME is a remote registry to push the MQ Image to (if required)
MQ_DELIVERY_REGISTRY_HOSTNAME ?=
# MQ_DELIVERY_REGISTRY_NAMESPACE is the namespace/path on the delivery registry (if required)
MQ_DELIVERY_REGISTRY_NAMESPACE ?=
# MQ_DELIVERY_REGISTRY_USER is the user for the remote registry (if required)
MQ_DELIVERY_REGISTRY_USER ?=
# MQ_DELIVERY_REGISTRY_CREDENTIAL is the password/API key for the remote registry (if required)
MQ_DELIVERY_REGISTRY_CREDENTIAL ?=
# REGISTRY_USER is the username used to login to the Red Hat registry
REGISTRY_USER ?=
# REGISTRY_PASS is the password used to login to the Red Hat registry
REGISTRY_PASS ?=
# DOCKER_USER is the username used to login to docker hub
DOCKER_USER ?=
# DOCKER_PASS is the password used to login to docker hub
DOCKER_PASS ?=
# ARCH is the platform architecture (e.g. amd64, ppc64le or s390x)
ARCH ?= $(if $(findstring x86_64,$(shell uname -m)),amd64,$(shell uname -m))
# LTS is a boolean value to enable/disable LTS container build
LTS ?= false
############################################################################### ###############################################################################
# Other variables # Other variables
############################################################################### ###############################################################################
GO_PKG_DIRS = ./cmd ./internal ./test GO_PKG_DIRS = ./cmd ./internal ./test
MQ_ARCHIVE_TYPE=LINUX MQ_ARCHIVE_TYPE=LINUX
MQ_ARCHIVE_DEV_TYPE=Linux MQ_ARCHIVE_DEV_PLATFORM=linux
# ARCH is the platform architecture (e.g. amd64, ppc64le or s390x)
ARCH=$(if $(findstring x86_64,$(shell uname -m)),amd64,$(shell uname -m))
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time # BUILD_SERVER_CONTAINER is the name of the web server container used at build time
BUILD_SERVER_CONTAINER=build-server BUILD_SERVER_CONTAINER=build-server
# NUM_CPU is the number of CPUs available to Docker. Used to control how many # NUM_CPU is the number of CPUs available to Docker. Used to control how many
# test run in parallel # test run in parallel
NUM_CPU ?= $(or $(shell docker info --format "{{ .NCPU }}"),2) NUM_CPU = $(or $(shell docker info --format "{{ .NCPU }}"),2)
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag # BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
BASE_IMAGE_TAG=$(lastword $(subst /, ,$(subst :,-,$(BASE_IMAGE)))) BASE_IMAGE_TAG=$(lastword $(subst /, ,$(subst :,-,$(BASE_IMAGE))))
#BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE))) #BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
@@ -95,7 +68,7 @@ IMAGE_REVISION=$(shell git rev-parse HEAD)
IMAGE_SOURCE=$(shell git config --get remote.origin.url) IMAGE_SOURCE=$(shell git config --get remote.origin.url)
EMPTY:= EMPTY:=
SPACE:= $(EMPTY) $(EMPTY) SPACE:= $(EMPTY) $(EMPTY)
# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.2.0 instead of 9.2.0.0 # MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.3 instead of 9.1.3.0
MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION)))) MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION))))
ifneq (,$(findstring Microsoft,$(shell uname -r))) ifneq (,$(findstring Microsoft,$(shell uname -r)))
@@ -109,87 +82,19 @@ endif
# Try to figure out which archive to use from the architecture # Try to figure out which archive to use from the architecture
ifeq "$(ARCH)" "amd64" ifeq "$(ARCH)" "amd64"
MQ_ARCHIVE_ARCH=X86-64 MQ_ARCHIVE_ARCH=X86-64
MQ_ARCHIVE_DEV_ARCH=X64 MQ_DEV_ARCH=x86-64
else ifeq "$(ARCH)" "ppc64le" else ifeq "$(ARCH)" "ppc64le"
MQ_ARCHIVE_ARCH=PPC64LE MQ_ARCHIVE_ARCH=LE_POWER
MQ_DEV_ARCH=ppcle
else ifeq "$(ARCH)" "s390x" else ifeq "$(ARCH)" "s390x"
MQ_ARCHIVE_ARCH=S390X MQ_ARCHIVE_ARCH=SYSTEM_Z
MQ_DEV_ARCH=s390x
endif endif
# Archive names for IBM MQ Advanced for Developers
# If this is a fake master build, push images to alternative location (pipeline wont consider these images GA candidates) MQ_ARCHIVE_DEV_9.1.0.0=mqadv_dev910_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
ifeq ($(shell [ "$(TRAVIS)" = "true" ] && [ -n "$(MAIN_BRANCH)" ] && [ -n "$(SOURCE_BRANCH)" ] && [ "$(MAIN_BRANCH)" != "$(SOURCE_BRANCH)" ] && echo "true"), true) MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
MQ_DELIVERY_REGISTRY_NAMESPACE="master-fake" MQ_ARCHIVE_DEV_9.1.2.0=mqadv_dev912_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
endif MQ_ARCHIVE_DEV_9.1.3.0=mqadv_dev913_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
# LTS_TAG is the tag modifier for an LTS container build
LTS_TAG=
ifeq "$(LTS)" "true"
ifneq "$(LTS_TAG_OVERRIDE)" "$(EMPTY)"
LTS_TAG=$(LTS_TAG_OVERRIDE)
else
LTS_TAG=-lts
endif
MQ_ARCHIVE:=$(MQ_VERSION)-IBM-MQ-Advanced-Non-Install-Linux$(MQ_ARCHIVE_ARCH).tar.gz
MQ_DELIVERY_REGISTRY_NAMESPACE:=$(MQ_DELIVERY_REGISTRY_NAMESPACE)$(LTS_TAG)
endif
ifneq (,$(findstring release-candidate,$(TRAVIS_TAG)))
MQ_DELIVERY_REGISTRY_NAMESPACE=release-candidates
endif
ifneq "$(MQ_DELIVERY_REGISTRY_NAMESPACE)" "$(EMPTY)"
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_DELIVERY_REGISTRY_NAMESPACE)
else
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)
endif
# image tagging
ifneq "$(RELEASE)" "$(EMPTY)"
EXTRA_LABELS_RELEASE=--label "release=$(RELEASE)"
RELEASE_TAG="-$(RELEASE)"
endif
ifneq "$(MQ_ARCHIVE_LEVEL)" "$(EMPTY)"
EXTRA_LABELS_LEVEL=--label "mq-build=$(MQ_ARCHIVE_LEVEL)"
endif
EXTRA_LABELS=$(EXTRA_LABELS_RELEASE) $(EXTRA_LABELS_LEVEL)
ifeq "$(TIMESTAMPFLAT)" "$(EMPTY)"
TIMESTAMPFLAT=$(shell date "+%Y%m%d%H%M%S")
endif
ifeq "$(GIT_COMMIT)" "$(EMPTY)"
GIT_COMMIT=$(shell git rev-parse --short HEAD)
endif
ifeq ($(shell [ ! -z $(TRAVIS) ] && [ "$(TRAVIS_PULL_REQUEST)" = "false" ] && [ "$(TRAVIS_BRANCH)" = "$(MAIN_BRANCH)" ] && echo true), true)
MQ_MANIFEST_TAG_SUFFIX=.$(TIMESTAMPFLAT).$(GIT_COMMIT)
endif
PATH_TO_MQ_TAG_CACHE=$(TRAVIS_BUILD_DIR)/.tagcache
ifneq "$(TRAVIS)" "$(EMPTY)"
ifneq ("$(wildcard $(PATH_TO_MQ_TAG_CACHE))","")
include $(PATH_TO_MQ_TAG_CACHE)
endif
endif
MQ_AMD64_TAG=$(MQ_MANIFEST_TAG)-amd64
MQ_S390X_TAG?=$(MQ_MANIFEST_TAG)-s390x
# end image tagging
MQ_IMAGE_FULL_RELEASE_NAME=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
MQ_IMAGE_DEV_FULL_RELEASE_NAME=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
#setup variables for fat-manifests
MQ_IMAGE_DEVSERVER_MANIFEST=$(MQ_IMAGE_DEVSERVER):$(MQ_MANIFEST_TAG)
MQ_IMAGE_ADVANCEDSERVER_MANIFEST=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_MANIFEST_TAG)
MQ_IMAGE_DEVSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_AMD64_TAG)
MQ_IMAGE_DEVSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_S390X_TAG)
MQ_IMAGE_ADVANCEDSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_AMD64_TAG)
MQ_IMAGE_ADVANCEDSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_S390X_TAG)
############################################################################### ###############################################################################
# Build targets # Build targets
@@ -207,9 +112,6 @@ test-all: build-devjmstest test-devserver test-advancedserver
.PHONY: devserver .PHONY: devserver
devserver: build-devserver build-devjmstest test-devserver devserver: build-devserver build-devjmstest test-devserver
.PHONY: advancedserver
advancedserver: build-advancedserver test-advancedserver
# Build incubating components # Build incubating components
.PHONY: incubating .PHONY: incubating
incubating: build-explorer incubating: build-explorer
@@ -217,48 +119,19 @@ incubating: build-explorer
downloads/$(MQ_ARCHIVE_DEV): downloads/$(MQ_ARCHIVE_DEV):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads mkdir -p downloads
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)" cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
# Use key which is not stored in the repository to fetch the files from the fileserver
curl -L $(BUILD_RSYNC_ENCRYPTED_KEY_URL) -o ./host.key.gpg
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --passphrase-fd 0 ./host.key.gpg
chmod 600 ./host.key
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE_DEV)
-@rm host.key.gpg host.key
else
ifneq "$(MQ_ARCHIVE_REPOSITORY_DEV)" "$(EMPTY)"
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" -o downloads/$(MQ_ARCHIVE_DEV)
else
curl -L https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV) -o downloads/$(MQ_ARCHIVE_DEV)
endif
endif
downloads/$(MQ_ARCHIVE): downloads/$(MQ_SDK_ARCHIVE):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced "$(MQ_VERSION)$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads mkdir -p downloads
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)" cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_SDK_ARCHIVE)
# Use key which is not stored in the repository to fetch the files from the fileserver
-@rm host.key.gpg host.key
curl -L $(BUILD_RSYNC_ENCRYPTED_KEY_URL) -o ./host.key.gpg
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --passphrase-fd 0 ./host.key.gpg
chmod 600 ./host.key
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE)
-@rm host.key.gpg host.key
else
ifneq "$(MQ_ARCHIVE_REPOSITORY)" "$(EMPTY)"
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY)" -o downloads/$(MQ_ARCHIVE)
endif
endif
.PHONY: downloads .PHONY: downloads
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE) downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
.PHONY: cache-mq-tag
cache-mq-tag:
@printf "MQ_MANIFEST_TAG=$(MQ_MANIFEST_TAG)\n" | tee $(PATH_TO_MQ_TAG_CACHE)
# Vendor Go dependencies for the Docker tests # Vendor Go dependencies for the Docker tests
test/docker/vendor: test/docker/vendor:
cd test/docker && go mod vendor cd test/docker && dep ensure -vendor-only
# Shortcut to just run the unit tests # Shortcut to just run the unit tests
.PHONY: test-unit .PHONY: test-unit
@@ -269,10 +142,10 @@ test-unit:
test-advancedserver: test/docker/vendor test-advancedserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell docker --version)"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
docker inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) docker inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) $(TEST_OPTS_DOCKER) cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
.PHONY: build-devjmstest .PHONY: build-devjmstest
build-devjmstest: registry-login build-devjmstest:
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) . cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
@@ -280,7 +153,7 @@ build-devjmstest: registry-login
test-devserver: test/docker/vendor test-devserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell docker --version)"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
docker inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) docker inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=true go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER) cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=true go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER)
.PHONY: coverage .PHONY: coverage
coverage: coverage:
@@ -312,25 +185,27 @@ test-advancedserver-cover: test/docker/vendor coverage
# Build an MQ image. The commands used are slightly different between Docker and Podman # Build an MQ image. The commands used are slightly different between Docker and Podman
define build-mq define build-mq
$(if $(findstring docker,$(COMMAND)), @docker network create build,) $(if $(findstring docker,$(COMMAND)), @docker network create build,)
$(if $(findstring docker,$(COMMAND)), @docker run --rm --name $(BUILD_SERVER_CONTAINER) --network build --network-alias build --volume $(DOWNLOADS_DIR):/opt/app-root/src:ro --detach registry.redhat.io/ubi8/nginx-118 nginx -g "daemon off;",) $(if $(findstring docker,$(COMMAND)), @docker run --rm --name $(BUILD_SERVER_CONTAINER) --network build --network-alias build --volume $(DOWNLOADS_DIR):/usr/share/nginx/html:ro --detach docker.io/nginx:alpine,)
$(eval EXTRA_ARGS=$(if $(findstring docker,$(COMMAND)), --network build --build-arg MQ_URL=http://build:8080/$4, --volume $(DOWNLOADS_DIR):/var/downloads --build-arg MQ_URL=file:///var/downloads/$4)) $(eval EXTRA_ARGS=$(if $(findstring docker,$(COMMAND)), --network build --build-arg MQ_URL=http://build:80/$4, --volume $(DOWNLOADS_DIR):/var/downloads --build-arg MQ_URL=file:///var/downloads/$4))
# Build the new image # Build the new image
$(COMMAND) build \ $(COMMAND) build \
--tag $1:$2 \ --tag $1:$2 \
--file $3 \ --file $3 \
$(EXTRA_ARGS) \ $(EXTRA_ARGS) \
--build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \
--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 MQM_UID=$(MQM_UID) \
--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) \
--label release="$(RELEASE)" \
--label architecture="$(ARCH)" \ --label architecture="$(ARCH)" \
--label run="docker run -d -e LICENSE=accept $1:$2" \ --label run="docker run -d -e LICENSE=accept $1:$2" \
--label vcs-ref=$(IMAGE_REVISION) \ --label vcs-ref=$(IMAGE_REVISION) \
--label vcs-type=git \ --label vcs-type=git \
--label vcs-url=$(IMAGE_SOURCE) \ --label vcs-url=$(IMAGE_SOURCE) \
$(EXTRA_LABELS) \
--target $5 \ --target $5 \
. .
$(if $(findstring docker,$(COMMAND)), @docker kill $(BUILD_SERVER_CONTAINER)) $(if $(findstring docker,$(COMMAND)), @docker kill $(BUILD_SERVER_CONTAINER))
@@ -355,7 +230,7 @@ endif
build-advancedserver-host: build-advancedserver build-advancedserver-host: build-advancedserver
.PHONY: build-advancedserver .PHONY: build-advancedserver
build-advancedserver: docker-login registry-login log-build-env downloads/$(MQ_ARCHIVE) command-version build-advancedserver: log-build-env downloads/$(MQ_ARCHIVE) command-version
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)"$(END)))
$(call build-mq,$(MQ_IMAGE_ADVANCEDSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE),mq-server) $(call build-mq,$(MQ_IMAGE_ADVANCEDSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE),mq-server)
@@ -363,46 +238,33 @@ build-advancedserver: docker-login registry-login log-build-env downloads/$(MQ_A
build-devserver-host: build-devserver build-devserver-host: build-devserver
.PHONY: build-devserver .PHONY: build-devserver
build-devserver: docker-login registry-login log-build-env downloads/$(MQ_ARCHIVE_DEV) command-version build-devserver: log-build-env downloads/$(MQ_ARCHIVE_DEV) command-version
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)"$(END))) $(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)"$(END)))
$(call build-mq,$(MQ_IMAGE_DEVSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE_DEV),mq-dev-server) $(call build-mq,$(MQ_IMAGE_DEVSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE_DEV),mq-dev-server)
.PHONY: build-advancedserver-cover .PHONY: build-advancedserver-cover
build-advancedserver-cover: registry-login command-version build-advancedserver-cover: command-version
$(COMMAND) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) -t $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover -f Dockerfile-server.cover . $(COMMAND) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) -t $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover -f Dockerfile-server.cover .
.PHONY: build-explorer .PHONY: build-explorer
build-explorer: registry-login downloads/$(MQ_ARCHIVE_DEV) build-explorer: downloads/$(MQ_ARCHIVE_DEV)
$(call build-mq,mq-explorer,latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),mq-explorer) $(call build-mq,mq-explorer,latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),mq-explorer)
.PHONY: build-sdk .PHONY: build-sdk
build-sdk: registry-login downloads/$(MQ_ARCHIVE_DEV) build-sdk: downloads/$(MQ_ARCHIVE_DEV)
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_SDK)"$(END))) $(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_SDK)"$(END)))
$(call build-mq,mq-sdk,$(MQ_TAG),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),mq-sdk) $(call build-mq,mq-sdk,$(MQ_TAG),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),mq-sdk)
.PHONY: registry-login
registry-login:
ifneq ($(REGISTRY_USER),)
$(COMMAND) login -u $(REGISTRY_USER) -p $(REGISTRY_PASS) registry.redhat.io
endif
.PHONY: docker-login
docker-login:
ifneq ($(DOCKER_USER),)
docker login -u $(DOCKER_USER) -p $(DOCKER_PASS)
endif
.PHONY: log-build-env .PHONY: log-build-env
log-build-vars: log-build-vars:
$(info $(SPACER)$(shell printf $(TITLE)"Build environment"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Build environment"$(END)))
@echo ARCH=$(ARCH) @echo ARCH=$(ARCH)
@echo MQ_VERSION=$(MQ_VERSION) @echo MQ_VERSION=$(MQ_VERSION)
@echo MQ_ARCHIVE=$(MQ_ARCHIVE) @echo MQ_ARCHIVE=$(MQ_ARCHIVE)
@echo MQ_ARCHIVE_DEV=$(MQ_ARCHIVE_DEV)
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER) @echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER) @echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
@echo COMMAND=$(COMMAND) @echo COMMAND=$(COMMAND)
@echo REGISTRY_USER=$(REGISTRY_USER) @echo MQM_UID=$(MQM_UID)
.PHONY: log-build-env .PHONY: log-build-env
log-build-env: log-build-vars log-build-env: log-build-vars
@@ -412,87 +274,15 @@ log-build-env: log-build-vars
include formatting.mk include formatting.mk
.PHONY: pull-mq-archive
pull-mq-archive:
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY)" -o downloads/$(MQ_ARCHIVE)
.PHONY: pull-mq-archive-dev
pull-mq-archive-dev:
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" -o downloads/$(MQ_ARCHIVE_DEV)
.PHONY: push-advancedserver
push-advancedserver:
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
fi
$(info $(SPACER)$(shell printf $(TITLE)"Push production image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) tag $(MQ_IMAGE_ADVANCEDSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
$(COMMAND) push $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
.PHONY: push-devserver
push-devserver:
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
fi
$(info $(SPACER)$(shell printf $(TITLE)"Push developer image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) tag $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
$(COMMAND) push $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
.PHONY: pull-advancedserver
pull-advancedserver:
$(info $(SPACER)$(shell printf $(TITLE)"Pull production image from $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) pull $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
$(COMMAND) tag $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME) $(MQ_IMAGE_ADVANCEDSERVER)\:$(MQ_TAG)
.PHONY: pull-devserver
pull-devserver:
$(info $(SPACER)$(shell printf $(TITLE)"Pull developer image from $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) pull $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
$(COMMAND) tag $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME) $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG)
.PHONY: push-manifest
push-manifest: build-skopeo-container
$(info $(SPACER)$(shell printf $(TITLE)"** Determining the image digests **"$(END)))
ifneq "$(LTS)" "true"
$(eval MQ_IMAGE_DEVSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux --override-arch s390x inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_AMD64) | jq -r .Digest))
$(eval MQ_IMAGE_DEVSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_S390X) | jq -r .Digest))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_AMD64) has a digest of $(MQ_IMAGE_DEVSERVER_AMD64_DIGEST)**"$(END)))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_S390X) has a digest of $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)**"$(END)))
endif
$(eval MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_AMD64) | jq -r .Digest))
$(eval MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_S390X) | jq -r .Digest))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_AMD64) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST)**"$(END)))
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_S390X) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)**"$(END)))
ifneq "$(LTS)" "true"
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_DEVSERVER_MANIFEST)**"$(END)))
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_DEVSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_DEVSERVER_AMD64_DIGEST) $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)" $(END))
endif
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_ADVANCEDSERVER_MANIFEST)**"$(END)))
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)" $(END))
.PHONY: build-skopeo-container
build-skopeo-container: docker-login
$(COMMAND) images | grep -q "skopeo"; if [ $$? != 0 ]; then docker build -t skopeo:latest ./docker-builds/skopeo/; fi
.PHONY: clean .PHONY: clean
clean: clean:
rm -rf ./coverage rm -rf ./coverage
rm -rf ./build rm -rf ./build
rm -rf ./deps rm -rf ./deps
.PHONY: install-build-deps .PHONY: deps
install-build-deps: deps:
ARCH=$(ARCH) ./install-build-deps.sh glide install --strip-vendor
.PHONY: install-credential-helper
install-credential-helper:
ifeq ($(ARCH),amd64)
ARCH=$(ARCH) ./travis-build-scripts/install-credential-helper.sh
endif
.PHONY: build-cov .PHONY: build-cov
build-cov: build-cov:
@@ -513,8 +303,7 @@ lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
golint -set_exit_status $(sort $(dir $(wildcard $(addsuffix /*/*.go, $(GO_PKG_DIRS))))) golint -set_exit_status $(sort $(dir $(wildcard $(addsuffix /*/*.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)))
@gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\ @gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\
cat "gosec_results.json" ;\ cat "gosec_results.json" ;\
cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\ cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\
@@ -540,17 +329,3 @@ gosec:
fi ;\ fi ;\
include formatting.mk include formatting.mk
.PHONY: update-release-information
update-release-information:
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_LTS_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"/g' Dockerfile-server && rm Dockerfile-server.bak
$(eval MQ_VERSION_1=$(shell echo '${MQ_VERSION}' | rev | cut -c 3- | rev))
sed -i.bak 's/IBM_MQ_.*_LINUX_X86-64_NOINST.tar.gz/IBM_MQ_${MQ_LTS_VERSION}_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_LTS_VERSION)-amd64/g' docs/security.md
sed -i.bak 's/ibm-mqadvanced-server-dev.*-amd64/ibm-mqadvanced-server-dev:$(MQ_LTS_VERSION)-amd64/g' docs/security.md && rm docs/security.md.bak
sed -i.bak 's/MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:.*-amd64/MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:$(MQ_LTS_VERSION)-amd64/g' docs/testing.md && rm docs/testing.md.bak
$(eval MQ_VERSION_2=$(shell echo '${MQ_VERSION_1}' | sed "s/\.//g"))
sed -i.bak 's/MQ_..._ARCHIVE_REPOSITORY/MQ_${MQ_VERSION_2}_ARCHIVE_REPOSITORY/g' .travis.yml && rm .travis.yml.bak
sed -i.bak 's/MQ_LTS_VERSION=[0-9]\.[0-9]\.[0-9]\.[0-9]/MQ_LTS_VERSION=${MQ_LTS_VERSION}/g' .travis.yml && rm .travis.yml.bak
$(eval MQ_LTS_VERSION_1=$(shell echo '${MQ_LTS_VERSION}' | sed "s/\.//g"))
sed -i.bak 's/MQ_...._EUS_ARCHIVE_REPOSITORY/MQ_${MQ_LTS_VERSION_1}_EUS_ARCHIVE_REPOSITORY/g' .travis.yml && rm .travis.yml.bak

21089
NOTICES.txt

File diff suppressed because it is too large Load Diff

View File

@@ -44,11 +44,12 @@ For issues relating specifically to the container image or Helm chart, please us
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
Licenses for the products installed within the images are as follows: Licenses for the products installed within the images are as follows:
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-BMKG5H) (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-BBZHCQ) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-BMJJBM) (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-BBSHJL) (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.
- License information for Ubuntu packages may be found in `/usr/share/doc/${package}/copyright`
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, 2021 © Copyright IBM Corporation 2015, 2019

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -23,7 +23,7 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/ibm-messaging/mq-container/pkg/name" "github.com/ibm-messaging/mq-container/internal/name"
) )
func queueManagerHealthy() (bool, error) { func queueManagerHealthy() (bool, error) {
@@ -36,11 +36,11 @@ func queueManagerHealthy() (bool, error) {
cmd := exec.Command("dspmq", "-n", "-m", name) cmd := exec.Command("dspmq", "-n", "-m", name)
// Run the command and wait for completion // Run the command and wait for completion
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
fmt.Printf("%s", out)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return false, err return false, err
} }
fmt.Printf("%s", out)
if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") { if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") {
return false, nil return false, nil
} }

View File

@@ -22,8 +22,8 @@ import (
"net" "net"
"os" "os"
"github.com/ibm-messaging/mq-container/internal/name"
"github.com/ibm-messaging/mq-container/internal/ready" "github.com/ibm-messaging/mq-container/internal/ready"
"github.com/ibm-messaging/mq-container/pkg/name"
) )
func main() { func main() {

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2020 © 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.
@@ -22,10 +22,11 @@ import (
"os/exec" "os/exec"
"syscall" "syscall"
"github.com/ibm-messaging/mq-container/internal/htpasswd" "github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/pkg/containerruntimelogger" "github.com/ibm-messaging/mq-container/internal/containerruntimelogger"
"github.com/ibm-messaging/mq-container/pkg/logger" "github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-container/pkg/name" "github.com/ibm-messaging/mq-container/internal/mqtemplate"
"github.com/ibm-messaging/mq-container/internal/name"
) )
var log *logger.Logger var log *logger.Logger
@@ -42,7 +43,7 @@ func setPassword(user string, password string) error {
if err != nil { if err != nil {
log.Errorf("Error closing password stdin: %v", err) log.Errorf("Error closing password stdin: %v", err)
} }
out, err := cmd.CombinedOutput() out, _, err := command.RunCmd(cmd)
if err != nil { if err != nil {
// Include the command output in the error // Include the command output in the error
return fmt.Errorf("%v: %v", err.Error(), out) return fmt.Errorf("%v: %v", err.Error(), out)
@@ -89,6 +90,11 @@ func configureLogger() error {
return nil return nil
} }
func configureWeb(qmName string) error {
out := "/etc/mqm/web/installations/Installation1/angular.persistence/admin.json"
return mqtemplate.ProcessTemplateFile("/etc/mqm/admin.json.tpl", out, map[string]string{"QueueManagerName": qmName}, log)
}
func logTerminationf(format string, args ...interface{}) { func logTerminationf(format string, args ...interface{}) {
logTermination(fmt.Sprintf(format, args...)) logTermination(fmt.Sprintf(format, args...))
} }
@@ -120,23 +126,16 @@ func doMain() error {
} }
adminPassword, set := os.LookupEnv("MQ_ADMIN_PASSWORD") adminPassword, set := os.LookupEnv("MQ_ADMIN_PASSWORD")
if !set { if set {
adminPassword = "passw0rd" err = setPassword("admin", adminPassword)
err = os.Setenv("MQ_ADMIN_PASSWORD", adminPassword)
if err != nil { if err != nil {
logTerminationf("Error setting admin password variable: %v", err) logTerminationf("Error setting admin password: %v", err)
return err return err
} }
} }
err = htpasswd.SetPassword("admin", adminPassword, false)
if err != nil {
logTerminationf("Error setting admin password: %v", err)
return err
}
appPassword, set := os.LookupEnv("MQ_APP_PASSWORD") appPassword, set := os.LookupEnv("MQ_APP_PASSWORD")
if set { if set {
err = htpasswd.SetPassword("app", appPassword, false) err = setPassword("app", appPassword)
if err != nil { if err != nil {
logTerminationf("Error setting app password: %v", err) logTerminationf("Error setting app password: %v", err)
return err return err
@@ -149,6 +148,18 @@ func doMain() error {
return err return err
} }
name, err := name.GetQueueManagerName()
if err != nil {
logTerminationf("Error getting queue manager name: %v", err)
return err
}
err = configureWeb(name)
if err != nil {
logTermination("Error configuring admin.json")
return err
}
return nil return nil
} }
@@ -161,7 +172,7 @@ func main() {
} else { } else {
// Replace this process with runmqserver // Replace this process with runmqserver
// #nosec G204 // #nosec G204
err = syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver", "-nologruntime", "-dev"}, os.Environ()) err = syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver", "-dev"}, os.Environ())
if err != nil { if err != nil {
log.Errorf("Error replacing this process with runmqserver: %v", err) log.Errorf("Error replacing this process with runmqserver: %v", err)
} }

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -17,10 +17,14 @@ package main
import ( import (
"os" "os"
"runtime"
"syscall"
"github.com/ibm-messaging/mq-container/internal/command"
) )
func createVolume(dataPath string) error { func createVolume(dataPath string) error {
_, err := os.Stat(dataPath) fi, err := os.Stat(dataPath)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
// #nosec G301 // #nosec G301
@@ -32,5 +36,25 @@ func createVolume(dataPath string) error {
return err return err
} }
} }
fi, err = os.Stat(dataPath)
if err != nil {
return err
}
sys := fi.Sys()
if sys != nil && runtime.GOOS == "linux" {
stat := sys.(*syscall.Stat_t)
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return err
}
log.Debugf("mqm user is %v (%v)", mqmUID, mqmGID)
if int(stat.Uid) != mqmUID || int(stat.Gid) != mqmGID {
err = os.Chown(dataPath, mqmUID, mqmGID)
if err != nil {
log.Printf("Error: Unable to change ownership of %v", dataPath)
return err
}
}
}
return nil return nil
} }

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -23,13 +23,12 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"sync" "sync"
"github.com/ibm-messaging/mq-container/internal/command" "github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/pkg/logger" "github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-container/pkg/mqini" "github.com/ibm-messaging/mq-container/internal/mqini"
) )
// var debug = false // var debug = false
@@ -61,25 +60,8 @@ func getLogFormat() string {
return os.Getenv("LOG_FORMAT") return os.Getenv("LOG_FORMAT")
} }
// formatBasic formats a log message parsed from JSON, as "basic" text func formatSimple(datetime string, message string) string {
func formatBasic(obj map[string]interface{}) string { return fmt.Sprintf("%v %v\n", datetime, message)
// Emulate the MQ "MessageDetail=Extended" option, by appending inserts to the message
// This is important for certain messages, where key details are only available in the extended message content
inserts := make([]string, 0)
for k, v := range obj {
if strings.HasPrefix(k, "ibm_commentInsert") {
inserts = append(inserts, fmt.Sprintf("%s(%v)", strings.Replace(k, "ibm_comment", "Comment", 1), obj[k]))
} else if strings.HasPrefix(k, "ibm_arithInsert") {
if v.(float64) != 0 {
inserts = append(inserts, fmt.Sprintf("%s(%v)", strings.Replace(k, "ibm_arith", "Arith", 1), obj[k]))
}
}
}
sort.Strings(inserts)
if len(inserts) > 0 {
return fmt.Sprintf("%s %s [%v]\n", obj["ibm_datetime"], obj["message"], strings.Join(inserts, ", "))
}
return fmt.Sprintf("%s %s\n", obj["ibm_datetime"], obj["message"])
} }
// mirrorSystemErrorLogs starts a goroutine to mirror the contents of the MQ system error logs // mirrorSystemErrorLogs starts a goroutine to mirror the contents of the MQ system error logs
@@ -144,8 +126,7 @@ func configureLogger(name string) (mirrorFunc, error) {
if err != nil { if err != nil {
log.Printf("Failed to unmarshall JSON - %v", err) log.Printf("Failed to unmarshall JSON - %v", err)
} else { } else {
fmt.Printf(formatBasic(obj)) fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
// fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
} }
return true return true
}, nil }, nil
@@ -173,43 +154,41 @@ func filterQMLogMessage(obj map[string]interface{}) bool {
} }
func logDiagnostics() { func logDiagnostics() {
if getDebug() { log.Debug("--- Start Diagnostics ---")
log.Debug("--- Start Diagnostics ---")
// show the directory ownership/permissions // show the directory ownership/permissions
// #nosec G104 // #nosec G104
out, _, _ := command.Run("ls", "-l", "/mnt/") out, _, _ := command.Run("ls", "-l", "/mnt/")
log.Debugf("/mnt/:\n%s", out) log.Debugf("/mnt/:\n%s", out)
// #nosec G104 // #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm") out, _, _ = command.Run("ls", "-l", "/mnt/mqm")
log.Debugf("/mnt/mqm:\n%s", out) log.Debugf("/mnt/mqm:\n%s", out)
// #nosec G104 // #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm/data") out, _, _ = command.Run("ls", "-l", "/mnt/mqm/data")
log.Debugf("/mnt/mqm/data:\n%s", out) log.Debugf("/mnt/mqm/data:\n%s", out)
// #nosec G104 // #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm-log/log") out, _, _ = command.Run("ls", "-l", "/mnt/mqm-log/log")
log.Debugf("/mnt/mqm-log/log:\n%s", out) log.Debugf("/mnt/mqm-log/log:\n%s", out)
// #nosec G104 // #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm-data/qmgrs") out, _, _ = command.Run("ls", "-l", "/mnt/mqm-data/qmgrs")
log.Debugf("/mnt/mqm-data/qmgrs:\n%s", out) log.Debugf("/mnt/mqm-data/qmgrs:\n%s", out)
// #nosec G104 // #nosec G104
out, _, _ = command.Run("ls", "-l", "/var/mqm") out, _, _ = command.Run("ls", "-l", "/var/mqm")
log.Debugf("/var/mqm:\n%s", out) log.Debugf("/var/mqm:\n%s", out)
// #nosec G104 // #nosec G104
out, _, _ = command.Run("ls", "-l", "/var/mqm/errors") out, _, _ = command.Run("ls", "-l", "/var/mqm/errors")
log.Debugf("/var/mqm/errors:\n%s", out) log.Debugf("/var/mqm/errors:\n%s", out)
// #nosec G104 // #nosec G104
out, _, _ = command.Run("ls", "-l", "/etc/mqm") out, _, _ = command.Run("ls", "-l", "/etc/mqm")
log.Debugf("/etc/mqm:\n%s", out) log.Debugf("/etc/mqm:\n%s", out)
// Print out summary of any FDCs // Print out summary of any FDCs
// #nosec G204 // #nosec G204
cmd := exec.Command("/opt/mqm/bin/ffstsummary") cmd := exec.Command("/opt/mqm/bin/ffstsummary")
cmd.Dir = "/var/mqm/errors" cmd.Dir = "/var/mqm/errors"
// #nosec G104 // #nosec G104
outB, _ := cmd.CombinedOutput() outB, _ := cmd.CombinedOutput()
log.Debugf("ffstsummary:\n%s", string(outB)) log.Debugf("ffstsummary:\n%s", string(outB))
log.Debug("--- End Diagnostics ---") log.Debug("--- End Diagnostics ---")
}
} }

View File

@@ -1,55 +0,0 @@
/*
© Copyright IBM Corporation 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 (
"encoding/json"
"fmt"
"strings"
"testing"
)
var formatBasicTests = []struct {
in []byte
outContains string
}{
{
[]byte("{\"ibm_datetime\":\"2020/06/24 00:00:00\",\"message\":\"Hello world\"}"),
"Hello",
},
{
[]byte("{\"ibm_datetime\":\"2020/06/24 00:00:00\",\"message\":\"Hello world\", \"ibm_commentInsert1\":\"foo\"}"),
"CommentInsert1(foo)",
},
{
[]byte("{\"ibm_datetime\":\"2020/06/24 00:00:00\",\"message\":\"Hello world\", \"ibm_arithInsert1\":1}"),
"ArithInsert1(1)",
},
}
func TestFormatBasic(t *testing.T) {
for i, table := range formatBasicTests {
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
var inObj map[string]interface{}
json.Unmarshal(table.in, &inObj)
t.Logf("Unmarshalled: %+v", inObj)
out := formatBasic(inObj)
if !strings.Contains(out, table.outContains) {
t.Errorf("formatBasic() with input=%v - expected output to contain %v, got %v", string(table.in), table.outContains, out)
}
})
}
}

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -24,18 +24,18 @@ import (
"os" "os"
"sync" "sync"
"github.com/ibm-messaging/mq-container/internal/containerruntimelogger"
"github.com/ibm-messaging/mq-container/internal/metrics" "github.com/ibm-messaging/mq-container/internal/metrics"
"github.com/ibm-messaging/mq-container/internal/name"
"github.com/ibm-messaging/mq-container/internal/ready" "github.com/ibm-messaging/mq-container/internal/ready"
"github.com/ibm-messaging/mq-container/internal/tls" "github.com/ibm-messaging/mq-container/internal/tls"
"github.com/ibm-messaging/mq-container/pkg/containerruntimelogger" "github.com/ibm-messaging/mq-container/internal/mqini"
"github.com/ibm-messaging/mq-container/pkg/name"
) )
func doMain() error { func doMain() error {
var initFlag = flag.Bool("i", false, "initialize volume only, then exit") var initFlag = flag.Bool("i", false, "initialize volume only, then exit")
var infoFlag = flag.Bool("info", false, "Display debug info, then exit") var infoFlag = flag.Bool("info", false, "Display debug info, then exit")
var noLogRuntimeFlag = flag.Bool("nologruntime", false, "used when running this program from another program, to control log output") var devFlag = flag.Bool("dev", false, "used when running this program from runmqdevserver to control log output")
var devFlag = flag.Bool("dev", false, "used when running this program from runmqdevserver to control how TLS is configured")
flag.Parse() flag.Parse()
name, nameErr := name.GetQueueManagerName() name, nameErr := name.GetQueueManagerName()
@@ -88,7 +88,7 @@ func doMain() error {
// Enable diagnostic collecting on failure // Enable diagnostic collecting on failure
collectDiagOnFail = true collectDiagOnFail = true
if *noLogRuntimeFlag == false { if *devFlag == false {
err = containerruntimelogger.LogContainerDetails(log) err = containerruntimelogger.LogContainerDetails(log)
if err != nil { if err != nil {
logTermination(err) logTermination(err)
@@ -112,29 +112,12 @@ func doMain() error {
return err return err
} }
enableTraceCrtmqdir := os.Getenv("MQ_ENABLE_TRACE_CRTMQDIR")
if enableTraceCrtmqdir == "true" || enableTraceCrtmqdir == "1" {
err = startMQTrace()
if err != nil {
logTermination(err)
return err
}
}
err = createDirStructure() err = createDirStructure()
if err != nil { if err != nil {
logTermination(err) logTermination(err)
return err return err
} }
if enableTraceCrtmqdir == "true" || enableTraceCrtmqdir == "1" {
err = endMQTrace()
if err != nil {
logTermination(err)
return err
}
}
// If init flag is set, exit now // If init flag is set, exit now
if *initFlag { if *initFlag {
return nil return nil
@@ -143,30 +126,29 @@ func doMain() error {
// Print out versioning information // Print out versioning information
logVersionInfo() logVersionInfo()
keyLabel, cmsKeystore, p12Truststore, err := tls.ConfigureTLSKeystores() keylabel, cmsDB, p12Trust, _, err := tls.ConfigureTLSKeystores(keyDir, trustDir, keyStoreDir)
if err != nil { if err != nil {
logTermination(err) logTermination(err)
return err return err
} }
err = tls.ConfigureTLS(keyLabel, cmsKeystore, *devFlag, log) err = configureTLS(keylabel, cmsDB, *devFlag)
if err != nil { if err != nil {
logTermination(err) logTermination(err)
return err return err
} }
err = postInit(name, keyLabel, p12Truststore) err = postInit(name, keylabel, p12Trust)
if err != nil { if err != nil {
logTermination(err) logTermination(err)
return err return err
} }
newQM, err := createQueueManager(name, *devFlag) newQM, err := createQueueManager(name)
if err != nil { if err != nil {
logTermination(err) logTermination(err)
return err return err
} }
var wg sync.WaitGroup var wg sync.WaitGroup
defer func() { defer func() {
log.Debug("Waiting for log mirroring to complete") log.Debug("Waiting for log mirroring to complete")
@@ -194,23 +176,10 @@ func doMain() error {
return err return err
} }
enableTraceStrmqm := os.Getenv("MQ_ENABLE_TRACE_STRMQM") err = mqini.AddStanzas(name)
if enableTraceStrmqm == "true" || enableTraceStrmqm == "1" { if err != nil {
err = startMQTrace() logTermination(err)
if err != nil { return err
logTermination(err)
return err
}
}
// This is a developer image only change
// This workaround should be removed and handled via <crtmqm -ii>, when inimerge is ready to handle stanza ordering
if *devFlag {
err = updateQMini(name)
if err != nil {
logTermination(err)
return err
}
} }
err = startQueueManager(name) err = startQueueManager(name)
@@ -218,9 +187,8 @@ func doMain() error {
logTermination(err) logTermination(err)
return err return err
} }
if standby, _ := ready.IsRunningAsStandbyQM(name); !standby {
if enableTraceStrmqm == "true" || enableTraceStrmqm == "1" { err = configureQueueManager()
err = endMQTrace()
if err != nil { if err != nil {
logTermination(err) logTermination(err)
return err return err

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2019 © Copyright IBM Corporation 2017, 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.
@@ -23,7 +23,7 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/ibm-messaging/mq-container/pkg/logger" "github.com/ibm-messaging/mq-container/internal/logger"
) )
var test *bool var test *bool

View File

@@ -22,23 +22,18 @@ import (
) )
// postInit is run after /var/mqm is set up // postInit is run after /var/mqm is set up
func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error { func postInit(name, keylabel string, p12Trust 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" {
// Configure the web server (if enabled) // Configure the web server (if enabled)
webKeystore, err := configureWebServer(keyLabel, p12Truststore) keystore, err := configureWebServer(keylabel, p12Trust)
if err != nil { if err != nil {
return err return err
} }
// If trust-store is empty, set reference to point to the keystore
webTruststoreRef := "MQWebTrustStore"
if len(p12Truststore.TrustedCerts) == 0 {
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() {
err = startWebServer(webKeystore, p12Truststore.Password, webTruststoreRef) err = startWebServer(keystore, p12Trust.Password)
if err != nil { if err != nil {
log.Printf("Error starting web server: %v", err) log.Printf("Error starting web server: %v", err)
} }

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -16,12 +16,12 @@ limitations under the License.
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"regexp"
"strconv"
"strings" "strings"
"github.com/ibm-messaging/mq-container/internal/command" "github.com/ibm-messaging/mq-container/internal/command"
@@ -32,25 +32,18 @@ import (
// createDirStructure creates the default MQ directory structure under /var/mqm // createDirStructure creates the default MQ directory structure under /var/mqm
func createDirStructure() error { func createDirStructure() error {
// log file diagnostics before and after crtmqdir if DEBUG=true out, _, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-a")
logDiagnostics()
out, rc, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-a")
if err != nil { if err != nil {
if rc == 10 { log.Printf("Error creating directory structure: %v\n", string(out))
log.Printf("Warning creating directory structure: %v\n", string(out)) return err
} else {
log.Printf("Error creating directory structure: %v\n", string(out))
return err
}
} }
log.Println("Created directory structure under /var/mqm") log.Println("Created directory structure under /var/mqm")
logDiagnostics()
return nil return nil
} }
// createQueueManager creates a queue manager, if it doesn't already exist. // createQueueManager creates a queue manager, if it doesn't already exist.
// It returns true if one was created (or a standby was created), or false if one already existed // It returns true if one was created (or a standby was created), or false if one already existed
func createQueueManager(name string, devMode bool) (bool, error) { func createQueueManager(name string) (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 // Run 'dspmqinf' to check if 'mqs.ini' configuration file exists
@@ -73,7 +66,7 @@ func createQueueManager(name string, devMode bool) (bool, error) {
_, 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
args := getCreateQueueManagerArgs(mounts, name, devMode) args := getCreateQueueManagerArgs(mounts, name)
out, rc, err := command.Run("crtmqm", args...) out, rc, err := command.Run("crtmqm", args...)
if err != nil { if err != nil {
log.Printf("Error %v creating queue manager: %v", rc, string(out)) log.Printf("Error %v creating queue manager: %v", rc, string(out))
@@ -123,20 +116,74 @@ func startQueueManager(name string) error {
return nil return nil
} }
func stopQueueManager(name string) error { func configureQueueManager() error {
log.Println("Stopping queue manager") const configDir string = "/etc/mqm"
qmGracePeriod := os.Getenv("MQ_GRACE_PERIOD") files, err := ioutil.ReadDir(configDir)
isStandby, err := ready.IsRunningAsStandbyQM(name)
if err != nil { if err != nil {
log.Printf("Error getting status for queue manager %v: %v", name, err.Error()) log.Println(err)
return err return err
} }
args := []string{"-w", "-r", "-tp", qmGracePeriod, name} for _, file := range files {
if strings.HasSuffix(file.Name(), ".mqsc") {
abs := filepath.Join(configDir, file.Name())
// #nosec G204
verify := exec.Command("runmqsc", "-v", "-e")
// #nosec G204 - command is fixed, no injection vector
cmd := exec.Command("runmqsc")
// Read mqsc file into variable
// #nosec G304 - filename variable is derived from contents of 'configDir' which is a defined constant
mqsc, err := ioutil.ReadFile(abs)
if err != nil {
log.Printf("Error reading file %v: %v", abs, err)
continue
}
// Write mqsc to buffer
var buffer bytes.Buffer
_, err = buffer.Write(mqsc)
if err != nil {
log.Printf("Error writing MQSC file %v to buffer: %v", abs, err)
continue
}
verifyBuffer := buffer
// Buffer mqsc to stdin of runmqsc
cmd.Stdin = &buffer
verify.Stdin = &verifyBuffer
// Verify the MQSC commands
out, err := verify.CombinedOutput()
if err != nil {
log.Errorf("Error verifying MQSC file %v (%v):\n\t%v", file.Name(), err, formatMQSCOutput(string(out)))
return fmt.Errorf("Error verifying MQSC file %v (%v):\n\t%v", file.Name(), err, formatMQSCOutput(string(out)))
}
// Run runmqsc command
out, err = cmd.CombinedOutput()
if err != nil {
log.Errorf("Error running MQSC file %v (%v):\n\t%v", file.Name(), err, formatMQSCOutput(string(out)))
continue
} else {
// Print the runmqsc output, adding tab characters to make it more readable as part of the log
log.Printf("Output for \"runmqsc\" with %v:\n\t%v", abs, formatMQSCOutput(string(out)))
}
}
}
return nil
}
func stopQueueManager(name string) error {
log.Println("Stopping queue manager")
isStandby, err := ready.IsRunningAsStandbyQM(name)
if err != nil {
log.Printf("Error getting status for queue manager %v: ", name, err.Error())
return err
}
args := []string{"-w", "-r", name}
if os.Getenv("MQ_MULTI_INSTANCE") == "true" { if os.Getenv("MQ_MULTI_INSTANCE") == "true" {
if isStandby { if isStandby {
args = []string{"-x", name} args = []string{"-x", name}
} else { } else {
args = []string{"-s", "-w", "-r", "-tp", qmGracePeriod, name} args = []string{"-s", "-w", "-r", name}
} }
} }
out, rc, err := command.Run("endmqm", args...) out, rc, err := command.Run("endmqm", args...)
@@ -152,28 +199,6 @@ func stopQueueManager(name string) error {
return nil return nil
} }
func startMQTrace() error {
log.Println("Starting MQ trace")
out, rc, err := command.Run("strmqtrc")
if err != nil {
log.Printf("Error %v starting trace: %v", rc, string(out))
return err
}
log.Println("Started MQ trace")
return nil
}
func endMQTrace() error {
log.Println("Ending MQ Trace")
out, rc, err := command.Run("endmqtrc")
if err != nil {
log.Printf("Error %v ending trace: %v", rc, string(out))
return err
}
log.Println("Ended MQ trace")
return nil
}
func formatMQSCOutput(out string) string { func formatMQSCOutput(out string) string {
// redact sensitive information // redact sensitive information
out, _ = mqscredact.Redact(out) out, _ = mqscredact.Redact(out)
@@ -202,11 +227,8 @@ func getQueueManagerDataDir(mounts map[string]string, name string) string {
return dataDir return dataDir
} }
func getCreateQueueManagerArgs(mounts map[string]string, name string, devMode bool) []string { func getCreateQueueManagerArgs(mounts map[string]string, name string) []string {
args := []string{"-ii", "/etc/mqm/", "-ic", "/etc/mqm/", "-q", "-p", "1414"} args := []string{"-q", "-p", "1414"}
if devMode {
args = append(args, "-oa", "user")
}
if _, ok := mounts["/mnt/mqm-log"]; ok { if _, ok := mounts["/mnt/mqm-log"]; ok {
args = append(args, "-ld", "/mnt/mqm-log/log") args = append(args, "-ld", "/mnt/mqm-log/log")
} }
@@ -225,48 +247,3 @@ func getCreateStandbyQueueManagerArgs(name string) []string {
args = append(args, "-v", fmt.Sprintf("DataPath=/mnt/mqm-data/qmgrs/%v", name)) args = append(args, "-v", fmt.Sprintf("DataPath=/mnt/mqm-data/qmgrs/%v", name))
return args return args
} }
// updateQMini removes the original ServicecCmponent stanza so we can add a new one
func updateQMini(qmname string) error {
val, set := os.LookupEnv("MQ_CONNAUTH_USE_HTP")
if !set {
//htpasswd mode not enabled.
return nil
}
bval, err := strconv.ParseBool(strings.ToLower(val))
if err != nil {
return err
}
if bval == false {
//htpasswd mode not enabled.
return nil
}
log.Printf("Removing existing ServiceComponent configuration")
mounts, err := containerruntime.GetMounts()
if err != nil {
log.Printf("Error getting mounts for queue manager")
return err
}
dataDir := getQueueManagerDataDir(mounts, qmname)
qmgrDir := filepath.Join(dataDir, "qm.ini")
//read the initial version.
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
iniFileBytes, err := ioutil.ReadFile(qmgrDir)
if err != nil {
return err
}
qminiConfigStr := string(iniFileBytes)
if strings.Contains(qminiConfigStr, "ServiceComponent:") {
var re = regexp.MustCompile(`(?m)^.*ServiceComponent.*$\s^.*Service.*$\s^.*Name.*$\s^.*Module.*$\s^.*ComponentDataSize.*$`)
curFile := re.ReplaceAllString(qminiConfigStr, "")
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
err := ioutil.WriteFile(qmgrDir, []byte(curFile), 0660)
if err != nil {
return err
}
}
return nil
}

163
cmd/runmqserver/tls.go Normal file
View File

@@ -0,0 +1,163 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/keystore"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
"github.com/ibm-messaging/mq-container/internal/tls"
)
// Location to store the keystores
const keyStoreDir = "/run/runmqserver/tls/"
// KeyDir is the location of the certificate keys to import
const keyDir = "/etc/mqm/pki/keys"
// TrustDir is the location of the Certifates to add
const trustDir = "/etc/mqm/pki/trust"
// configureWebTLS configures TLS for Web Console
func configureWebTLS(label string) error {
// Return immediately if we have no certificate to use as identity
if label == "" && os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME") == "" {
return nil
}
webConfigDir := "/etc/mqm/web/installations/Installation1/servers/mqweb"
tls := "tls.xml"
tlsConfig := filepath.Join(webConfigDir, tls)
newTLSConfig := filepath.Join(webConfigDir, tls+".tpl")
err := os.Remove(tlsConfig)
if err != nil {
return fmt.Errorf("Could not delete file %s: %v", tlsConfig, err)
}
// we symlink here to prevent issues on restart
err = os.Symlink(newTLSConfig, tlsConfig)
if err != nil {
return fmt.Errorf("Could not create symlink %s->%s: %v", newTLSConfig, tlsConfig, err)
}
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return fmt.Errorf("Could not find mqm user or group: %v", err)
}
err = os.Chown(tlsConfig, mqmUID, mqmGID)
if err != nil {
return fmt.Errorf("Could change ownership of %s to mqm: %v", tlsConfig, err)
}
return nil
}
// configureTLSDev configures TLS for developer defaults
func configureTLSDev() error {
const mqsc string = "/etc/mqm/20-dev-tls.mqsc"
const mqscTemplate string = mqsc + ".tpl"
if os.Getenv("MQ_DEV") == "true" {
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{}, log)
if err != nil {
return err
}
} else {
_, err := os.Stat(mqsc)
if !os.IsNotExist(err) {
err = os.Remove(mqsc)
if err != nil {
log.Errorf("Error removing file %s: %v", mqsc, err)
return err
}
}
}
return nil
}
// configureTLS configures TLS for queue manager
func configureTLS(certLabel string, cmsKeystore tls.KeyStoreData, devmode bool) error {
log.Debug("Configuring TLS")
const mqsc string = "/etc/mqm/15-tls.mqsc"
const mqscTemplate string = mqsc + ".tpl"
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
"SSLKeyR": strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb"),
"CertificateLabel": certLabel,
}, log)
if err != nil {
return err
}
if devmode && certLabel != "" {
err = configureTLSDev()
if err != nil {
return err
}
}
return nil
}
// configureSSOTLS configures MQ Console TLS for Single Sign-On
func configureSSOTLS(p12TrustStore tls.KeyStoreData) (string, error) {
// TODO find way to supply this
// Override the webstore variables to hard coded defaults
webKeyStoreName := tls.IntegrationDefaultLabel + ".p12"
// Check keystore exists
ks := filepath.Join(keyStoreDir, webKeyStoreName)
_, err := os.Stat(ks)
// Now we know if the file exists let's check whether we should have it or not.
// Check if we're being told to generate the certificate
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
if genHostName != "" {
// We've got to generate the certificate with the hostname given
if err == nil {
log.Printf("Replacing existing keystore %s - generating new certificate", ks)
}
// Keystore doesn't exist so create it and populate a certificate
newKS := keystore.NewPKCS12KeyStore(ks, p12TrustStore.Password)
err = newKS.Create()
if err != nil {
return "", fmt.Errorf("Failed to create keystore %s: %v", ks, err)
}
err = newKS.CreateSelfSignedCertificate("default", fmt.Sprintf("CN=%s", genHostName), genHostName)
if err != nil {
return "", fmt.Errorf("Failed to generate certificate in keystore %s with DN of 'CN=%s': %v", ks, genHostName, err)
}
} else {
// Keystore should already exist
if err != nil {
return "", fmt.Errorf("Failed to find existing keystore %s: %v", ks, err)
}
}
// Check truststore exists
_, err = os.Stat(p12TrustStore.Keystore.Filename)
if err != nil {
return "", fmt.Errorf("Failed to find existing truststore %s: %v", p12TrustStore.Keystore.Filename, err)
}
return webKeyStoreName, nil
}

View File

@@ -20,7 +20,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/mqversion"
) )
var ( var (
@@ -51,7 +50,7 @@ func logImageTag() {
} }
func logMQVersion() { func logMQVersion() {
mqVersion, err := mqversion.Get() mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
if err != nil { if err != nil {
log.Printf("Error Getting MQ version: %v", strings.TrimSuffix(string(mqVersion), "\n")) log.Printf("Error Getting MQ version: %v", strings.TrimSuffix(string(mqVersion), "\n"))
} }

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2020 © 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.
@@ -19,15 +19,19 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"syscall"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/copy" "github.com/ibm-messaging/mq-container/internal/copy"
"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"
) )
func startWebServer(webKeystore, webkeystorePW, webTruststoreRef string) error { func startWebServer(keystore, keystorepw string) error {
_, err := os.Stat("/opt/mqm/bin/strmqweb") _, err := os.Stat("/opt/mqm/bin/strmqweb")
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
log.Debug("Skipping web server, because it's not installed") log.Debug("Skipping web server, because it's not installed")
@@ -46,13 +50,29 @@ func startWebServer(webKeystore, webkeystorePW, webTruststoreRef string) error {
} }
// TLS enabled // TLS enabled
if webKeystore != "" { if keystore != "" {
cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTORE="+webKeystore) cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTORE="+keystore)
cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTOREPW="+webkeystorePW) cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTOREPW="+keystorepw)
cmd.Env = append(cmd.Env, "AMQ_WEBTRUSTSTOREREF="+webTruststoreRef)
} }
out, err := cmd.CombinedOutput()
rc := cmd.ProcessState.ExitCode() uid, gid, err := command.LookupMQM()
if err != nil {
return err
}
u, err := user.Current()
if err != nil {
return err
}
currentUID, err := strconv.Atoi(u.Uid)
if err != nil {
return fmt.Errorf("Error converting UID to string: %v", err)
}
// Add credentials to run as 'mqm', only if we aren't already 'mqm'
if currentUID != uid {
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
}
out, rc, err := command.RunCmd(cmd)
if err != nil { if err != nil {
log.Printf("Error %v starting web server: %v", rc, string(out)) log.Printf("Error %v starting web server: %v", rc, string(out))
return err return err
@@ -61,9 +81,10 @@ func startWebServer(webKeystore, webkeystorePW, webTruststoreRef string) error {
return nil return nil
} }
func configureSSO(p12TrustStore tls.KeyStoreData, webKeystore string) (string, error) { func configureSSO(p12TrustStore tls.KeyStoreData) (string, error) {
// Ensure all required environment variables are set for SSO // Ensure all required environment variables are set for SSO
requiredEnvVars := []string{ requiredEnvVars := []string{
"MQ_WEB_ADMIN_USERS",
"MQ_OIDC_CLIENT_ID", "MQ_OIDC_CLIENT_ID",
"MQ_OIDC_CLIENT_SECRET", "MQ_OIDC_CLIENT_SECRET",
"MQ_OIDC_UNIQUE_USER_IDENTIFIER", "MQ_OIDC_UNIQUE_USER_IDENTIFIER",
@@ -96,49 +117,46 @@ func configureSSO(p12TrustStore tls.KeyStoreData, webKeystore string) (string, e
} }
// Configure SSO TLS // Configure SSO TLS
return tls.ConfigureWebKeystore(p12TrustStore, webKeystore) return configureSSOTLS(p12TrustStore)
} }
func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string, error) { func configureWebServer(keyLabel string, p12Trust tls.KeyStoreData) (string, error) {
var webKeystore string var keystore string
// Configure TLS for Web Console first if we have a certificate to use // Configure TLS for Web Console first if we have a certificate to use
err := tls.ConfigureWebTLS(keyLabel) err := configureWebTLS(keyLabel)
if err != nil { if err != nil {
return "", err return keystore, err
} }
if keyLabel != "" { if keyLabel != "" {
webKeystore = keyLabel + ".p12" keystore = keyLabel + ".p12"
} }
// Configure Single-Sign-On for the web server (if enabled) // Configure Single-Sign-On for the web server (if enabled)
enableSSO := os.Getenv("MQ_BETA_ENABLE_SSO") enableSSO := os.Getenv("MQ_BETA_ENABLE_SSO")
if enableSSO == "true" || enableSSO == "1" { if enableSSO == "true" || enableSSO == "1" {
webKeystore, err = configureSSO(p12Truststore, webKeystore) keystore, err = configureSSO(p12Trust)
if err != nil { if err != nil {
return "", err return keystore, err
}
} else if keyLabel == "" && os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME") != "" {
webKeystore, err = tls.ConfigureWebKeystore(p12Truststore, webKeystore)
if err != nil {
return "", err
} }
} }
_, err = os.Stat("/opt/mqm/bin/strmqweb") _, err = os.Stat("/opt/mqm/bin/strmqweb")
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return "", nil return keystore, nil
} }
return "", err return keystore, err
} }
const webConfigDir string = "/etc/mqm/web" const webConfigDir string = "/etc/mqm/web"
_, err = os.Stat(webConfigDir) _, err = os.Stat(webConfigDir)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return "", nil return keystore, nil
} }
return "", err return keystore, err
}
uid, gid, err := command.LookupMQM()
if err != nil {
return keystore, err
} }
const prefix string = "/etc/mqm/web" const prefix string = "/etc/mqm/web"
err = filepath.Walk(prefix, func(from string, info os.FileInfo, err error) error { err = filepath.Walk(prefix, func(from string, info os.FileInfo, err error) error {
@@ -176,8 +194,11 @@ func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string
return err return err
} }
} }
err = os.Chown(to, uid, gid)
if err != nil {
return err
}
return nil return nil
}) })
return keystore, err
return webKeystore, err
} }

View File

@@ -1,8 +0,0 @@
###########################################################################################################################################################
# MQ_VERSION is the fully qualified MQ version number to build
MQ_VERSION ?= 9.2.0.0
MQ_LTS_VERSION ?= 9.2.0.6
###########################################################################################################################################################

View File

@@ -9,40 +9,27 @@ You need to have the following tools installed:
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.
You will also need a [Red Hat Account](https://access.redhat.com) to be able to access the Red Hat Registry.
## Building a production image ## Building a production image
From MQ 9.2.X, the MQ container adds support for MQ Long Term Support (LTS) **production licensed** releases. This procedure works for building the MQ Continuous Delivery release, on `amd64`, `ppc64le` and `s390x` architectures.
### MQ Continuous Delivery (CD)
Note: To build the latest Continuous Delivery (CD) version, follow the latest build [instructions](/../master/docs/building.md#building-a-production-image).
### MQ Long Term Support (LTS)
Note: 9.2.0.X is no longer the latest LTS release; MQ 9.3 is the latest MQ version with MQ Long Term Support (LTS). To build MQ 9.3, follow the building [instructions](/../master/docs/building.md#building-a-production-image) for MQ 9.3.
However, if you wish to build the previous 9.2.0.X MQ LTS, follow the procedure below for `amd64` and `s390x` architectures.
1. Create a `downloads` directory in the root of this repository 1. Create a `downloads` directory in the root of this repository
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/). Identify the correct 'Long Term Support for containers' eImage part number for your architecture from the appropriate 9.2.0.X LTS tab at https://www.ibm.com/support/pages/downloading-ibm-mq-92. 2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/) or [IBM Fix Central](https://www.ibm.com/support/fixcentral), and place the downloaded file (for example, `IBM_MQ_9.1.3_LINUX_X86-64.tar.gz`) in the `downloads` directory
3. Ensure the `tar.gz` file is in the `downloads` directory 3. Run `make build-advancedserver`
4. Run `LTS=true make build-advancedserver`
> **Warning**: Note that MQ offers two different sets of packaging on Linux: one is called "MQ for Linux" and contains RPM files for installing on Red Hat Enterprise Linux and SUSE Linux Enterprise Server; the other is for Ubuntu. The MQ container build uses a Red Hat Universal Base Image, so you need the "MQ for Linux" RPM files.
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example: If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
```bash ```bash
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 LTS=true make build-advancedserver MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
``` ```
## Building a developer image ## Building a developer image
Login to the Red Hat Registry: `docker login registry.redhat.io` using your Customer Portal credentials.
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers from IBM developerWorks. This is currently only available on the `amd64` architecture. 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 `Generate MQ package in INSTALLATION_DIR` section [here](../install-mq.sh), with the configured options being picked up at build time. This image includes the core MQ server, Java, language packs, GSKit, and web server. This can be configured by setting the `MQ_PACKAGES` argument to `make`.

View File

@@ -9,12 +9,14 @@ The MQ Developer Defaults supports some customization options, these are all con
* **MQ_DEV** - Set this to `false` to stop the default objects being created. * **MQ_DEV** - Set this to `false` to stop the default objects being created.
* **MQ_ADMIN_PASSWORD** - Changes the password of the `admin` user. Must be at least 8 characters long. * **MQ_ADMIN_PASSWORD** - Changes the password of the `admin` user. Must be at least 8 characters long.
* **MQ_APP_PASSWORD** - Changes the password of the app user. If set, this will cause the `DEV.APP.SVRCONN` channel to become secured and only allow connections that supply a valid userid and password. Must be at least 8 characters long. * **MQ_APP_PASSWORD** - Changes the password of the app user. If set, this will cause the `DEV.APP.SVRCONN` channel to become secured and only allow connections that supply a valid userid and password. Must be at least 8 characters long.
* **MQ_TLS_KEYSTORE** - **DEPRECATED**. See section `Supplying TLS certificates` in [usage document](usage.md). Allows you to supply the location of a PKCS#12 keystore containing a single certificate which you want to use in both the web console and the queue manager. Requires `MQ_TLS_PASSPHRASE`. When enabled the channels created will be secured using the `TLS_RSA_WITH_AES_128_CBC_SHA256` CipherSpec. *Note*: you will need to make the keystore available inside your container, this can be done by mounting a volume to your container.
* **MQ_TLS_PASSPHRASE** - **DEPRECATED**. See section `Supplying TLS certificates` in [usage document](usage.md). Passphrase for the keystore referenced in `MQ_TLS_KEYSTORE`.
## Details of the default configuration ## Details of the default configuration
The following users are created: The following users are created:
* User **admin** for administration. Default password is **passw0rd**. * User **admin** for administration (in the `mqm` group). Default password is **passw0rd**.
* User **app** for messaging (in a group called `mqclient`). No password by default. * User **app** for messaging (in a group called `mqclient`). No password by default.
Users in `mqclient` group have been given access connect to all queues and topics starting with `DEV.**` and have `put`, `get`, `pub`, `sub`, `browse` and `inq` permissions. Users in `mqclient` group have been given access connect to all queues and topics starting with `DEV.**` and have `put`, `get`, `pub`, `sub`, `browse` and `inq` permissions.
@@ -32,6 +34,11 @@ Two channels are created, one for administration, the other for normal messaging
* DEV.ADMIN.SVRCONN - configured to only allow the `admin` user to connect into it. A user and password must be supplied. * DEV.ADMIN.SVRCONN - configured to only allow the `admin` user to connect into it. A user and password must be supplied.
* DEV.APP.SVRCONN - does not allow administrative users to connect. Password is optional unless you choose a password for app users. * DEV.APP.SVRCONN - does not allow administrative users to connect. Password is optional unless you choose a password for app users.
A new listener is created (the SYSTEM listener is fine, but system objects are not shown by default in the web console):
* DEV.LISTENER.TCP - listens on port 1414.
## Web Console ## Web Console
By default the MQ Advanced for Developers image will start the IBM MQ Web Console that allows you to administer your Queue Manager running on your container. When the web console has been started, you can access it by opening a web browser and navigating to https://<Container IP>:9443/ibmmq/console. Where <Container IP> is replaced by the IP address of your running container. By default the MQ Advanced for Developers image will start the IBM MQ Web Console that allows you to administer your Queue Manager running on your container. When the web console has been started, you can access it by opening a web browser and navigating to https://<Container IP>:9443/ibmmq/console. Where <Container IP> is replaced by the IP address of your running container.
@@ -43,6 +50,6 @@ If you choose to accept the security warning, you will be presented with the log
* **User:** admin * **User:** admin
* **Password:** passw0rd * **Password:** passw0rd
If you wish to change the password for the admin user, this can be done using the `MQ_ADMIN_PASSWORD` environment variable. If you wish to change the password for the admin user, this can be done using the `MQ_ADMIN_PASSWORD` environment variable. If you supply a PKCS#12 keystore using the `MQ_TLS_KEYSTORE` environment variable, then the web console will be configured to use the certificate inside the keystore for HTTPS operations.
If you do not wish the web console to run, you can disable it by setting the environment variable `MQ_ENABLE_EMBEDDED_WEB_SERVER` to `false`. If you do not wish the web console to run, you can disable it by setting the environment variable `MQ_ENABLE_EMBEDDED_WEB_SERVER` to `false`.

View File

@@ -1,29 +0,0 @@
### Queue Manager Connection Authentication using a htpasswd file
This pluggable authentication mode is to allow developers using the mq-container developer image to define users and their credentials into a .htpasswd file. This is in addition to the existing methods of MQ Connection Authentication (`CONNAUTH`) using Operating System or LDAP users.
**Please note:**
1. This new feature is enabled only when environment variable `--env MQ_CONNAUTH_USE_HTP=true` is set while creating a container.
2. When enabled, the `AuthType` value of the ConnectionAuthentication (`CONNAUTH`) is ignored and htpasswd mode is used. However, the MQ authority records created using (`SETMQAUT` or `AUTHREC`) will be in effect while using the htpasswd mode.
3. Channel Authentication records (`CHLAUTH`) will be in effect while using the htpasswd mode.
4. Passwords should be encrypted using bcrypt (golang.org/x/crypto/bcrypt).
5. This is developer only feature and not recommended for use in Production.
### Preparing htpasswd file
1. A default `mq.htpasswd` file is provided and placed under /etc/mqm/ directory inside the container.
2. You can set the password for user `admin` by setting the environment variable `MQ_ADMIN_PASSWORD`.
3. You can add user `app` into mq.htpasswd file by setting the environment variable `MQ_APP_PASSWORD`. This user `app` can be used to access `DEV.*` objects of the queue manager.
#### Next Steps:
Use an administrative tool or your application to connect to queue manager using the credentials defined in the mq.htpasswd file.
**Please note**: When an authentication request is made with a userid that is not defined in the `mq.htpasswd` file, then the authentication process is delegated to queue manager to handle. This will then use `IDPWOS` or `LDAP` modes for further processing.
#### Troubleshooting
A log file named `amqpasdev.log` is generated under `/var/mqm/errors` directory path of the container. This file will contain all the failed connection authentication requests.
**Please note**: This log file is based on circular logging and the maximum size is restricted to 1MB.

View File

@@ -4,7 +4,7 @@
### User ### User
The MQ server image is run using with UID 1001, though this can be any UID, with a fixed GID of 0 (root). The MQ server image is run using the "mqm" user, with a fixed UID and GID of 888.
### Capabilities ### Capabilities
@@ -16,7 +16,7 @@ docker run \
--env LICENSE=accept \ --env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \ --env MQ_QMGR_NAME=QM1 \
--detach \ --detach \
ibm-mqadvanced-server:9.2.0.6-amd64 mqadvanced-server:9.1.3.0-amd64
``` ```
The MQ Advanced for Developers image does require the "chown", "setuid", "setgid" and "audit_write" capabilities (plus "dac_override" if you're using an image based on Red Hat Enterprise Linux). This is because it uses the "sudo" command to change passwords inside the container. For example, in Docker, you could do the following: The MQ Advanced for Developers image does require the "chown", "setuid", "setgid" and "audit_write" capabilities (plus "dac_override" if you're using an image based on Red Hat Enterprise Linux). This is because it uses the "sudo" command to change passwords inside the container. For example, in Docker, you could do the following:
@@ -31,5 +31,9 @@ docker run \
--env LICENSE=accept \ --env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \ --env MQ_QMGR_NAME=QM1 \
--detach \ --detach \
ibm-mqadvanced-server-dev:9.2.0.6-amd64 mqadvanced-server-dev:9.1.3.0-amd64
``` ```
### SELinux
The SELinux label "spc_t" (super-privileged container) is needed to run the MQ container on a host with SELinux enabled. This is due to a current limitation in how MQ data is stored on volumes, which violates the usual policy applied when using the standard "container_t" label.

View File

@@ -14,30 +14,29 @@ There are two main sets of tests:
2. Docker tests, which test a complete Docker image, using the Docker API 2. Docker tests, which test a complete Docker image, using the Docker API
### Running the Docker tests ### Running the Docker tests
The Docker tests can be run locally on a machine with Docker. For example:
The Docker tests can be run locally on a machine with Docker. For example:
``` ```
make devserver make test-devserver
make advancedserver 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.2.0.6-amd64 make test-advancedserver MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server:9.1.3.0-amd64 make test-advancedserver
``` ```
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command: You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command::
``` ```
TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver
``` ```
You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `ibm-mqadvanced-server:9.2.0.0-amd64`: You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `mqadvanced-server:9.1.3.0-amd64`:
``` ```
MQ_VERSION=9.2.0.0 make test-advancedserver MQ_VERSION=9.1.3.0 make test-advancedserver
``` ```
### Running the Docker tests with code coverage ### Running the Docker tests with code coverage
@@ -49,3 +48,12 @@ make test-advancedserver-cover
``` ```
In order to generate code coverage metrics from the Docker tests, the build step creates a new Docker image with an instrumented version of the code. Each test is then run individually, producing a coverage report each under `test/docker/coverage/`. These individual reports are then combined. The combined report is written to the `coverage` directory. In order to generate code coverage metrics from the Docker tests, the build step creates a new Docker image with an instrumented version of the code. Each test is then run individually, producing a coverage report each under `test/docker/coverage/`. These individual reports are then combined. The combined report is written to the `coverage` directory.
### Running the Kubernetes tests
For the Kubernetes tests, you need to have built the Docker image, and pushed it to the registry used by your Kubernetes cluster. Most of the configuration used by the tests is picked up from your `kubectl` configuration, but you will typically need to specify the image details. For example:
```bash
MQ_IMAGE=mycluster.icp:8500/default/mq-devserver make test-kubernetes-devserver
```

View File

@@ -60,18 +60,23 @@ You can customize the configuration in several ways:
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image 1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created. 2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
3. By using [remote MQ administration](https://www.ibm.com/docs/en/ibm-mq/9.2?topic=administering-working-remote-mq-objects), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer. 3. By using [remote MQ administration](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.1.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host. Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file: The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file, and an administrative user `alice`. Note that it is not normally recommended to include passwords in this way:
```dockerfile ```dockerfile
FROM ibmcom/mq FROM ibmcom/mq
USER 1001 USER root
RUN useradd alice -G mqm && \
echo alice:passw0rd | chpasswd
USER mqm
COPY 20-config.mqsc /etc/mqm/ COPY 20-config.mqsc /etc/mqm/
``` ```
The `USER` instructions are necessary to ensure that the `useradd` and `chpasswd` commands are run as the root user.
Here is an example corresponding `20-config.mqsc` script, which creates two local queues: Here is an example corresponding `20-config.mqsc` script, which creates two local queues:
```mqsc ```mqsc

View File

@@ -1,2 +0,0 @@
admin:$2y$05$M/C1U62RZ6q1kv4E7.S7ueNESJmFe85RsZcoMUReRXUDB8QcP3yqS
app:$2y$05$BnbPtcjXTjk5JRJ8gzHqIuHgoQbLF3qtbPV3Q3tLyr0XJNg.7dkxW

View File

@@ -1,11 +0,0 @@
ServiceComponent:
Service=AuthorizationService
Name=Dev.HtpAuth.Service
Module=/opt/mqm/lib64/amqpasdev.so
ComponentDataSize=0
ServiceComponent:
Service=AuthorizationService
Name=MQSeries.UNIX.auth.service
Module=amqzfu
ComponentDataSize=0

57
glide.lock generated Normal file
View File

@@ -0,0 +1,57 @@
hash: 6ebd5fb1c39729378c7256da6f312e9699bff1ddff9941d3c8c1ba785e22acfd
updated: 2019-05-21T10:38:01.227081+01:00
imports:
- name: github.com/beorn7/perks
version: 3a771d992973f24aa725d07868b467d1ddfceafb
subpackages:
- quantile
- name: github.com/genuinetools/amicontained
version: fcae88544f0212fbb1e20699c41566655b68679b
subpackages:
- container
- name: github.com/golang/protobuf
version: 70b3af33377e7aa25ae42977bed93cc6b90f0373
subpackages:
- proto
- name: github.com/ibm-messaging/mq-golang
version: 1b2a2ad95ba3c555944be28097d392c27bda4071
subpackages:
- ibmmq
- mqmetric
- name: github.com/matttproud/golang_protobuf_extensions
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
subpackages:
- pbutil
- name: github.com/prometheus/client_golang
version: c5b7fccd204277076155f10851dad72b76a49317
subpackages:
- prometheus
- name: github.com/prometheus/client_model
version: 5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f
subpackages:
- go
- name: github.com/prometheus/common
version: 7600349dcfe1abd18d72d3a1770870d9800a7801
subpackages:
- expfmt
- internal/bitbucket.org/ww/goautoneg
- model
- name: github.com/prometheus/procfs
version: ae68e2d4c00fed4943b5f6698d504a5fe083da8a
subpackages:
- internal/util
- nfs
- xfs
- name: github.com/syndtr/gocapability
version: 33e07d32887e1e06b7c025f27ce52f62c7990bc0
subpackages:
- capability
- name: golang.org/x/sys
version: 1b2967e3c290b7c545b3db0deeda16e9be4f98a2
subpackages:
- unix
- name: software.sslmate.com/src/go-pkcs12
version: 6e380ad96778cc63c6ea17649a9b74224bceafe9
subpackages:
- internal/rc2
testImports: []

30
glide.yaml Normal file
View File

@@ -0,0 +1,30 @@
# © Copyright IBM Corporation 2017, 2019
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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: github.com/ibm-messaging/mq-container
license: Apache-2.0
excludeDirs:
- build
- coverage
- test
import:
- package: golang.org/x/sys/unix
- package: github.com/prometheus/client_golang
version: 0.8.0
- package: github.com/ibm-messaging/mq-golang
version: 2.0.0
- package: github.com/genuinetools/amicontained
version: 0.4.0
- package: software.sslmate.com/src/go-pkcs12
commit: 6e380ad96778cc63c6ea17649a9b74224bceafe9

16
go.mod
View File

@@ -1,16 +0,0 @@
module github.com/ibm-messaging/mq-container
go 1.15
require (
github.com/genuinetools/amicontained v0.4.0
github.com/ibm-messaging/mq-golang v2.0.0+incompatible
github.com/prometheus/client_golang v1.7.1
github.com/prometheus/client_model v0.2.0
github.com/prometheus/common v0.14.0 // indirect
github.com/prometheus/procfs v0.2.0 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
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
)

413
go.sum
View File

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

View File

@@ -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 registry.redhat.io/ubi8/ubi-minimal AS mq-explorer FROM registry.access.redhat.com/ubi7/ubi-minimal AS mq-explorer
# 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_dev912_linux_x86-64.tar.gz" ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev912_linux_x86-64.tar.gz"
@@ -22,7 +22,7 @@ ENV MQ_PACKAGES="MQSeriesRuntime*.rpm MQSeriesJRE*.rpm MQSeriesExplorer*.rpm"
ARG MQM_UID=888 ARG MQM_UID=888
RUN microdnf install -y gtk2 libXtst \ RUN microdnf install -y --nodocs gtk2 libXtst \
&& microdnf clean all && microdnf clean all
ADD install-mq.sh /usr/local/bin/ ADD install-mq.sh /usr/local/bin/

View File

@@ -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 registry.redhat.io/rhel8/llvm-toolset:8.0.1-10 AS mq-sdk FROM registry.access.redhat.com/rhscl/devtoolset-7-toolchain-rhel7 AS mq-sdk
#FROM docker.io/centos/devtoolset-7-toolchain-centos7 AS mq-sdk #FROM docker.io/centos/devtoolset-7-toolchain-centos7 AS mq-sdk
# The URL to download the MQ installer from in tar.gz format # The URL to download the MQ installer from in tar.gz format

View File

@@ -13,6 +13,9 @@
* 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.
STOP LISTENER('SYSTEM.LISTENER.TCP.1') IGNSTATE(YES)
ALTER LISTENER('SYSTEM.LISTENER.TCP.1') TRPTYPE(TCP) CONTROL(MANUAL)
* Developer queues * Developer queues
DEFINE QLOCAL('DEV.QUEUE.1') REPLACE DEFINE QLOCAL('DEV.QUEUE.1') REPLACE
DEFINE QLOCAL('DEV.QUEUE.2') REPLACE DEFINE QLOCAL('DEV.QUEUE.2') REPLACE
@@ -40,9 +43,12 @@ SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('Back-sto
SET CHLAUTH('DEV.APP.SVRCONN') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT({{ .ChckClnt }}) DESCR('Allows connection via APP channel') ACTION(REPLACE) SET CHLAUTH('DEV.APP.SVRCONN') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT({{ .ChckClnt }}) DESCR('Allows connection via APP channel') ACTION(REPLACE)
SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allows admins on ADMIN channel') ACTION(REPLACE) SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allows admins on ADMIN channel') ACTION(REPLACE)
SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(USERMAP) CLNTUSER('admin') USERSRC(CHANNEL) DESCR('Allows admin user to connect via ADMIN channel') ACTION(REPLACE) SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(USERMAP) CLNTUSER('admin') USERSRC(CHANNEL) DESCR('Allows admin user to connect via ADMIN channel') ACTION(REPLACE)
SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(USERMAP) CLNTUSER('admin') USERSRC(MAP) MCAUSER ('mqm') DESCR ('Allow admin as MQ-admin') ACTION(REPLACE)
* Developer authority records * Developer authority records
SET AUTHREC PRINCIPAL('app') OBJTYPE(QMGR) AUTHADD(CONNECT,INQ) SET AUTHREC GROUP('mqclient') OBJTYPE(QMGR) AUTHADD(CONNECT,INQ)
SET AUTHREC PROFILE('DEV.**') PRINCIPAL('app') OBJTYPE(QUEUE) AUTHADD(BROWSE,GET,INQ,PUT) SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(QUEUE) AUTHADD(BROWSE,GET,INQ,PUT)
SET AUTHREC PROFILE('DEV.**') PRINCIPAL('app') OBJTYPE(TOPIC) AUTHADD(PUB,SUB) SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(TOPIC) AUTHADD(PUB,SUB)
* Developer listener
DEFINE LISTENER('DEV.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE
START LISTENER('DEV.LISTENER.TCP') IGNSTATE(YES)

View File

@@ -15,9 +15,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.
# Fail on any non-zero return code
set -ex
test -f /usr/bin/yum && YUM=true || YUM=false test -f /usr/bin/yum && YUM=true || YUM=false
test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
@@ -36,6 +33,6 @@ if ($YUM); then
fi fi
if ($MICRODNF); then if ($MICRODNF); then
microdnf install sudo microdnf install --nodocs sudo
microdnf clean all microdnf clean all
fi fi

View File

@@ -19,13 +19,8 @@
set -ex set -ex
sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.1/dep-linux-$ARCH curl https://glide.sh/get | sh
sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64
sudo chmod +x /usr/local/bin/dep sudo chmod +x /usr/local/bin/dep
sudo apt-get update || :
sudo apt-get install -y jq
( go get -u golang.org/x/lint/golint
cd "$(mktemp -d)"
go get -u golang.org/x/lint/golint
)
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin 2.0.0 || echo "Gosec not installed. Platform may not be supported."

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# -*- mode: sh -*- # -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2020 # © Copyright IBM Corporation 2015, 2019
# #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
@@ -63,10 +63,10 @@ if ($UBUNTU); then
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 coreutils file findutils gawk glibc-common grep passwd procps-ng sed shadow-utils tar util-linux which"
# 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 install ${EXTRA_RPMS} $MICRODNF && microdnf install --nodocs ${EXTRA_RPMS}
fi fi
# Apply any bug fixes not included in base Ubuntu or MQ image. # Apply any bug fixes not included in base Ubuntu or MQ image.

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# -*- mode: sh -*- # -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2020 # © Copyright IBM Corporation 2015, 2019
# #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,70 +18,74 @@
# Fail on any non-zero return code # Fail on any non-zero return code
set -ex set -ex
mqm_uid=${1:-888}
test -f /usr/bin/yum && YUM=true || YUM=false
test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false
test -f /usr/bin/rpm && RPM=true || RPM=false test -f /usr/bin/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
# Only install the SDK package as part of the build stage # Download and extract the MQ installation files
INSTALL_SDK=${INSTALL_SDK:-0} DIR_EXTRACT=/tmp/mq
mkdir -p ${DIR_EXTRACT}
# Download and extract the MQ unzippable server cd ${DIR_EXTRACT}
DIR_TMP=/tmp/mq
mkdir -p ${DIR_TMP}
cd ${DIR_TMP}
curl -LO $MQ_URL curl -LO $MQ_URL
tar -zxf ./*.tar.gz
tar -xzf ./*.tar.gz # Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images
rm -f ./*.tar.gz groupadd --system --gid ${mqm_uid} mqm
ls -la ${DIR_TMP} useradd --system --uid ${mqm_uid} --gid mqm --groups 0 mqm
# Generate MQ package in INSTALLATION_DIR # Find directory containing .deb files
export genmqpkg_inc32=0 $UBUNTU && DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1)
export genmqpkg_incadm=1 $RPM && DIR_RPM=$(find ${DIR_EXTRACT} -name "*.rpm" -printf "%h\n" | sort -u | head -1)
export genmqpkg_incamqp=0 # Find location of mqlicense.sh
export genmqpkg_incams=1 MQLICENSE=$(find ${DIR_EXTRACT} -name "mqlicense.sh")
export genmqpkg_inccbl=0
export genmqpkg_inccics=0
export genmqpkg_inccpp=0
export genmqpkg_incdnet=0
export genmqpkg_incjava=1
export genmqpkg_incjre=1
export genmqpkg_incman=0
export genmqpkg_incmqbc=0
export genmqpkg_incmqft=0
export genmqpkg_incmqsf=0
export genmqpkg_incmqxr=0
export genmqpkg_incnls=1
export genmqpkg_incras=1
export genmqpkg_incsamp=1
export genmqpkg_incsdk=$INSTALL_SDK
export genmqpkg_inctls=1
export genmqpkg_incunthrd=0
export genmqpkg_incweb=1
export INSTALLATION_DIR=/opt/mqm
${DIR_TMP}/bin/genmqpkg.sh -b ${INSTALLATION_DIR}
ls -la ${INSTALLATION_DIR}
rm -rf ${DIR_TMP}
# Accept the MQ license # Accept the MQ license
${INSTALLATION_DIR}/bin/mqlicense -accept ${MQLICENSE} -text_only -accept
$UBUNTU && echo "deb [trusted=yes] file:${DIR_DEB} ./" > /etc/apt/sources.list.d/IBM_MQ.list
# Install MQ using the DEB packages
$UBUNTU && apt-get update
$UBUNTU && apt-get install -y $MQ_PACKAGES
$RPM && cd $DIR_RPM && rpm -ivh $MQ_PACKAGES
# Remove 32-bit libraries from 64-bit container
# The "file" utility isn't installed by default in UBI, so only try this if it's installed
which file && find /opt/mqm /var/mqm -type f -exec file {} \; | awk -F: '/ELF 32-bit/{print $1}' | xargs --no-run-if-empty rm -f
# Remove tar.gz files unpacked by RPM postinst scripts
find /opt/mqm -name '*.tar.gz' -delete
# Recommended: Set the default MQ installation (makes the MQ commands available on the PATH)
/opt/mqm/bin/setmqinst -p /opt/mqm -i
# Clean up all the downloaded files
$UBUNTU && rm -f /etc/apt/sources.list.d/IBM_MQ.list
rm -rf ${DIR_EXTRACT}
# 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
# Remove the directory structure under /var/mqm which was created by the installer
rm -rf /var/mqm
# Create the mount point for volumes, ensuring MQ has permissions to all directories # Create the mount point for volumes, ensuring MQ has permissions to all directories
install --directory --mode 2775 --owner 1001 --group root /mnt install --directory --mode 0775 --owner mqm --group root /mnt
install --directory --mode 2775 --owner 1001 --group root /mnt/mqm install --directory --mode 0775 --owner mqm --group root /mnt/mqm
install --directory --mode 2775 --owner 1001 --group root /mnt/mqm/data install --directory --mode 0775 --owner mqm --group root /mnt/mqm/data
install --directory --mode 2775 --owner 1001 --group root /mnt/mqm-log install --directory --mode 0775 --owner mqm --group root /mnt/mqm-log
install --directory --mode 2775 --owner 1001 --group root /mnt/mqm-log/log install --directory --mode 0775 --owner mqm --group root /mnt/mqm-log/log
install --directory --mode 2775 --owner 1001 --group root /mnt/mqm-data install --directory --mode 0775 --owner mqm --group root /mnt/mqm-data
install --directory --mode 2775 --owner 1001 --group root /mnt/mqm-data/qmgrs install --directory --mode 0775 --owner mqm --group root /mnt/mqm-data/qmgrs
# Create the directory for MQ configuration files # Create the directory for MQ configuration files
install --directory --mode 2775 --owner 1001 --group root /etc/mqm install --directory --mode 0775 --owner mqm --group root /etc/mqm
# Create the directory for MQ runtime files # Create the directory for MQ runtime files
install --directory --mode 2775 --owner 1001 --group root /run/mqm install --directory --mode 0775 --owner mqm --group root /run/mqm
# Create a symlink for /var/mqm -> /mnt/mqm/data # Create a symlink for /var/mqm -> /mnt/mqm/data
ln -s /mnt/mqm/data /var/mqm ln -s /mnt/mqm/data /var/mqm
@@ -90,7 +94,7 @@ ln -s /mnt/mqm/data /var/mqm
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' /etc/login.defs sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' /etc/login.defs
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' /etc/login.defs sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' /etc/login.defs
sed -i 's/PASS_MIN_LEN\t5/PASS_MIN_LEN\t8/' /etc/login.defs sed -i 's/PASS_MIN_LEN\t5/PASS_MIN_LEN\t8/' /etc/login.defs
$RPM && sed -i 's/# minlen/minlen/' /etc/security/pwquality.conf sed -i 's/# minlen = 9/minlen = 8/' /etc/security/pwquality.conf
$UBUNTU && PAM_FILE=/etc/pam.d/common-password $UBUNTU && PAM_FILE=/etc/pam.d/common-password
$RPM && PAM_FILE=/etc/pam.d/password-auth $RPM && PAM_FILE=/etc/pam.d/password-auth
@@ -100,9 +104,6 @@ sed -i 's/password\t\[success=1 default=ignore\]\tpam_unix\.so obscure sha512/pa
$RPM && rpm -q --all || true $RPM && rpm -q --all || true
$UBUNTU && dpkg --list || true $UBUNTU && dpkg --list || true
#Update the license file to include UBI 8 instead of UBI 7
sed -i 's/v7.0/v8.0/g' /opt/mqm/licenses/non_ibm_license.txt
# Copy MQ Licenses into the correct location # Copy MQ Licenses into the correct location
mkdir -p /licenses mkdir -p /licenses
cp /opt/mqm/licenses/*.txt /licenses/ cp /opt/mqm/licenses/*.txt /licenses/

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -20,20 +20,69 @@ package command
import ( import (
"fmt" "fmt"
"os/exec" "os/exec"
"os/user"
"runtime"
"strconv"
"syscall"
) )
// RunCmd runs an OS command. On Linux it waits for the command to
// complete and returns the exit status (return code).
// Do not use this function to run shell built-ins (like "cd"), because
// the error handling works differently
func RunCmd(cmd *exec.Cmd) (string, int, error) {
// Run the command and wait for completion
out, err := cmd.CombinedOutput()
if err != nil {
// Assert that this is an ExitError
exiterr, ok := err.(*exec.ExitError)
// If the type assertion was correct, and we're on Linux
if ok && runtime.GOOS == "linux" {
status, ok := exiterr.Sys().(syscall.WaitStatus)
if ok {
return string(out), status.ExitStatus(), fmt.Errorf("%v: %v", cmd.Path, err)
}
}
return string(out), -1, err
}
return string(out), 0, nil
}
// Run runs an OS command. On Linux it waits for the command to // Run runs an OS command. On Linux it waits for the command to
// complete and returns the exit status (return code). // complete and returns the exit status (return code).
// Do not use this function to run shell built-ins (like "cd"), because // Do not use this function to run shell built-ins (like "cd"), because
// the error handling works differently // the error handling works differently
func Run(name string, arg ...string) (string, int, error) { func Run(name string, arg ...string) (string, int, error) {
// Run the command and wait for completion // #nosec G204
return RunCmd(exec.Command(name, arg...))
}
// RunAsMQM runs the specified command as the mqm user
func RunAsMQM(name string, arg ...string) (string, int, error) {
// #nosec G204 // #nosec G204
cmd := exec.Command(name, arg...) cmd := exec.Command(name, arg...)
out, err := cmd.CombinedOutput() cmd.SysProcAttr = &syscall.SysProcAttr{}
rc := cmd.ProcessState.ExitCode() uid, gid, err := LookupMQM()
if err != nil { if err != nil {
return string(out), rc, fmt.Errorf("%v: %v", cmd.Path, err) return "", 0, err
} }
return string(out), rc, nil cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
return RunCmd(cmd)
}
// LookupMQM looks up the UID & GID of the mqm user
func LookupMQM() (int, int, error) {
mqm, err := user.Lookup("mqm")
if err != nil {
return -1, -1, err
}
mqmUID, err := strconv.Atoi(mqm.Uid)
if err != nil {
return -1, -1, err
}
mqmGID, err := strconv.Atoi(mqm.Gid)
if err != nil {
return -1, -1, err
}
return mqmUID, mqmGID, nil
} }

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -22,8 +22,8 @@ import (
"strings" "strings"
"github.com/ibm-messaging/mq-container/internal/containerruntime" "github.com/ibm-messaging/mq-container/internal/containerruntime"
"github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-container/internal/user" "github.com/ibm-messaging/mq-container/internal/user"
"github.com/ibm-messaging/mq-container/pkg/logger"
) )
// LogContainerDetails logs details about the container runtime // LogContainerDetails logs details about the container runtime
@@ -45,14 +45,11 @@ func LogContainerDetails(log *logger.Logger) error {
log.Printf("Base image: %v", bi) log.Printf("Base image: %v", bi)
} }
u, err := user.GetUser() u, err := user.GetUser()
if err != nil {
log.Printf("Error: %v\nUser:\n uid: %v\n gid: %v\n supGid: %v", err, u.UID, u.PrimaryGID, u.SupplementalGID)
}
if err == nil { if err == nil {
if len(u.SupplementalGID) == 0 { if len(u.SupplementalGID) == 0 {
log.Printf("Running as user ID %v with primary group %v", u.UID, u.PrimaryGID) log.Printf("Running as user ID %v (%v) with primary group %v", u.UID, u.Name, u.PrimaryGID)
} else { } else {
log.Printf("Running as user ID %v with primary group %v, and supplementary groups %v", u.UID, u.PrimaryGID, strings.Trim(strings.Join(strings.Fields(fmt.Sprint(u.SupplementalGID)), ","), "[]")) log.Printf("Running as user ID %v (%v) with primary group %v, and supplementary groups %v", u.UID, u.Name, u.PrimaryGID, strings.Join(u.SupplementalGID, ","))
} }
} }
caps, err := containerruntime.GetCapabilities() caps, err := containerruntime.GetCapabilities()

View File

@@ -1,153 +0,0 @@
/*
© Copyright IBM Corporation 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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.
*/
//This is a developer only configuration and not recommended for production usage.
package htpasswd
import (
"fmt"
"io/ioutil"
"strings"
"golang.org/x/crypto/bcrypt"
)
type mapHtPasswd map[string]string
func encryptPassword(password string) (string, error) {
passwordBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(passwordBytes), nil
}
// SetPassword sets encrypted password for the user into htpasswd file
func SetPassword(user string, password string, isTest bool) error {
if len(strings.TrimSpace(user)) == 0 || len(strings.TrimSpace(password)) == 0 {
return fmt.Errorf("UserId or Password are empty")
}
passwords := mapHtPasswd(map[string]string{})
// Read the password file
err := passwords.ReadHtPasswordFile(isTest)
if err != nil {
return err
}
pwd, err := encryptPassword(password)
if err != nil {
return err
}
// Set the new password
passwords[user] = pwd
// Update the password file
return passwords.updateHtPasswordFile(isTest)
}
// GetBytes return the Bytes representation of the htpassword file
func (htpfile mapHtPasswd) GetBytes() (passwordBytes []byte) {
passwordBytes = []byte{}
for name, hash := range htpfile {
passwordBytes = append(passwordBytes, []byte(name+":"+hash+"\n")...)
}
return passwordBytes
}
// ReadHtPasswordFile parses the htpasswd file
func (htpfile mapHtPasswd) ReadHtPasswordFile(isTest bool) error {
file := "/etc/mqm/mq.htpasswd"
if isTest {
file = "my.htpasswd"
}
pwdsBytes, err := ioutil.ReadFile(file)
if err != nil {
return err
}
lines := strings.Split(string(pwdsBytes), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if len(line) == 0 {
continue
}
parts := strings.Split(line, ":")
if len(parts) != 2 {
continue
}
for i, part := range parts {
parts[i] = strings.TrimSpace(part)
}
htpfile[parts[0]] = parts[1]
}
return nil
}
func (htpfile mapHtPasswd) updateHtPasswordFile(isTest bool) error {
file := "/etc/mqm/mq.htpasswd"
if isTest {
file = "my.htpasswd"
}
return ioutil.WriteFile(file, htpfile.GetBytes(), 0660)
}
// AuthenticateUser verifies if the given user password match with htpasswrd
func AuthenticateUser(user string, password string, isTest bool) (bool, bool, error) {
passwords := mapHtPasswd(map[string]string{})
if len(strings.TrimSpace(user)) == 0 || len(strings.TrimSpace(password)) == 0 {
return false, false, fmt.Errorf("UserId or Password are empty")
}
err := passwords.ReadHtPasswordFile(isTest)
if err != nil {
return false, false, err
}
ok := false
value, found := passwords[user]
if !found {
return found, ok, fmt.Errorf("User not found in the mq.htpasswd file")
}
err = bcrypt.CompareHashAndPassword([]byte(value), []byte(password))
return found, err == nil, err
}
// ValidateUser validates the given user
func ValidateUser(user string, isTest bool) (bool, error) {
passwords := mapHtPasswd(map[string]string{})
if len(strings.TrimSpace(user)) == 0 {
return false, fmt.Errorf("Userid is empty for AuthenticateUser")
}
err := passwords.ReadHtPasswordFile(isTest)
if err != nil {
return false, err
}
_, found := passwords[strings.TrimSpace(user)]
return found, nil
}

View File

@@ -1,62 +0,0 @@
/*
© Copyright IBM Corporation 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 htpasswd
import (
"testing"
)
// TestCheckUser verifies Htpassword's use
func TestCheckUser(t *testing.T) {
err := SetPassword("guest", "guestpw", true)
if err != nil {
t.Fatalf("htpassword test failed due to error:%s\n", err.Error())
}
found, ok, err := AuthenticateUser("guest", "guestpw", true)
if err != nil {
t.Fatalf("htpassword test1 failed as user could not be found:%s\n", err.Error())
}
if found == false || ok == false {
t.Fatalf("htpassword test1 failed as user could not be found:%v, ok:%v\n", found, ok)
}
found, ok, err = AuthenticateUser("myguest", "guestpw", true)
if err == nil {
t.Fatalf("htpassword test2 failed as no error received for non-existing user\n")
}
if found == true || ok == true {
t.Fatalf("htpassword test2 failed for non-existing user found :%v, ok:%v\n", found, ok)
}
found, ok, err = AuthenticateUser("guest", "guest", true)
if err == nil {
t.Fatalf("htpassword test3 failed as incorrect password of user did not return error\n")
}
if found == false || ok == true {
t.Fatalf("htpassword test3 failed for existing user with incorrect passwored found :%v, ok:%v\n", found, ok)
}
found, err = ValidateUser("guest", true)
if err != nil || found == false {
t.Fatalf("htpassword test4 failed as user could not be found:%v, ok:%v\n", found, ok)
}
found, err = ValidateUser("myguest", true)
if err != nil || found == true {
t.Fatalf("htpassword test5 failed as non-existing user returned to be found:%v, ok:%v\n", found, ok)
}
}

View File

@@ -1 +0,0 @@
guest:$2y$05$ifFP0nCmFed6.m4iB9CHRuHFps2YeeuwopmOvszWt0GRnN59p8qxW

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2020 © 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.
@@ -105,6 +105,14 @@ func (ks *KeyStore) Create() error {
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)
} }
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return err
}
err = os.Chown(ks.Filename, mqmUID, mqmGID)
if err != nil {
return err
}
return nil return nil
} }
@@ -122,6 +130,14 @@ func (ks *KeyStore) CreateStash() error {
} }
return err return err
} }
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return err
}
err = os.Chown(stashFile, mqmUID, mqmGID)
if err != nil {
return err
}
return nil return nil
} }
@@ -136,7 +152,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", "-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)
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)
} }
@@ -191,7 +207,7 @@ func (ks *KeyStore) RenameCertificate(from, to string) error {
// #nosec G204 // #nosec G204
cmd := exec.Command("/opt/mqm/gskit8/bin/gsk8capicmd_64", "-cert", "-rename", "-db", ks.Filename, "-pw", ks.Password, "-label", from, "-new_label", to) cmd := exec.Command("/opt/mqm/gskit8/bin/gsk8capicmd_64", "-cert", "-rename", "-db", ks.Filename, "-pw", ks.Password, "-label", from, "-new_label", to)
cmd.Env = append(os.Environ(), "LD_LIBRARY_PATH=/opt/mqm/gskit8/lib64/:/opt/mqm/gskit8/lib") cmd.Env = append(os.Environ(), "LD_LIBRARY_PATH=/opt/mqm/gskit8/lib64/:/opt/mqm/gskit8/lib")
out, err := cmd.CombinedOutput() out, _, err := command.RunCmd(cmd)
if err != nil { if err != nil {
return fmt.Errorf("error running \"%v -cert -rename\": %v %s", "/opt/mqm/gskit8/bin/gsk8capicmd_64", err, out) return fmt.Errorf("error running \"%v -cert -rename\": %v %s", "/opt/mqm/gskit8/bin/gsk8capicmd_64", err, out)
} }

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2019 © 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.

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2019 © 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.
@@ -18,7 +18,7 @@ limitations under the License.
package metrics package metrics
import ( import (
"github.com/ibm-messaging/mq-container/pkg/logger" "github.com/ibm-messaging/mq-container/internal/logger"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )

View File

@@ -23,10 +23,9 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-container/internal/ready" "github.com/ibm-messaging/mq-container/internal/ready"
"github.com/ibm-messaging/mq-container/pkg/logger"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
) )
const ( const (
@@ -84,7 +83,7 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
} }
// Setup HTTP server to handle requests from Prometheus // Setup HTTP server to handle requests from Prometheus
http.Handle("/metrics", promhttp.Handler()) http.Handle("/metrics", prometheus.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200) w.WriteHeader(200)
// #nosec G104 // #nosec G104

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2019 © 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.
@@ -22,7 +22,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/ibm-messaging/mq-container/pkg/logger" "github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-golang/ibmmq" "github.com/ibm-messaging/mq-golang/ibmmq"
"github.com/ibm-messaging/mq-golang/mqmetric" "github.com/ibm-messaging/mq-golang/mqmetric"
) )

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2019 © 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.
@@ -19,7 +19,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/ibm-messaging/mq-container/pkg/logger" "github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-golang/mqmetric" "github.com/ibm-messaging/mq-golang/mqmetric"
) )

20
internal/mqini/mqat.ini Normal file
View File

@@ -0,0 +1,20 @@
#*******************************************************************#
#* Module Name: mqat.ini *#
#* Type : IBM MQ queue manager configuration file *#
# Function : Define the configuration of application activity *#
#* trace for a single queue manager. *#
#*******************************************************************#
# Global settings stanza, default values
AllActivityTrace:
ActivityInterval=1
ActivityCount=100
TraceLevel=MEDIUM
TraceMessageData=0
StopOnGetTraceMsg=ON
SubscriptionDelivery=BATCHED
# Prevent the sample activity trace program from generating data
ApplicationTrace:
ApplName=amqsact*
Trace=OFF

328
internal/mqini/mqini.go Normal file
View File

@@ -0,0 +1,328 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 mqini provides information about queue managers
package mqini
import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
// QueueManager describe high-level configuration information for a queue manager
type QueueManager struct {
Name string
Prefix string
Directory string
DataPath string
InstallationName string
}
var qmgrDir string
var stanzasQMINI []string
var stanzasMQATINI []string
// getQueueManagerFromStanza parses a queue manager stanza
func getQueueManagerFromStanza(stanza string) (*QueueManager, error) {
scanner := bufio.NewScanner(strings.NewReader(stanza))
qm := QueueManager{}
for scanner.Scan() {
l := scanner.Text()
l = strings.TrimSpace(l)
t := strings.Split(l, "=")
switch t[0] {
case "Name":
qm.Name = t[1]
case "Prefix":
qm.Prefix = t[1]
case "Directory":
qm.Directory = t[1]
case "DataPath":
qm.DataPath = t[1]
case "InstallationName":
qm.InstallationName = t[1]
}
}
return &qm, scanner.Err()
}
// GetQueueManager returns queue manager configuration information
func GetQueueManager(name string) (*QueueManager, error) {
// dspmqinf essentially returns a subset of mqs.ini, but it's simpler to parse
out, _, err := command.Run("dspmqinf", "-o", "stanza", name)
if err != nil {
return nil, err
}
return getQueueManagerFromStanza(out)
}
// GetErrorLogDirectory returns the directory holding the error logs for the
// specified queue manager
func GetErrorLogDirectory(qm *QueueManager) string {
if qm.DataPath != "" {
return filepath.Join(qm.DataPath, "errors")
}
return filepath.Join(qm.Prefix, "qmgrs", qm.Directory, "errors")
}
//AddStanzas Reads supplied mq ini configuration files and updates the stanzas
//into queue manager's ini configuration files.
func AddStanzas(qmname string) error {
//find the qmgr directory.
qm, err := GetQueueManager(qmname)
if err != nil {
return err
}
qmgrDir = filepath.Join(qm.Prefix, "qmgrs", qm.Directory)
//Find the users ini configuration file
files := getIniFileList()
if len(files) > 1 {
msg := fmt.Sprintf("[ %v ]", files)
return errors.New("Only a single ini file can be provided. Following ini files are found:" + msg)
}
if len(files) == 0 {
//no ini file update required.
return nil
}
iniFileBytes, err := ioutil.ReadFile(files[0])
if err != nil {
return err
}
userconfig := string(iniFileBytes)
if len(userconfig) == 0 {
return nil
}
//Prepare a list of all supported stanzas
PopulateAllAvailableStanzas()
//Update the qmgr ini file with user config.
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
return err
}
err = writeConfigStanzas(qmConfig, atConfig)
if err != nil {
return err
}
return nil
}
// PopulateAllAvailableStanzas initializes the ini stanzas prescribed by mq specification.
func PopulateAllAvailableStanzas() {
stanzasQMINI = []string{"ExitPath",
"Log",
"Service",
"ServiceComponent",
"Channels",
"TCP",
"ApiExitLocal",
"AccessMode",
"RestrictedMode",
"XAResourceManager",
"DefaultBindType",
"SSL",
"DiagnosticMessages",
"Filesystem",
"Security",
"TuningParameters",
"ExitPropertiesLocal",
"LU62",
"NETBIOS"}
stanzasMQATINI = []string{"AllActivityTrace", "ApplicationTrace"}
}
// getIniFileList Checks for the user supplied ini file in /etc/mqm directory.
func getIniFileList() []string {
fileList := []string{}
filepath.Walk("/etc/mqm", func(path string, f os.FileInfo, err error) error {
if strings.HasSuffix(path, ".ini") {
fileList = append(fileList, path)
}
return nil
})
return fileList
}
//PrepareConfigStanzasToWrite Reads through the user supplied ini config file and prepares list of
//updates to be written into corresponding mq ini files (qm.ini and/or mqat.ini files.)
func PrepareConfigStanzasToWrite(userconfig string) (string, string, error) {
var qminiConfigStr string
var mqatiniConfigStr string
//read the initial version.
iniFileBytes, err := ioutil.ReadFile(filepath.Join(qmgrDir, "qm.ini"))
if err != nil {
return "", "", err
}
qminiConfigStr = string(iniFileBytes)
iniFileBytes, err = ioutil.ReadFile(filepath.Join(qmgrDir, "mqat.ini"))
if err != nil {
return "", "", err
}
mqatiniConfigStr = string(iniFileBytes)
stanzaListMerge := make(map[string]strings.Builder)
stanzaListAppend := make(map[string]strings.Builder)
var sbAppend strings.Builder
var sbMerger strings.Builder
scanner := bufio.NewScanner(strings.NewReader(userconfig))
scanner.Split(bufio.ScanLines)
consumetoAppend := false
consumeToMerge := false
var stanza string
//read through the user file and prepare what we want.
for scanner.Scan() {
if strings.Contains(scanner.Text(), ":") {
consumetoAppend = false
consumeToMerge = false
stanza = scanner.Text()
//check if this stanza exists in the qm.ini/mqat.ini files
if strings.Contains(qminiConfigStr, stanza) ||
(strings.Contains(mqatiniConfigStr, stanza) && !(strings.Contains(stanza, "ApplicationTrace"))) {
consumeToMerge = true
sbMerger = strings.Builder{}
stanzaListMerge[stanza] = sbMerger
} else {
consumetoAppend = true
sbAppend = strings.Builder{}
stanzaListAppend[stanza] = sbAppend
}
} else {
if consumetoAppend {
sb := stanzaListAppend[stanza]
sb.WriteString(scanner.Text() + "\n")
stanzaListAppend[stanza] = sb
}
if consumeToMerge {
sb := stanzaListMerge[stanza]
sb.WriteString(scanner.Text() + "\n")
stanzaListMerge[stanza] = sb
}
}
}
//merge if stanza exits.
if len(stanzaListMerge) > 0 {
for key := range stanzaListMerge {
toWrite, filename := ValidateStanzaToWrite(key)
if toWrite {
attrList := stanzaListMerge[key]
switch filename {
case "qm.ini":
qminiConfigStr = prepareStanzasToMerge(key, attrList, qminiConfigStr)
case "mqat.ini":
mqatiniConfigStr = prepareStanzasToMerge(key, attrList, mqatiniConfigStr)
default:
}
}
}
}
//append new stanzas.
if len(stanzaListAppend) > 0 {
for key := range stanzaListAppend {
attrList := stanzaListAppend[key]
if strings.Contains(strings.Join(stanzasMQATINI, ", "), strings.TrimSuffix(strings.TrimSpace(key), ":")) {
mqatiniConfigStr = prepareStanzasToAppend(key, attrList, mqatiniConfigStr)
} else {
qminiConfigStr = prepareStanzasToAppend(key, attrList, qminiConfigStr)
}
}
}
return qminiConfigStr, mqatiniConfigStr, nil
}
//ValidateStanzaToWrite Validates stanza to be written and the file it belongs to.
func ValidateStanzaToWrite(stanza string) (bool, string) {
stanza = strings.TrimSpace(stanza)
if strings.Contains(stanza, ":") {
stanza = stanza[:len(stanza)-1]
}
if strings.Contains(strings.Join(stanzasQMINI, ", "), stanza) {
return true, "qm.ini"
} else if strings.Contains(strings.Join(stanzasMQATINI, ", "), stanza) {
return true, "mqat.ini"
} else {
return false, ""
}
}
//prepareStanzasToAppend Prepares list of stanzas that are to be appended into qm ini files(qm.ini/mqat.ini)
func prepareStanzasToAppend(key string, attrList strings.Builder, iniConfig string) string {
newVal := key + "\n" + attrList.String()
iniConfig = iniConfig + newVal
return iniConfig
}
//prepareStanzasToMerge Prepares list of stanzas that are to be updated into qm ini files(qm.ini/mqat.ini)
//These stanzas are already present in mq ini files and their values have to be updated with user supplied ini.
func prepareStanzasToMerge(key string, attrList strings.Builder, iniConfig string) string {
lineScanner := bufio.NewScanner(strings.NewReader(attrList.String()))
lineScanner.Split(bufio.ScanLines)
for lineScanner.Scan() {
attrLine := lineScanner.Text()
keyvalue := strings.Split(attrLine, "=")
//this line present in qm.ini, update value.
if strings.Contains(iniConfig, keyvalue[0]) {
re := regexp.MustCompile(keyvalue[0] + "=.*")
iniConfig = re.ReplaceAllString(iniConfig, attrLine)
} else { //this line not present in qm.ini file, add it.
re := regexp.MustCompile(key)
newVal := key + "\n" + attrLine
iniConfig = re.ReplaceAllString(iniConfig, newVal)
}
}
return iniConfig
}
//writeConfigStanzas Writes the ini file updates into corresponding mq ini files.
func writeConfigStanzas(qmConfig string, atConfig string) error {
err := ioutil.WriteFile(filepath.Join(qmgrDir, "qm.ini"), []byte(qmConfig), 0644)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(qmgrDir, "mqat.ini"), []byte(atConfig), 0644)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,202 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 mqini
import (
"bufio"
"io/ioutil"
"strings"
"testing"
)
var getQueueManagerTests = []struct {
file string
name string
prefix string
directory string
errorLogDir string
}{
{"dspmqinf1.txt", "foo", "/var/mqm", "foo", "/var/mqm/qmgrs/foo/errors"},
{"dspmqinf2.txt", "a/b", "/var/mqm", "a&b", "/var/mqm/qmgrs/a&b/errors"},
{"dspmqinf3.txt", "..", "/var/mqm", "!!", "/var/mqm/qmgrs/!!/errors"},
}
func TestGetQueueManager(t *testing.T) {
for _, table := range getQueueManagerTests {
t.Run(table.file, func(t *testing.T) {
b, err := ioutil.ReadFile(table.file)
if err != nil {
t.Fatal(err)
}
qm, err := getQueueManagerFromStanza(string(b))
if err != nil {
t.Fatal(err)
}
t.Logf("%#v", qm)
if qm.Name != table.name {
t.Errorf("Expected name=%v; got %v", table.name, qm.Name)
}
if qm.Prefix != table.prefix {
t.Errorf("Expected prefix=%v; got %v", table.prefix, qm.Prefix)
}
if qm.Directory != table.directory {
t.Errorf("Expected directory=%v; got %v", table.directory, qm.Directory)
}
// Test
d := GetErrorLogDirectory(qm)
if d != table.errorLogDir {
t.Errorf("Expected error log directory=%v; got %v", table.errorLogDir, d)
}
})
}
}
func TestIniFileStanzas(t *testing.T) {
PopulateAllAvailableStanzas()
checkReturns("ApiExitLocal", true, true, t)
checkReturns("Channels", true, true, t)
checkReturns("TCP", true, true, t)
checkReturns("ServiceComponent", true, true, t)
checkReturns("Service", true, true, t)
checkReturns("AccessMode", true, true, t)
checkReturns("RestrictedMode", true, true, t)
checkReturns("XAResourceManager", true, true, t)
checkReturns("SSL", true, true, t)
checkReturns("Security", true, true, t)
checkReturns("TuningParameters", true, true, t)
checkReturns("ABC", false, false, t)
checkReturns("#1234ABD", true, false, t)
checkReturns("AllActivityTrace", false, true, t)
checkReturns("ApplicationTrace", false, true, t)
checkReturns("xyz123abvc", false, false, t)
}
func TestIniFile1Update(t *testing.T) {
iniFileBytes, err := ioutil.ReadFile("test1qm.ini")
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
userconfig := string(iniFileBytes)
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(atConfig) == 0 {
t.Errorf("Unexpected stanza file update: mqat.ini[%s]\n", atConfig)
}
if len(qmConfig) == 0 {
t.Errorf("Expected stanza file not found: qm.ini\n")
}
scanner := bufio.NewScanner(strings.NewReader(userconfig))
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
if !strings.Contains(qmConfig, line) {
t.Errorf("Expected stanza line not found in updated string. line=%s\n, Stanza:%s\n", line, qmConfig)
break
}
}
}
func TestIniFile2Update(t *testing.T) {
iniFileBytes, err := ioutil.ReadFile("test2qm.ini")
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
userconfig := string(iniFileBytes)
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(atConfig) == 0 {
t.Errorf("Expected stanza file not found: mqat.ini\n")
}
if len(qmConfig) == 0 {
t.Errorf("Expected stanza file not found: qm.ini\n")
}
scanner := bufio.NewScanner(strings.NewReader(userconfig))
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
if !strings.Contains(atConfig, line) {
t.Errorf("Expected stanza line not found in updated string. line=%s\n, Stanza:%s\n", line, qmConfig)
break
}
}
}
func TestIniFile3Update(t *testing.T) {
i := 0
iniFileBytes, err := ioutil.ReadFile("test3qm.ini")
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
userconfig := string(iniFileBytes)
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(qmConfig) == 0 {
t.Errorf("Unexpected stanza file update: qm.ini[%s]\n", atConfig)
}
if len(atConfig) == 0 {
t.Errorf("Expected stanza file not found: mqat.ini\n")
}
scanner := bufio.NewScanner(strings.NewReader(userconfig))
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
i++
//first 20 lines of test3qm.ini shall go into qm.ini file and rest into mqat.ini file.
if i < 20 {
if !strings.Contains(qmConfig, line) {
t.Errorf("Expected stanza line not found in updated string. line=%s\n, Stanza:%s\n", line, qmConfig)
}
} else if i > 20 {
if !strings.Contains(atConfig, line) {
t.Errorf("Expected stanza line not found in updated string. line=%s\n, Stanza:%s\n", line, qmConfig)
}
}
}
}
func checkReturns(stanza string, isqmini bool, shouldexist bool, t *testing.T) {
exists, filename := ValidateStanzaToWrite(stanza)
if exists != shouldexist {
t.Errorf("Stanza should exist %t but found was %t", shouldexist, exists)
}
if shouldexist {
if isqmini {
if filename != "qm.ini" {
t.Errorf("Expected filename:qm.ini for stanza:%s. But got %s", stanza, filename)
}
} else {
if filename != "mqat.ini" {
t.Errorf("Expected filename:mqat.ini for stanza:%s. But got %s", stanza, filename)
}
}
}
}

45
internal/mqini/qm.ini Normal file
View File

@@ -0,0 +1,45 @@
#*******************************************************************#
#* Module Name: qm.ini *#
#* Type : IBM MQ queue manager configuration file *#
# Function : Define the configuration of a single queue manager *#
#* *#
#*******************************************************************#
#* Notes : *#
#* 1) This file defines the configuration of the queue manager *#
#* *#
#*******************************************************************#
ExitPath:
ExitsDefaultPath=C:\ProgramData\IBM\MQ\exits
ExitsDefaultPath64=C:\ProgramData\IBM\MQ\exits64
InstanceData:
InstanceID=1562831591
Startup=ServiceManual
#* *#
#* *#
Log:
LogPrimaryFiles=3
LogSecondaryFiles=2
LogFilePages=4096
LogType=CIRCULAR
LogBufferPages=0
LogPath=C:\ProgramData\IBM\MQ\log\INI1\
LogWriteIntegrity=TripleWrite
Service:
Name=AuthorizationService
EntryPoints=14
ServiceComponent:
Service=AuthorizationService
Name=MQSeries.WindowsNT.auth.service
Module=amqzfu.dll
ComponentDataSize=0
Channels:
ChlauthEarlyAdopt=Y
TCP:
SndBuffSize=0
RcvBuffSize=0
RcvSndBuffSize=0
RcvRcvBuffSize=0
ClntSndBuffSize=0
ClntRcvBuffSize=0
SvrSndBuffSize=0
SvrRcvBuffSize=0

View File

@@ -0,0 +1,5 @@
ApiExitLocal:   
Sequence=1
Function=EntryPoint
Module=/opt/mylibs/mylib.so
Name=mylib

View File

@@ -0,0 +1,7 @@
AllActivityTrace:
ActivityInterval=11
ActivityCount=1
TraceLevel=INFO
ApplicationTrace:
ApplName=amqsget
Trace=ON

View File

@@ -0,0 +1,23 @@
ApiExitLocal:   
Sequence=1
Function=EntryPoint
Module=/opt/MQOpenTracing/MQOpenTracingExit.so
Name=MQOpenTracingExit
Channels:
MQIBindType=FASTPATH
Log:
LogPrimaryFiles=30
LogType=CIRCULAR
LogPath=/ProgramfILES/IBM/MQ/log/INI1/
TCP:
SndBuffSize=4095
RcvBuffSize=4095
RcvSndBuffSize=4095
RcvRcvBuffSize=4095
ClntSndBuffSize=2049
ClntRcvBuffSize=2049
SvrSndBuffSize=2049
SvrRcvBuffSize=2049
ApplicationTrace:
ApplName=amqsput
Trace=ON

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2020 © 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.
@@ -22,7 +22,8 @@ import (
"path" "path"
"text/template" "text/template"
"github.com/ibm-messaging/mq-container/pkg/logger" "github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/logger"
) )
// ProcessTemplateFile takes a Go templateFile, and processes it with the // ProcessTemplateFile takes a Go templateFile, and processes it with the
@@ -44,6 +45,16 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
log.Error(err) log.Error(err)
return err return err
} }
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
log.Error(err)
return err
}
err = os.Chown(dir, mqmUID, mqmGID)
if err != nil {
log.Error(err)
return err
}
} else { } else {
return err return err
} }
@@ -56,5 +67,15 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
log.Error(err) log.Error(err)
return err return err
} }
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
log.Error(err)
return err
}
err = os.Chown(destFile, mqmUID, mqmGID)
if err != nil {
log.Error(err)
return err
}
return nil return nil
} }

View File

@@ -1,51 +0,0 @@
/*
© Copyright IBM Corporation 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 mqversion
import (
"fmt"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
// Get will return the current MQ version
func Get() (string, error) {
mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
if err != nil {
return "", fmt.Errorf("Error Getting MQ version: %v", err)
}
return strings.TrimSpace(mqVersion), nil
}
// Compare returns an integer comparing two MQ version strings lexicographically. The result will be 0 if currentVersion==checkVersion, -1 if currentVersion < checkVersion, and +1 if currentVersion > checkVersion
func Compare(checkVersion string) (int, error) {
currentVersion, err := Get()
if err != nil {
return 0, err
}
// trim any suffix from MQ version x.x.x.x
currentVersion = currentVersion[0:7]
if currentVersion < checkVersion {
return -1, nil
} else if currentVersion == checkVersion {
return 0, nil
} else if currentVersion > checkVersion {
return 1, nil
}
return 0, fmt.Errorf("Failed to compare MQ versions")
}

View File

@@ -1,55 +0,0 @@
/*
© Copyright IBM Corporation 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 mqversion
import "testing"
func TestCompareLower(t *testing.T) {
checkVersion := "9.9.9.9"
mqVersionCheck, err := Compare(checkVersion)
if err != nil {
t.Fatalf("Failed to compare MQ versions: %v", err)
}
if mqVersionCheck != -1 {
t.Errorf("MQ version compare result failed. Expected -1, Got %v", mqVersionCheck)
}
}
func TestCompareHigher(t *testing.T) {
checkVersion := "1.1.1.1"
mqVersionCheck, err := Compare(checkVersion)
if err != nil {
t.Fatalf("Failed to compare MQ versions: %v", err)
}
if mqVersionCheck != 1 {
t.Errorf("MQ version compare result failed. Expected 1, Got %v", mqVersionCheck)
}
}
func TestCompareEqual(t *testing.T) {
checkVersion, err := Get()
if err != nil {
t.Fatalf("Failed to get current MQ version: %v", err)
}
mqVersionCheck, err := Compare(checkVersion)
if err != nil {
t.Fatalf("Failed to compare MQ versions: %v", err)
}
if mqVersionCheck != 0 {
t.Errorf("MQ version compare result failed. Expected 0, Got %v", mqVersionCheck)
}
}

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2019 © Copyright IBM Corporation 2017
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.

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2019 © Copyright IBM Corporation 2017
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.

View File

@@ -1,299 +0,0 @@
/*
© Copyright IBM Corporation 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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.
*/
//This is a developer only configuration and not recommended for production usage.
package main
/*
#cgo !windows CFLAGS: -I/opt/mqm/lib64 -D_REENTRANT
#cgo !windows,!darwin LDFLAGS: -L/opt/mqm/lib64 -lmqm_r -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64
#cgo darwin LDFLAGS: -L/opt/mqm/lib64 -lmqm_r -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64
#cgo windows CFLAGS: -I"C:/Program Files/IBM/MQ/Tools/c/include"
#cgo windows LDFLAGS: -L "C:/Program Files/IBM/MQ/bin64" -lmqm
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cmqc.h>
#include <cmqxc.h>
#include <cmqzc.h>
#include <cmqec.h>
#include <time.h>
static MQZ_INIT_AUTHORITY PASStart;
static MQZ_AUTHENTICATE_USER OAAuthUser;
static MQZ_FREE_USER OAFreeUser;
static MQZ_TERM_AUTHORITY OATermAuth;
extern int Authenticate(char *, char *);
extern int CheckAuthority(char *);
static char *OAEnvStr(MQLONG);
static void FindSize();
static void PrintDateTime();
static FILE *fp = NULL;
static int primary_process = 0;
static void MQENTRY PASStart(
MQHCONFIG hc,
MQLONG Options,
MQCHAR48 QMgrName,
MQLONG ComponentDataLength,
PMQBYTE ComponentData,
PMQLONG Version,
PMQLONG pCompCode,
PMQLONG pReason) {
MQLONG CC = MQCC_OK;
MQLONG Reason = MQRC_NONE;
if ((Options & MQZIO_PRIMARY) == MQZIO_PRIMARY)
primary_process = 1;
fp=fopen("/var/mqm/errors/amqpasdev.log","a");
if (CC == MQCC_OK)
hc->MQZEP_Call(hc, MQZID_INIT_AUTHORITY,(PMQFUNC)PASStart,&CC,&Reason);
if (CC == MQCC_OK)
hc->MQZEP_Call(hc,MQZID_TERM_AUTHORITY,(PMQFUNC)OATermAuth,&CC,&Reason);
if (CC == MQCC_OK)
hc->MQZEP_Call(hc,MQZID_AUTHENTICATE_USER,(PMQFUNC)OAAuthUser,&CC,&Reason);
if (CC == MQCC_OK)
hc->MQZEP_Call(hc,MQZID_FREE_USER,(PMQFUNC)OAFreeUser,&CC,&Reason);
*Version = MQZAS_VERSION_5;
*pCompCode = CC;
*pReason = Reason;
PrintDateTime();
fprintf(fp, "Pluggable OAM Initialized.\n");
fprintf(fp, "THIS IS A DEVELOPER ONLY CONFIGURATION AND NOT RECOMMENDED FOR PRODUCTION USAGE");
return;
}
static char *authuserfmt =
"\tUser : \"%12.12s\"\n"\
"\tEffUser : \"%12.12s\"\n"\
"\tAppName : \"%28.28s\"\n"\
"\tApIdDt : \"%32.32s\"\n"\
"\tEnv : \"%s\"\n"\
"\tApp Pid : %d\n"\
"\tApp Tid : %d\n"\
;
static void MQENTRY OAAuthUser (
PMQCHAR pQMgrName,
PMQCSP pSecurityParms,
PMQZAC pApplicationContext,
PMQZIC pIdentityContext,
PMQPTR pCorrelationPtr,
PMQBYTE pComponentData,
PMQLONG pContinuation,
PMQLONG pCompCode,
PMQLONG pReason)
{
char *spuser = NULL;
char *sppass = NULL;
int gorc = MQRC_NOT_AUTHORIZED;
if ((pSecurityParms->CSPUserIdLength) > 0) {
//Grab the user creds from csp.
spuser = malloc(pSecurityParms->CSPUserIdLength+1);
strncpy(spuser,pSecurityParms->CSPUserIdPtr,pSecurityParms->CSPUserIdLength);
spuser[pSecurityParms->CSPUserIdLength]=0;
sppass = malloc(pSecurityParms->CSPPasswordLength+1);
strncpy(sppass,pSecurityParms->CSPPasswordPtr,pSecurityParms->CSPPasswordLength);
sppass[pSecurityParms->CSPPasswordLength]=0;
gorc = Authenticate(spuser,sppass);
if (gorc == MQRC_NONE) {
*pCompCode = MQCC_OK;
*pReason = MQRC_NONE;
*pContinuation = MQZCI_CONTINUE;
memcpy( pIdentityContext->UserIdentifier
, spuser
, sizeof(pIdentityContext->UserIdentifier) );
} else {
*pCompCode = MQCC_WARNING;
*pReason = MQRC_NONE;
*pContinuation = MQZCI_CONTINUE;
//we print to error file only if error'd
PrintDateTime();
if (fp) {
fprintf(fp, authuserfmt,
pIdentityContext->UserIdentifier,
pApplicationContext->EffectiveUserID,
pApplicationContext->ApplName,
pIdentityContext->ApplIdentityData,
OAEnvStr(pApplicationContext->Environment),
pApplicationContext->ProcessId,
pApplicationContext->ThreadId);
fprintf(fp,"\tCSP UserId : %s\n", spuser);
fprintf(fp,"\tCSP Password : %s\n", "****..");
fprintf(fp,"\tPAS-Compcode:%d\n",*pCompCode);
fprintf(fp,"\tPAS-Reasoncode:%d\n",*pReason);
}
}
free(spuser);
free(sppass);
} else {
//this is only a normal UID authentication.
spuser = malloc(sizeof(PMQCHAR12));
strncpy(spuser,pApplicationContext->EffectiveUserID,strlen(pApplicationContext->EffectiveUserID));
spuser[sizeof(PMQCHAR12)]=0;
gorc = CheckAuthority(spuser);
if (gorc == MQRC_NONE){
*pCompCode = MQCC_OK;
*pReason = MQRC_NONE;
*pContinuation = MQZCI_CONTINUE;
memcpy( pIdentityContext->UserIdentifier
, spuser
, sizeof(pIdentityContext->UserIdentifier) );
} else {
*pCompCode = MQCC_WARNING;
*pReason = MQRC_NONE;
*pContinuation = MQZCI_CONTINUE;
//we print only if error'd
PrintDateTime();
if (fp)
{
fprintf(fp, authuserfmt,
pIdentityContext->UserIdentifier,
pApplicationContext->EffectiveUserID,
pApplicationContext->ApplName,
pIdentityContext->ApplIdentityData,
OAEnvStr(pApplicationContext->Environment),
pApplicationContext->ProcessId,
pApplicationContext->ThreadId
);
fprintf(fp,"\tUID : %s\n", spuser);
fprintf(fp,"\tPAS-Compcode:%d\n",*pCompCode);
fprintf(fp,"\tPAS-Reasoncode:%d\n",*pReason);
}
}
}
return;
}
static void MQENTRY OAFreeUser (
PMQCHAR pQMgrName,
PMQZFP pFreeParms,
PMQBYTE pComponentData,
PMQLONG pContinuation,
PMQLONG pCompCode,
PMQLONG pReason)
{
*pCompCode = MQCC_WARNING;
*pReason = MQRC_NONE;
*pContinuation = MQZCI_CONTINUE;
return;
}
static void MQENTRY OATermAuth(
MQHCONFIG hc,
MQLONG Options,
PMQCHAR pQMgrName,
PMQBYTE pComponentData,
PMQLONG pCompCode,
PMQLONG pReason)
{
if ((primary_process) && ((Options & MQZTO_PRIMARY) == MQZTO_PRIMARY) ||
((Options & MQZTO_SECONDARY) == MQZTO_SECONDARY))
{
if (fp)
{
fclose(fp);
fp = NULL;
}
}
*pCompCode = MQCC_OK;
*pReason = MQRC_NONE;
}
static void PrintDateTime() {
FindSize();
struct tm *local;
time_t t;
t = time(NULL);
local = localtime(&t);
if (fp) {
fprintf(fp, "-------------------------------------------------\n");
fprintf(fp, "Local time: %s", asctime(local));
local = gmtime(&t);
fprintf(fp, "UTC time: %s", asctime(local));
}
return;
}
static char *OAEnvStr(MQLONG x)
{
switch (x)
{
case MQXE_OTHER: return "Application";
case MQXE_MCA: return "Channel";
case MQXE_MCA_SVRCONN: return "Channel SvrConn";
case MQXE_COMMAND_SERVER: return "Command Server";
case MQXE_MQSC: return "MQSC";
default: return "Invalid Environment";
}
}
static void FindSize()
{
int sz = 0;
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
sz=ftell(fp);
//if log file size goes over 1mb, rewind it.
if (sz > 1000000) {
rewind(fp);
} else {
fseek(fp, prev, SEEK_SET);
}
}
*/
import "C"
import "github.com/ibm-messaging/mq-container/internal/htpasswd"
//export MQStart
func MQStart(hc C.MQHCONFIG, Options C.MQLONG, QMgrName C.PMQCHAR, ComponentDataLength C.MQLONG, ComponentData C.PMQBYTE, Version C.PMQLONG, pCompCode C.PMQLONG, pReason C.PMQLONG) {
C.PASStart(hc, Options, QMgrName, ComponentDataLength, ComponentData, Version, pCompCode, pReason)
}
//export Authenticate
func Authenticate(x *C.char, y *C.char) C.int {
user := C.GoString(x)
pwd := C.GoString(y)
found, ok, err := htpasswd.AuthenticateUser(user, pwd, false)
if !found || !ok || err != nil {
return C.MQRC_UNKNOWN_OBJECT_NAME
}
return C.MQRC_NONE
}
//export CheckAuthority
func CheckAuthority(x *C.char) C.int {
user := C.GoString(x)
found, err := htpasswd.ValidateUser(user, false)
if !found || err != nil {
return C.MQRC_UNKNOWN_OBJECT_NAME
}
return C.MQRC_NONE
}
func main() {}

File diff suppressed because it is too large Load Diff

View File

@@ -1,97 +0,0 @@
/*
© Copyright IBM Corporation 2019, 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 tls
import (
"fmt"
"os"
"path/filepath"
"github.com/ibm-messaging/mq-container/internal/keystore"
)
// webKeystoreDefault is the name of the default web server Keystore
const webKeystoreDefault = "default.p12"
// ConfigureWebTLS configures TLS for the web server
func ConfigureWebTLS(keyLabel string) error {
// Return immediately if we have no certificate to use as identity
if keyLabel == "" && os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME") == "" {
return nil
}
webConfigDir := "/etc/mqm/web/installations/Installation1/servers/mqweb"
tls := "tls.xml"
tlsConfig := filepath.Join(webConfigDir, tls)
newTLSConfig := filepath.Join(webConfigDir, tls+".tpl")
err := os.Remove(tlsConfig)
if err != nil {
return fmt.Errorf("Failed to delete file %s: %v", tlsConfig, err)
}
// Symlink here to prevent issues on restart
err = os.Symlink(newTLSConfig, tlsConfig)
if err != nil {
return fmt.Errorf("Failed to create symlink %s->%s: %v", newTLSConfig, tlsConfig, err)
}
return nil
}
// ConfigureWebKeyStore configures the Web Keystore
func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (string, error) {
if webKeystore == "" {
webKeystore = webKeystoreDefault
}
webKeystoreFile := filepath.Join(keystoreDir, webKeystore)
// Check if a new self-signed certificate should be generated
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
if genHostName != "" {
// Create the Web Keystore
newWebKeystore := keystore.NewPKCS12KeyStore(webKeystoreFile, p12Truststore.Password)
err := newWebKeystore.Create()
if err != nil {
return "", fmt.Errorf("Failed to create Web Keystore %s: %v", webKeystoreFile, err)
}
// Generate a new self-signed certificate in the Web Keystore
err = newWebKeystore.CreateSelfSignedCertificate("default", fmt.Sprintf("CN=%s", genHostName), genHostName)
if err != nil {
return "", fmt.Errorf("Failed to generate certificate in Web Keystore %s with DN of 'CN=%s': %v", webKeystoreFile, genHostName, err)
}
} else {
// Check Web Keystore already exists
_, err := os.Stat(webKeystoreFile)
if err != nil {
return "", fmt.Errorf("Failed to find existing Web Keystore %s: %v", webKeystoreFile, err)
}
}
// Check Web Truststore already exists
_, err := os.Stat(p12Truststore.Keystore.Filename)
if err != nil {
return "", fmt.Errorf("Failed to find existing Web Truststore %s: %v", p12Truststore.Keystore.Filename, err)
}
return webKeystore, nil
}

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2018, 2020 © 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.
@@ -16,26 +16,66 @@ limitations under the License.
package user package user
import ( import (
"golang.org/x/sys/unix" "fmt"
"os/user"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
) )
// User holds information on primary and supplemental OS groups // User holds information on primary and supplemental OS groups
type User struct { type User struct {
UID int UID string
PrimaryGID int Name string
SupplementalGID []int PrimaryGID string
SupplementalGID []string
} }
// GetUser returns the current user and group information // GetUser returns the current user and group information
func GetUser() (User, error) { func GetUser() (User, error) {
u := User{ u, err := user.Current()
UID: unix.Geteuid(),
PrimaryGID: unix.Getgid(),
}
groups, err := unix.Getgroups()
if err != nil { if err != nil {
return u, err return User{}, err
} }
u.SupplementalGID = groups g, err := getCurrentUserGroups()
return u, nil if err != nil {
return User{}, err
}
if err != nil && len(g) == 0 {
return User{
UID: u.Uid,
Name: u.Name,
PrimaryGID: u.Gid,
SupplementalGID: []string{},
}, nil
}
// Look for the primary group in the list of group IDs
for i, v := range g {
if v == u.Gid {
// Remove the element from the slice
g = append(g[:i], g[i+1:]...)
}
}
return User{
UID: u.Uid,
Name: u.Name,
PrimaryGID: u.Gid,
SupplementalGID: g,
}, nil
}
func getCurrentUserGroups() ([]string, error) {
var nilArray []string
out, _, err := command.Run("id", "--groups")
if err != nil {
return nilArray, err
}
out = strings.TrimSpace(out)
if out == "" {
return nilArray, fmt.Errorf("Unable to determine groups for current user")
}
groups := strings.Split(out, " ")
return groups, nil
} }

View File

@@ -1,7 +1,7 @@
Fat manifests Fat manifests
============= =============
These are the fat manifests used by Docker Hub to handle images with multiple CPU architectures. These are the fat manifests used by Docker Hub and Docker store to handle images with multiple CPU architectures.
They are used in conjunction with [manifest-tool](https://github.com/estesp/manifest-tool), for example: They are used in conjunction with [manifest-tool](https://github.com/estesp/manifest-tool), for example:

View File

@@ -12,17 +12,17 @@
# 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.
image: ibmcom/mq:9.1.3.0-r3 image: ibmcom/mq:9.1.3.0-r2
manifests: manifests:
- image: ibmcom/mq:9.1.3.0-r3-amd64 - image: ibmcom/mq:9.1.3.0-r2-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- image: ibmcom/mq:9.1.3.0-r3-ppc64le - image: ibmcom/mq:9.1.3.0-r2-ppc64le
platform: platform:
architecture: ppc64le architecture: ppc64le
os: linux os: linux
- image: ibmcom/mq:9.1.3.0-r3-s390x - image: ibmcom/mq:9.1.3.0-r2-s390x
platform: platform:
architecture: s390x architecture: s390x
os: linux os: linux

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2020 # © 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.
@@ -14,7 +14,15 @@
image: ibmcom/mq:latest image: ibmcom/mq:latest
manifests: manifests:
- image: ibmcom/mq:9.2.0.0-r1-amd64 - image: ibmcom/mq:9.1.3.0-r2-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- image: ibmcom/mq:9.1.3.0-r2-ppc64le
platform:
architecture: ppc64le
os: linux
- image: ibmcom/mq:9.1.3.0-r2-s390x
platform:
architecture: s390x
os: linux

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2020 # © 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.
@@ -12,17 +12,18 @@
# 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.
image: ibmcom/mq:9.1.5.0-r1 image: ibmcorp/mqadvanced-server-dev:9.1.1.0
manifests: manifests:
- image: ibmcom/mq:9.1.5.0-r1-amd64 - image: ibmcorp/mqadvanced-server-dev:9.1.1.0-x86_64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- image: ibmcom/mq:9.1.5.0-r1-ppc64le - image: ibmcorp/mqadvanced-server-dev:9.1.1.0-ppc64le
platform: platform:
architecture: ppc64le architecture: ppc64le
os: linux os: linux
- image: ibmcom/mq:9.1.5.0-r1-s390x - image: ibmcorp/mqadvanced-server-dev:9.1.1.0-s390x
platform: platform:
architecture: s390x architecture: s390x
os: linux os: linux

View File

@@ -0,0 +1,28 @@
# © Copyright IBM Corporation 2019
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
image: ibmcorp/mqadvanced-server-dev:9.1.2.0-UBI
manifests:
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-UBI-amd64
platform:
architecture: amd64
os: linux
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-UBI-ppc64le
platform:
architecture: ppc64le
os: linux
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-UBI-s390x
platform:
architecture: s390x
os: linux

View File

@@ -0,0 +1,29 @@
# © Copyright IBM Corporation 2018, 2019
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
image: ibmcorp/mqadvanced-server-dev:9.1.2.0
manifests:
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-x86_64
platform:
architecture: amd64
os: linux
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-ppc64le
platform:
architecture: ppc64le
os: linux
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-s390x
platform:
architecture: s390x
os: linux

View File

@@ -12,17 +12,17 @@
# 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.
image: ibmcom/mq:9.1.4.0-r1 image: ibmcorp/mqadvanced-server-dev:9.1.3.0-r2
manifests: manifests:
- image: ibmcom/mq:9.1.4.0-r1-amd64 - image: ibmcorp/mqadvanced-server-dev:9.1.3.0-r2-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- image: ibmcom/mq:9.1.4.0-r1-ppc64le - image: ibmcorp/mqadvanced-server-dev:9.1.3.0-r2-ppc64le
platform: platform:
architecture: ppc64le architecture: ppc64le
os: linux os: linux
- image: ibmcom/mq:9.1.4.0-r1-s390x - image: ibmcorp/mqadvanced-server-dev:9.1.3.0-r2-s390x
platform: platform:
architecture: s390x architecture: s390x
os: linux os: linux

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2020 # © 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.
@@ -12,9 +12,18 @@
# 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.
image: ibmcom/mq:9.2.0.0-r1 image: ibmcorp/mqadvanced-server-dev:9.1.0.0
manifests: manifests:
- image: ibmcom/mq:9.2.0.0-r1-amd64 - image: ibmcorp/mqadvanced-server-dev:9.1.0.0-x86_64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- image: ibmcorp/mqadvanced-server-dev:9.1.0.0-ppc64le
platform:
architecture: ppc64le
os: linux
- image: ibmcorp/mqadvanced-server-dev:9.1.0.0-s390x
platform:
architecture: s390x
os: linux

View File

@@ -1,92 +0,0 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 mqini provides information about queue managers
package mqini
import (
"bufio"
"errors"
"os"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
// QueueManager describe high-level configuration information for a queue manager
type QueueManager struct {
Name string
Prefix string
Directory string
DataPath string
InstallationName string
}
// getQueueManagerFromStanza parses a queue manager stanza
func getQueueManagerFromStanza(stanza string) (*QueueManager, error) {
scanner := bufio.NewScanner(strings.NewReader(stanza))
qm := QueueManager{}
for scanner.Scan() {
l := scanner.Text()
l = strings.TrimSpace(l)
t := strings.Split(l, "=")
switch t[0] {
case "Name":
qm.Name = t[1]
case "Prefix":
qm.Prefix = t[1]
case "Directory":
qm.Directory = t[1]
case "DataPath":
qm.DataPath = t[1]
case "InstallationName":
qm.InstallationName = t[1]
}
}
return &qm, scanner.Err()
}
// GetQueueManager returns queue manager configuration information
func GetQueueManager(name string) (*QueueManager, error) {
_, err := os.Stat("/var/mqm/mqs.ini")
if err != nil {
// Don't run dspmqinf, which will generate an FDC if mqs.ini isn't there yet
return nil, errors.New("dspmqinf should not be run before crtmqdir")
}
// dspmqinf essentially returns a subset of mqs.ini, but it's simpler to parse
out, _, err := command.Run("dspmqinf", "-o", "stanza", name)
if err != nil {
return nil, err
}
return getQueueManagerFromStanza(out)
}
// GetErrorLogDirectory returns the directory holding the error logs for the
// specified queue manager
func GetErrorLogDirectory(qm *QueueManager) string {
return filepath.Join(GetDataDirectory(qm), "errors")
}
// GetDataDirectory returns the data directory for the specified queue manager
func GetDataDirectory(qm *QueueManager) string {
if qm.DataPath != "" {
// Data path has been set explicitly (e.g. for multi-instance queue manager)
return qm.DataPath
} else {
return filepath.Join(qm.Prefix, "qmgrs", qm.Directory)
}
}

View File

@@ -1,64 +0,0 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 mqini
import (
"io/ioutil"
"testing"
)
var getQueueManagerTests = []struct {
file string
name string
prefix string
directory string
errorLogDir string
}{
{"dspmqinf1.txt", "foo", "/var/mqm", "foo", "/var/mqm/qmgrs/foo/errors"},
{"dspmqinf2.txt", "a/b", "/var/mqm", "a&b", "/var/mqm/qmgrs/a&b/errors"},
{"dspmqinf3.txt", "..", "/var/mqm", "!!", "/var/mqm/qmgrs/!!/errors"},
}
func TestGetQueueManager(t *testing.T) {
for _, table := range getQueueManagerTests {
t.Run(table.file, func(t *testing.T) {
b, err := ioutil.ReadFile(table.file)
if err != nil {
t.Fatal(err)
}
qm, err := getQueueManagerFromStanza(string(b))
if err != nil {
t.Fatal(err)
}
t.Logf("%#v", qm)
if qm.Name != table.name {
t.Errorf("Expected name=%v; got %v", table.name, qm.Name)
}
if qm.Prefix != table.prefix {
t.Errorf("Expected prefix=%v; got %v", table.prefix, qm.Prefix)
}
if qm.Directory != table.directory {
t.Errorf("Expected directory=%v; got %v", table.directory, qm.Directory)
}
// Test
d := GetErrorLogDirectory(qm)
if d != table.errorLogDir {
t.Errorf("Expected error log directory=%v; got %v", table.errorLogDir, d)
}
})
}
}

View File

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

114
test/docker/Gopkg.lock generated Normal file
View File

@@ -0,0 +1,114 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/Azure/go-ansiterm"
packages = [
".",
"winterm"
]
revision = "d6e3b3328b783f23731bc4d058875b0371ff8109"
[[projects]]
name = "github.com/Microsoft/go-winio"
packages = ["."]
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
version = "v0.4.7"
[[projects]]
name = "github.com/Sirupsen/logrus"
packages = ["."]
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5"
[[projects]]
name = "github.com/docker/distribution"
packages = [
"digest",
"reference"
]
revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89"
version = "v2.6.2"
[[projects]]
name = "github.com/docker/docker"
packages = [
"api/types",
"api/types/blkiodev",
"api/types/container",
"api/types/events",
"api/types/filters",
"api/types/mount",
"api/types/network",
"api/types/reference",
"api/types/registry",
"api/types/strslice",
"api/types/swarm",
"api/types/time",
"api/types/versions",
"api/types/volume",
"client",
"pkg/jsonlog",
"pkg/jsonmessage",
"pkg/stdcopy",
"pkg/term",
"pkg/term/windows",
"pkg/tlsconfig"
]
revision = "f5ec1e2936dcbe7b5001c2b817188b095c700c27"
version = "v17.03.2-ce"
[[projects]]
name = "github.com/docker/go-connections"
packages = [
"nat",
"sockets",
"tlsconfig"
]
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
version = "v0.3.0"
[[projects]]
name = "github.com/docker/go-units"
packages = ["."]
revision = "0dadbb0345b35ec7ef35e228dabb8de89a65bf52"
version = "v0.3.2"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "88942b9c40a4c9d203b82b3731787b672d6e809b"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"proxy"
]
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "13d03a9a82fba647c21a0ef8fba44a795d0f0835"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "c792836365447209421d5dc68a75fa77063408b8a6a2f9325b976581a0d60107"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2020 # © Copyright IBM Corporation 2017, 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.
@@ -12,6 +12,13 @@
# 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:32 [[constraint]]
RUN yum install skopeo -y -qq name = "github.com/docker/docker"
ENTRYPOINT [ "skopeo" ] version = "=v17.03.2-ce"
[[constraint]]
name = "github.com/docker/go-connections"
version = "0.4.0"
[prune]
go-tests = true

View File

@@ -81,6 +81,8 @@ func TestDevSecure(t *testing.T) {
"LICENSE=accept", "LICENSE=accept",
"MQ_QMGR_NAME=" + qm, "MQ_QMGR_NAME=" + qm,
"MQ_APP_PASSWORD=" + appPassword, "MQ_APP_PASSWORD=" + appPassword,
"MQ_TLS_KEYSTORE=/var/tls/server.p12",
"MQ_TLS_PASSPHRASE=" + tlsPassPhrase,
"DEBUG=1", "DEBUG=1",
}, },
Image: imageName(), Image: imageName(),
@@ -88,7 +90,7 @@ func TestDevSecure(t *testing.T) {
hostConfig := container.HostConfig{ hostConfig := container.HostConfig{
Binds: []string{ Binds: []string{
coverageBind(t), coverageBind(t),
tlsDir(t, false) + ":/etc/mqm/pki/keys/default", tlsDir(t, false) + ":/var/tls",
}, },
// Assign a random port for the web server on the host // Assign a random port for the web server on the host
// TODO: Don't do this for all tests // TODO: Don't do this for all tests
@@ -143,7 +145,7 @@ func TestDevWebDisabled(t *testing.T) {
defer cleanContainer(t, cli, id) defer cleanContainer(t, cli, id)
waitForReady(t, cli, id) waitForReady(t, cli, id)
t.Run("Web", func(t *testing.T) { t.Run("Web", func(t *testing.T) {
_, dspmqweb := execContainer(t, cli, id, "", []string{"dspmqweb"}) _, dspmqweb := execContainer(t, cli, id, "mqm", []string{"dspmqweb"})
if !strings.Contains(dspmqweb, "Server mqweb is not running.") && !strings.Contains(dspmqweb, "MQWB1125I") { if !strings.Contains(dspmqweb, "Server mqweb is not running.") && !strings.Contains(dspmqweb, "MQWB1125I") {
t.Errorf("Expected dspmqweb to say 'Server is not running' or 'MQWB1125I'; got \"%v\"", dspmqweb) t.Errorf("Expected dspmqweb to say 'Server is not running' or 'MQWB1125I'; got \"%v\"", dspmqweb)
} }
@@ -174,7 +176,7 @@ func TestDevConfigDisabled(t *testing.T) {
defer cleanContainer(t, cli, id) defer cleanContainer(t, cli, id)
waitForReady(t, cli, id) waitForReady(t, cli, id)
waitForWebReady(t, cli, id, insecureTLSConfig) waitForWebReady(t, cli, id, insecureTLSConfig)
rc, _ := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"}) rc, _ := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"})
if rc == 0 { if rc == 0 {
t.Errorf("Expected DEV queues to be missing") t.Errorf("Expected DEV queues to be missing")
} }

View File

@@ -1,8 +1,7 @@
//go:build mqdev
// +build mqdev // +build mqdev
/* /*
© Copyright IBM Corporation 2018, 2021 © 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.
@@ -50,7 +49,7 @@ var insecureTLSConfig *tls.Config = &tls.Config{
func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) { func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
httpClient := http.Client{ httpClient := http.Client{
Timeout: time.Duration(10 * time.Second), Timeout: time.Duration(3 * time.Second),
Transport: &http.Transport{ Transport: &http.Transport{
TLSClientConfig: tlsConfig, TLSClientConfig: tlsConfig,
}, },
@@ -83,7 +82,7 @@ func tlsDir(t *testing.T, unixPath bool) string {
// runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID // runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID
func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string) { func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string) {
containerConfig := container.Config{ containerConfig := container.Config{
// -e MQ_PORT_1414_TCP_ADDR=9.145.14.173 -e MQ_USERNAME=app -e MQ_PASSWORD=passw0rd -e MQ_CHANNEL=DEV.APP.SVRCONN -e MQ_TLS_TRUSTSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest // -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_KEYSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest
Env: []string{ Env: []string{
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID), "MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
"MQ_USERNAME=" + user, "MQ_USERNAME=" + user,

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -75,29 +75,6 @@ func TestLicenseView(t *testing.T) {
} }
} }
//Start a container with qm grace set to x seconds
//Check that when the container is stopped that the command endmqm has option -tp and x
func TestEndMQMOpts(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
containerConfig := container.Config{
Env: []string{"LICENSE=accept", "MQ_GRACE_PERIOD=27"},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
killContainer(t, cli, id, "SIGTERM")
_, out := execContainer(t, cli, id, "", []string{"bash", "-c", "ps -ef | grep 'endmqm -w -r -tp 27'"})
t.Log(out)
if !strings.Contains(out, "endmqm -w -r -tp 27") {
t.Errorf("Expected endmqm options endmqm -w -r -tp 27; got \"%v\"", out)
}
}
// TestGoldenPath starts a queue manager successfully when metrics are enabled // TestGoldenPath starts a queue manager successfully when metrics are enabled
func TestGoldenPathWithMetrics(t *testing.T) { func TestGoldenPathWithMetrics(t *testing.T) {
t.Parallel() t.Parallel()
@@ -182,7 +159,7 @@ func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName stri
id := runContainer(t, cli, &containerConfig) id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id) defer cleanContainer(t, cli, id)
waitForReady(t, cli, id) waitForReady(t, cli, id)
_, out := execContainer(t, cli, id, "", []string{"dspmq"}) _, out := execContainer(t, cli, id, "mqm", []string{"dspmq"})
if !strings.Contains(out, search) { if !strings.Contains(out, search) {
t.Errorf("Expected result of running dspmq to contain name=%v, got name=%v", search, out) t.Errorf("Expected result of running dspmq to contain name=%v, got name=%v", search, out)
} }
@@ -414,7 +391,9 @@ func TestCreateQueueManagerFail(t *testing.T) {
FROM %v FROM %v
USER root USER root
RUN echo '#!/bin/bash\nexit 999' > /opt/mqm/bin/crtmqm RUN echo '#!/bin/bash\nexit 999' > /opt/mqm/bin/crtmqm
USER 1001`, imageName())}, RUN chown mqm:mqm /opt/mqm/bin/crtmqm
RUN chmod 6550 /opt/mqm/bin/crtmqm
USER mqm`, imageName())},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
defer deleteImage(t, cli, tag) defer deleteImage(t, cli, tag)
@@ -447,7 +426,9 @@ func TestStartQueueManagerFail(t *testing.T) {
FROM %v FROM %v
USER root USER root
RUN echo '#!/bin/bash\ndltmqm $@ && strmqm $@' > /opt/mqm/bin/strmqm RUN echo '#!/bin/bash\ndltmqm $@ && strmqm $@' > /opt/mqm/bin/strmqm
USER 1001`, imageName())}, RUN chown mqm:mqm /opt/mqm/bin/strmqm
RUN chmod 6550 /opt/mqm/bin/strmqm
USER mqm`, imageName())},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
defer deleteImage(t, cli, tag) defer deleteImage(t, cli, tag)
@@ -506,12 +487,12 @@ func TestVolumeUnmount(t *testing.T) {
t.Fatalf("Expected umount to work with rc=0, got %v. Output was: %s", rc, out) t.Fatalf("Expected umount to work with rc=0, got %v. Output was: %s", rc, out)
} }
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
rc, _ = execContainer(t, cli, ctr.ID, "", []string{"chkmqhealthy"}) rc, _ = execContainer(t, cli, ctr.ID, "mqm", []string{"chkmqhealthy"})
if rc == 0 { if rc == 0 {
t.Errorf("Expected chkmqhealthy to fail") t.Errorf("Expected chkmqhealthy to fail")
_, df := execContainer(t, cli, ctr.ID, "", []string{"df"}) _, df := execContainer(t, cli, ctr.ID, "mqm", []string{"df"})
t.Logf(df) t.Logf(df)
_, ps := execContainer(t, cli, ctr.ID, "", []string{"ps", "-ef"}) _, ps := execContainer(t, cli, ctr.ID, "mqm", []string{"ps", "-ef"})
t.Logf(ps) t.Logf(ps)
} }
} }
@@ -537,14 +518,14 @@ func TestZombies(t *testing.T) {
waitForReady(t, cli, id) waitForReady(t, cli, id)
// Kill an MQ process with children. After it is killed, its children // Kill an MQ process with children. After it is killed, its children
// will be adopted by PID 1, and should then be reaped when they die. // will be adopted by PID 1, and should then be reaped when they die.
_, out := execContainer(t, cli, id, "", []string{"pkill", "--signal", "kill", "-c", "amqzxma0"}) _, out := execContainer(t, cli, id, "mqm", []string{"pkill", "--signal", "kill", "-c", "amqzxma0"})
if out == "0" { if out == "0" {
t.Log("Failed to kill process 'amqzxma0'") t.Log("Failed to kill process 'amqzxma0'")
_, out := execContainer(t, cli, id, "", []string{"ps", "-lA"}) _, out := execContainer(t, cli, id, "root", []string{"ps", "-lA"})
t.Fatalf("Here is a list of currently running processes:\n%s", out) t.Fatalf("Here is a list of currently running processes:\n%s", out)
} }
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
_, out = execContainer(t, cli, id, "", []string{"bash", "-c", "ps -lA | grep '^. Z'"}) _, out = execContainer(t, cli, id, "mqm", []string{"bash", "-c", "ps -lA | grep '^. Z'"})
if out != "" { if out != "" {
count := strings.Count(out, "\n") + 1 count := strings.Count(out, "\n") + 1
t.Errorf("Expected zombies=0, got %v", count) t.Errorf("Expected zombies=0, got %v", count)
@@ -571,7 +552,7 @@ func TestMQSC(t *testing.T) {
RUN rm -f /etc/mqm/*.mqsc RUN rm -f /etc/mqm/*.mqsc
ADD test.mqsc /etc/mqm/ ADD test.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/test.mqsc RUN chmod 0660 /etc/mqm/test.mqsc
USER 1001`, imageName())}, USER mqm`, imageName())},
{"test.mqsc", "DEFINE QLOCAL(test)"}, {"test.mqsc", "DEFINE QLOCAL(test)"},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
@@ -584,16 +565,7 @@ func TestMQSC(t *testing.T) {
id := runContainer(t, cli, &containerConfig) id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id) defer cleanContainer(t, cli, id)
waitForReady(t, cli, id) waitForReady(t, cli, id)
rc, mqscOutput := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test)' | runmqsc"})
rc := -1
mqscOutput := ""
for i := 0; i < 60; i++ {
rc, mqscOutput = execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test)' | runmqsc"})
if rc == 0 {
return
}
time.Sleep(1 * time.Second)
}
if rc != 0 { if rc != 0 {
r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E") r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E")
t.Fatalf("Expected runmqsc to exit with rc=0, got %v with error %v", rc, r.FindString(mqscOutput)) t.Fatalf("Expected runmqsc to exit with rc=0, got %v with error %v", rc, r.FindString(mqscOutput))
@@ -623,7 +595,7 @@ func TestLargeMQSC(t *testing.T) {
RUN rm -f /etc/mqm/*.mqsc RUN rm -f /etc/mqm/*.mqsc
ADD test.mqsc /etc/mqm/ ADD test.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/test.mqsc RUN chmod 0660 /etc/mqm/test.mqsc
USER 1001`, imageName())}, USER mqm`, imageName())},
{"test.mqsc", buf.String()}, {"test.mqsc", buf.String()},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
@@ -637,15 +609,7 @@ func TestLargeMQSC(t *testing.T) {
defer cleanContainer(t, cli, id) defer cleanContainer(t, cli, id)
waitForReady(t, cli, id) waitForReady(t, cli, id)
rc := -1 rc, mqscOutput := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test" + strconv.Itoa(numQueues) + ")' | runmqsc"})
mqscOutput := ""
for i := 0; i < 60; i++ {
rc, mqscOutput = execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test" + strconv.Itoa(numQueues) + ")' | runmqsc"})
if rc == 0 {
return
}
time.Sleep(1 * time.Second)
}
if rc != 0 { if rc != 0 {
r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E") r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E")
t.Fatalf("Expected runmqsc to exit with rc=0, got %v with error %v", rc, r.FindString(mqscOutput)) t.Fatalf("Expected runmqsc to exit with rc=0, got %v with error %v", rc, r.FindString(mqscOutput))
@@ -703,7 +667,7 @@ func TestRedactValidMQSC(t *testing.T) {
RUN rm -f /etc/mqm/*.mqsc RUN rm -f /etc/mqm/*.mqsc
ADD test.mqsc /etc/mqm/ ADD test.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/test.mqsc RUN chmod 0660 /etc/mqm/test.mqsc
USER 1001`, imageName())}, USER mqm`, imageName())},
{"test.mqsc", buf.String()}, {"test.mqsc", buf.String()},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
@@ -775,7 +739,7 @@ func TestRedactInvalidMQSC(t *testing.T) {
RUN rm -f /etc/mqm/*.mqsc RUN rm -f /etc/mqm/*.mqsc
ADD test.mqsc /etc/mqm/ ADD test.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/test.mqsc RUN chmod 0660 /etc/mqm/test.mqsc
USER 1001`, imageName())}, USER mqm`, imageName())},
{"test.mqsc", buf.String()}, {"test.mqsc", buf.String()},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
@@ -821,7 +785,7 @@ func TestInvalidMQSC(t *testing.T) {
RUN rm -f /etc/mqm/*.mqsc RUN rm -f /etc/mqm/*.mqsc
ADD mqscTest.mqsc /etc/mqm/ ADD mqscTest.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/mqscTest.mqsc RUN chmod 0660 /etc/mqm/mqscTest.mqsc
USER 1001`, imageName())}, USER mqm`, imageName())},
{"mqscTest.mqsc", "DEFINE INVALIDLISTENER('TEST.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE"}, {"mqscTest.mqsc", "DEFINE INVALIDLISTENER('TEST.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE"},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
@@ -840,187 +804,6 @@ func TestInvalidMQSC(t *testing.T) {
expectTerminationMessage(t, cli, id) expectTerminationMessage(t, cli, id)
} }
func TestSimpleMQIniMerge(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
var files = []struct {
Name, Body string
}{
{"Dockerfile", fmt.Sprintf(`
FROM %v
USER root
ADD test1.ini /etc/mqm/
RUN chmod 0660 /etc/mqm/test1.ini
USER 1001`, imageName())},
{"test1.ini",
"Log:\n LogSecondaryFiles=28"},
}
tag := createImage(t, cli, files)
defer deleteImage(t, cli, tag)
containerConfig := container.Config{
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
Image: tag,
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/qm1/qm.ini")
_, test := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand})
merged := strings.Contains(test, "LogSecondaryFiles=28")
if !merged {
t.Error("ERROR: The Files are not merged correctly")
}
}
func TestMultipleIniMerge(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
var files = []struct {
Name, Body string
}{
{"Dockerfile", fmt.Sprintf(`
FROM %v
USER root
ADD test1.ini /etc/mqm/
ADD test2.ini /etc/mqm/
ADD test3.ini /etc/mqm/
RUN chmod 0660 /etc/mqm/test1.ini
RUN chmod 0660 /etc/mqm/test2.ini
RUN chmod 0660 /etc/mqm/test3.ini
USER 1001`, imageName())},
{"test1.ini",
"Log:\n LogSecondaryFiles=28"},
{"test2.ini",
"Log:\n LogSecondaryFiles=28"},
{"test3.ini",
"ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF"},
}
tag := createImage(t, cli, files)
defer deleteImage(t, cli, tag)
containerConfig := container.Config{
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
Image: tag,
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/qm1/qm.ini")
_, test := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand})
//checks that no duplicates are created by adding 2 ini files with the same line
numberOfDuplicates := strings.Count(test, "LogSecondaryFiles=28")
newStanza := strings.Contains(test, "ApplicationTrace:\n ApplName=amqsact*")
if (numberOfDuplicates > 1) || !newStanza {
t.Error("ERROR: The Files are not merged correctly")
}
}
func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) {
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
var filesFirstContainer = []struct {
Name, Body string
}{
{"Dockerfile", fmt.Sprintf(`
FROM %v
USER root
ADD test1.ini /etc/mqm/
RUN chmod 0660 /etc/mqm/test1.ini
USER 1001`, imageName())},
{"test1.ini",
"ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF"},
}
firstImage := createImage(t, cli, filesFirstContainer)
defer deleteImage(t, cli, firstImage)
vol := createVolume(t, cli, t.Name())
defer removeVolume(t, cli, vol.Name)
containerConfig := container.Config{
Image: firstImage,
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
}
hostConfig := container.HostConfig{
Binds: []string{
coverageBind(t),
vol.Name + ":/mnt/mqm",
},
}
networkingConfig := network.NetworkingConfig{}
ctr1, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
startContainer(t, cli, ctr1.ID)
waitForReady(t, cli, ctr1.ID)
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/qm1/qm.ini")
_, test := execContainer(t, cli, ctr1.ID, "", []string{"bash", "-c", catIniFileCommand})
addedStanza := strings.Contains(test, "ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF")
if addedStanza != true {
t.Error("ERROR: The Files are not merged correctly")
}
// Delete the first container
cleanContainer(t, cli, ctr1.ID)
var filesSecondContainer = []struct {
Name, Body string
}{
{"Dockerfile", fmt.Sprintf(`
FROM %v
USER root
ADD test1.ini /etc/mqm/
RUN chmod 0660 /etc/mqm/test1.ini
USER 1001`, imageName())},
{"test1.ini",
"Log:\n LogFilePages=5000"},
}
secondImage := createImage(t, cli, filesSecondContainer)
defer deleteImage(t, cli, secondImage)
containerConfig2 := container.Config{
Image: secondImage,
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
}
ctr2, err := cli.ContainerCreate(context.Background(), &containerConfig2, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ctr2.ID)
startContainer(t, cli, ctr2.ID)
waitForReady(t, cli, ctr2.ID)
_, test2 := execContainer(t, cli, ctr2.ID, "", []string{"bash", "-c", catIniFileCommand})
changedStanza := strings.Contains(test2, "LogFilePages=5000")
//check if stanza that was merged in the first container doesnt exist in this one.
firstMergedStanza := strings.Contains(test2, "ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF")
if !changedStanza || firstMergedStanza {
t.Error("ERROR: The Files are not merged correctly after removing first container")
}
}
// TestReadiness creates a new image with large amounts of MQSC in, to // TestReadiness creates a new image with large amounts of MQSC in, to
// ensure that the readiness check doesn't pass until configuration has finished. // ensure that the readiness check doesn't pass until configuration has finished.
// WARNING: This test is sensitive to the speed of the machine it's running on. // WARNING: This test is sensitive to the speed of the machine it's running on.
@@ -1045,7 +828,7 @@ func TestReadiness(t *testing.T) {
RUN rm -f /etc/mqm/*.mqsc RUN rm -f /etc/mqm/*.mqsc
ADD test.mqsc /etc/mqm/ ADD test.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/test.mqsc RUN chmod 0660 /etc/mqm/test.mqsc
USER 1001`, imageName())}, USER mqm`, imageName())},
{"test.mqsc", buf.String()}, {"test.mqsc", buf.String()},
} }
tag := createImage(t, cli, files) tag := createImage(t, cli, files)
@@ -1058,27 +841,20 @@ func TestReadiness(t *testing.T) {
id := runContainer(t, cli, &containerConfig) id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id) defer cleanContainer(t, cli, id)
queueCheckCommand := fmt.Sprintf("echo 'DISPLAY QLOCAL(test%v)' | runmqsc", numQueues) queueCheckCommand := fmt.Sprintf("echo 'DISPLAY QLOCAL(test%v)' | runmqsc", numQueues)
_, mqsc := execContainer(t, cli, id, "", []string{"cat", "/etc/mqm/test.mqsc"}) _, mqsc := execContainer(t, cli, id, "root", []string{"cat", "/etc/mqm/test.mqsc"})
t.Log(mqsc) t.Log(mqsc)
for { for {
readyRC, _ := execContainer(t, cli, id, "", []string{"chkmqready"}) readyRC, _ := execContainer(t, cli, id, "mqm", []string{"chkmqready"})
queueCheckRC, queueCheckOut := execContainer(t, cli, id, "mqm", []string{"bash", "-c", queueCheckCommand})
t.Logf("readyRC=%v,queueCheckRC=%v\n", readyRC, queueCheckRC)
if readyRC == 0 { if readyRC == 0 {
queueCheckRC := -1
queueCheckOut := ""
for i := 1; i < 60; i++ {
queueCheckRC, queueCheckOut = execContainer(t, cli, id, "", []string{"bash", "-c", queueCheckCommand})
t.Logf("readyRC=%v,queueCheckRC=%v\n", readyRC, queueCheckRC)
if queueCheckRC == 0 {
break
}
time.Sleep(1 * time.Second)
}
if queueCheckRC != 0 { if queueCheckRC != 0 {
r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E") r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E")
t.Fatalf("Runmqsc returned %v with error %v. chkmqready returned %v when MQSC had not finished", queueCheckRC, r.FindString(queueCheckOut), readyRC) t.Fatalf("Runmqsc returned %v with error %v. chkmqready returned %v when MQSC had not finished", queueCheckRC, r.FindString(queueCheckOut), readyRC)
} else { } else {
// chkmqready says OK, and the last queue exists, so return // chkmqready says OK, and the last queue exists, so return
_, runmqsc := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test1)' | runmqsc"}) _, runmqsc := execContainer(t, cli, id, "root", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test1)' | runmqsc"})
t.Log(runmqsc) t.Log(runmqsc)
return return
} }
@@ -1087,7 +863,6 @@ func TestReadiness(t *testing.T) {
} }
func TestErrorLogRotation(t *testing.T) { func TestErrorLogRotation(t *testing.T) {
t.Skipf("Skipping %v until test defect fixed", t.Name())
t.Parallel() t.Parallel()
cli, err := client.NewEnvClient() cli, err := client.NewEnvClient()
@@ -1128,7 +903,7 @@ func TestErrorLogRotation(t *testing.T) {
for { for {
execContainer(t, cli, id, "fred", []string{"bash", "-c", "/opt/mqm/samp/bin/amqsput FAKE"}) execContainer(t, cli, id, "fred", []string{"bash", "-c", "/opt/mqm/samp/bin/amqsput FAKE"})
_, atoiStr := execContainer(t, cli, id, "", []string{"bash", "-c", "wc -c < " + filepath.Join(dir, "AMQERR02.json")}) _, atoiStr := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "wc -c < " + filepath.Join(dir, "AMQERR02.json")})
amqerr02size, _ := strconv.Atoi(atoiStr) amqerr02size, _ := strconv.Atoi(atoiStr)
if amqerr02size > 0 { if amqerr02size > 0 {
@@ -1136,7 +911,7 @@ func TestErrorLogRotation(t *testing.T) {
break break
} }
} }
_, out := execContainer(t, cli, id, "", []string{"ls", "-l", dir}) _, out := execContainer(t, cli, id, "root", []string{"ls", "-l", dir})
t.Log(out) t.Log(out)
stopContainer(t, cli, id) stopContainer(t, cli, id)
b := copyFromContainer(t, cli, id, filepath.Join(dir, "AMQERR01.json")) b := copyFromContainer(t, cli, id, filepath.Join(dir, "AMQERR01.json"))
@@ -1280,7 +1055,7 @@ func TestCorrectLicense(t *testing.T) {
defer cleanContainer(t, cli, id) defer cleanContainer(t, cli, id)
waitForReady(t, cli, id) waitForReady(t, cli, id)
rc, license := execContainer(t, cli, id, "", []string{"dspmqver", "-f", "8192", "-b"}) rc, license := execContainer(t, cli, id, "mqm", []string{"dspmqver", "-f", "8192", "-b"})
if rc != 0 { if rc != 0 {
t.Fatalf("Failed to get license string. RC=%d. Output=%s", rc, license) t.Fatalf("Failed to get license string. RC=%d. Output=%s", rc, license)
} }
@@ -1410,68 +1185,3 @@ func TestVersioning(t *testing.T) {
} }
} }
func TestTraceStrmqm(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_ENABLE_TRACE_STRMQM=1",
},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
rc, _ := execContainer(t, cli, id, "", []string{"bash", "-c", "ls -A /var/mqm/trace | grep .TRC"})
if rc != 0 {
t.Fatalf("No trace files found in trace directory /var/mqm/trace. RC=%d.", rc)
}
}
// utilTestHealthCheck is used by TestHealthCheck* to run a container with
// privileges enabled or disabled. Otherwise the same as the golden path tests.
func utilTestHealthCheck(t *testing.T, nonewpriv bool) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
containerConfig := container.Config{
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
}
hostConfig := getDefaultHostConfig(t, cli)
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("no-new-privileges:%v", nonewpriv))
id := runContainerWithHostConfig(t, cli, &containerConfig, hostConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
rc, out := execContainer(t, cli, id, "", []string{"chkmqhealthy"})
t.Log(out)
if rc != 0 {
t.Errorf("Expected chkmqhealthy to return with exit code 0; got \"%v\"", rc)
t.Logf("Output from chkmqhealthy:\n%v", out)
}
// Stop the container cleanly
stopContainer(t, cli, id)
}
// TestHealthCheckWithNoNewPrivileges tests golden path start/stop plus
// chkmqhealthy, when running in a container where no new privileges are
// allowed (i.e. setuid is disabled)
func TestHealthCheckWithNoNewPrivileges(t *testing.T) {
utilTestHealthCheck(t, true)
}
// TestHealthCheckWithNoNewPrivileges tests golden path start/stop plus
// chkmqhealthy when running in a container where new privileges are
// allowed (i.e. setuid is allowed)
// See https://github.com/ibm-messaging/mq-container/issues/428
func TestHealthCheckWithNewPrivileges(t *testing.T) {
utilTestHealthCheck(t, false)
}

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017, 2020 © Copyright IBM Corporation 2017, 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.
@@ -24,7 +24,6 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"math/rand"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@@ -260,15 +259,20 @@ func cleanContainer(t *testing.T, cli *client.Client, ID string) {
} }
} }
func generateRandomUID() string { // runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
rand.Seed(time.Now().UnixNano()) // If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
min := 1000 // environment variable.
max := 9999 func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *container.Config, ports []int) string {
return fmt.Sprint(rand.Intn(max-min) + min) if containerConfig.Image == "" {
} containerConfig.Image = imageName()
}
// getDefaultHostConfig creates a HostConfig and populates it with the defaults used in testing // Always run as the "mqm" user, unless the test has specified otherwise
func getDefaultHostConfig(t *testing.T, cli *client.Client) *container.HostConfig { if containerConfig.User == "" {
containerConfig.User = "mqm"
}
// if coverage
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
hostConfig := container.HostConfig{ hostConfig := container.HostConfig{
Binds: []string{ Binds: []string{
coverageBind(t), coverageBind(t),
@@ -277,9 +281,15 @@ func getDefaultHostConfig(t *testing.T, cli *client.Client) *container.HostConfi
CapDrop: []string{ CapDrop: []string{
"ALL", "ALL",
}, },
Privileged: false,
} }
if devImage(t, cli) { if devImage(t, cli) {
t.Logf("Detected MQ Advanced for Developers image — adding extra Linux capabilities to container")
hostConfig.CapAdd = []string{
"CHOWN",
"SETUID",
"SETGID",
"AUDIT_WRITE",
}
// Only needed for a RHEL-based image // Only needed for a RHEL-based image
if baseImage(t, cli) != "ubuntu" { if baseImage(t, cli) != "ubuntu" {
hostConfig.CapAdd = append(hostConfig.CapAdd, "DAC_OVERRIDE") hostConfig.CapAdd = append(hostConfig.CapAdd, "DAC_OVERRIDE")
@@ -287,37 +297,6 @@ func getDefaultHostConfig(t *testing.T, cli *client.Client) *container.HostConfi
} else { } else {
t.Logf("Detected MQ Advanced image - dropping all capabilities") t.Logf("Detected MQ Advanced image - dropping all capabilities")
} }
return &hostConfig
}
// runContainerWithHostConfig creates and starts a container, using the supplied HostConfig.
// Note that a default HostConfig can be created using getDefaultHostConfig.
func runContainerWithHostConfig(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig) string {
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))
networkingConfig := network.NetworkingConfig{}
t.Logf("Running container (%s)", containerConfig.Image)
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
startContainer(t, cli, ctr.ID)
return ctr.ID
}
// runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
// If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
// environment variable.
func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *container.Config, ports []int) string {
hostConfig := getDefaultHostConfig(t, cli)
for _, p := range ports { for _, p := range ports {
port := nat.Port(fmt.Sprintf("%v/tcp", p)) port := nat.Port(fmt.Sprintf("%v/tcp", p))
hostConfig.PortBindings[port] = []nat.PortBinding{ hostConfig.PortBindings[port] = []nat.PortBinding{
@@ -326,7 +305,14 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co
}, },
} }
} }
return runContainerWithHostConfig(t, cli, containerConfig, hostConfig) networkingConfig := network.NetworkingConfig{}
t.Logf("Running container (%s)", containerConfig.Image)
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
startContainer(t, cli, ctr.ID)
return ctr.ID
} }
// runContainer creates and starts a container. If no image is specified in // runContainer creates and starts a container. If no image is specified in
@@ -394,78 +380,6 @@ func runContainerOneShotWithVolume(t *testing.T, cli *client.Client, bind string
return rc, out return rc, out
} }
func startMultiVolumeQueueManager(t *testing.T, cli *client.Client, dataVol bool, qmsharedlogs string, qmshareddata string, env []string) (error, string, string) {
id := strconv.FormatInt(time.Now().UnixNano(), 10)
qmdata := createVolume(t, cli, id)
containerConfig := container.Config{
Image: imageName(),
Env: env,
}
var hostConfig container.HostConfig
if !dataVol {
hostConfig = container.HostConfig{}
} else if qmsharedlogs == "" && qmshareddata == "" {
hostConfig = getHostConfig(t, 1, "", "", qmdata.Name)
} else if qmsharedlogs == "" {
hostConfig = getHostConfig(t, 2, "", qmshareddata, qmdata.Name)
} else if qmshareddata == "" {
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", qmdata.Name)
} else {
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, qmdata.Name)
}
networkingConfig := network.NetworkingConfig{}
qm, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
if err != nil {
return err, "", ""
}
startContainer(t, cli, qm.ID)
return nil, qm.ID, qmdata.Name
}
func getHostConfig(t *testing.T, mounts int, qmsharedlogs string, qmshareddata string, qmdata string) container.HostConfig {
var hostConfig container.HostConfig
switch mounts {
case 1:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
},
}
case 2:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmshareddata + ":/mnt/mqm-data",
},
}
case 3:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmsharedlogs + ":/mnt/mqm-log",
},
}
case 4:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmsharedlogs + ":/mnt/mqm-log",
qmshareddata + ":/mnt/mqm-data",
},
}
}
return hostConfig
}
func startContainer(t *testing.T, cli *client.Client, 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 := types.ContainerStartOptions{} startOptions := types.ContainerStartOptions{}
@@ -538,7 +452,6 @@ func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.
// execContainer runs a command in a running container, and returns the exit code and output // execContainer runs a command in a running container, and returns the exit code and output
func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd []string) (int, string) { func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd []string) (int, string) {
t.Logf("Running command: %v", cmd)
config := types.ExecConfig{ config := types.ExecConfig{
User: user, User: user,
Privileged: false, Privileged: false,
@@ -607,15 +520,13 @@ func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd
} }
func waitForReady(t *testing.T, cli *client.Client, ID string) { func waitForReady(t *testing.T, cli *client.Client, ID string) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel() defer cancel()
for { for {
select { select {
case <-time.After(1 * time.Second): case <-time.After(1 * time.Second):
rc, _ := execContainer(t, cli, ID, "", []string{"chkmqready"}) rc, _ := execContainer(t, cli, ID, "mqm", []string{"chkmqready"})
if rc == 0 { if rc == 0 {
t.Log("MQ is ready") t.Log("MQ is ready")
return return
@@ -798,23 +709,12 @@ func copyFromContainer(t *testing.T, cli *client.Client, id string, file string)
} }
func getPort(t *testing.T, cli *client.Client, ID string, port int) string { func getPort(t *testing.T, cli *client.Client, ID string, port int) string {
var inspectInfo types.ContainerJSON i, err := cli.ContainerInspect(context.Background(), ID)
var err error if err != nil {
for attemptsRemaining := 3; attemptsRemaining > 0; attemptsRemaining-- { t.Fatal(err)
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") portNat := nat.Port(fmt.Sprintf("%d/tcp", port))
return "" return i.NetworkSettings.Ports[portNat][0].HostPort
} }
func countLines(t *testing.T, r io.Reader) int { func countLines(t *testing.T, r io.Reader) int {

View File

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

View File

@@ -1,98 +0,0 @@
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Sirupsen/logrus v1.0.5 h1:447dy9LxSj+Iaa2uN3yoFHOzU9yJcJYiQPtNz8OXtv0=
github.com/Sirupsen/logrus v1.0.5/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.13.2-0.20170601211448-f5ec1e2936dc h1:y4nIGNQUH6JtUV3pd6HjnzdnHq+96wMDVXhkfZ6jc4E=
github.com/docker/docker v1.13.2-0.20170601211448-f5ec1e2936dc/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2019, 2020 © Copyright IBM Corporation 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.
@@ -32,7 +32,6 @@ var miEnv = []string{
// TestMultiInstanceStartStop creates 2 containers in a multi instance queue manager configuration // TestMultiInstanceStartStop creates 2 containers in a multi instance queue manager configuration
// 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())
cli, err := client.NewEnvClient() cli, err := client.NewEnvClient()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@@ -19,10 +19,13 @@ import (
"context" "context"
"fmt" "fmt"
"regexp" "regexp"
"strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client" "github.com/docker/docker/client"
) )
@@ -62,6 +65,78 @@ func singleMultiInstanceQueueManager(t *testing.T, cli *client.Client, qmsharedl
qmsChannel <- QMChan{QMId: qmId, QMData: qmData} qmsChannel <- QMChan{QMId: qmId, QMData: qmData}
} }
func getHostConfig(t *testing.T, mounts int, qmsharedlogs string, qmshareddata string, qmdata string) container.HostConfig {
var hostConfig container.HostConfig
switch mounts {
case 1:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
},
}
case 2:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmshareddata + ":/mnt/mqm-data",
},
}
case 3:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmsharedlogs + ":/mnt/mqm-log",
},
}
case 4:
hostConfig = container.HostConfig{
Binds: []string{
coverageBind(t),
qmdata + ":/mnt/mqm",
qmsharedlogs + ":/mnt/mqm-log",
qmshareddata + ":/mnt/mqm-data",
},
}
}
return hostConfig
}
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)
qmdata := createVolume(t, cli, id)
containerConfig := container.Config{
Image: imageName(),
Env: env,
}
var hostConfig container.HostConfig
if !dataVol {
hostConfig = container.HostConfig{}
} else if qmsharedlogs == "" && qmshareddata == "" {
hostConfig = getHostConfig(t, 1, "", "", qmdata.Name)
} else if qmsharedlogs == "" {
hostConfig = getHostConfig(t, 2, "", qmshareddata, qmdata.Name)
} else if qmshareddata == "" {
hostConfig = getHostConfig(t, 3, qmsharedlogs, "", qmdata.Name)
} else {
hostConfig = getHostConfig(t, 4, qmsharedlogs, qmshareddata, qmdata.Name)
}
networkingConfig := network.NetworkingConfig{}
qm, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+id)
if err != nil {
return err, "", ""
}
startContainer(t, cli, qm.ID)
return nil, qm.ID, qmdata.Name
}
func getActiveStandbyQueueManager(t *testing.T, cli *client.Client, 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")
@@ -76,7 +151,7 @@ func getActiveStandbyQueueManager(t *testing.T, cli *client.Client, qm1aId strin
} }
func getQueueManagerStatus(t *testing.T, cli *client.Client, 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, "mqm", []string{"bash", "-c", "dspmq", "-m", queueManagerName})
regex := regexp.MustCompile(`STATUS\(.*\)`) regex := regexp.MustCompile(`STATUS\(.*\)`)
status := regex.FindString(dspmqOut) status := regex.FindString(dspmqOut)
status = strings.TrimSuffix(strings.TrimPrefix(status, "STATUS("), ")") status = strings.TrimSuffix(strings.TrimPrefix(status, "STATUS("), ")")

View File

@@ -286,12 +286,12 @@ func TestQMRestart(t *testing.T) {
// Restart just the QM (to simulate a lost connection) // Restart just the QM (to simulate a lost connection)
t.Log("Stopping queue manager\n") t.Log("Stopping queue manager\n")
rc, out := execContainer(t, cli, id, "", []string{"endmqm", "-w", "-r", defaultMetricQMName}) rc, out := execContainer(t, cli, id, "mqm", []string{"endmqm", "-w", "-r", defaultMetricQMName})
if rc != 0 { if rc != 0 {
t.Fatalf("Failed to stop the queue manager. rc=%d, err=%s", rc, out) t.Fatalf("Failed to stop the queue manager. rc=%d, err=%s", rc, out)
} }
t.Log("starting queue manager\n") t.Log("starting queue manager\n")
rc, out = execContainer(t, cli, id, "", []string{"strmqm", defaultMetricQMName}) rc, out = execContainer(t, cli, id, "mqm", []string{"strmqm", defaultMetricQMName})
if rc != 0 { if rc != 0 {
t.Fatalf("Failed to start the queue manager. rc=%d, err=%s", rc, out) t.Fatalf("Failed to start the queue manager. rc=%d, err=%s", rc, out)
} }

View File

@@ -1,6 +1,5 @@
.classpath .classpath
.gradle .gradle
*.class
.project .project
.settings .settings
bin bin

View File

@@ -15,24 +15,22 @@
############################################################################### ###############################################################################
# Application build environment (Maven) # Application build environment (Maven)
############################################################################### ###############################################################################
FROM registry.redhat.io/ubi8/openjdk-8 as builder FROM docker.io/maven:3-ibmjava as builder
COPY pom.xml . COPY pom.xml /usr/src/mymaven/
#WORKDIR /usr/src/mymaven WORKDIR /usr/src/mymaven
# Download dependencies separately, so Docker caches them # Download dependencies separately, so Docker caches them
RUN mvn dependency:go-offline install RUN mvn dependency:go-offline install
# Copy source # Copy source
COPY src . COPY src /usr/src/mymaven/src
# Run the main build # Run the main build
RUN mvn --offline install RUN mvn --offline install
# Print a list of all the files (useful for debugging) # Print a list of all the files (useful for debugging)
RUN find . RUN find /usr/src/mymaven
############################################################################### ###############################################################################
# Application runtime (JRE only, no build environment) # Application runtime (JRE only, no build environment)
############################################################################### ###############################################################################
# OpenJDK is not technically supported with the MQ client, but is good enough for these tests FROM docker.io/ibmjava:8-jre
FROM registry.redhat.io/ubi8/openjdk-8-runtime COPY --from=builder /usr/src/mymaven/target/*.jar /opt/app/
COPY --from=builder /home/jboss/target/*.jar /opt/app/ COPY --from=builder /usr/src/mymaven/target/lib/*.jar /opt/app/
COPY --from=builder /home/jboss/target/lib/*.jar /opt/app/
USER 1001
ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"] ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]

View File

@@ -26,25 +26,25 @@ limitations under the License.
<dependency> <dependency>
<groupId>com.ibm.mq</groupId> <groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId> <artifactId>com.ibm.mq.allclient</artifactId>
<version>9.3.0.0</version> <version>9.0.5.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
<version>5.5.2</version> <version>5.3.2</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId> <artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version> <version>5.3.2</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.platform</groupId> <groupId>org.junit.platform</groupId>
<artifactId>junit-platform-console-standalone</artifactId> <artifactId>junit-platform-console-standalone</artifactId>
<version>1.5.2</version> <version>1.3.2</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
</dependencies> </dependencies>

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#!/bin/bash -ex #!/bin/bash
# -*- mode: sh -*- # -*- mode: sh -*-
# © Copyright IBM Corporation 2018, 2021 # © 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.
@@ -23,7 +23,6 @@ PASSWORD=passw0rd
openssl req \ openssl req \
-newkey rsa:2048 -nodes -keyout ${KEY} \ -newkey rsa:2048 -nodes -keyout ${KEY} \
-subj "/CN=localhost" \ -subj "/CN=localhost" \
-addext "subjectAltName = DNS:localhost" \
-x509 -days 3650 -out ${CERT} -x509 -days 3650 -out ${CERT}
# Add the key and certificate to a PKCS #12 key store, for the server to use # Add the key and certificate to a PKCS #12 key store, for the server to use

View File

@@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICwzCCAaugAwIBAgIJAKnwG0VGiDelMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV MIICpDCCAYwCCQC6vpJFnfYO6TANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
BAMMCWxvY2FsaG9zdDAeFw0yMTA5MDYxNTIyMDlaFw0zMTA5MDQxNTIyMDlaMBQx b2NhbGhvc3QwHhcNMTkwMzIxMTYxMzUxWhcNMjkwMzE4MTYxMzUxWjAUMRIwEAYD
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCu
ggEBALLmDX3OB/4DlzJzKz/Edc5qVdjdIN/u8pApSQPevT0mAsSK1uw2MObeOo4C 48qtIDwmihFqj2HY3dZjPfROA1MJ+D0c6aEA08ooOczthLB7XdZBQDapj8LFldyt
DCBmabYeuvGzZ4t3SiejdsHK+qAYMFW51lxTbulv5kUPvTBOY2JCENkVDFjqcK8S 4ZMbTkqtF5QtPXmJY0wi39foLYlcGXPL1b7y3mypaFou88BcSM3VmfILKXhNeAlt
9ItI/UzTmnBolvZmUKzROHzA/pFb/jkhlzqJO+TqIBXKLF5gdFFTiHHcqfoUyVOV rXevnuT5kDU7sLVgKGhGwas20T1MU7d0I3bQ5z5c7egL76Hk9fYucjN6RkbwlrJ3
n+49V8z6W2rokz4QIWa5Dlh6VS1B6VXdihJv5P9HV8P8FOtefhA85yaSVKlFS/AC TrCXrGIziofn3Zq1t51ygv21c80JD3XJ44YmuCrede4rhOS/4NpwRuZyiwpJ6tlv
XRb5FmtmYHBnghLktHS71s/KcPeX27Q1NcKhmZMvHRH95hqEcP25S6SGu69eiCLk 0L0QSDGCmt2JT3ty28UAsGznFzC5Qu9KyaR+9Gk4aftiyKxrYWZkgtJmMRU+C1X2
xpbJKqG3fntfooLUDfR2PHQUJ7UCAwEAAaMYMBYwFAYDVR0RBA0wC4IJbG9jYWxo kFLOHsucGmJswjwubSR7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEdlmXVGy86P
b3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBamIH23oDh1XxOeMPUEyPLHm5M8LM8FNhT XIX5a4ZmHQ5Ns4wm7rY8vzUxlymEQ86En1PN1zAO9gV94tLyNeMptjsFEEo/uJhC
GEpf1ICy4TSLipSFhIs3hGzVt22zBBzU59apQ8rXUME5SK+9PLag/t/48rG1SfUA Yvg3l5TIr/WCiY2+2XsSHvnbXrlbF3S0fRHa9VaCMRKjzRT68uq2Y891906YGtUE
VyYvaeu/cA5NQMWwuyCLqZL1MWn+BLsdAiNtbNHANesnl0i+vUb0GPzSP8soe3PP m6fCjHqVzX8qaplDf79aVkPydYaYOIZ1a/mCfQcD9XMZ/v5zI9IUDhdoq97bgPhB
N7Fh8SO3Qq6e9zT3iE2tP2OFxzcpg538Xn3qoVPJwmLIfBtvsiK07zqAWdqBWtt6 gBOzWLI+hkzyU8jxKAFw1Hwi9lD/P6RXL5arNb/+arOgA3vTW+xGWGevgjVK1Ay9
cBXyagnmgKvOyv6sKAlTpwP9HqVem3XxZVrhm1KiPHs4Dnks6e79txmB8lqzvWu5 81beWiQmn0KbeLZxj+WJ9Nntlf1M4EqPYgsSYs/IlJTYS8W1B0mDJEoovPdFTryY
tu4h2ePGJjqUy5JkkoDY0j6hALwEe3ZXBvJ6XUQDi9Hou2k+MaQd GyIuQEVcjUE=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCy5g19zgf+A5cy MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu48qtIDwmihFq
cys/xHXOalXY3SDf7vKQKUkD3r09JgLEitbsNjDm3jqOAgwgZmm2Hrrxs2eLd0on j2HY3dZjPfROA1MJ+D0c6aEA08ooOczthLB7XdZBQDapj8LFldyt4ZMbTkqtF5Qt
o3bByvqgGDBVudZcU27pb+ZFD70wTmNiQhDZFQxY6nCvEvSLSP1M05pwaJb2ZlCs PXmJY0wi39foLYlcGXPL1b7y3mypaFou88BcSM3VmfILKXhNeAltrXevnuT5kDU7
0Th8wP6RW/45IZc6iTvk6iAVyixeYHRRU4hx3Kn6FMlTlZ/uPVfM+ltq6JM+ECFm sLVgKGhGwas20T1MU7d0I3bQ5z5c7egL76Hk9fYucjN6RkbwlrJ3TrCXrGIziofn
uQ5YelUtQelV3YoSb+T/R1fD/BTrXn4QPOcmklSpRUvwAl0W+RZrZmBwZ4IS5LR0 3Zq1t51ygv21c80JD3XJ44YmuCrede4rhOS/4NpwRuZyiwpJ6tlv0L0QSDGCmt2J
u9bPynD3l9u0NTXCoZmTLx0R/eYahHD9uUukhruvXogi5MaWySqht357X6KC1A30 T3ty28UAsGznFzC5Qu9KyaR+9Gk4aftiyKxrYWZkgtJmMRU+C1X2kFLOHsucGmJs
djx0FCe1AgMBAAECggEAagD5A49+mtwjzigB+4H80Def8KVuomIi5psgAaQM+9u3 wjwubSR7AgMBAAECggEAH9t6teKjUlngJksMBdcTEGzerb9JRw2jBDtCisYJkx5E
DiC6ozKlHVeW2KiL6PLmNpzU5v0IINKpZP1uE/yjLxPGKDW6t/BUKww8JLXjw2jf SBfdlftX5fbufiCj2B4eXsYyZ8zxKWqcIUmLdA1Udx3TVIXG+bHhOAYtjEwb+xf5
aMx+0TKwo0sfRA32S0YPmWNVAsBmm1AbA5vhXcK51QXuiInH406H5+d25ZJrYevF JYhdR/IzHG+4eXQKaAIvpXztyl3lU9iC+eaMg4GYzRrGN2wSAG9XgZ5cLF2TLJYU
liKWSjx9CM/0XO7t20j18mCa8RjBEdsZoHxHsoWNvFJ6DCR25cFShAhR7s4OtkUk jPxp7goz9X6V57aL2G/EFlbFsMaI/6cW7+XoRdo0I4N2Z766gz7GgyxtTVwR5Peq
yELm1tYYrFOffUM0Q/Fp9uSlCHWMSqPtf/6NEfnszfFEtzDh/N+YqC1Bexv0XPsD LjOpqSNS0W57KJxReURfySok9CP1DfyigopsYW8O4jGVDDRLdiN3I8+JhWya2E0j
dBPOkUZjWA2Sc8Se1t2GLfrRURzj3GvWH1+GssjsAQKBgQDeIdyzQSqce4Kn0opa 96hHpN04Oz6HnMm7bdZDVtkZCOiu6xIzLJJxZ4o+kQKBgQDYqOA/hSod7s7w4LBE
vdS5moCiv3pyfNd0nYe0awgVos4kHY7/nBq0eyMZAatRHeD3DunVsw3LmvWyEw53 A6Mp+e0//PYH6/N9SKmSIgQNec9bMGI4yanoblMbg4GM1g7pkvjlC0nTdjnUbLkB
app7MTTjVrYaadoBlB6jy2elyF5RcW2jGchZExoNh+0ZQWUiMbYEozPLQTy9ZxMz vIvtVh3XwTIlrZ/4lc7VB23/hmKU+lRc+NJP5fgasAQu0W3+qp2cXo0pnHVwBEku
t0OcZ1hHPngGgmj5TELZKkwEtQKBgQDOLLh7pdKrdudtim+o4H20jl5yYKl25Iq/ Z7FwDPX0JNDIi/Or2I7dt8JojQKBgQDOpU1AnIXv1/cToYK4nz8BWLxRxwLTxy5A
DKVodwUd94cM7xAIOQJrx2XK/YPCfRkKRN1wxzAhYdIVkaaKDVhI8Jeu+H18QOa6 ucafNKacPlxb5luZRCExiPZwAM8Z3zI9o99rYXOPQmsnknZWJV66Zx0Vo0yTD1CT
5OlzzZcqJCtACpbVqLaDcmq8pRrAYekiwMIKwC95llvktjilvLfoUnQoXAaX8E8B DWMUj0ugI1wORNMhwZP6YBYWjAeupyU9a7FyU1Geg4sdQt5rMyAEQOoECc8x8foP
yCSUvDh3AQKBgQCxa0h04DLho4Da/D3HdmHHERF3bAqoEPCh0wTF5MsjRNLzY6yI rySHuO/TJwKBgBjMM2ZxymFErQDa5rHSLMGoLmRtgodjlSnYwDfOluIn9/i67/MJ
mq11w/hni77C3mOF0SKRrh7xpcZiQfhHBx12EfpVLjfq5uraYe0LFHanol87G6bf +d11iyOSCKji8y/+t2gXw6plVLcgfohZWTaf7ah9H006sx2Tn+m4APoHGo9sm21M
I8Oy6Z/geNW2W1YktqHUGGpRCL0z5nUe1FyrOpv2431Ibbbcj73A6JipFQKBgHdl uV2Vt7DuRnxJUiqcwo9cLxH9K1/Xzbx299MYWKpJ8G+TvR8FGUz9NE4dAoGAM5gs
vJyWpk73+AQe1JUnFIU4oYd5ZQpeRd9n8m5x5ru4+jPKSi2I3lcOTWvlrqU2Dwc8 KKSsAE1QwFMEG2qPRZvNMTHaL9w8XSbFQ7zWmI4tazihyCutifujZCWfj9sdZSyE
ZEUIhV3/qUsmYxy1p7ft5NnGO912NGhtYqjWmcEk2wsmVr17C99JpniC4OAik4G1 PQBQ5QT1UiUMbMfZ1fqm1V83YERjnsOp6Fk6zZnmgx2GBZiahNn2ydxekqni72nz
wWm6bIPsSGFGCb4pcROQlIY+7O6WkxqEDnM4ITcBAoGAHXBKmadFpupUeGSkCwEo HRNWfphjZIPsmqFiLg2zIBz+4X6EK+RT35s6LeMCgYEAwF/9jX8kONW5KKZdoNHa
/VjeI4QoKKcWj9K8z8ifCVPz1FiQ1AJ91WMTM7PAmpEDX058Hor9xxJ2bEtQFwUS opkLpa9qkwTGQ9M3AZiRUjM4rtvggYt8FBEP+3BLDLHqfUOkPq82MCRXm+6Cz+sT
QKvjeU+/Ig0TWjsJBgBPvc0xYLaJptAbjvG4a5nBn7hwbRzLTcKx2OVTmdAkz00H gyPnsPlAh/sr3Pys3olJbUDE9H24k1LU0CI/sSwAFkka0+Q7PVTTe/Dcavitrcrm
1lq8cwizfwNgt8ldFFDDRvw= +fyiT2oSPZeHSjQE9iIW3OY=
-----END PRIVATE KEY----- -----END PRIVATE KEY-----

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