Compare commits

..

17 Commits

Author SHA1 Message Date
Robert Parker
d131a325da Security fixes, Nov 2018 2018-11-07 14:58:52 +00:00
Robert Parker
cbdd80118b update apparmor 2018-10-09 09:53:48 +01:00
Stephen Marshall
2ddb7322d7 Fix RTC ppcle_linux build (#209) 2018-09-19 17:11:16 +01:00
Stephen Marshall
4ca342251d Fix lint error - 9.1.0 (#187)
* Fix lint error

* Remove incorrect import
2018-08-13 12:33:33 +01:00
Rob Parker
741ed9451f Merge pull request #185 from arthurbarr/9.1.0
Port latest fixes to 9.1.0
2018-08-08 08:41:02 +01:00
Arthur Barr
48e9001416 Remove unused variable in Dockerfiles 2018-08-07 17:05:12 +01:00
Arthur Barr
4dc843a569 Remove debug statements 2018-08-07 17:05:04 +01:00
Arthur Barr
bbbd305654 Enable only app user to do REST messaging 2018-08-07 17:04:56 +01:00
Arthur Barr
739a01a83d Fix Mac incompatibility of image creation date 2018-08-07 17:04:49 +01:00
Arthur Barr
0c9338b7d6 Enable admin and app users to do REST messaging 2018-08-07 17:04:40 +01:00
Arthur Barr
5dc5d2f3a5 Merge commit 'b8f96d0148a4743807f7493c2f818b907192c615' into 9.1.0 2018-08-07 17:04:29 +01:00
Robert Parker
e8f8655408 make sure to use -aG not -G 2018-08-07 17:04:06 +01:00
Rob Parker
3a1db1a04e force string output in chkmqhealthy (#174) 2018-08-07 17:03:58 +01:00
Rob Parker
acbde18921 check explicitly for /mnt/mqm (#175) 2018-08-07 17:03:50 +01:00
Arthur Barr
1f8bb5fe05 Merge commit '29dfe38d32f50ecbb43cc02c3c482d5c610cc9c7' into 9.1.0 2018-08-07 17:03:31 +01:00
Robert Parker
8afcb56ea8 only download the sdk image if we need to 2018-08-07 17:02:46 +01:00
Robert Parker
0caf879a70 Update license to 9.1 2018-07-25 12:37:01 +01:00
81 changed files with 1079 additions and 3117 deletions

5
.gitignore vendored
View File

@@ -7,8 +7,3 @@ build
coverage
downloads
incubating/mqipt/ms81*
vendor/github.com/prometheus/client_model/bin/
vendor/github.com/prometheus/client_model/.classpath
vendor/github.com/prometheus/client_model/.project
vendor/github.com/prometheus/client_model/.settings*
gosec_results.json

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2019
# © Copyright IBM Corporation 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
dist: xenial
sudo: required
language: go
@@ -29,51 +27,43 @@ cache:
directories:
- downloads
env:
- BASE_IMAGE=ubuntu:16.04
# Commented out temporarily until Issue 166 is resolved
# - BASE_IMAGE=centos:latest
jobs:
include:
- stage: build and test
env:
- BASE_IMAGE=ubuntu:16.04
- DOCKER_DOWNGRADE="echo nothing to be done"
- env:
- BASE_IMAGE=centos:7
- DOCKER_DOWNGRADE="echo nothing to be done"
- if: type IN (pull_request) OR tag IS present
env:
- BASE_IMAGE=ubuntu:16.04
- DOCKER_DOWNGRADE="docker save -o images.tar mqadvanced-server-dev mq-dev-jms-test &&
sudo apt-get autoremove -y docker-ce &&
curl -fsSL \"https://apt.dockerproject.org/gpg\" | sudo apt-key add - &&
sudo apt-add-repository \"deb https://apt.dockerproject.org/repo ubuntu-$(lsb_release -cs) main\" &&
sudo apt-get update &&
sudo apt-get install docker-engine=1.12.6-0~ubuntu-$(lsb_release -cs) &&
docker load -q -i images.tar &&
export DOCKER_API_VERSION=\"1.24\""
- if: type IN (pull_request)
env: DOCKER_DOWNGRADE="docker save -o images.tar mqadvanced-server-dev mq-dev-jms-test &&
sudo apt-get autoremove -y docker-ce &&
curl -fsSL \"https://apt.dockerproject.org/gpg\" | sudo apt-key add - &&
sudo apt-add-repository \"deb https://apt.dockerproject.org/repo ubuntu-$(lsb_release -cs) main\" &&
sudo apt-get update &&
sudo apt-get install docker-engine=1.12.6-0~ubuntu-$(lsb_release -cs) &&
docker load -q -i images.tar &&
export DOCKER_API_VERSION=\"1.24\""
- env: DOCKER_DOWNGRADE="echo nothing to be done"
before_install:
- ./install-build-deps-ubuntu.sh
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- sudo apt-get update
- sudo apt-get -y install docker-ce
- curl https://glide.sh/get | sh
- sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64
- sudo chmod +x /usr/local/bin/dep
install:
- 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'
- make deps
- make build-devserver
- make build-devjmstest
- 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:
- go get golang.org/x/lint/golint
- make lint

View File

@@ -1,30 +1,5 @@
# Change log
## vNext
* Now runs using the "mqm" user instead of root. See new [security doc](https://github.com/ibm-messaging/mq-container/blob/master/docs/security.md)
* New [IGNSTATE](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.pro.doc/q132310_.htm#q132310___ignstateparm) parameter used in default developer config
* Termination log moved from `/dev/termination-log` to `/run/termination-log`, to make permissions easier to handle
* Fixes for the following issues:
* Brackets no longer appear in termination log
* Test timeouts weren't being used correctly
## 9.1.1.0 (2018-11-30)
* Updated to MQ version 9.1.1.0
* Created seperate RedHat Makefile for building images on RedHat machines with buildah
* Enabled REST messaging capability for app user.
* Added support for container supplementary groups
* Removed IBM MQ version 9.0.5 details.
* Added additional Diagnostics ([#203](https://github.com/ibm-messaging/mq-container/pull/203))
* Implementted GOSec to perform code scans for security vulnerabilities. (([#227](https://github.com/ibm-messaging/mq-container/pull/227)))
* Removed Queue manager create option from the MQ Console.
* Fixes for the following issues:
* Check explicitly for `/mnt/mqm` ([#175](https://github.com/ibm-messaging/mq-container/pull/175))
* Force string output in chkmqhealthy ([#174](https://github.com/ibm-messaging/mq-container/pull/174))
* Use -aG not -G when adding a group for a user
* Security fixes for libsystemd0 systemd systemd-sysv & libudev1
## 9.1.0.0 (2018-07-23)
* Updated to MQ version 9.1.0.0

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2019
# © Copyright IBM Corporation 2015, 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
# limitations under the License.
ARG BASE_IMAGE=ubuntu:16.04
ARG BUILDER_IMAGE=mq-golang-sdk:9.1.1.0-x86_64-ubuntu-16.04
ARG BUILDER_IMAGE=mq-golang-sdk:9.0.5.0-x86_64-ubuntu-16.04
###############################################################################
# Build stage to build Go code
@@ -22,11 +22,10 @@ FROM $BUILDER_IMAGE as builder
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
ARG IMAGE_REVISION="Not specified"
ARG IMAGE_SOURCE="Not specified"
ARG IMAGE_TAG="Not specified"
COPY cmd/ ./cmd
COPY internal/ ./internal
COPY vendor/ ./vendor
RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\" -X \"main.ImageTag=$IMAGE_TAG\"" ./cmd/runmqserver/
RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\"" ./cmd/runmqserver/
RUN go build ./cmd/chkmqready/
RUN go build ./cmd/chkmqhealthy/
# Run all unit tests
@@ -48,15 +47,12 @@ ARG MQ_URL
# The MQ packages to install - see install-mq.sh for default value
ARG MQ_PACKAGES
# The UID to use for the "mqm" user
ARG MQM_UID=999
COPY install-mq.sh /usr/local/bin/
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
RUN chmod u+x /usr/local/bin/install-mq.sh \
&& sleep 1 \
&& install-mq.sh $MQM_UID
&& install-mq.sh
# Create a directory for runtime data from runmqserver
RUN mkdir -p /run/runmqserver \
@@ -68,21 +64,11 @@ COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
RUN chmod ug+x /usr/local/bin/runmqserver \
&& chown mqm:mqm /usr/local/bin/*mq* \
&& chmod ug+xs /usr/local/bin/chkmq* \
&& install --directory --mode 0775 --owner mqm --group root /run/runmqserver \
&& install --directory --mode 0775 --owner mqm --group root /run/tls \
&& touch /run/termination-log \
&& chown mqm:root /run/termination-log \
&& chmod 0660 /run/termination-log
&& chmod ug+xs /usr/local/bin/chkmq*
# Always use port 1414 for MQ, 9157 for the metrics & 9443 for the web console
EXPOSE 1414 9157 9443
# Copy web XML files
COPY web /etc/mqm/web
# Always use port 1414 for MQ & 9157 for the metrics
EXPOSE 1414 9157
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic
USER $MQM_UID
ENTRYPOINT ["runmqserver"]

View File

@@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS
© Copyright IBM Corporation. 2015, 2019
© Copyright IBM Corporation. 2015, 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

366
Makefile
View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2019
# © Copyright IBM Corporation 2017, 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,163 +13,287 @@
# limitations under the License.
###############################################################################
# Variables
# Conditional variables - you can override the values of these variables from
# the command line
###############################################################################
GO_PKG_DIRS = ./cmd ./internal ./test
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
BASE_IMAGE ?= ubuntu:16.04
# MQ_VERSION is the fully qualified MQ version number to build
MQ_VERSION ?= 9.1.0.0
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
# Does not apply to MQ Advanced for Developers.
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION)_$(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
# for Developers can be installed
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 ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
# Options to `go test` for the Docker tests
TEST_OPTS_DOCKER ?=
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image
MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# MQ_IMAGE_SDK is the name and tag of the built MQ Advanced for Developers SDK image
MQ_IMAGE_SDK ?=mq-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# MQ_IMAGE_GOLANG_SDK is the name and tag of the built MQ Advanced for Developers SDK image, plus Go tools
MQ_IMAGE_GOLANG_SDK ?=mq-golang-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# DOCKER is the Docker command to run
DOCKER ?= docker
# MQ_PACKAGES specifies the MQ packages (.deb or .rpm) to install. Defaults vary on base image.
MQ_PACKAGES ?=
# Set variable if running on a Red Hat Enterprise Linux host
ifneq ($(wildcard /etc/redhat-release),)
REDHAT_RELEASE = $(shell cat /etc/redhat-release)
ifeq "$(findstring Red Hat,$(REDHAT_RELEASE))" "Red Hat"
RHEL_HOST = "true"
###############################################################################
# Other variables
###############################################################################
# ARCH is the platform architecture (e.g. x86_64, ppc64le or s390x)
ARCH = $(shell uname -m)
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
BUILD_SERVER_CONTAINER=build-server
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
# test run in parallel
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=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# Docker image name to use for JMS tests
DEV_JMS_IMAGE=mq-dev-jms-test
# Variables for versioning
IMAGE_REVISION=$(shell git rev-parse HEAD)
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
ifneq (,$(findstring Microsoft,$(shell uname -r)))
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
else
DOWNLOADS_DIR=$(realpath ./downloads/)
endif
# Try to figure out which archive to use from the BASE_IMAGE
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
MQ_ARCHIVE_TYPE=UBUNTU
MQ_ARCHIVE_DEV_PLATFORM=ubuntu
else
MQ_ARCHIVE_TYPE=LINUX
MQ_ARCHIVE_DEV_PLATFORM=linux
endif
# Try to figure out which archive to use from the architecture
ifeq "$(ARCH)" "x86_64"
MQ_ARCHIVE_ARCH=X86-64
MQ_DEV_ARCH=x86-64
else ifeq "$(ARCH)" "ppc64le"
MQ_ARCHIVE_ARCH=LE_POWER
MQ_DEV_ARCH=ppcle
else ifeq "$(ARCH)" "s390x"
MQ_ARCHIVE_ARCH=SYSTEM_Z
MQ_DEV_ARCH=s390x
endif
# Archive names for IBM MQ Advanced for Developers
MQ_ARCHIVE_DEV_9.0.5.0=mqadv_dev905_$(MQ_ARCHIVE_DEV_PLATFORM)_x86-64.tar.gz
MQ_ARCHIVE_DEV_9.1.0.0=mqadv_dev910_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
###############################################################################
# Build targets
###############################################################################
.PHONY: vars
vars:
#ifeq "$(findstring ubuntu,$(BASE_IMAGE))","ubuntu"
@echo $(MQ_ARCHIVE_ARCH)
@echo $(MQ_ARCHIVE_TYPE)
@echo $(MQ_ARCHIVE)
# Targets default to a RHEL image on a RHEL host, or an Ubuntu image everywhere else
.PHONY: default
default: build-devserver test
.PHONY: build-devserver
ifdef RHEL_HOST
build-devserver: build-devserver-rhel
else
build-devserver: build-devserver-ubuntu
endif
# Build all components (except incubating ones)
.PHONY: all
all: build-devserver build-advancedserver
.PHONY: build-advancedserver
ifdef RHEL_HOST
build-advancedserver: build-advancedserver-rhel
else
build-advancedserver: build-advancedserver-ubuntu
endif
.PHONY: test-all
test-all: test-devserver test-advancedserver
.PHONY: precommit
precommit: fmt lint all test-all
.PHONY: test-devserver
ifdef RHEL_HOST
test-devserver: test-devserver-rhel
else
test-devserver: test-devserver-ubuntu
endif
.PHONY: devserver
devserver: build-devserver test-devserver
.PHONY: test-advancedserver
ifdef RHEL_HOST
test-advancedserver: test-advancedserver-rhel
else
test-advancedserver: test-advancedserver-ubuntu
endif
# Build incubating components
.PHONY: incubating
incubating: build-explorer
.PHONY: build-devjmstest
ifdef RHEL_HOST
build-devjmstest: build-devjmstest-rhel
else
build-devjmstest: build-devjmstest-ubuntu
endif
# UBUNTU building targets
.PHONY: build-devserver-ubuntu
build-devserver-ubuntu:
$(MAKE) -f Makefile-UBUNTU build-devserver
.PHONY: test-devserver-ubuntu
test-devserver-ubuntu:
$(MAKE) -f Makefile-UBUNTU test-devserver
.PHONY: build-devjmstest-ubuntu
$(MAKE) -f Makefile-UBUNTU build-devjmstest
.PHONY: build-advancedserver-ubuntu
build-advancedserver-ubuntu:
$(MAKE) -f Makefile-UBUNTU build-advancedserver
.PHONY: test-advancedserver-ubuntu
test-advancedserver-ubuntu:
$(MAKE) -f Makefile-UBUNTU test-advancedserver
.PHONY: build-devjmstest-ubuntu
build-devjmstest-ubuntu:
$(MAKE) -f Makefile-UBUNTU build-devjmstest
# RHEL building targets
.PHONY: build-devserver-rhel
build-devserver-rhel:
$(MAKE) -f Makefile-RHEL build-devserver
.PHONY: test-devserver-rhel
test-devserver-rhel:
$(MAKE) -f Makefile-RHEL test-devserver
.PHONY: build-advancedserver-rhel
build-advancedserver-rhel:
$(MAKE) -f Makefile-RHEL build-advancedserver
.PHONY: test-advancedserver-rhel
test-advancedserver-rhel:
$(MAKE) -f Makefile-RHEL test-advancedserver
.PHONY: build-devjmstest-rhel
build-devjmstest-rhel:
$(MAKE) -f Makefile-RHEL build-devjmstest
# Common targets
.PHONY: clean
clean:
rm -rf ./coverage
rm -rf ./build
rm -rf ./deps
downloads/$(MQ_ARCHIVE_DEV):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
downloads/$(MQ_SDK_ARCHIVE):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_SDK_ARCHIVE)
.PHONY: downloads
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
.PHONY: deps
deps:
glide install --strip-vendor
# Vendor Go dependencies for the Docker tests
test/docker/vendor:
cd test/docker && dep ensure -vendor-only
.PHONY: build-cov
build-cov:
mkdir -p build
cd build; go test -c -covermode=count ../cmd/runmqserver
.PHONY: precommit
precommit: fmt lint
# Shortcut to just run the unit tests
.PHONY: test-unit
test-unit:
docker build --target builder --file Dockerfile-server .
.PHONY: test-advancedserver
test-advancedserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on $(shell docker --version)"$(END)))
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
.PHONY: build-devjmstest
build-devjmstest:
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
.PHONY: test-devserver
test-devserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on $(shell docker --version)"$(END)))
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER)
coverage:
mkdir coverage
.PHONY: test-advancedserver-cover
test-advancedserver-cover: test/docker/vendor coverage
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) with code coverage on $(shell docker --version)"$(END)))
rm -f ./coverage/unit*.cov
# Run unit tests with coverage, for each package under 'internal'
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
# ls -1 ./cmd | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./cmd/{}/...
echo 'mode: count' > ./coverage/unit.cov
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
rm -f ./test/docker/coverage/*.cov
rm -f ./coverage/docker.*
mkdir -p ./test/docker/coverage/
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER)-cover TEST_COVER=true go test $(TEST_OPTS_DOCKER)
echo 'mode: count' > ./coverage/docker.cov
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
echo 'mode: count' > ./coverage/combined.cov
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
define docker-build-mq
# Create a temporary network to use for the build
$(DOCKER) network create build
# Start a web server to host the MQ downloadable (tar.gz) file
$(DOCKER) run \
--rm \
--name $(BUILD_SERVER_CONTAINER) \
--network build \
--network-alias build \
--volume $(DOWNLOADS_DIR):/usr/share/nginx/html:ro \
--detach \
nginx:alpine
# Build the new image
$(DOCKER) build \
--tag $1 \
--file $2 \
--network build \
--build-arg MQ_URL=http://build:80/$3 \
--build-arg BASE_IMAGE=$(BASE_IMAGE) \
--build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) \
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
--label IBM_PRODUCT_ID=$4 \
--label IBM_PRODUCT_NAME=$5 \
--label IBM_PRODUCT_VERSION=$6 \
--build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \
. ; $(DOCKER) kill $(BUILD_SERVER_CONTAINER) && $(DOCKER) network rm build
endef
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
DOCKER_CLIENT_VERSION=$(shell docker version --format "{{ .Client.Version }}")
.PHONY: docker-version
docker-version:
@test "$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
.PHONY: build-advancedserver
build-advancedserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE)
build-advancedserver: downloads/$(MQ_ARCHIVE) docker-version build-golang-sdk-ex
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
$(call docker-build-mq,$(MQ_IMAGE_ADVANCEDSERVER),Dockerfile-server,$(MQ_ARCHIVE),"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced",$(MQ_VERSION))
.PHONY: build-devserver
# Target-specific variable to add web server into devserver image
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
build-devserver: MQ_PACKAGES=ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams ibmmq-web
else
build-devserver: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm MQSeriesWeb-*.rpm
endif
build-devserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE_DEV)
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version build-golang-sdk-ex
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER_BASE)"$(END)))
$(call docker-build-mq,$(MQ_IMAGE_DEVSERVER_BASE),Dockerfile-server,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
$(DOCKER) build --tag $(MQ_IMAGE_DEVSERVER) --build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" --build-arg IMAGE_REVISION="$(IMAGE_REVISION)" --build-arg BASE_IMAGE=$(MQ_IMAGE_DEVSERVER_BASE) --build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) --file incubating/mqadvanced-server-dev/Dockerfile .
.PHONY: build-advancedserver-cover
build-advancedserver-cover: docker-version
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_IMAGE_ADVANCEDSERVER)-cover -f Dockerfile-server.cover .
.PHONY: build-explorer docker-pull
build-explorer: downloads/$(MQ_ARCHIVE_DEV)
$(call docker-build-mq,mq-explorer:latest-$(ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
.PHONY: build-sdk
build-sdk: downloads/$(MQ_SDK_ARCHIVE) build-sdk-ex
.PHONY: build-sdk-ex
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
build-sdk-ex: MQ_PACKAGES=ibmmq-sdk ibmmq-samples build-essential
else
build-sdk-ex: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm
endif
build-sdk-ex: docker-version docker-pull
$(call docker-build-mq,$(MQ_IMAGE_SDK),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))
.PHONY: build-golang-sdk
build-golang-sdk: downloads/$(MQ_SDK_ARCHIVE) build-golang-sdk-ex
.PHONY: build-golang-sdk-ex
build-golang-sdk-ex: docker-version build-sdk-ex
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_SDK) -t $(MQ_IMAGE_GOLANG_SDK) -f incubating/mq-golang-sdk/Dockerfile .
# $(call docker-build-mq,$(MQ_IMAGE_GOLANG_SDK),incubating/mq-golang-sdk/Dockerfile,$(MQ_IMAGE_SDK),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))
docker-pull:
$(DOCKER) pull $(BASE_IMAGE)
GO_PKG_DIRS = ./cmd ./internal ./test
.PHONY: fmt
fmt: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
go fmt $(addsuffix /..., $(GO_PKG_DIRS))
.PHONY: lint
lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
@# This expression is necessary because /... includes the vendor directory in golint
@# As of 11/04/2018 there is an open issue to fix it: https://github.com/golang/lint/issues/320
golint -set_exit_status $(sort $(dir $(wildcard $(addsuffix /*/*.go, $(GO_PKG_DIRS)))))
.PHONY: gosec
gosec: $(info $(SPACER)$(shell printf "Running gosec test"$(END)))
@gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\
cat "gosec_results.json" ;\
cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\
if [ $$? -eq 0 ]; then \
printf "\nFAILURE: gosec found files containing HIGH severity issues - see results.json\n" ;\
exit 1 ;\
else \
printf "\ngosec found no HIGH severity issues\n" ;\
fi ;\
cat gosec_results.json | grep MEDIUM | grep severity > /dev/null ;\
if [ $$? -eq 0 ]; then \
printf "\nFAILURE: gosec found files containing MEDIUM severity issues - see results.json\n" ;\
exit 1 ;\
else \
printf "\ngosec found no MEDIUM severity issues\n" ;\
fi ;\
cat gosec_results.json | grep LOW | grep severity > /dev/null;\
if [ $$? -eq 0 ]; then \
printf "\nFAILURE: gosec found files containing LOW severity issues - see results.json\n" ;\
exit 1;\
else \
printf "\ngosec found no LOW severity issues\n" ;\
fi ;\
.PHONY: unknownos
unknownos:
$(info $(SPACER)$(shell printf "ERROR: Unknown OS ("$(BASE_OS)") please run specific make targets"$(END)))
exit 1
include formatting.mk

View File

@@ -1,203 +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.
###############################################################################
# Conditional variables - you can override the values of these variables from
# the command line
###############################################################################
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
BASE_IMAGE ?= rhel
# MQ_VERSION is the fully qualified MQ version number to build
MQ_VERSION ?= 9.1.1.0
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
# Does not apply to MQ Advanced for Developers.
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_LINUX_$(MQ_ARCHIVE_ARCH).tar.gz
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
# for Developers can be installed
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
# MQ_SDK_ARCHIVE specifies the archive to use for the MQ redistributable client, which is used for building the golang programs.
MQ_SDK_ARCHIVE ?= 9.1.1.0-IBM-MQC-Redist-LinuxX64.tar.gz
# Options to `go test` for the Docker tests
TEST_OPTS_DOCKER ?=
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-integration-$(ARCH)
# MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image
MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev:$(MQ_VERSION)-integration-$(ARCH)
# MQ_IMAGE_SDK is the name and tag of the built MQ Advanced for Developers SDK image
MQ_IMAGE_SDK ?=mq-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# MQ_IMAGE_GOLANG_SDK is the name and tag of the built MQ Advanced for Developers SDK image, plus Go tools
MQ_IMAGE_GOLANG_SDK ?=mq-golang-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# MQ_PACKAGES specifies the MQ packages to install. Defaults vary on base image.
MQ_PACKAGES ?= MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm MQSeriesWeb-*.rpm
###############################################################################
# Other variables
###############################################################################
# ARCH is the platform architecture (e.g. x86_64, ppc64le or s390x)
ARCH = $(shell uname -m)
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# Docker image name to use for JMS tests
DEV_JMS_IMAGE=mq-dev-jms-test:latest
# Variables for versioning
IMAGE_REVISION=$(shell git rev-parse HEAD)
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
MQDEV=
EMPTY:=
SPACE:= $(EMPTY) $(EMPTY)
# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.1 instead of 9.1.1.0
MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION))))
ifneq (,$(findstring Microsoft,$(shell uname -r)))
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
else
DOWNLOADS_DIR=$(realpath ./downloads/)
endif
# Try to figure out which archive to use from the architecture
ifeq "$(ARCH)" "x86_64"
MQ_ARCHIVE_ARCH=X86-64
MQ_DEV_ARCH=x86-64
else ifeq "$(ARCH)" "ppc64le"
MQ_ARCHIVE_ARCH=LE_POWER
MQ_DEV_ARCH=ppcle
else ifeq "$(ARCH)" "s390x"
MQ_ARCHIVE_ARCH=SYSTEM_Z
MQ_DEV_ARCH=s390x
endif
# Archive names for IBM MQ Advanced for Developers
MQ_ARCHIVE_DEV_9.0.5.0=mqadv_dev905_linux_x86-64.tar.gz
MQ_ARCHIVE_DEV_9.1.0.0=mqadv_dev910_linux_$(MQ_DEV_ARCH).tar.gz
MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_linux_$(MQ_DEV_ARCH).tar.gz
###############################################################################
# Build targets
###############################################################################
.PHONY: vars
vars:
#ifeq "$(findstring ubuntu,$(BASE_IMAGE))","ubuntu"
@echo $(MQ_ARCHIVE_ARCH)
@echo $(MQ_ARCHIVE_TYPE)
@echo $(MQ_ARCHIVE)
.PHONY: default
default: build-devserver test-devserver
# Build all components (except incubating ones)
.PHONY: all
all: build-devserver build-advancedserver
.PHONY: test-all
test-all: build-devjmstest test-devserver test-advancedserver
.PHONY: devserver
devserver: build-devserver build-devjmstest test-devserver
# Build incubating components
.PHONY: incubating
incubating: build-explorer
downloads/$(MQ_ARCHIVE_DEV):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
downloads/$(MQ_SDK_ARCHIVE):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced redistributable client "$(MQ_VERSION)$(END)))
mkdir -p downloads
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist/$(MQ_SDK_ARCHIVE)
.PHONY: downloads
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
# Vendor Go dependencies for the Docker tests
test/docker/vendor:
cd test/docker && dep ensure -vendor-only
.PHONY: check-prereqs
check-prereqs:
$(info $(SPACER)$(shell printf $(TITLE)"Checking for prereqs"$(END)))
which buildah || (echo "Missing required program buildah" && exit 1)
which podman || (echo "Missing required program podman" && exit 1)
yum list | grep yum-utils || (echo "Missing required package yum-utils" && exit 1)
.PHONY: check-test-prereqs
check-test-prereqs:
$(info $(SPACER)$(shell printf $(TITLE)"Checking for prereqs"$(END)))
which buildah || (echo "Missing required program buildah" && exit 1)
which docker || (echo "Missing required program docker" && exit 1)
.PHONY: test-advancedserver
test-advancedserver: check-test-prereqs test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on $(shell docker --version)"$(END)))
sudo buildah push $(MQ_IMAGE_ADVANCEDSERVER) docker-daemon:$(MQ_IMAGE_ADVANCEDSERVER)
docker tag docker.io/$(MQ_IMAGE_ADVANCEDSERVER) $(MQ_IMAGE_ADVANCEDSERVER)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) EXPECTED_LICENSE=Production go test $(TEST_OPTS_DOCKER)
.PHONY: test-devserver
test-devserver: check-test-prereqs test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on $(shell docker --version)"$(END)))
sudo buildah push $(MQ_IMAGE_DEVSERVER) docker-daemon:$(MQ_IMAGE_DEVSERVER)
docker tag docker.io/$(MQ_IMAGE_DEVSERVER) $(MQ_IMAGE_DEVSERVER)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) go test -tags mqdev $(TEST_OPTS_DOCKER)
.PHONY: build-advancedserver
build-advancedserver: check-prereqs downloads/$(MQ_ARCHIVE) build-go-programs
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
sudo mq-advanced-server-rhel/mq-buildah.sh "$(MQ_ARCHIVE)" "$(MQ_PACKAGES)" "$(MQ_IMAGE_ADVANCEDSERVER)" "$(MQ_VERSION)" "$(MQDEV)"
.PHONY: build-devserver
build-devserver: MQDEV=TRUE
build-devserver: check-prereqs downloads/$(MQ_ARCHIVE_DEV) build-go-programs
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER)"$(END)))
sudo mq-advanced-server-rhel/mq-buildah.sh "$(MQ_ARCHIVE_DEV)" "$(MQ_PACKAGES)" "$(MQ_IMAGE_DEVSERVER_BASE)" "$(MQ_VERSION)" "$(MQDEV)"
sudo mq-advanced-server-rhel/mqdev-buildah.sh "$(MQ_IMAGE_DEVSERVER_BASE)" "$(MQ_IMAGE_DEVSERVER)" "$(MQ_VERSION)"
.PHONY: build-mqgolang-sdk
build-mqgolang-sdk: check-prereqs downloads/$(MQ_SDK_ARCHIVE)
$(info $(SPACER)$(shell printf $(TITLE)"Build mq-golang SDK"$(END)))
sudo mq-advanced-server-rhel/mq-golang-sdk-buildah.sh "$(MQ_SDK_ARCHIVE)" "$(MQ_IMAGE_GOLANG_SDK)"
.PHONY: build-go-programs
build-go-programs: check-prereqs downloads/$(MQ_SDK_ARCHIVE) build-mqgolang-sdk
$(info $(SPACER)$(shell printf $(TITLE)"Build go programs"$(END)))
IMAGE_REVISION=$(IMAGE_REVISION) IMAGE_SOURCE=$(IMAGE_SOURCE) sudo --preserve-env mq-advanced-server-rhel/go-buildah.sh "$(MQ_IMAGE_GOLANG_SDK)" "$(MQDEV)"
.PHONY: build-devjmstest
build-devjmstest: check-test-prereqs
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
cd test/messaging && sudo ./buildah.sh $(DEV_JMS_IMAGE)
sudo buildah push $(DEV_JMS_IMAGE) docker-daemon:$(DEV_JMS_IMAGE)
docker tag docker.io/$(DEV_JMS_IMAGE) $(DEV_JMS_IMAGE)
.PHONY: debug-vars
debug-vars:
@echo MQ_VERSION=$(MQ_VERSION)
@echo MQ_VERSION_VRM=$(MQ_VERSION_VRM)
@echo MQ_ARCHIVE=$(MQ_ARCHIVE)
@echo MQ_SDK_ARCHIVE=$(MQ_SDK_ARCHIVE)
@echo MQ_IMAGE_GOLANG_SDK=$(MQ_IMAGE_GOLANG_SDK)
@echo MQ_IMAGE_DEVSERVER_BASE=$(MQ_IMAGE_DEVSERVER_BASE)
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
include formatting.mk

View File

@@ -1,283 +0,0 @@
# © 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.
###############################################################################
# Conditional variables - you can override the values of these variables from
# the command line
###############################################################################
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
BASE_IMAGE ?= ubuntu:16.04
# MQ_VERSION is the fully qualified MQ version number to build
MQ_VERSION ?= 9.1.1.0
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
# 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
# for Developers can be installed
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 ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
# Options to `go test` for the Docker tests
TEST_OPTS_DOCKER ?=
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-integration-$(ARCH)
# MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image
MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev:$(MQ_VERSION)-integration-$(ARCH)
# MQ_IMAGE_SDK is the name and tag of the built MQ Advanced for Developers SDK image
MQ_IMAGE_SDK ?=mq-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# MQ_IMAGE_GOLANG_SDK is the name and tag of the built MQ Advanced for Developers SDK image, plus Go tools
MQ_IMAGE_GOLANG_SDK ?=mq-golang-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# DOCKER is the Docker command to run
DOCKER ?= docker
# MQ_PACKAGES specifies the MQ packages (.deb or .rpm) to install. Defaults vary on base image.
MQ_PACKAGES ?=
###############################################################################
# Other variables
###############################################################################
# ARCH is the platform architecture (e.g. x86_64, ppc64le or s390x)
ARCH = $(shell uname -m)
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
BUILD_SERVER_CONTAINER=build-server
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
# test run in parallel
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=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# Docker image name to use for JMS tests
DEV_JMS_IMAGE=mq-dev-jms-test
# Variables for versioning
IMAGE_REVISION=$(shell git rev-parse HEAD)
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
EMPTY:=
SPACE:= $(EMPTY) $(EMPTY)
# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.1 instead of 9.1.1.0
MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION))))
ifneq (,$(findstring Microsoft,$(shell uname -r)))
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
else
DOWNLOADS_DIR=$(realpath ./downloads/)
endif
# Try to figure out which archive to use from the BASE_IMAGE
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
MQ_ARCHIVE_TYPE=UBUNTU
MQ_ARCHIVE_DEV_PLATFORM=ubuntu
MQM_UID=999
else
MQ_ARCHIVE_TYPE=LINUX
MQ_ARCHIVE_DEV_PLATFORM=linux
MQM_UID=888
endif
# Try to figure out which archive to use from the architecture
ifeq "$(ARCH)" "x86_64"
MQ_ARCHIVE_ARCH=X86-64
MQ_DEV_ARCH=x86-64
else ifeq "$(ARCH)" "ppc64le"
MQ_ARCHIVE_ARCH=LE_POWER
MQ_DEV_ARCH=ppcle
else ifeq "$(ARCH)" "s390x"
MQ_ARCHIVE_ARCH=SYSTEM_Z
MQ_DEV_ARCH=s390x
endif
# Archive names for IBM MQ Advanced for Developers
MQ_ARCHIVE_DEV_9.0.5.0=mqadv_dev905_$(MQ_ARCHIVE_DEV_PLATFORM)_x86-64.tar.gz
MQ_ARCHIVE_DEV_9.1.0.0=mqadv_dev910_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
###############################################################################
# Build targets
###############################################################################
.PHONY: vars
vars:
#ifeq "$(findstring ubuntu,$(BASE_IMAGE))","ubuntu"
@echo $(MQ_ARCHIVE_ARCH)
@echo $(MQ_ARCHIVE_TYPE)
@echo $(MQ_ARCHIVE)
.PHONY: default
default: build-devserver test
# Build all components (except incubating ones)
.PHONY: all
all: build-devserver build-advancedserver
.PHONY: test-all
test-all: build-devjmstest test-devserver test-advancedserver
.PHONY: devserver
devserver: build-devserver build-devjmstest test-devserver
# Build incubating components
.PHONY: incubating
incubating: build-explorer
downloads/$(MQ_ARCHIVE_DEV):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
downloads/$(MQ_SDK_ARCHIVE):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_SDK_ARCHIVE)
.PHONY: downloads
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
# Vendor Go dependencies for the Docker tests
test/docker/vendor:
cd test/docker && dep ensure -vendor-only
# Shortcut to just run the unit tests
.PHONY: test-unit
test-unit:
docker build --target builder --file Dockerfile-server .
.PHONY: test-advancedserver
test-advancedserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on $(shell docker --version)"$(END)))
docker inspect $(MQ_IMAGE_ADVANCEDSERVER)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
.PHONY: build-devjmstest
build-devjmstest:
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
.PHONY: test-devserver
test-devserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on $(shell docker --version)"$(END)))
docker inspect $(MQ_IMAGE_DEVSERVER)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=true go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER)
coverage:
mkdir coverage
.PHONY: test-advancedserver-cover
test-advancedserver-cover: test/docker/vendor coverage
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) with code coverage on $(shell docker --version)"$(END)))
rm -f ./coverage/unit*.cov
# Run unit tests with coverage, for each package under 'internal'
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
# ls -1 ./cmd | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./cmd/{}/...
echo 'mode: count' > ./coverage/unit.cov
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
rm -f ./test/docker/coverage/*.cov
rm -f ./coverage/docker.*
mkdir -p ./test/docker/coverage/
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER)-cover TEST_COVER=true go test $(TEST_OPTS_DOCKER)
echo 'mode: count' > ./coverage/docker.cov
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
echo 'mode: count' > ./coverage/combined.cov
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
define docker-build-mq
# Create a temporary network to use for the build
$(DOCKER) network create build
# Start a web server to host the MQ downloadable (tar.gz) file
$(DOCKER) run \
--rm \
--name $(BUILD_SERVER_CONTAINER) \
--network build \
--network-alias build \
--volume $(DOWNLOADS_DIR):/usr/share/nginx/html:ro \
--detach \
nginx:alpine
# Build the new image
$(DOCKER) build \
--tag $1 \
--file $2 \
--network build \
--build-arg MQ_URL=http://build:80/$3 \
--build-arg BASE_IMAGE=$(BASE_IMAGE) \
--build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) \
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
--build-arg IMAGE_TAG="$1" \
--build-arg MQM_UID=$(MQM_UID) \
--label IBM_PRODUCT_ID=$4 \
--label IBM_PRODUCT_NAME=$5 \
--label IBM_PRODUCT_VERSION=$6 \
--build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \
. ; $(DOCKER) kill $(BUILD_SERVER_CONTAINER) && $(DOCKER) network rm build
endef
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
DOCKER_CLIENT_VERSION=$(shell docker version --format "{{ .Client.Version }}")
.PHONY: docker-version
docker-version:
@test "$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
.PHONY: build-advancedserver
build-advancedserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE)
build-advancedserver: downloads/$(MQ_ARCHIVE) docker-version build-golang-sdk-ex
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
$(call docker-build-mq,$(MQ_IMAGE_ADVANCEDSERVER),Dockerfile-server,$(MQ_ARCHIVE),"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced",$(MQ_VERSION))
.PHONY: build-devserver
build-devserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE_DEV)
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version build-golang-sdk-ex
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER_BASE)"$(END)))
$(call docker-build-mq,$(MQ_IMAGE_DEVSERVER_BASE),Dockerfile-server,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
$(DOCKER) build --tag $(MQ_IMAGE_DEVSERVER) --build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" --build-arg IMAGE_REVISION="$(IMAGE_REVISION)" --build-arg IMAGE_TAG="$(MQ_IMAGE_DEVSERVER)" --build-arg BASE_IMAGE=$(MQ_IMAGE_DEVSERVER_BASE) --build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) --build-arg MQM_UID=$(MQM_UID) --file incubating/mqadvanced-server-dev/Dockerfile .
.PHONY: build-advancedserver-cover
build-advancedserver-cover: docker-version
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_IMAGE_ADVANCEDSERVER)-cover -f Dockerfile-server.cover .
.PHONY: build-explorer
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
build-explorer: MQ_PACKAGES=ibmmq-explorer
else
build-explorer: MQ_PACKAGES=MQSeriesRuntime*.rpm MQSeriesJRE*.rpm MQSeriesExplorer*.rpm
endif
build-explorer: downloads/$(MQ_ARCHIVE_DEV) docker-pull
$(call docker-build-mq,mq-explorer:latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
.PHONY: build-sdk
build-sdk: downloads/$(MQ_SDK_ARCHIVE) build-sdk-ex
.PHONY: build-sdk-ex
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
build-sdk-ex: MQ_PACKAGES=ibmmq-sdk ibmmq-samples build-essential
else
build-sdk-ex: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm
endif
build-sdk-ex: docker-version docker-pull
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_SDK)"$(END)))
$(call docker-build-mq,$(MQ_IMAGE_SDK),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))
.PHONY: build-golang-sdk
build-golang-sdk: downloads/$(MQ_SDK_ARCHIVE) build-golang-sdk-ex
.PHONY: build-golang-sdk-ex
build-golang-sdk-ex: docker-version build-sdk-ex
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_GOLANG_SDK)"$(END)))
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_SDK) -t $(MQ_IMAGE_GOLANG_SDK) -f incubating/mq-golang-sdk/Dockerfile .
.PHONY: docker-pull
docker-pull:
$(DOCKER) pull $(BASE_IMAGE)
include formatting.mk

View File

@@ -1,29 +1,26 @@
# IBM MQ container
![IBM MQ logo](https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png)
[![Build Status](https://travis-ci.org/ibm-messaging/mq-container.svg?branch=master)](https://travis-ci.org/ibm-messaging/mq-container)
**Note**: The `singularity` branch may be in an *unstable or even broken state* during development.
To get a stable version, please use the correct [branch](https://github.com/ibm-messaging/mq-container/branches) for your MQ version, instead of the `singularity` branch.
<img src="https://raw.githubusercontent.com/IBM/charts/master/logo/ibm-mq-icon.svg?sanitize=true" width="100" alt="IBM MQ logo" />
## Overview
# Overview
Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container.
You can build an image containing either IBM MQ Advanced, or IBM MQ Advanced for Developers. The developer image includes a [default developer configuration](docs/developer-config.md), to make it easier to get started. There is also an [incubating](incubating) folder for additional images for other MQ components, which you might find useful.
## Build
# Current status
MQ Advanced for Developers image [![Build Status](https://travis-ci.org/ibm-messaging/mq-container.svg?branch=master)](https://travis-ci.org/ibm-messaging/mq-container)
# Build
After extracting the code from this repository, you can follow the [build documentation](docs/building.md) to build an image.
## Usage
# Usage
See the [usage documentation](docs/usage.md) for details on how to run a container.
Note that in order to use the image, it is necessary to accept the terms of the [IBM MQ license](#license).
### Environment variables supported by this image
## Environment variables supported by this image
- **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
- **LANG** - Set this to the language you would like the license to be printed in.
@@ -33,25 +30,25 @@ Note that in order to use the image, it is necessary to accept the terms of the
See the [default developer configuration docs](docs/developer-config.md) for the extra environment variables supported by the MQ Advanced for Developers image.
### Kubernetes
## Kubernetes
If you want to use IBM MQ in [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM charts](https://github.com/IBM/charts). This can be used to run the container on a cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
## Issues and contributions
# Issues and contributions
For issues relating specifically to the container image or Helm chart, please use the [GitHub issue tracker](https://github.com/ibm-messaging/mq-container/issues). If you do submit a Pull Request related to this Docker image, please indicate in the Pull Request that you accept and agree to be bound by the terms of the [IBM Contributor License Agreement](CLA.md).
## License
# License
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
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-AVCJ4S) (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-AZYF4X) (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-AV6GV5) (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.
## Copyright
# Copyright
© Copyright IBM Corporation 2015, 2018

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");
you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@ func queueManagerHealthy() (bool, error) {
return false, err
}
// Specify the queue manager name, just in case someone's created a second queue manager
// #nosec G204
cmd := exec.Command("dspmq", "-n", "-m", name)
// Run the command and wait for completion
out, err := cmd.CombinedOutput()

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");
you may not use this file except in compliance with the License.
@@ -37,8 +37,5 @@ func main() {
fmt.Println(err)
os.Exit(1)
}
err = conn.Close()
if err != nil {
fmt.Println(err)
}
conn.Close()
}

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");
you may not use this file except in compliance with the License.
@@ -13,9 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package keystore contains code to create and update keystores
package keystore
package main
import (
"bufio"
@@ -25,7 +23,6 @@ import (
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/logger"
)
// KeyStore describes information about a keystore file
@@ -57,7 +54,7 @@ func NewCMSKeyStore(filename, password string) *KeyStore {
}
// Create a key store, if it doesn't already exist
func (ks *KeyStore) Create(log *logger.Logger) error {
func (ks *KeyStore) Create() error {
_, err := os.Stat(ks.Filename)
if err == nil {
// Keystore already exists so we should refresh it by deleting it.
@@ -68,27 +65,11 @@ func (ks *KeyStore) Create(log *logger.Logger) error {
stashFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".sth"
rdbFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".rdb"
crlFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".crl"
err = os.Remove(stashFile)
if err != nil {
log.Errorf("Error removing %s: %v", stashFile, err)
return err
}
err = os.Remove(rdbFile)
if err != nil {
log.Errorf("Error removing %s: %v", rdbFile, err)
return err
}
err = os.Remove(crlFile)
if err != nil {
log.Errorf("Error removing %s: %v", crlFile, err)
return err
}
}
err = os.Remove(ks.Filename)
if err != nil {
log.Errorf("Error removing %s: %v", ks.Filename, err)
return err
os.Remove(stashFile)
os.Remove(rdbFile)
os.Remove(crlFile)
}
os.Remove(ks.Filename)
} else if !os.IsNotExist(err) {
// If the keystore exists but cannot be accessed then return the error
return err
@@ -99,11 +80,22 @@ func (ks *KeyStore) Create(log *logger.Logger) error {
if err != nil {
return fmt.Errorf("error running \"%v -keydb -create\": %v %s", ks.command, err, out)
}
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
log.Error(err)
return err
}
err = os.Chown(ks.Filename, mqmUID, mqmGID)
if err != nil {
log.Error(err)
return err
}
return nil
}
// CreateStash creates a key stash, if it doesn't already exist
func (ks *KeyStore) CreateStash(log *logger.Logger) error {
func (ks *KeyStore) CreateStash() error {
extension := filepath.Ext(ks.Filename)
stashFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".sth"
log.Debugf("TLS stash file: %v", stashFile)
@@ -117,14 +109,15 @@ func (ks *KeyStore) CreateStash(log *logger.Logger) error {
}
return err
}
return nil
}
// GeneratePKCS12 generates a PKCS12 file
func (ks *KeyStore) GeneratePKCS12(keyFile, crtFile, pkcs12File, label, password string) error {
out, _, err := command.Run("openssl", "pkcs12", "-export", "-inkey", keyFile, "-in", crtFile, "-out", pkcs12File, "-name", label, "-passout", "pass:"+password)
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return fmt.Errorf("error running \"openssl pkcs12 -export\": %v %s", err, out)
log.Error(err)
return err
}
err = os.Chown(stashFile, mqmUID, mqmGID)
if err != nil {
log.Error(err)
return err
}
return nil
}
@@ -138,24 +131,6 @@ func (ks *KeyStore) Import(inputFile, password string) error {
return nil
}
// CreateSelfSignedCertificate creates a self-signed certificate in the keystore
func (ks *KeyStore) CreateSelfSignedCertificate(label, dn string) error {
out, _, err := command.Run(ks.command, "-cert", "-create", "-db", ks.Filename, "-pw", ks.Password, "-label", label, "-dn", dn)
if err != nil {
return fmt.Errorf("error running \"%v -cert -create\": %v %s", ks.command, err, out)
}
return nil
}
// Add adds a CA certificate to the keystore
func (ks *KeyStore) Add(inputFile, label string) error {
out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile, "-label", label)
if err != nil {
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
}
return nil
}
// GetCertificateLabels returns the labels of all certificates in the key store
func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)

View File

@@ -1,68 +0,0 @@
/*
© 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 main
import (
"runtime"
"strings"
containerruntime "github.com/ibm-messaging/mq-container/internal/containerruntime"
"github.com/ibm-messaging/mq-container/internal/user"
)
func logContainerDetails() {
log.Printf("CPU architecture: %v", runtime.GOARCH)
kv, err := containerruntime.GetKernelVersion()
if err == nil {
log.Printf("Linux kernel version: %v", kv)
}
cr, err := containerruntime.GetContainerRuntime()
if err == nil {
log.Printf("Container runtime: %v", cr)
}
bi, err := containerruntime.GetBaseImage()
if err == nil {
log.Printf("Base image: %v", bi)
}
u, err := user.GetUser()
if err == nil {
if len(u.SupplementalGID) == 0 {
log.Printf("Running as user ID %v (%v) with primary group %v", u.UID, u.Name, u.PrimaryGID)
} else {
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()
capLogged := false
if err == nil {
for k, v := range caps {
if len(v) > 0 {
log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ","))
capLogged = true
}
}
if !capLogged {
log.Print("Capabilities: none")
}
} else {
log.Errorf("Error getting capabilities: %v", err)
}
sc, err := containerruntime.GetSeccomp()
if err == nil {
log.Printf("seccomp enforcing mode: %v", sc)
}
log.Printf("Process security attributes: %v", containerruntime.GetSecurityAttributes())
}

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");
you may not use this file except in compliance with the License.
@@ -24,28 +24,22 @@ import (
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
"github.com/ibm-messaging/mq-container/internal/name"
)
var log *logger.Logger
func setPassword(user string, password string) error {
// #nosec G204
cmd := exec.Command("sudo", "chpasswd")
cmd := exec.Command("chpasswd")
stdin, err := cmd.StdinPipe()
if err != nil {
return err
}
fmt.Fprintf(stdin, "%s:%s", user, password)
err = stdin.Close()
stdin.Close()
_, _, err = command.RunCmd(cmd)
if err != nil {
log.Errorf("Error closing password stdin: %v", err)
}
out, _, err := command.RunCmd(cmd)
if err != nil {
// Include the command output in the error
return fmt.Errorf("%v: %v", err.Error(), out)
return err
}
log.Printf("Set password for \"%v\" user", user)
return nil
@@ -91,20 +85,20 @@ func configureLogger() error {
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)
return processTemplateFile("/etc/mqm/admin.json.tpl", out, map[string]string{"QueueManagerName": qmName})
}
func logTerminationf(format string, args ...interface{}) {
logTermination(fmt.Sprintf(format, args...))
logTermination(fmt.Sprintf(format, args))
}
// TODO: Duplicated code
func logTermination(args ...interface{}) {
msg := fmt.Sprint(args...)
// Write the message to the termination log. This is not the default place
msg := fmt.Sprint(args)
// Write the message to the termination log. This is the default place
// that Kubernetes will look for termination information.
log.Debugf("Writing termination message: %v", msg)
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
err := ioutil.WriteFile("/dev/termination-log", []byte(msg), 0660)
if err != nil {
log.Debug(err)
}
@@ -117,9 +111,6 @@ func doMain() error {
logTermination(err)
return err
}
logContainerDetails()
adminPassword, set := os.LookupEnv("MQ_ADMIN_PASSWORD")
if set {
err = setPassword("admin", adminPassword)
@@ -174,10 +165,6 @@ func main() {
osExit(1)
} else {
// Replace this process with runmqserver
// #nosec G204
err = syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver", "-dev"}, os.Environ())
if err != nil {
log.Errorf("Error replacing this process with runmqserver: %v", err)
}
syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver"}, os.Environ())
}
}

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");
you may not use this file except in compliance with the License.
@@ -17,8 +17,6 @@ package main
import (
"os"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
)
func updateMQSC(appPasswordRequired bool) error {
@@ -32,19 +30,12 @@ func updateMQSC(appPasswordRequired bool) error {
if os.Getenv("MQ_DEV") == "true" {
const mqscTemplate string = mqsc + ".tpl"
// Re-configure channel if app password not set
err := mqtemplate.ProcessTemplateFile(mqsc+".tpl", mqsc, map[string]string{"ChckClnt": checkClient}, log)
err := processTemplateFile(mqsc+".tpl", mqsc, map[string]string{"ChckClnt": checkClient})
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
}
}
os.Remove(mqsc)
}
return nil
}

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");
you may not use this file except in compliance with the License.
@@ -13,21 +13,20 @@ 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 mqtemplate contains code to process template files
package mqtemplate
package main
import (
"os"
"path"
"text/template"
"github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-container/internal/command"
)
// ProcessTemplateFile takes a Go templateFile, and processes it with the
// processTemplateFile takes a Go templateFile, and processes it with the
// supplied data, writing to destFile
func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *logger.Logger) error {
func processTemplateFile(templateFile, destFile string, data interface{}) error {
// Re-configure channel if app password not set
t, err := template.ParseFiles(templateFile)
if err != nil {
log.Error(err)
@@ -37,8 +36,13 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
_, err = os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
// #nosec G301
err = os.MkdirAll(dir, 0770)
os.MkdirAll(dir, 0660)
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
@@ -47,7 +51,6 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
return err
}
}
// #nosec G302
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
defer f.Close()
err = t.Execute(f, data)
@@ -55,5 +58,15 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
log.Error(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
}

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");
you may not use this file except in compliance with the License.
@@ -21,22 +21,20 @@ import (
"path/filepath"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/keystore"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
)
func configureWebTLS(cms *keystore.KeyStore) error {
func configureWebTLS(cms *KeyStore) error {
dir := "/run/runmqdevserver/tls"
ks := keystore.NewJKSKeyStore(filepath.Join(dir, "key.jks"), cms.Password)
ts := keystore.NewJKSKeyStore(filepath.Join(dir, "trust.jks"), cms.Password)
ks := NewJKSKeyStore(filepath.Join(dir, "key.jks"), cms.Password)
ts := NewJKSKeyStore(filepath.Join(dir, "trust.jks"), cms.Password)
log.Debug("Creating key store")
err := ks.Create(log)
err := ks.Create()
if err != nil {
return err
}
log.Debug("Creating trust store")
err = ts.Create(log)
err = ts.Create()
if err != nil {
return err
}
@@ -58,19 +56,24 @@ func configureWebTLS(cms *keystore.KeyStore) error {
if err != nil {
return err
}
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
log.Error(err)
return err
}
err = os.Chown(tlsConfig, mqmUID, mqmGID)
if err != nil {
log.Error(err)
return err
}
return nil
}
func configureTLS(qmName string, inputFile string, passPhrase string) error {
err := createDevTLSDir()
if err != nil {
return err
}
log.Debug("Configuring TLS")
_, err = os.Stat(inputFile)
_, err := os.Stat(inputFile)
if err != nil {
return err
}
@@ -79,14 +82,36 @@ func configureTLS(qmName string, inputFile string, passPhrase string) error {
dir := "/run/runmqdevserver/tls"
keyFile := filepath.Join(dir, "key.kdb")
cms := keystore.NewCMSKeyStore(keyFile, passPhrase)
_, err = os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
err = os.MkdirAll(dir, 0770)
if err != nil {
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 {
return err
}
}
err = cms.Create(log)
cms := NewCMSKeyStore(keyFile, passPhrase)
err = cms.Create()
if err != nil {
return err
}
err = cms.CreateStash(log)
err = cms.CreateStash()
if err != nil {
return err
}
@@ -120,11 +145,11 @@ func configureTLS(qmName string, inputFile string, passPhrase string) error {
const mqsc string = "/etc/mqm/20-dev-tls.mqsc"
const mqscTemplate string = mqsc + ".tpl"
err = mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
err = processTemplateFile(mqscTemplate, mqsc, map[string]string{
"SSLKeyR": filepath.Join(dir, "key"),
"CertificateLabel": newLabel,
"SSLCipherSpec": sslCipherSpec,
}, log)
})
if err != nil {
return err
}
@@ -136,32 +161,3 @@ func configureTLS(qmName string, inputFile string, passPhrase string) error {
return nil
}
func createDevTLSDir() error {
// TODO: Use a persisted file (on the volume) instead?
dir := "/run/runmqdevserver/tls"
_, err := os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
// #nosec G301
err = os.MkdirAll(dir, 0770)
if err != nil {
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 {
return err
}
}
return nil
}

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");
you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@ func createVolume(path string) error {
fi, err := os.Stat(dataPath)
if err != nil {
if os.IsNotExist(err) {
// #nosec G301
err = os.MkdirAll(dataPath, 0755)
if err != nil {
return err
@@ -60,61 +59,3 @@ func createVolume(path string) error {
}
return nil
}
func createWebConsoleTLSDirStructure() error {
// Create tls directory
dir := "/run/tls"
_, err := os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
err = os.MkdirAll(dir, 0770)
if err != nil {
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 {
return err
}
}
return nil
}
/* TODO: remove duplicated code */
func createDevTLSDir() error {
// TODO: Use a persisted file (on the volume) instead?
dir := "/run/runmqdevserver/tls"
_, err := os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
// #nosec G301
err = os.MkdirAll(dir, 0770)
if err != nil {
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 {
return err
}
}
return nil
}

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");
you may not use this file except in compliance with the License.
@@ -78,7 +78,6 @@ func checkLicense() (bool, error) {
return true, nil
case ok && lic == "view":
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
// #nosec G304
buf, err := ioutil.ReadFile(file)
if err != nil {
log.Println(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");
you may not use this file except in compliance with the License.
@@ -21,11 +21,9 @@ import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sync"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-container/internal/mqini"
)
@@ -33,26 +31,20 @@ import (
// var debug = false
var log *logger.Logger
var collectDiagOnFail = false
func logTerminationf(format string, args ...interface{}) {
logTermination(fmt.Sprintf(format, args...))
logTermination(fmt.Sprintf(format, args))
}
func logTermination(args ...interface{}) {
msg := fmt.Sprint(args...)
// Write the message to the termination log. This is not the default place
msg := fmt.Sprint(args)
// Write the message to the termination log. This is the default place
// that Kubernetes will look for termination information.
log.Debugf("Writing termination message: %v", msg)
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
err := ioutil.WriteFile("/dev/termination-log", []byte(msg), 0660)
if err != nil {
log.Debug(err)
}
log.Error(msg)
if collectDiagOnFail {
logDiagnostics()
}
}
func getLogFormat() string {
@@ -108,12 +100,8 @@ func configureLogger(name string) (mirrorFunc, error) {
return func(msg string) {
// Parse the JSON message, and print a simplified version
var obj map[string]interface{}
err := json.Unmarshal([]byte(msg), &obj)
if err != nil {
fmt.Printf("Failed to Unmarshall JSON - %v", err)
} else {
fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
}
json.Unmarshal([]byte(msg), &obj)
fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
}, nil
default:
log, err = logger.NewLogger(os.Stdout, d, false, name)
@@ -123,37 +111,3 @@ func configureLogger(name string) (mirrorFunc, error) {
return nil, fmt.Errorf("invalid value for LOG_FORMAT: %v", f)
}
}
func logDiagnostics() {
log.Debug("--- Start Diagnostics ---")
// show the directory ownership/permissions
// #nosec G104
out, _, _ := command.Run("ls", "-l", "/mnt/")
log.Debugf("/mnt/:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm")
log.Debugf("/mnt/mqm:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm/data")
log.Debugf("/mnt/mqm/data:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/etc/mqm")
log.Debugf("/etc/mqm:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/var/mqm")
log.Debugf("/var/mqm:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/var/mqm/errors")
log.Debugf("/var/mqm/errors:\n%s", out)
// Print out summary of any FDCs
// #nosec G204
cmd := exec.Command("/opt/mqm/bin/ffstsummary")
cmd.Dir = "/var/mqm/errors"
// #nosec G104
outB, _ := cmd.CombinedOutput()
log.Debugf("ffstsummary:\n%s", string(outB))
log.Debug("--- End Diagnostics ---")
}

View File

@@ -1,86 +0,0 @@
/*
© 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 main
import (
"fmt"
"runtime"
"strings"
containerruntime "github.com/ibm-messaging/mq-container/internal/containerruntime"
"github.com/ibm-messaging/mq-container/internal/user"
)
func logContainerDetails() error {
if runtime.GOOS != "linux" {
return fmt.Errorf("Unsupported platform: %v", runtime.GOOS)
}
log.Printf("CPU architecture: %v", runtime.GOARCH)
kv, err := containerruntime.GetKernelVersion()
if err == nil {
log.Printf("Linux kernel version: %v", kv)
}
cr, err := containerruntime.GetContainerRuntime()
if err == nil {
log.Printf("Container runtime: %v", cr)
}
bi, err := containerruntime.GetBaseImage()
if err == nil {
log.Printf("Base image: %v", bi)
}
u, err := user.GetUser()
if err == nil {
if len(u.SupplementalGID) == 0 {
log.Printf("Running as user ID %v (%v) with primary group %v", u.UID, u.Name, u.PrimaryGID)
} else {
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()
capLogged := false
if err == nil {
for k, v := range caps {
if len(v) > 0 {
log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ","))
capLogged = true
}
}
if !capLogged {
log.Print("Capabilities: none")
}
} else {
log.Errorf("Error getting capabilities: %v", err)
}
sc, err := containerruntime.GetSeccomp()
if err == nil {
log.Printf("seccomp enforcing mode: %v", sc)
}
log.Printf("Process security attributes: %v", containerruntime.GetSecurityAttributes())
m, err := containerruntime.GetMounts()
if err == nil {
if len(m) == 0 {
log.Print("No volume detected. Persistent messages may be lost")
} else {
for mountPoint, fsType := range m {
log.Printf("Detected '%v' volume mounted to %v", fsType, mountPoint)
if !containerruntime.SupportedFilesystem(fsType) {
return fmt.Errorf("%v uses unsupported filesystem type: %v", mountPoint, fsType)
}
}
}
}
return nil
}

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");
you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@ package main
import (
"context"
"errors"
"flag"
"os"
"sync"
@@ -30,35 +29,12 @@ import (
)
func doMain() error {
var initFlag = flag.Bool("i", false, "initialize volume only, then exit")
var infoFlag = flag.Bool("info", false, "Display debug info, then exit")
var devFlag = flag.Bool("dev", false, "used when running this program from runmqdevserver to control log output")
flag.Parse()
name, nameErr := name.GetQueueManagerName()
mf, err := configureLogger(name)
if err != nil {
logTermination(err)
return err
}
// Check whether they only want debug info
if *infoFlag {
logVersionInfo()
err = logContainerDetails()
if err != nil {
log.Printf("Error displaying container details: %v", err)
}
return nil
}
err = verifySingleProcess()
if err != nil {
// We don't do the normal termination here as it would create a termination file.
log.Error(err)
return err
}
if nameErr != nil {
logTermination(err)
return err
@@ -82,17 +58,12 @@ func doMain() error {
// Start signal handler
signalControl := signalHandler(name)
// Enable diagnostic collecting on failure
collectDiagOnFail = true
if *devFlag == false {
err = logContainerDetails()
if err != nil {
logTermination(err)
return err
}
err = logConfig()
if err != nil {
logTermination(err)
return err
}
err = createVolume("/mnt/mqm")
if err != nil {
logTermination(err)
@@ -104,25 +75,6 @@ func doMain() error {
return err
}
err = createWebConsoleTLSDirStructure()
if err != nil {
logTermination(err)
return err
}
if *devFlag == true {
err = createDevTLSDir()
if err != nil {
logTermination(err)
return err
}
}
// If init flag is set, exit now
if *initFlag {
return nil
}
// Print out versioning information
logVersionInfo()
@@ -168,11 +120,7 @@ func doMain() error {
logTermination(err)
return err
}
err = configureQueueManager()
if err != nil {
logTermination(err)
return err
}
configureQueueManager()
enableMetrics := os.Getenv("MQ_ENABLE_METRICS")
if enableMetrics == "true" || enableMetrics == "1" {
@@ -188,11 +136,7 @@ func doMain() error {
// Reap zombies now, just in case we've already got some
signalControl <- reapNow
// Write a file to indicate that chkmqready should now work as normal
err = ready.Set()
if err != nil {
logTermination(err)
return err
}
ready.Set()
// Wait for terminate signal
<-signalControl
return nil

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");
you may not use this file except in compliance with the License.
@@ -44,6 +44,7 @@ func waitForFile(ctx context.Context, path string) (os.FileInfo, error) {
return nil, fmt.Errorf("mirror: unable to get info on file %v", path)
}
}
log.Debugf("File exists: %v, %v", path, fi.Size())
return fi, nil
}
}
@@ -120,7 +121,6 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
if fi == nil {
return
}
log.Debugf("File exists: %v, %v", path, fi.Size())
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
log.Error(err)
@@ -139,10 +139,7 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
// Always start at the beginning if we've been told to go from the start
if offset != 0 && !fromStart {
log.Debugf("Seeking offset %v in file %v", offset, path)
_, err = f.Seek(offset, 0)
if err != nil {
log.Errorf("Unable to return to offset %v: %v", offset, err)
}
f.Seek(offset, 0)
}
closing := false
for {
@@ -162,10 +159,7 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
// could skip all those messages. This could happen with a very small
// MQ error log size.
mirrorAvailableMessages(f, mf)
err = f.Close()
if err != nil {
log.Errorf("Unable to close mirror file handle: %v", err)
}
f.Close()
// Re-open file
log.Debugf("Re-opening error log file %v", path)
f, err = os.OpenFile(path, os.O_RDONLY, 0)

177
cmd/runmqserver/mqconfig.go Normal file
View File

@@ -0,0 +1,177 @@
/*
© Copyright IBM Corporation 2017, 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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"
"io/ioutil"
"os/user"
"runtime"
"strings"
"github.com/genuinetools/amicontained/container"
)
func logContainerRuntime() error {
r, err := container.DetectRuntime()
if err != nil {
return err
}
log.Printf("Container runtime: %v", r)
return nil
}
func logBaseImage() error {
buf, err := ioutil.ReadFile("/etc/os-release")
if err != nil {
return err
}
lines := strings.Split(string(buf), "\n")
for _, l := range lines {
if strings.HasPrefix(l, "PRETTY_NAME=") {
words := strings.Split(l, "\"")
if len(words) >= 2 {
log.Printf("Base image: %v", words[1])
return nil
}
}
}
return nil
}
func logUser() {
u, err := user.Current()
if err == nil {
g, err := u.GroupIds()
if err != nil {
log.Printf("Running as user ID %v (%v) with primary group %v", u.Uid, u.Name, u.Gid)
} else {
// 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:]...)
}
}
log.Printf("Running as user ID %v (%v) with primary group %v, and supplemental groups %v", u.Uid, u.Name, u.Gid, strings.Join(g, ","))
}
}
}
// logCapabilities logs the Linux capabilities (e.g. setuid, setgid). See https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
func logCapabilities() error {
caps, err := container.Capabilities()
if err != nil {
return err
}
for k, v := range caps {
if len(v) > 0 {
log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ","))
}
}
return nil
}
// logSeccomp logs the seccomp enforcing mode, which affects which kernel calls can be made
func logSeccomp() error {
s, err := container.SeccompEnforcingMode()
if err != nil {
return err
}
log.Printf("seccomp enforcing mode: %v", s)
return nil
}
// logSecurityAttributes logs the security attributes of the current process.
// The security attributes indicate whether AppArmor or SELinux are being used,
// and what the level of confinement is.
func logSecurityAttributes() error {
a, err := readProc("/proc/self/attr/current")
// On some systems, if AppArmor or SELinux are not installed, you get an
// error when you try and read `/proc/self/attr/current`, even though the
// file exists.
if err != nil || a == "" {
a = "none"
}
log.Printf("Process security attributes: %v", a)
return nil
}
func readProc(filename string) (value string, err error) {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return strings.TrimSpace(string(buf)), nil
}
func readMounts() error {
all, err := readProc("/proc/mounts")
if err != nil {
log.Print("Error: Couldn't read /proc/mounts")
return err
}
lines := strings.Split(all, "\n")
detected := false
for i := range lines {
parts := strings.Split(lines[i], " ")
//dev := parts[0]
mountPoint := parts[1]
fsType := parts[2]
if strings.Contains(mountPoint, "/mnt/mqm") {
log.Printf("Detected '%v' volume mounted to %v", fsType, mountPoint)
detected = true
}
}
if !detected {
log.Print("No volume detected. Persistent messages may be lost")
} else {
return checkFS("/mnt/mqm")
}
return nil
}
func logConfig() error {
log.Printf("CPU architecture: %v", runtime.GOARCH)
if runtime.GOOS == "linux" {
var err error
osr, err := readProc("/proc/sys/kernel/osrelease")
if err != nil {
log.Print(err)
} else {
log.Printf("Linux kernel version: %v", osr)
}
logContainerRuntime()
logBaseImage()
fileMax, err := readProc("/proc/sys/fs/file-max")
if err != nil {
log.Print(err)
} else {
log.Printf("Maximum file handles: %v", fileMax)
}
logUser()
logCapabilities()
logSeccomp()
logSecurityAttributes()
err = readMounts()
if err != nil {
return err
}
} else {
return fmt.Errorf("Unsupported platform: %v", runtime.GOOS)
}
return nil
}

View File

@@ -1,7 +1,7 @@
// +build linux
/*
© Copyright IBM Corporation 2017, 2019
© Copyright IBM Corporation 2017, 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,9 +15,11 @@ 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 runtime
package main
import (
"fmt"
"golang.org/x/sys/unix"
)
@@ -99,27 +101,24 @@ var fsTypes = map[int64]string{
0x58295829: "zsmalloc",
}
// GetFilesystem returns the filesystem type for the specified path
func GetFilesystem(path string) (string, error) {
func checkFS(path string) error {
statfs := &unix.Statfs_t{}
err := unix.Statfs(path, statfs)
if err != nil {
return "", err
log.Println(err)
return nil
}
// Use a type conversion to make type an int64. On s390x it's a uint32.
t, ok := fsTypes[int64(statfs.Type)]
if !ok {
return "unknown", nil
log.Printf("WARNING: detected %v has unknown filesystem type %x", path, statfs.Type)
return nil
}
return t, nil
}
// SupportedFilesystem returns true if the supplied filesystem type is supported for MQ data
func SupportedFilesystem(fsType string) bool {
switch fsType {
switch t {
case "aufs", "overlayfs", "tmpfs":
return false
return fmt.Errorf("%v uses unsupported filesystem type: %v", path, t)
default:
return true
log.Printf("Detected %v has filesystem type '%v'", path, t)
return nil
}
}

View File

@@ -1,7 +1,7 @@
// +build !linux
/*
© Copyright IBM Corporation 2018, 2019
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@ 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 runtime
package main
// Dummy version of this function, only for non-Linux systems.
// Having this allows unit tests to be run on other platforms (e.g. macOS)

View File

@@ -1,3 +1,5 @@
// +build mqdev
/*
© Copyright IBM Corporation 2018
@@ -20,26 +22,18 @@ import (
)
// postInit is run after /var/mqm is set up
// This version of postInit is only included as part of the MQ Advanced for Developers build
func postInit(name string) error {
disable := os.Getenv("MQ_DISABLE_WEB_CONSOLE")
if disable != "true" && disable != "1" {
// Configure Single-Sign-On for the web server (if enabled)
enableSSO := os.Getenv("MQ_ENABLE_SSO")
if enableSSO == "true" || enableSSO == "1" {
err := configureSSO()
if err != nil {
return err
}
}
// Configure the web server (if installed)
err := configureWebServer()
if err != nil {
return err
}
// 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,
// which is why it's limited to use with MQ Advanced for Developers only
go func() {
startWebServer()
}()

View File

@@ -0,0 +1,22 @@
// +build !mqdev
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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
func postInit(name string) error {
return nil
}

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 main
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
// Verifies that we are the main or only instance of this program
func verifySingleProcess() error {
programName, err := determineExecutable()
if err != nil {
return fmt.Errorf("Failed to determine name of this program - %v", err)
}
// Verify that there is only one runmqserver
_, err = verifyOnlyOne(programName)
if err != nil {
return fmt.Errorf("You cannot run more than one instance of this program")
}
return nil
}
// Verifies that there is only one instance running of the given program name.
func verifyOnlyOne(programName string) (int, error) {
// #nosec G104
out, _, _ := command.Run("ps", "-e", "--format", "cmd")
//if this goes wrong then assume we are the only one
numOfProg := strings.Count(out, programName)
if numOfProg != 1 {
return numOfProg, fmt.Errorf("Expected there to be only 1 instance of %s but found %d", programName, numOfProg)
}
return numOfProg, nil
}
// Determines the name of the currently running executable.
func determineExecutable() (string, error) {
file, err := os.Executable()
if err != nil {
return "", err
}
_, exec := filepath.Split(file)
return exec, nil
}

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");
you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ func createDirStructure() error {
return err
}
log.Println("Created directory structure under /var/mqm")
return nil
}
@@ -91,7 +90,6 @@ func configureQueueManager() error {
for _, file := range files {
if strings.HasSuffix(file.Name(), ".mqsc") {
abs := filepath.Join(configDir, file.Name())
// #nosec G204
cmd := exec.Command("runmqsc")
stdin, err := cmd.StdinPipe()
if err != nil {
@@ -99,7 +97,6 @@ func configureQueueManager() error {
return err
}
// Open the MQSC file for reading
// #nosec G304
f, err := os.Open(abs)
if err != nil {
log.Printf("Error opening %v: %v", abs, err)
@@ -107,20 +104,14 @@ func configureQueueManager() error {
// Copy the contents to stdin of the runmqsc process
_, err = io.Copy(stdin, f)
if err != nil {
log.Errorf("Error reading %v: %v", abs, err)
}
err = f.Close()
if err != nil {
log.Errorf("Failed to close MQSC file handle: %v", err)
}
err = stdin.Close()
if err != nil {
log.Errorf("Failed to close MQSC stdin: %v", err)
log.Printf("Error reading %v: %v", abs, err)
}
f.Close()
stdin.Close()
// Run the command and wait for completion
out, err := cmd.CombinedOutput()
if err != nil {
log.Errorf("Error running MQSC file %v (%v):\n\t%v", file.Name(), err, strings.Replace(string(out), "\n", "\n\t", -1))
log.Println(err)
}
// 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, strings.Replace(string(out), "\n", "\n\t", -1))
@@ -131,7 +122,7 @@ func configureQueueManager() error {
func stopQueueManager(name string) error {
log.Println("Stopping queue manager")
out, _, err := command.Run("endmqm", "-w", "-r", name)
out, _, err := command.Run("endmqm", "-w", name)
if err != nil {
log.Printf("Error stopping queue manager: %v", string(out))
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");
you may not use this file except in compliance with the License.
@@ -43,8 +43,7 @@ func signalHandler(qmgr string) chan int {
log.Printf("Signal received: %v", sig)
signal.Stop(reapSignals)
signal.Stop(stopSignals)
metrics.StopMetricsGathering(log)
// #nosec G104
metrics.StopMetricsGathering()
stopQueueManager(qmgr)
// One final reap
reapZombies()

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");
you may not use this file except in compliance with the License.
@@ -29,8 +29,6 @@ var (
ImageRevision = "Not specified"
// ImageSource is the URL to get source code for building the image
ImageSource = "Not specified"
// ImageTag is the tag of the image
ImageTag = "Not specified"
)
func logDateStamp() {
@@ -45,10 +43,6 @@ func logGitCommit() {
log.Printf("Image source: %v", ImageSource)
}
func logImageTag() {
log.Printf("Image tag: %v", ImageTag)
}
func logMQVersion() {
mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
if err != nil {
@@ -73,6 +67,5 @@ func logVersionInfo() {
logDateStamp()
logGitRepo()
logGitCommit()
logImageTag()
logMQVersion()
}

View File

@@ -1,5 +1,7 @@
// +build mqdev
/*
© Copyright IBM Corporation 2018, 2019
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,15 +22,10 @@ import (
"io"
"os"
"os/exec"
"os/user"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/keystore"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
)
func startWebServer() error {
@@ -45,23 +42,12 @@ func startWebServer() error {
// Take all current environment variables, and add the app password
cmd.Env = append(os.Environ(), "MQ_APP_PASSWORD=passw0rd")
}
cmd.SysProcAttr = &syscall.SysProcAttr{}
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)}
}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
out, rc, err := command.RunCmd(cmd)
if err != nil {
log.Printf("Error %v starting web server: %v", rc, string(out))
@@ -91,82 +77,6 @@ func CopyFile(src, dest string) error {
return err
}
func configureSSO() error {
// Ensure all required environment variables are set for SSO
requiredEnvVars := []string{
"MQ_WEB_ADMIN_USERS",
"MQ_OIDC_CLIENT_ID",
"MQ_OIDC_CLIENT_SECRET",
"MQ_OIDC_UNIQUE_USER_IDENTIFIER",
"MQ_OIDC_AUTHORIZATION_ENDPOINT",
"MQ_OIDC_TOKEN_ENDPOINT",
"MQ_OIDC_JWK_ENDPOINT",
"MQ_OIDC_ISSUER_IDENTIFIER",
"MQ_OIDC_CERTIFICATE",
}
for _, envVar := range requiredEnvVars {
if len(os.Getenv(envVar)) == 0 {
return fmt.Errorf("%v must be set when MQ_ENABLE_SSO=true", envVar)
}
}
// Check mqweb directory exists
const mqwebDir string = "/etc/mqm/web/installations/Installation1/servers/mqweb"
_, err := os.Stat(mqwebDir)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
// Process SSO template for generating file mqwebuser.xml
adminUsers := strings.Split(os.Getenv("MQ_WEB_ADMIN_USERS"), "\n")
err = mqtemplate.ProcessTemplateFile(mqwebDir+"/mqwebuser.xml.tpl", mqwebDir+"/mqwebuser.xml", map[string][]string{"AdminUser": adminUsers}, log)
if err != nil {
return err
}
// Configure SSO TLS
return configureSSO_TLS()
}
func configureSSO_TLS() error {
// Create tls directory
dir := "/run/tls"
mntdir := "/mnt/tls/"
// Setup key store & trust store
ks := keystore.NewJKSKeyStore(filepath.Join(dir, "key.jks"), "password")
ts := keystore.NewJKSKeyStore(filepath.Join(dir, "trust.jks"), "password")
log.Debug("Creating key store")
err := ks.Create(log)
if err != nil {
return err
}
log.Debug("Creating trust store")
err = ts.Create(log)
if err != nil {
return err
}
log.Debug("Generating PKCS12 file")
err = ks.GeneratePKCS12(filepath.Join(mntdir, "tls.key"), filepath.Join(mntdir, "tls.crt"), filepath.Join(dir, "tls.p12"), "default", "password")
if err != nil {
return err
}
log.Debug("Importing certificate into key store")
err = ks.Import(filepath.Join(dir, "tls.p12"), "password")
if err != nil {
return err
}
log.Debug("Adding OIDC certificate to trust store")
err = ts.Add(os.Getenv("MQ_OIDC_CERTIFICATE"), "OIDC")
return err
}
func configureWebServer() error {
_, err := os.Stat("/opt/mqm/bin/strmqweb")
if err != nil {
@@ -183,6 +93,10 @@ func configureWebServer() error {
}
return err
}
uid, gid, err := command.LookupMQM()
if err != nil {
return err
}
const prefix string = "/etc/mqm/web"
err = filepath.Walk(prefix, func(from string, info os.FileInfo, err error) error {
if err != nil {
@@ -218,6 +132,10 @@ func configureWebServer() error {
return err
}
}
err = os.Chown(to, uid, gid)
if err != nil {
return err
}
return nil
})
return err

View File

@@ -1,46 +1,25 @@
# Building a container image
# Building a Docker image
## Prerequisites
### Prerequisites for building an Ubuntu image
If you want to build a container image with Ubuntu Linux as the base OS, then you need to have the following tools installed:
You need to ensure you have the following tools installed:
* [Docker](https://www.docker.com/) V17.06.1 or later
* [GNU make](https://www.gnu.org/software/make/)
If you are working in the Windows Subsystem for Linux, follow [this guide by Microsoft to set up Docker](https://blogs.msdn.microsoft.com/commandline/2017/12/08/cross-post-wsl-interoperability-with-docker/) first.
### Prerequisites for building a Red Hat Enterprise Linux image
If you want to build a container image with Red Hat Enterprise Linux as the base OS, then you need to use a host server with Red Hat Enterprise Linux. You must also have the following tools installed:
* [`buildah`](https://buildah.io) (available in `rhel-7-server-extras`)
* [`podman`](https://podman.io) (available in `rhel-7-server-extras`)
In addition, you need the following commonly installed tools:
* `bash`
* `coreutils`
* `findutils`
* `make`
* `sed`
* `shadow-utils`
* `tar`
## Building a production image
This procedure works for building the MQ Continuous Delivery release, on `x86_64`, `ppc64le` and `s390x` architectures.
1. Create a `downloads` directory in the root of this repository
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/) or [IBM Fix Central](https://www.ibm.com/support/fixcentral), and place the downloaded file (for example, `IBM_MQ_9.1.1_UBUNTU_X86-64.tar.gz` for MQ V9.1.1 for Ubuntu on x86_64 architecture) in the `downloads` directory
3. Run `make build-advancedserver`
2. Download MQ from IBM Passport Advantage, and place the downloaded file (for example, `IBM_MQ_9.1.0.0_UBUNTU_X86-64.tar.gz` for MQ V9.1.0 for Ubuntu on x86_64 architecture) in the `downloads` directory
2. Run `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 package is called "MQ for Ubuntu", and contains DEB files for installing on Ubuntu.
On a Red Hat Enterprise Linux host, the command `make build-advancedserver` will build a container image using Red Hat Enterprise Linux as the base. On all other hosts, the base image will be Ubuntu.
You can build a different version of MQ by setting the `MQ_VERSION` environment variable, for example:
```bash
MQ_VERSION=9.1.0.0 make build-advancedserver
MQ_VERSION=9.0.5.0 make build-advancedserver
```
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:
@@ -50,10 +29,22 @@ MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
```
## Building a developer image
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 `x86_64` architecture. On a Red Hat Enterprise Linux host, this command will build a container image using Red Hat Enterprise Linux as the base. On all other hosts, the base image will be Ubuntu.
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 `x86_64` 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).
## Building on a different base image
By default, the MQ images use Ubuntu as the base layer. You can build using a Red Hat Enterprise Linux compatible base layer by setting the `BASE_IMAGE` environment variable. For example:
```
BASE_IMAGE=centos:7 make build-advancedserver
```
The `make` tool will try and locate the right archive file under the `downloads` directory, based on your platform architecture and your `MQ_VERSION` environment variable, for example `IBM_MQ_9.1.0.0_LINUX_X86_64.tar.gz` for MQ V9.1.0.0 on x86_64. You can also set the `MQ_ARCHIVE` environment variable to set the specific file name.
Note that if you are using Red Hat Enterprise Linux, you will need to create your own base image layer, with your subscription enabled, as described [here](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/getting_started_with_containers/get_started_with_docker_formatted_container_images). The MQ image build needs to install some additional packages, and a subscription is required to access the Red Hat repositories.
## Installed components
This image includes the core MQ server, Java, language packs, and GSKit. This can be configured by setting the `MQ_PACKAGES` argument to `make`. For the Ubuntu-based image, you can also directly set a [Docker build argument](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables-build-arg).
This image includes the core MQ server, Java, language packs, and GSKit. This can be configured by setting the `MQ_PACKAGES` argument to `make`, or directly as a [Docker build argument](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables-build-arg).

View File

@@ -1,39 +0,0 @@
# Security
## Container runtime
### User
The MQ server image is run using the "mqm" user. On the Ubuntu-based image, this uses the UID and GID of 999. On the Red Hat Enterprise Linux image, it uses the UID and GID of 888.
### Capabilities
The MQ Advanced image requires no Linux capabilities, so you can drop any capabilities which are added by default. For example, in Docker you could do the following:
```sh
docker run \
--cap-drop=ALL \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--detach \
mqadvanced-server:9.1.1.0-x86_64-ubuntu-16.04
```
The MQ Advanced for Developers image does requires 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:
```sh
docker run \
--cap-drop=ALL \
--cap-add=CHOWN \
--cap-add=SETUID \
--cap-add=SETGID \
--cap-add=AUDIT_WRITE \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--detach \
mqadvanced-server-dev:9.1.1.0-x86_64-ubuntu-16.04
```
### 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

@@ -8,12 +8,6 @@ You need to ensure you have the following tools installed:
* [dep](https://github.com/golang/dep) (official Go dependency management tool) - needed to prepare for running the tests
* [Helm](https://helm.sh) - only needed for running the Kubernetes tests
### Prerequisites for testing a RedHat image
If you want to test a container image with Red Hat Enterprise Linux as the base OS, then you need to use a host server with Red Hat Enterprise Linux. You must also have the following tools installed:
* [Yum](http://yum.baseurl.org/) (available in `rhel-7-server-extras`)
* [Buildah](https://buildah.io) (available in `rhel-7-server-extras`)
## Running the tests
There are two main sets of tests:
@@ -31,7 +25,7 @@ make test-advancedserver
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
```
MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server:9.1.1.0-x86_64-ubuntu-16.04 make test-advancedserver
MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server:9.1.0.0-x86_64-ubuntu-16.04 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::
@@ -40,10 +34,10 @@ You can pass parameters to `go test` with an environment variable. For example,
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 `mqadvanced-server:9.1.0.0-x86_64-ubuntu-16.04`:
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.0.5.0-x86_64-ubuntu-16.04`:
```
MQ_VERSION=9.1.0.0 make test-advancedserver
MQ_VERSION=9.0.5.0 make test-advancedserver
```
### Running the Docker tests with code coverage

View File

@@ -5,7 +5,7 @@ In order to use the image, it is necessary to accept the terms of the IBM MQ lic
## Running with the default configuration
You can run a queue manager with the default configuration and a listener on port 1414 using the following command. For example, the following command creates and starts a queue manager called `QM1`, and maps port 1414 on the host to the MQ listener on port 1414 inside the container, as well as port 9443 on the host to the web console on port 9443 inside the container:
```sh
```
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
@@ -16,15 +16,15 @@ docker run \
```
## Running with the default configuration and a volume
The above example will not persist any configuration data or messages across container runs. In order to do this, you need to use a [volume](https://docs.docker.com/storage/volumes/). For example, you can create a volume with the following command:
The above example will not persist any configuration data or messages across container runs. In order to do this, you need to use a [volume](https://docs.docker.com/engine/admin/volumes/volumes/). For example, you can create a volume with the following command:
```sh
```
docker volume create qm1data
```
You can then run a queue manager using this volume as follows:
```sh
```
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
@@ -40,7 +40,7 @@ The Docker image always uses `/mnt/mqm` for MQ data, which is correctly linked f
## Running with the default configuration and Prometheus metrics enabled
You can run a queue manager with [Prometheus](https://prometheus.io) metrics enabled. The following command will generate Prometheus metrics for your queue manager on `/metrics` port `9157`:
```sh
```
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
@@ -58,36 +58,34 @@ You can customize the configuration in several ways:
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
3. By using [remote MQ administration](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.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.
3. By using [remote MQ administration](http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file, and an administrative user `alice`. Note that it is not normally recommended to include passwords in this way:
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom `config.mqsc` and an administrative user `alice`. Note that it is not normally recommended to include passwords in this way:
```dockerfile
FROM ibmcom/mq
USER root
RUN useradd alice -G mqm && \
echo alice:passw0rd | chpasswd
USER 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 from the [mqdev blog](https://www.ibm.com/developerworks/community/blogs/messaging/entry/getting_going_without_turning_off_mq_security?lang=en), which allows users with passwords to connect on the `PASSWORD.SVRCONN` channel:
Here is an example corresponding `20-config.mqsc` script, which creates two local queues:
```mqsc
DEFINE QLOCAL(MY.QUEUE.1) REPLACE
DEFINE QLOCAL(MY.QUEUE.2) REPLACE
```
The file `20-config.mqsc` should be saved into the same directory as the `Dockerfile`.
DEFINE CHANNEL(PASSWORD.SVRCONN) CHLTYPE(SVRCONN) REPLACE
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allow privileged users on this channel')
SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('BackStop rule')
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT(REQUIRED)
ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) ADOPTCTX(YES)
REFRESH SECURITY TYPE(CONNAUTH)
```
## Running MQ commands
It is recommended that you configure MQ in your own custom image. However, you may need to run MQ commands directly inside the process space of the container. To run a command against a running queue manager, you can use `docker exec`, for example:
```sh
```
docker exec \
--tty \
--interactive \

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2019
# © Copyright IBM Corporation 2015, 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,16 +15,14 @@
FROM ubuntu:16.04
# The URL to download the MQ installer from in tar.gz format
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev911_ubuntu_x86-64.tar.gz
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz
# The MQ packages to install
ARG MQ_PACKAGES="ibmmq-sfbridge"
ARG MQM_UID=999
ADD install-mq.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/install-mq.sh \
&& install-mq.sh $MQM_UID
&& install-mq.sh
ENV LANG=en_US.UTF-8

View File

@@ -0,0 +1,7 @@
This is a work-in-progress for a Docker image based on Red Hat Enterprise Linux (RHEL).
The current MQ container build requires Docker V17.05 or greater (required features include multi-stage Docker build, and "ARG"s in the "FROM" statement). Red Hat Enterprise Linux V7.5 includes Docker up to version V1.13.
In order to build images with Red Hat Enterprise Linux, license registration is required. The license of the host server can be used, as long as you either use Red Hat's patched version of Docker (which is an old version), or if you use alternative container management tools such as [`buildah`](https://github.com/projectatomic/buildah/) and `podman` (from [`libpod`](https://github.com/projectatomic/libpod)).
This directory contains scripts for building with `buildah`. The build itself isn't containerized, so more software than usual is needed on the RHEL host, so an Ansible playbook is also provided to help set up the host.

View File

@@ -0,0 +1 @@
hosts

View File

@@ -0,0 +1,62 @@
# © Copyright IBM Corporation 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
---
# Sets up a server for building the Red Hat image.
- hosts: rhbuild
become: true
any_errors_fatal: true
tasks:
- name: install buildah
package:
name: buildah
state: present
when: ansible_distribution == "RedHat"
- name: install podman
package:
name: buildah
state: present
when: ansible_distribution == "RedHat"
- name: install golang
package:
name: golang
state: absent
- name: install make
package:
name: make
state: present
- name: install git
package:
name: git
state: present
- name: install golang 1.10 from TAR
unarchive:
src: "https://dl.google.com/go/go1.10.3.linux-amd64.tar.gz"
dest: "/usr/local"
remote_src: yes
# TODO: Re-factor to use get_url first, so we can use the checksum
#checksum: sha256:fa1b0e45d3b647c252f51f5e1204aba049cde4af177ef9f2181f43004f901035
creates: /usr/local/go/doc/go1.10.html
- name: add golang to PATH
copy:
dest: "/etc/profile.d/golang.sh"
content: |
PATH=$PATH:/usr/local/go/bin
- name: install dep from GitHub
get_url:
url: https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64
dest: /usr/local/bin/dep
mode: 0755
checksum: sha256:31144e465e52ffbc0035248a10ddea61a09bf28b00784fd3fdd9882c8cbb2315
when: ansible_architecture == "x86_64"
# TODO: Install MQ SDK

View File

@@ -0,0 +1,141 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2018
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
# Build a RHEL image, using the buildah tool
set -x
set -e
MQ_ARCHIVE=downloads/mqadv_dev905_linux_x86-64.tar.gz
MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm"
# Use a "scratch" container, so the resulting image has minimal files
# Resulting image won't have yum, for example
ctr=$(buildah from scratch)
scratchmnt=$(buildah mount $ctr)
# Initialize yum for use with the scratch container
rpm --root $scratchmnt --initdb
yum install yum-utils
yumdownloader --destdir=/tmp redhat-release-server
rpm --root $scratchmnt -ihv /tmp/redhat-release-server*.rpm
# Install the packages required by MQ
yum install -y --installroot=$scratchmnt \
bash \
bc \
coreutils \
file \
findutils \
gawk \
glibc-common \
grep \
passwd \
procps-ng \
sed \
tar \
util-linux
# Clean up cached files
yum clean all --installroot=$scratchmnt
rm -rf $scratchmnt/var/cache/yum/*
groupadd --root $scratchmnt --system --gid 888 mqm
useradd --root $scratchmnt --system --uid 888 --gid mqm mqm
usermod --root $scratchmnt -G root mqm
DIR_EXTRACT=$scratchmnt/tmp/extract
mkdir -p $scratchmnt/tmp/extract
tar -zxvf ${MQ_ARCHIVE} -C ${DIR_EXTRACT}
DIR_RPM=$(find ${DIR_EXTRACT} -name "*.rpm" -printf "%h\n" | sort -u | head -1)
DIR_RPM=${DIR_RPM#$scratchmnt}
#DIR_RPM=$(buildah run $ctr -- find ${DIR_EXTRACT} -name "*.rpm" -printf "%h\n" | sort -u | head -1)
# Find location of mqlicense.sh
#MQLICENSE=$(buildah run $ctr -- find ${DIR_EXTRACT} -name "mqlicense.sh")
MQLICENSE=$(find ${DIR_EXTRACT} -name "mqlicense.sh")
MQLICENSE=${MQLICENSE#$scratchmnt}
# Accept the MQ license
buildah run $ctr -- ${MQLICENSE} -text_only -accept
buildah run $ctr -- bash -c "cd $DIR_RPM && rpm -ivh $MQ_PACKAGES"
rm -rf ${DIR_EXTRACT}
# Remove 32-bit libraries from 64-bit container
find $scratchmnt/opt/mqm $scratchmnt/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 $scratchmnt/opt/mqm -name '*.tar.gz' -delete
# Recommended: Set the default MQ installation (makes the MQ commands available on the PATH)
buildah run $ctr -- /opt/mqm/bin/setmqinst -p /opt/mqm -i
# Remove the directory structure under /var/mqm which was created by the installer
rm -rf $scratchmnt/var/mqm
# Create the mount point for volumes
mkdir -p $scratchmnt/mnt/mqm
# Create the directory for MQ configuration files
mkdir -p $scratchmnt/etc/mqm
# Create a symlink for /var/mqm -> /mnt/mqm/data
buildah run $ctr ln -s /mnt/mqm/data /var/mqm
# Optional: Set these values for the Bluemix Vulnerability Report
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' $scratchmnt/etc/login.defs
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' $scratchmnt/etc/login.defs
sed -i 's/password\t\[success=1 default=ignore\]\tpam_unix\.so obscure sha512/password\t[success=1 default=ignore]\tpam_unix.so obscure sha512 minlen=8/' $scratchmnt/etc/pam.d/password-auth
# Build and test the Go code
go build ./cmd/runmqserver/
go build ./cmd/chkmqready/
go build ./cmd/chkmqhealthy/
go test -v ./cmd/runmqserver/
go test -v ./cmd/chkmqready/
go test -v ./cmd/chkmqhealthy/
go test -v ./internal/...
go vet ./cmd/... ./internal/...
# Install the Go binaries into the image
cp runmqserver $scratchmnt/usr/local/bin/
cp chkmq* $scratchmnt/usr/local/bin/
cp NOTICES.txt $scratchmnt/opt/mqm/licenses/notices-container.txt
chmod ug+x $scratchmnt/usr/local/bin/runmqserver
chown mqm:mqm $scratchmnt/usr/local/bin/*mq*
chmod ug+xs $scratchmnt/usr/local/bin/chkmq*
buildah config \
--port 1414/tcp \
--port 9157/tcp \
--os linux \
--label architecture=x86_64 \
--label io.openshift.tags="mq messaging" \
--label io.k8s.display-name="IBM MQ Advanced Server" \
--label io.k8s.description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
--label name="mqadvanced-server" \
--label vendor="IBM" \
--label version="9.0.5.0" \
--env AMQ_ADDITIONAL_JSON_LOG=1 \
--env LANG=en_US.UTF-8 \
--env LOG_FORMAT=basic \
--entrypoint runmqserver \
--user 888 \
$ctr
buildah unmount $ctr
buildah commit $ctr mymq
# TODO: Leaves the working container lying around. Good for dev.

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2019
# © Copyright IBM Corporation 2015, 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,12 +15,10 @@
FROM ubuntu:16.04
# The URL to download the MQ installer from in tar.gz format
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev911_ubuntu_x86-64.tar.gz
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz
# The MQ packages to install
ARG MQ_PACKAGES
ARG MQM_UID=999
ARG MQ_PACKAGES="ibmmq-explorer"
RUN export DEBIAN_FRONTEND=noninteractive \
&& apt-get update \

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2019
# © Copyright IBM Corporation 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -11,8 +11,8 @@
# 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.
ARG BASE_IMAGE=mq-sdk:9.1.1.0-x86_64-ubuntu-16.04
ARG BASE_IMAGE=mq-sdk:9.0.5.0-x86_64-ubuntu-16.04
FROM $BASE_IMAGE
@@ -30,4 +30,4 @@ RUN chmod +x /usr/local/bin/install-golang.sh \
&& sleep 1 \
&& install-golang.sh
WORKDIR $GOPATH
WORKDIR $GOPATH

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2018, 2019
# © Copyright IBM Corporation 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ ARG MQ_URL
# The packages to install in install-mq.sh
ARG MQ_PACKAGES
ARG MQM_UID=999
COPY install-mq.sh /usr/local/bin/
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
@@ -32,6 +30,6 @@ COPY install-mq.sh /usr/local/bin/
# errors with some commands (e.g. `dspmqver`)
RUN chmod u+x /usr/local/bin/install-mq.sh \
&& sleep 1 \
&& install-mq.sh $MQM_UID \
&& install-mq.sh \
&& rm -rf /var/mqm \
&& /opt/mqm/bin/crtmqdir -f -s

View File

@@ -1,4 +1,4 @@
* © Copyright IBM Corporation 2017, 2019
* © Copyright IBM Corporation 2017, 2018
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
STOP LISTENER('SYSTEM.LISTENER.TCP.1') IGNSTATE(YES)
STOP LISTENER('SYSTEM.LISTENER.TCP.1')
* Developer queues
DEFINE QLOCAL('DEV.QUEUE.1') REPLACE
@@ -50,4 +50,4 @@ 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)
START LISTENER('DEV.LISTENER.TCP')

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2019
# © Copyright IBM Corporation 2015, 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
ARG BASE_IMAGE=mqadvanced-server-dev-base:9.1.1.0-x86_64-ubuntu-16.04
ARG BUILDER_IMAGE=mq-golang-sdk:9.1.1.0-x86_64-ubuntu-16.04
ARG BASE_IMAGE=mqadvanced-server-dev-base:9.0.5.0-x86_64-ubuntu-16.04
ARG BUILDER_IMAGE=mq-golang-sdk:9.0.5.0-x86_64-ubuntu-16.04
###############################################################################
# Build stage to build Go code
@@ -21,13 +21,12 @@ ARG BUILDER_IMAGE=mq-golang-sdk:9.1.1.0-x86_64-ubuntu-16.04
FROM $BUILDER_IMAGE as builder
ARG IMAGE_REVISION="Not specified"
ARG IMAGE_SOURCE="Not specified"
ARG IMAGE_TAG="Not specified"
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
COPY cmd/ ./cmd
COPY internal/ ./internal
COPY vendor/ ./vendor
# Re-build runmqserver, with code tagged with 'mqdev' enabled
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\"" --tags 'mqdev' ./cmd/runmqserver
RUN go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\"" --tags 'mqdev' ./cmd/runmqserver
RUN go build ./cmd/runmqdevserver/
# Run all unit tests
RUN go test -v ./cmd/runmqdevserver/...
@@ -43,20 +42,6 @@ ENV MQ_DEV=true
# Default administrator password
ENV MQ_ADMIN_PASSWORD=passw0rd
ARG MQM_UID=999
USER root
COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/install-extra-packages.sh \
&& sleep 1 \
&& install-extra-packages.sh
# 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 \
@@ -69,16 +54,12 @@ RUN mkdir -p /run/runmqdevserver \
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqserver /usr/local/bin/
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/
# Copy template files
COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/
# Copy web XML files for default developer configuration
COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
RUN chmod +x /usr/local/bin/runmq*
RUN chown -R mqm:mqm /etc/mqm/* \
&& chmod +x /usr/local/bin/runmq* \
&& install --directory --mode 0775 --owner mqm --group root /run/runmqdevserver
USER $MQM_UID
EXPOSE 9443
ENTRYPOINT ["runmqdevserver"]

View File

@@ -1,32 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
test -f /usr/bin/yum && RHEL=true || RHEL=false
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
if ($UBUNTU); then
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends sudo
rm -rf /var/lib/apt/lists/*
fi
if ($RHEL); then
yum -y install sudo
yum -y clean all
rm -rf /var/cache/yum/*
fi

View File

@@ -1,30 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<server>
<!-- ****************************************************************** -->
<!-- -->
<!-- IBM MQ security configuration for MQ Console and REST API. -->
<!-- -->
<!-- Name: mqwebuser.xml -->
<!-- -->
<!-- Description: Default webconsole configuration -->
<!-- -->
<!-- ****************************************************************** -->
<!-- <copyright -->
<!-- notice='lm-source-program' -->
<!-- pids='5724-H72' -->
<!-- years='2018,2019' -->
<!-- crc='0' > -->
<!-- -->
<!-- Licensed Materials - Property of IBM -->
<!-- -->
<!-- 5724-H72 -->
<!-- -->
<!-- (C) Copyright IBM Corp. 2018, 2019 All Rights Reserved. -->
<!-- -->
<!-- US Government Users Restricted Rights - Use, duplication or -->
<!-- disclosure restricted by GSA ADP Schedule Contract with -->
<!-- IBM Corp. -->
<!-- </copyright> -->
<featureManager>
<feature>appSecurity-2.0</feature>
<feature>basicAuthenticationMQ-1.0</feature>
@@ -60,6 +35,5 @@
</group>
</basicRegistry>
<variable name="httpHost" value="*"/>
<variable name="managementMode" value="externallyprovisioned"/>
<include location="tls.xml"/>
</server>

View File

@@ -1,30 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<server>
<!-- ****************************************************************** -->
<!-- -->
<!-- IBM MQ security configuration for MQ Console and REST API. -->
<!-- -->
<!-- Name: mqwebuser.xml -->
<!-- -->
<!-- Description: Default webconsole configuration -->
<!-- -->
<!-- ****************************************************************** -->
<!-- <copyright -->
<!-- notice='lm-source-program' -->
<!-- pids='5724-H72' -->
<!-- years='2018,2019' -->
<!-- crc='0' > -->
<!-- -->
<!-- Licensed Materials - Property of IBM -->
<!-- -->
<!-- 5724-H72 -->
<!-- -->
<!-- (C) Copyright IBM Corp. 2018, 2019 All Rights Reserved. -->
<!-- -->
<!-- US Government Users Restricted Rights - Use, duplication or -->
<!-- disclosure restricted by GSA ADP Schedule Contract with -->
<!-- IBM Corp. -->
<!-- </copyright> -->
<keyStore id="MQWebKeyStore" location="/run/runmqdevserver/tls/key.jks" type="JKS" password="${env.MQ_TLS_PASSPHRASE}"/>
<keyStore id="MQWebTrustStore" location="/run/runmqdevserver/tls/trust.jks" type="JKS" password="${env.MQ_TLS_PASSPHRASE}"/>
<ssl id="thisSSLConfig" clientAuthenticationSupported="true" keyStoreRef="MQWebKeyStore" trustStoreRef="MQWebTrustStore" sslProtocol="TLSv1.2" serverKeyAlias="devcert"/>

View File

@@ -1,26 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 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.
# Install Docker and dep, required by build (assumes Ubuntu host, as used by Travis build)
set -ex
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
go get -u golang.org/x/lint/golint

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2019
# © Copyright IBM Corporation 2015, 2018
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,15 +18,13 @@
# Fail on any non-zero return code
set -ex
mqm_uid=${1:-999}
test -f /usr/bin/yum && RHEL=true || RHEL=false
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
# If MQ_PACKAGES isn't specifically set, then choose a valid set of defaults
if [ -z "$MQ_PACKAGES" ]; then
$UBUNTU && MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams ibmmq-web"
$RHEL && MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm MQSeriesWeb-*.rpm"
$UBUNTU && MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams"
$RHEL && MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm"
fi
if ($UBUNTU); then
@@ -65,8 +63,7 @@ if ($UBUNTU); then
procps \
sed \
tar \
util-linux \
openssl
util-linux
fi
# Install additional packages required by MQ, this install process and the runtime scripts
@@ -85,8 +82,7 @@ $RHEL && yum -y install \
procps-ng \
sed \
tar \
util-linux \
openssl
util-linux
# Download and extract the MQ installation files
DIR_EXTRACT=/tmp/mq
@@ -106,8 +102,11 @@ $UBUNTU && apt-get purge -y \
$UBUNTU && apt-get autoremove -y
# Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images
groupadd --system --gid ${mqm_uid} mqm
useradd --system --uid ${mqm_uid} --gid mqm --groups 0 mqm
$UBUNTU && groupadd --system --gid 999 mqm
$UBUNTU && useradd --system --uid 999 --gid mqm mqm
$RHEL && groupadd --system --gid 888 mqm
$RHEL && useradd --system --uid 888 --gid mqm mqm
usermod -aG mqm root
# Find directory containing .deb files
$UBUNTU && DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1)
@@ -140,7 +139,7 @@ rm -rf ${DIR_EXTRACT}
# Apply any bug fixes not included in base Ubuntu or MQ image.
# Don't upgrade everything based on Docker best practices https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#run
$UBUNTU && apt-get install -y libapparmor1 libsystemd0 systemd systemd-sysv libudev1 perl-base --only-upgrade
$UBUNTU && apt-get install -y libapparmor1 libsystemd0 systemd systemd-sysv libudev1 --only-upgrade
# End of bug fixes
# Clean up cached files
@@ -154,18 +153,16 @@ $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
install --directory --mode 0775 --owner mqm --group root /mnt
install --directory --mode 0775 --owner mqm --group root /mnt/mqm
install --directory --mode 0775 --owner mqm --group root /mnt/mqm/data
# Create the mount point for volumes
mkdir -p /mnt/mqm
# Create the directory for MQ configuration files
install --directory --mode 0775 --owner mqm --group root /etc/mqm
mkdir -p /etc/mqm
# Create a symlink for /var/mqm -> /mnt/mqm/data
ln -s /mnt/mqm/data /var/mqm
# Optional: Ensure any passwords expire in a timely manner
# Optional: Set these values for the Bluemix Vulnerability Report
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

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");
you may not use this file except in compliance with the License.
@@ -53,13 +53,11 @@ func RunCmd(cmd *exec.Cmd) (string, int, error) {
// Do not use this function to run shell built-ins (like "cd"), because
// the error handling works differently
func Run(name string, arg ...string) (string, int, error) {
// #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
cmd := exec.Command(name, arg...)
cmd.SysProcAttr = &syscall.SysProcAttr{}
uid, gid, err := LookupMQM()

View File

@@ -1,109 +0,0 @@
/*
© 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.
*/
package runtime
import (
"fmt"
"io/ioutil"
"strings"
"github.com/genuinetools/amicontained/container"
)
func GetContainerRuntime() (string, error) {
return container.DetectRuntime()
}
func GetBaseImage() (string, error) {
buf, err := ioutil.ReadFile("/etc/os-release")
if err != nil {
return "", fmt.Errorf("Failed to read /etc/os-release: %v", err)
}
lines := strings.Split(string(buf), "\n")
for _, l := range lines {
if strings.HasPrefix(l, "PRETTY_NAME=") {
words := strings.Split(l, "\"")
if len(words) >= 2 {
return words[1], nil
}
}
}
return "unknown", nil
}
// GetCapabilities gets the Linux capabilities (e.g. setuid, setgid). See https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
func GetCapabilities() (map[string][]string, error) {
return container.Capabilities()
}
// GetSeccomp gets the seccomp enforcing mode, which affects which kernel calls can be made
func GetSeccomp() (string, error) {
s, err := container.SeccompEnforcingMode()
if err != nil {
return "", fmt.Errorf("Failed to get container SeccompEnforcingMode: %v", err)
}
return s, nil
}
// GetSecurityAttributes gets the security attributes of the current process.
// The security attributes indicate whether AppArmor or SELinux are being used,
// and what the level of confinement is.
func GetSecurityAttributes() string {
a, err := readProc("/proc/self/attr/current")
// On some systems, if AppArmor or SELinux are not installed, you get an
// error when you try and read `/proc/self/attr/current`, even though the
// file exists.
if err != nil || a == "" {
a = "none"
}
return a
}
func readProc(filename string) (value string, err error) {
// #nosec G304
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return strings.TrimSpace(string(buf)), nil
}
func GetMounts() (map[string]string, error) {
all, err := readProc("/proc/mounts")
if err != nil {
return nil, fmt.Errorf("Couldn't read /proc/mounts")
}
result := make(map[string]string)
lines := strings.Split(all, "\n")
for i := range lines {
parts := strings.Split(lines[i], " ")
//dev := parts[0]
mountPoint := parts[1]
fsType := parts[2]
if strings.Contains(mountPoint, "/mnt/mqm") {
result[mountPoint] = fsType
}
}
return result, nil
}
func GetKernelVersion() (string, error) {
return readProc("/proc/sys/kernel/osrelease")
}
func GetMaxFileHandles() (string, error) {
return readProc("/proc/sys/fs/file-max")
}

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");
you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ type Logger struct {
pid string
serverName string
host string
userName string
user *user.User
}
// NewLogger creates a new logger
@@ -53,13 +53,9 @@ func NewLogger(writer io.Writer, debug bool, json bool, serverName string) (*Log
if err != nil {
return nil, err
}
// This can fail because the container's running as a random UID which
// is not known by the OS. We don't want this to break the logging
// entirely, so just use a blank user name.
user, err := user.Current()
userName := ""
if err == nil {
userName = user.Username
if err != nil {
return nil, err
}
return &Logger{
mutex: sync.Mutex{},
@@ -70,7 +66,7 @@ func NewLogger(writer io.Writer, debug bool, json bool, serverName string) (*Log
pid: strconv.Itoa(os.Getpid()),
serverName: serverName,
host: hostname,
userName: userName,
user: user,
}, nil
}
@@ -97,7 +93,7 @@ func (l *Logger) log(level string, msg string) {
"ibm_serverName": l.serverName,
"ibm_processName": l.processName,
"ibm_processId": l.pid,
"ibm_userName": l.userName,
"ibm_userName": l.user.Username,
"type": "mq_containerlog",
}
s, err := l.format(entry)

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");
you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ func GatherMetrics(qmName string, log *logger.Logger) {
err := startMetricsGathering(qmName, log)
if err != nil {
log.Errorf("Metrics Error: %s", err.Error())
StopMetricsGathering(log)
StopMetricsGathering()
}
}
@@ -76,7 +76,6 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
http.Handle("/metrics", prometheus.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
// #nosec G104
w.Write([]byte("Status: METRICS ACTIVE"))
})
@@ -84,7 +83,7 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
err = metricsServer.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
log.Errorf("Metrics Error: Failed to handle metrics request: %v", err)
StopMetricsGathering(log)
StopMetricsGathering()
}
}()
@@ -92,7 +91,7 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
}
// StopMetricsGathering stops gathering metrics for the queue manager
func StopMetricsGathering(log *logger.Logger) {
func StopMetricsGathering() {
if metricsEnabled {
@@ -102,9 +101,6 @@ func StopMetricsGathering(log *logger.Logger) {
// Shutdown HTTP server
timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := metricsServer.Shutdown(timeout)
if err != nil {
log.Errorf("Failed to shutdown metrics server: %v", err)
}
metricsServer.Shutdown(timeout)
}
}

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");
you may not use this file except in compliance with the License.
@@ -62,7 +62,6 @@ func processMetrics(log *logger.Logger, qmName string) {
firstConnect = false
startChannel <- true
}
// #nosec G104
metrics, _ = initialiseMetrics(log)
}

View File

@@ -1,81 +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 user
import (
"fmt"
"os/user"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
// User holds information on primary and supplemental OS groups
type User struct {
UID string
Name string
PrimaryGID string
SupplementalGID []string
}
// GetUser returns the current user and group information
func GetUser() (User, error) {
u, err := user.Current()
if err != nil {
return User{}, err
}
g, err := getCurrentUserGroups()
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

@@ -12,17 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
image: ibmcom/mq:9.1.1.0
image: ibmcom/mq:9
manifests:
- image: ibmcom/mq:9.1.1.0-x86_64
- image: ibmcom/mq:9.1.0.0-x86_64
platform:
architecture: amd64
os: linux
- image: ibmcom/mq:9.1.1.0-ppc64le
- image: ibmcom/mq:9.1.0.0-ppc64le
platform:
architecture: ppc64le
os: linux
- image: ibmcom/mq:9.1.1.0-s390x
- image: ibmcom/mq:9.1.0.0-s390x
platform:
architecture: s390x
os: linux

View File

@@ -14,15 +14,15 @@
image: ibmcom/mq:latest
manifests:
- image: ibmcom/mq:9.1.1.0-x86_64
- image: ibmcom/mq:9.1.0.0-x86_64
platform:
architecture: amd64
os: linux
- image: ibmcom/mq:9.1.1.0-ppc64le
- image: ibmcom/mq:9.1.0.0-ppc64le
platform:
architecture: ppc64le
os: linux
- image: ibmcom/mq:9.1.1.0-s390x
- image: ibmcom/mq:9.1.0.0-s390x
platform:
architecture: s390x
os: linux

View File

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

View File

@@ -1,3 +0,0 @@
# RHEL-based container build
Build scripts for building a container image based on Red Hat Enterprise Linux (RHEL), using the [`buildah`](https://github.com/containers/buildah) tool. buildah is supported on RHEL V7.5 and greater.

View File

@@ -1,49 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
# Builds and tests the golang programs used by the MQ image.
set -ex
# Handle a GOPATH with multiple entries (just choose the first one)
IFS=':' read -ra DIR <<< "$GOPATH"
cd ${DIR[0]}/src/github.com/ibm-messaging/mq-container/
# Build and test the Go code
mkdir -p build
cd build
rm -f chkmqready chkmqhealthy runmqserver runmqdevserver
if [ "$MQDEV" = "TRUE" ]; then
# Build and test the Go code
go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\"" --tags 'mqdev' ../cmd/runmqserver/
go build ../cmd/runmqdevserver/
else
go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\"" ../cmd/runmqserver/
fi
go build ../cmd/chkmqready/
go build ../cmd/chkmqhealthy/
go test -v ../cmd/runmqserver/
go test -v ../cmd/chkmqready/
go test -v ../cmd/chkmqhealthy/
if [ "$MQDEV" = "TRUE" ]; then
go test -v ../cmd/runmqdevserver
fi
go test -v ../internal/...
go vet ../cmd/... ../internal/...

View File

@@ -1,49 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
# Run the Go build script inside the Go container, mounting the source
# directory in
function usage {
echo "Usage: $0 TAG DevModeFlag"
exit 20
}
if [ "$#" -ne 2 ]; then
echo "ERROR: Invalid number of parameters"
usage
fi
readonly tag=$1
readonly dev=$2
IMAGE_REVISION=${IMAGE_REVISION:="Not Applicable"}
IMAGE_SOURCE=${IMAGE_SOURCE:="Not Applicable"}
# Run the build in a container
# Note the ":Z" on the volume is to allow the container to access the files when SELinux is enabled
# Note the "podman" network is used explicitly, to avoid problems other CNI networks (e.g. on an OpenShift node)
podman run \
--volume ${PWD}:/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/:Z \
--env IMAGE_REVISION="$IMAGE_REVISION" \
--env IMAGE_SOURCE="$IMAGE_SOURCE" \
--env MQDEV=${dev} \
--user $(id -u) \
--rm \
--network podman \
${tag} \
bash -c "cd /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/ && ./mq-advanced-server-rhel/go-build.sh"

View File

@@ -1,88 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
# Install one or more MQ components into a buildah container
set -ex
function usage {
echo "Usage: $0 MQContainer MountLocation ARCHIVENAME PACKAGES"
exit 20
}
if [ "$#" -ne 4 ]; then
echo "ERROR: Invalid number of parameters"
usage
fi
readonly ctr_mq=$1
readonly mnt_mq=$2
readonly archive=$3
readonly mq_packages=$4
readonly dir_extract=/tmp/extract
readonly mqm_uid=888
readonly mqm_gid=888
if [ ! -d ${dir_extract}/MQServer ]; then
mkdir -p ${dir_extract}
echo Extracting $archive
tar -zxf $archive -C ${dir_extract}
echo Extracting finished
fi
# Accept the MQ license
buildah run --user root --volume ${dir_extract}:/mnt/mq-download:Z $ctr_mq -- /mnt/mq-download/MQServer/mqlicense.sh -text_only -accept
# Install MQ
buildah run --user root --volume ${dir_extract}:/mnt/mq-download:Z $ctr_mq -- bash -c "cd /mnt/mq-download/MQServer && rpm -ivh $mq_packages"
rm -rf ${dir_extract}/MQServer
# Remove 32-bit libraries from 64-bit container
find $mnt_mq/opt/mqm $mnt_mq/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 $mnt_mq/opt/mqm -name '*.tar.gz' -delete
# Recommended: Set the default MQ installation (makes the MQ commands available on the PATH)
buildah run $ctr_mq -- /opt/mqm/bin/setmqinst -p /opt/mqm -i
mkdir -p $mnt_mq/run/runmqserver
chown ${mqm_uid}:${mqm_gid} $mnt_mq/run/runmqserver
# Remove the directory structure under /var/mqm which was created by the installer
rm -rf $mnt_mq/var/mqm
# Create the mount point for volumes, ensuring MQ has permissions to all directories
mkdir -p $mnt_mq/mnt/mqm
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/mnt
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/mnt/mqm
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/mnt/mqm/data
# Create the directory for MQ configuration files
mkdir -p /etc/mqm
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/etc/mqm
# Create a symlink for /var/mqm -> /mnt/mqm/data
buildah run --user root $ctr_mq -- ln -s /mnt/mqm/data /var/mqm
# Optional: Set these values for the IBM Cloud Vulnerability Report
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' $mnt_mq/etc/login.defs
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' $mnt_mq/etc/login.defs
sed -i 's/password\t\[success=1 default=ignore\]\tpam_unix\.so obscure sha512/password\t[success=1 default=ignore]\tpam_unix.so obscure sha512 minlen=8/' $mnt_mq/etc/pam.d/password-auth
buildah run $ctr_mq -- cp -rs /opt/mqm/licenses/ /

View File

@@ -1,173 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
# Build a RHEL image, using the buildah tool
set -x
set -e
function usage {
echo "Usage: $0 ARCHIVE-NAME PACKAGES TAG VERSION MQDevFlag"
exit 20
}
if [ "$#" -ne 5 ]; then
echo "ERROR: Invalid number of parameters"
usage
fi
###############################################################################
# Setup MQ server working container
###############################################################################
# Use RHEL 7 minimal container (which doesn't include things like Python or Yum)
readonly ctr_mq=$(buildah from rhel7-minimal)
if [ -z "$ctr_mq" ]
then
echo "ERROR: ctr_mq is empty. Check above output for errors"
exit 50
fi
readonly mnt_mq=$(buildah mount $ctr_mq)
if [ -z "$mnt_mq" ]
then
echo "ERROR: mnt_mq is empty. Check above output for errors"
exit 50
fi
readonly archive=downloads/$1
readonly packages=$2
readonly tag=$3
readonly version=$4
readonly mqdev=$5
readonly mqm_uid=888
readonly mqm_gid=888
###############################################################################
# Install MQ server
###############################################################################
microdnf_opts="--nodocs"
# Check whether the host is registered with Red Hat
if subscription-manager status ; then
# Host is subscribed, but the minimal image has no enabled repos
# Note that the "bc" package is the only one in "extras"
microdnf_opts="${microdnf_opts} --enablerepo=rhel-7-server-rpms --enablerepo=rhel-7-server-extras-rpms"
else
# Use the Yum repositories configured on the host
cp -R /etc/yum.repos.d/* ${mnt_mq}/etc/yum.repos.d/
fi
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} install \
bash \
bc \
coreutils \
file \
findutils \
gawk \
glibc-common \
grep \
passwd \
procps-ng \
sed \
shadow-utils \
tar \
util-linux \
openssl \
which
# Install "sudo" if using MQ Advanced for Developers
if [ "$mqdev" = "TRUE" ]; then
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} install sudo
fi
# Clean up cached files
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} clean all
rm -rf ${mnt_mq}/etc/yum.repos.d/*
buildah run --user root $ctr_mq -- groupadd --system --gid ${mqm_gid} mqm
buildah run --user root $ctr_mq -- useradd --system --uid ${mqm_uid} --gid mqm --groups 0 mqm
# Install MQ server packages into the MQ builder image
./mq-advanced-server-rhel/install-mq-rhel.sh ${ctr_mq} "${mnt_mq}" "${archive}" "${packages}"
# Create the directory for MQ configuration files
mkdir -p ${mnt_mq}/etc/mqm
chown ${mqm_uid}:${mqm_gid} ${mnt_mq}/etc/mqm
# Install the Go binaries into the image
install --mode 0750 --owner ${mqm_uid} --group 0 ./build/runmqserver ${mnt_mq}/usr/local/bin/
install --mode 6750 --owner ${mqm_uid} --group 0 ./build/chk* ${mnt_mq}/usr/local/bin/
install --mode 0750 --owner ${mqm_uid} --group 0 ./NOTICES.txt ${mnt_mq}/opt/mqm/licenses/notices-container.txt
install --directory --mode 0775 --owner ${mqm_uid} --group 0 ${mnt_mq}/run/runmqserver
buildah run --user root $ctr_mq -- touch /run/termination-log
buildah run --user root $ctr_mq -- chown mqm:root /run/termination-log
buildah run --user root $ctr_mq -- chmod 0660 /run/termination-log
# Copy in licenses from installed packages
install --mode 0550 --owner root --group root ./mq-advanced-server-rhel/writePackages.sh ${mnt_mq}/usr/local/bin/writePackages
buildah run --user root $ctr_mq -- /usr/local/bin/writePackages
# Copy web XML files
cp -R web ${mnt_mq}/etc/mqm/web
# Copy web XML files
cp -R web ${mnt_mq}/etc/mqm/web
###############################################################################
# Final Buildah commands
###############################################################################
if [ "$mqdev" = "TRUE" ]; then
OSTAG="mq messaging developer"
DISNAME="IBM MQ Advanced Server Developer Edition"
PID="98102d16795c4263ad9ca075190a2d4d"
else
OSTAG="mq messaging"
DISNAME="IBM MQ Advanced Server"
PID="4486e8c4cc9146fd9b3ce1f14a2dfc5b"
fi
buildah config \
--port 1414/tcp \
--port 9157/tcp \
--port 9443/tcp \
--os linux \
--label architecture=x86_64 \
--label io.openshift.tags="$OSTAG" \
--label io.k8s.display-name="$DISNAME" \
--label io.k8s.description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
--label name="${tag%:*}" \
--label vendor="IBM" \
--label version="$version" \
--label release="1" \
--label run="docker run -d -e LICENSE=accept --name ibm-mq ${tag%:*}" \
--label summary="$DISNAME" \
--label description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
--label IBM_PRODUCT_ID="$PID" \
--label IBM_PRODUCT_NAME="$DISNAME" \
--label IBM_PRODUCT_VERSION="$version" \
--env AMQ_ADDITIONAL_JSON_LOG=1 \
--env LANG=en_US.UTF-8 \
--env LOG_FORMAT=basic \
--entrypoint runmqserver \
--user ${mqm_uid} \
$ctr_mq
buildah unmount $ctr_mq
buildah commit $ctr_mq $tag
buildah rm $ctr_mq

View File

@@ -1,65 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
# Build a RHEL image for building Go programs which use MQ
set -ex
function usage {
echo "Usage: $0 REDIST-ARCHIVE-NAME TAG"
exit 20
}
if [ "$#" -ne 2 ]; then
echo "ERROR: Invalid number of parameters"
usage
fi
readonly mq_redist_archive=downloads/$1
readonly tag=$2
# Use Red Hat's Go toolset image as the base
readonly ctr_mq=$(buildah from devtools/go-toolset-7-rhel7)
if [ -z "$ctr_mq" ]
then
echo "ERROR: ctr_mq is empty. Check above output for errors"
exit 50
fi
readonly mnt_mq_go=$(buildah mount $ctr_mq)
if [ -z "$mnt_mq_go" ]
then
echo "ERROR: mnt_mq_go is empty. Check above output for errors"
exit 50
fi
# Install the MQ redistributable client (including header files) into the Go builder image
mkdir -p ${mnt_mq_go}/opt/mqm
tar -xzf ${mq_redist_archive} -C ${mnt_mq_go}/opt/mqm
# Clean up Yum files
rm -rf ${mnt_mq_go}/etc/yum.repos.d/*
buildah unmount ${ctr_mq}
# Set environment variables for MQ/Go compilation
buildah config \
--os linux \
--env CGO_CFLAGS="-I/opt/mqm/inc/" \
--env CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
${ctr_mq}
buildah commit ${ctr_mq} ${tag}
buildah rm ${ctr_mq}

View File

@@ -1,117 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
# Build a RHEL image of MQ Advanced for Developers, using the buildah tool
set -x
set -e
function usage {
echo "Usage: $0 BASETAG TAG VERSION"
exit 20
}
if [ "$#" -ne 3 ]; then
echo "ERROR: Invalid number of parameters"
usage
fi
###############################################################################
# Setup MQ server working container
###############################################################################
# Use a "scratch" container, so the resulting image has minimal files
# Resulting image won't have yum, for example
readonly basetag=$1
readonly ctr_mq=$(buildah from $basetag)
if [ -z "$ctr_mq" ]
then
echo "ERROR: ctr_mq is empty. Check above output for errors"
exit 50
fi
readonly mnt_mq=$(buildah mount $ctr_mq)
if [ -z "$mnt_mq" ]
then
echo "ERROR: mnt_mq is empty. Check above output for errors"
exit 50
fi
readonly tag=$2
readonly version=$3
readonly mqm_uid=888
readonly mqm_gid=888
# 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.
echo "mqm ALL = NOPASSWD: /usr/sbin/chpasswd" > $mnt_mq/etc/sudoers.d/mq-dev-config
# Run these commands inside the container so that the SELinux context is handled correctly
buildah run --user root $ctr_mq -- useradd --gid mqm admin
buildah run --user root $ctr_mq -- groupadd --system mqclient
buildah run --user root $ctr_mq -- useradd --gid mqclient app
buildah run --user root $ctr_mq -- bash -c "echo admin:passw0rd | chpasswd"
mkdir --parents $mnt_mq/run/runmqdevserver
chown ${mqm_uid}:${mqm_gid} $mnt_mq/run/runmqdevserver
# Copy runmqdevserver program
install --mode 0750 --owner ${mqm_uid} --group ${mqm_gid} ./build/runmqdevserver ${mnt_mq}/usr/local/bin/
install --directory --mode 0775 --owner ${mqm_uid} --group 0 ${mnt_mq}/run/runmqdevserver
# Copy template files
cp ./incubating/mqadvanced-server-dev/*.tpl ${mnt_mq}/etc/mqm/
# Copy web XML files for default developer configuration
cp -R incubating/mqadvanced-server-dev/web/ ${mnt_mq}/etc/mqm/web
###############################################################################
# Final Buildah commands
###############################################################################
buildah config \
--port 1414/tcp \
--port 9157/tcp \
--port 9443/tcp \
--os linux \
--label architecture=x86_64 \
--label io.openshift.tags="mq messaging developer" \
--label io.k8s.display-name="IBM MQ Advanced Server Developer Edition" \
--label io.k8s.description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
--label name="${tag%:*}" \
--label vendor="IBM" \
--label version="$version" \
--label release="1" \
--label run="docker run -d -e LICENSE=accept --name ibm-mq-dev ${tag%:*}" \
--label summary="IBM MQ Advanced Server Developer Edition" \
--label description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
--label IBM_PRODUCT_ID="98102d16795c4263ad9ca075190a2d4d" \
--label IBM_PRODUCT_NAME="IBM MQ Advanced Server Developer Edition" \
--label IBM_PRODUCT_VERSION="$version" \
--env AMQ_ADDITIONAL_JSON_LOG=1 \
--env LANG=en_US.UTF-8 \
--env LOG_FORMAT=basic \
--env MQ_ADMIN_PASSWORD=passw0rd \
--env MQ_DEV=true \
--entrypoint runmqdevserver \
--user ${mqm_uid} \
$ctr_mq
buildah unmount $ctr_mq
buildah commit $ctr_mq $tag
buildah rm $ctr_mq

View File

@@ -1,30 +0,0 @@
#!/bin/bash
# -*- mode: sh -*-
# © 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.
# Copy in licenses from installed packages
set -e
rm -f /licenses/installed_package_notices
for p in $(rpm -qa | sort)
do
rpm -qi $p >> /licenses/installed_package_notices
printf "\n" >> /licenses/installed_package_notices
done
chmod 0444 /licenses/installed_package_notices

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2017, 2019
# © Copyright IBM Corporation 2017, 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
[[constraint]]
name = "github.com/docker/go-connections"
version = "0.4.0"
version = "0.3.0"
[prune]
go-tests = true

View File

@@ -33,7 +33,6 @@ import (
// Note: This test requires a separate container image to be available for the JMS tests.
func TestDevGoldenPath(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -67,12 +66,10 @@ func TestDevGoldenPath(t *testing.T) {
// Note: This test requires a separate container image to be available for the JMS tests
func TestDevSecure(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
const tlsPassPhrase string = "passw0rd"
qm := "qm1"
appPassword := "differentPassw0rd"
@@ -129,7 +126,6 @@ func TestDevSecure(t *testing.T) {
func TestDevWebDisabled(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -160,7 +156,6 @@ func TestDevWebDisabled(t *testing.T) {
func TestDevConfigDisabled(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)

View File

@@ -1,7 +1,7 @@
// +build mqdev
/*
© Copyright IBM Corporation 2018, 2019
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@ import (
"io/ioutil"
"net/http"
"net/http/httputil"
"os"
"path/filepath"
"strings"
"testing"
@@ -87,7 +86,6 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
"MQ_USERNAME=" + user,
"MQ_CHANNEL=DEV.APP.SVRCONN",
"IBMJRE=" + os.Getenv("IBMJRE"),
},
Image: imageNameDevJMS(),
}
@@ -114,7 +112,7 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa
t.Fatal(err)
}
startContainer(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 2*time.Minute)
rc := waitForContainer(t, cli, ctr.ID, 10)
if rc != 0 {
t.Errorf("JUnit container failed with rc=%v", rc)
}

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");
you may not use this file except in compliance with the License.
@@ -34,13 +34,10 @@ import (
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/ibm-messaging/mq-container/internal/command"
)
func TestLicenseNotSet(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -48,16 +45,15 @@ func TestLicenseNotSet(t *testing.T) {
containerConfig := container.Config{}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
rc := waitForContainer(t, cli, id, 20*time.Second)
rc := waitForContainer(t, cli, id, 5)
if rc != 1 {
t.Errorf("Expected rc=1, got rc=%v", rc)
}
expectTerminationMessage(t, cli, id)
expectTerminationMessage(t)
}
func TestLicenseView(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -67,7 +63,7 @@ func TestLicenseView(t *testing.T) {
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
rc := waitForContainer(t, cli, id, 20*time.Second)
rc := waitForContainer(t, cli, id, 5)
if rc != 1 {
t.Errorf("Expected rc=1, got rc=%v", rc)
}
@@ -81,14 +77,12 @@ func TestLicenseView(t *testing.T) {
// TestGoldenPath starts a queue manager successfully when metrics are enabled
func TestGoldenPathWithMetrics(t *testing.T) {
t.Parallel()
goldenPath(t, true)
}
// TestGoldenPath starts a queue manager successfully when metrics are disabled
func TestGoldenPathNoMetrics(t *testing.T) {
t.Parallel()
goldenPath(t, false)
}
@@ -112,11 +106,10 @@ func goldenPath(t *testing.T, metric bool) {
stopContainer(t, cli, id)
}
// TestSecurityVulnerabilitiesUbuntu checks for any vulnerabilities in the image, as reported
// TestSecurityVulnerabilities checks for any vulnerabilities in the image, as reported
// by Ubuntu
func TestSecurityVulnerabilitiesUbuntu(t *testing.T) {
func TestSecurityVulnerabilities(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -142,47 +135,6 @@ func TestSecurityVulnerabilitiesUbuntu(t *testing.T) {
}
}
// TestSecurityVulnerabilitiesRedHat checks for any vulnerabilities in the image, as reported
// by Red Hat
func TestSecurityVulnerabilitiesRedHat(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
_, ret, _ := command.Run("bash", "-c", "test -f /etc/redhat-release")
if ret != 0 {
t.Skip("Skipping test because host is not RedHat-based")
}
rc, _ := runContainerOneShot(t, cli, "bash", "-c", "test -f /etc/redhat-release")
if rc != 0 {
t.Skip("Skipping test because container is not RedHat-based")
}
id, _, err := command.Run("sudo", "buildah", "from", imageName())
if err != nil {
t.Log(id)
t.Fatal(err)
}
id = strings.TrimSpace(id)
defer command.Run("buildah", "rm", id)
mnt, _, err := command.Run("sudo", "buildah", "mount", id)
if err != nil {
t.Log(mnt)
t.Fatal(err)
}
mnt = strings.TrimSpace(mnt)
out, _, err := command.Run("bash", "-c", "sudo cp /etc/yum.repos.d/* "+filepath.Join(mnt, "/etc/yum.repos.d/"))
if err != nil {
t.Log(out)
t.Fatal(err)
}
out, ret, _ = command.Run("bash", "-c", "yum --installroot="+mnt+" updateinfo list sec | grep /Sec")
if ret != 1 {
t.Errorf("Expected no vulnerabilities, found the following:\n%v", out)
}
}
func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName string) {
search := "QMNAME(" + expectedName + ")"
cli, err := client.NewEnvClient()
@@ -203,13 +155,11 @@ func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName stri
}
func TestNoQueueManagerName(t *testing.T) {
t.Parallel()
utilTestNoQueueManagerName(t, "test", "test")
}
func TestNoQueueManagerNameInvalidHostname(t *testing.T) {
t.Parallel()
utilTestNoQueueManagerName(t, "test-1", "test1")
}
@@ -217,7 +167,6 @@ func TestNoQueueManagerNameInvalidHostname(t *testing.T) {
// container and starts a new one with same volume. With metrics enabled
func TestWithVolumeAndMetrics(t *testing.T) {
t.Parallel()
withVolume(t, true)
}
@@ -225,7 +174,6 @@ func TestWithVolumeAndMetrics(t *testing.T) {
// container and starts a new one with same volume. With metrics disabled
func TestWithVolumeNoMetrics(t *testing.T) {
t.Parallel()
withVolume(t, false)
}
@@ -277,7 +225,6 @@ func withVolume(t *testing.T, metric bool) {
// and restarted cleanly
func TestNoVolumeWithRestart(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -293,139 +240,58 @@ func TestNoVolumeWithRestart(t *testing.T) {
waitForReady(t, cli, id)
}
// TestVolumeRequiresRoot tests the case where only the root user can write
// to the persistent volume. In this case, an "init container" is needed,
// where `runmqserver -i` is run to initialize the storage. Then the
// container can be run as normal.
func TestVolumeRequiresRoot(t *testing.T) {
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
vol := createVolume(t, cli)
defer removeVolume(t, cli, vol.Name)
// Set permissions on the volume to only allow root to write it
// It's important that read and execute permissions are given to other users
rc, _ := runContainerOneShotWithVolume(t, cli, vol.Name+":/mnt/mqm:nocopy", "bash", "-c", "chown 65534:4294967294 /mnt/mqm/ && chmod 0755 /mnt/mqm/ && ls -lan /mnt/mqm/")
if rc != 0 {
t.Errorf("Expected one shot container to return rc=0, got rc=%v", rc)
}
containerConfig := container.Config{
Image: imageName(),
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
}
hostConfig := container.HostConfig{
Binds: []string{
coverageBind(t),
vol.Name + ":/mnt/mqm:nocopy",
},
}
networkingConfig := network.NetworkingConfig{}
// Run an "init container" as root, with the "-i" option, to initialize the volume
containerConfig = container.Config{
Image: imageName(),
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1", "DEBUG=true"},
User: "0",
Entrypoint: []string{"runmqserver", "-i"},
}
initCtr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"Init")
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, initCtr.ID)
t.Logf("Init container ID=%v", initCtr.ID)
startContainer(t, cli, initCtr.ID)
rc = waitForContainer(t, cli, initCtr.ID, 20*time.Second)
if rc != 0 {
t.Errorf("Expected init container to exit with rc=0, got rc=%v", rc)
}
containerConfig = container.Config{
Image: imageName(),
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1", "DEBUG=true"},
}
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"Main")
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ctr.ID)
t.Logf("Main container ID=%v", ctr.ID)
startContainer(t, cli, ctr.ID)
waitForReady(t, cli, ctr.ID)
}
// TestCreateQueueManagerFail causes a failure of `crtmqm`
func TestCreateQueueManagerFail(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
RUN echo '#!/bin/bash\nexit 999' > /opt/mqm/bin/crtmqm
RUN chown mqm:mqm /opt/mqm/bin/crtmqm
RUN chmod 6550 /opt/mqm/bin/crtmqm
USER mqm`, imageName())},
img, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
if err != nil {
t.Fatal(err)
}
tag := createImage(t, cli, files)
defer deleteImage(t, cli, tag)
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
containerConfig := container.Config{
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
Image: tag,
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
// Override the entrypoint to create the queue manager directory, but leave it empty.
// This will cause `crtmqm` to return with an exit code of 2.
Entrypoint: []string{"bash", "-c", "mkdir -p /mnt/mqm/data && mkdir -p /var/mqm/qmgrs/qm1 && exec " + oldEntrypoint},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
rc := waitForContainer(t, cli, id, 10*time.Second)
rc := waitForContainer(t, cli, id, 10)
if rc != 1 {
t.Errorf("Expected rc=1, got rc=%v", rc)
}
expectTerminationMessage(t, cli, id)
expectTerminationMessage(t)
}
// TestStartQueueManagerFail causes a failure of `strmqm`
func TestStartQueueManagerFail(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
RUN echo '#!/bin/bash\ndltmqm $@ && strmqm $@' > /opt/mqm/bin/strmqm
RUN chown mqm:mqm /opt/mqm/bin/strmqm
RUN chmod 6550 /opt/mqm/bin/strmqm
USER mqm`, imageName())},
img, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
if err != nil {
t.Fatal(err)
}
tag := createImage(t, cli, files)
defer deleteImage(t, cli, tag)
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
containerConfig := container.Config{
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
Image: tag,
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1", "DEBUG=1"},
// Override the entrypoint to replace `strmqm` with a script which deletes the queue manager.
// This will cause `strmqm` to return with an exit code of 72.
Entrypoint: []string{"bash", "-c", "echo '#!/bin/bash\ndltmqm $@ && strmqm $@' > /opt/mqm/bin/strmqm && exec " + oldEntrypoint},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
rc := waitForContainer(t, cli, id, 20*time.Second)
rc := waitForContainer(t, cli, id, 10)
if rc != 1 {
t.Errorf("Expected rc=1, got rc=%v", rc)
}
expectTerminationMessage(t, cli, id)
expectTerminationMessage(t)
}
// TestVolumeUnmount runs a queue manager with a volume, and then forces an
@@ -434,7 +300,6 @@ func TestStartQueueManagerFail(t *testing.T) {
// attached storage gets unmounted.
func TestVolumeUnmount(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -483,7 +348,6 @@ func TestVolumeUnmount(t *testing.T) {
// created, then checks that no zombies exist (runmqserver should reap them)
func TestZombies(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -520,7 +384,6 @@ func TestZombies(t *testing.T) {
// on that image, and checks that the MQSC has been applied correctly.
func TestMQSC(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -528,13 +391,7 @@ func TestMQSC(t *testing.T) {
var files = []struct {
Name, Body string
}{
{"Dockerfile", fmt.Sprintf(`
FROM %v
USER root
RUN rm -f /etc/mqm/*.mqsc
ADD test.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/test.mqsc
USER mqm`, imageName())},
{"Dockerfile", fmt.Sprintf("FROM %v\nRUN rm -f /etc/mqm/*.mqsc\nADD test.mqsc /etc/mqm/", imageName())},
{"test.mqsc", "DEFINE QLOCAL(test)"},
}
tag := createImage(t, cli, files)
@@ -554,48 +411,11 @@ func TestMQSC(t *testing.T) {
}
}
// TestInvalidMQSC creates a new image with an MQSC file containing invalid MQSC,
// tries to start a container based on that image, and checks that container terminates
// func TestInvalidMQSC(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
// RUN rm -f /etc/mqm/*.mqsc
// ADD mqscTest.mqsc /etc/mqm/
// RUN chmod 0660 /etc/mqm/mqscTest.mqsc
// USER mqm`, imageName())},
// {"mqscTest.mqsc", "DEFINE INVALIDLISTENER('TEST.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE"},
// }
// 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)
// rc := waitForContainer(t, cli, id, 60*time.Second)
// if rc != 1 {
// t.Errorf("Expected rc=1, got rc=%v", rc)
// }
// expectTerminationMessage(t, cli, id)
// }
// TestReadiness creates a new image with large amounts of MQSC in, to
// 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.
func TestReadiness(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -608,13 +428,7 @@ func TestReadiness(t *testing.T) {
var files = []struct {
Name, Body string
}{
{"Dockerfile", fmt.Sprintf(`
FROM %v
USER root
RUN rm -f /etc/mqm/*.mqsc
ADD test.mqsc /etc/mqm/
RUN chmod 0660 /etc/mqm/test.mqsc
USER mqm`, imageName())},
{"Dockerfile", fmt.Sprintf("FROM %v\nRUN rm -f /etc/mqm/*.mqsc\nADD test.mqsc /etc/mqm/", imageName())},
{"test.mqsc", buf.String()},
}
tag := createImage(t, cli, files)
@@ -650,34 +464,22 @@ func TestReadiness(t *testing.T) {
func TestErrorLogRotation(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
logsize := 65536
rc, _ := runContainerOneShot(t, cli, "bash", "-c", "test -d /etc/apt")
if rc != 0 {
// RHEL
logsize = 32768
}
qmName := "qm1"
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=" + qmName,
fmt.Sprintf("MQMAXERRORLOGSIZE=%d", logsize),
"MQMAXERRORLOGSIZE=65536",
"LOG_FORMAT=json",
fmt.Sprintf("AMQ_EXTRA_QM_STANZAS=QMErrorLog:ErrorLogSize=%d", logsize),
},
ExposedPorts: nat.PortSet{
"1414/tcp": struct{}{},
},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
@@ -685,7 +487,6 @@ func TestErrorLogRotation(t *testing.T) {
// Generate some content for the error logs, by trying to put messages under an unauthorized user
// execContainer(t, cli, id, "fred", []string{"bash", "-c", "for i in {1..30} ; do /opt/mqm/samp/bin/amqsput FAKE; done"})
execContainer(t, cli, id, "root", []string{"useradd", "fred"})
for {
execContainer(t, cli, id, "fred", []string{"bash", "-c", "/opt/mqm/samp/bin/amqsput FAKE"})
@@ -728,14 +529,12 @@ func TestErrorLogRotation(t *testing.T) {
// Tests the log comes out in JSON format when JSON format is enabled. With metrics enabled
func TestJSONLogFormatWithMetrics(t *testing.T) {
t.Parallel()
jsonLogFormat(t, true)
}
// Tests the log comes out in JSON format when JSON format is enabled. With metrics disabled
func TestJSONLogFormatNoMetrics(t *testing.T) {
t.Parallel()
jsonLogFormat(t, false)
}
@@ -776,7 +575,6 @@ func jsonLogFormat(t *testing.T, metric bool) {
func TestBadLogFormat(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -789,11 +587,11 @@ func TestBadLogFormat(t *testing.T) {
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
rc := waitForContainer(t, cli, id, 20*time.Second)
rc := waitForContainer(t, cli, id, 5)
if rc != 1 {
t.Errorf("Expected rc=1, got rc=%v", rc)
}
expectTerminationMessage(t, cli, id)
expectTerminationMessage(t)
}
// TestMQJSONDisabled tests the case where MQ's JSON logging feature is
@@ -886,11 +684,10 @@ func TestVersioning(t *testing.T) {
dataAr := strings.Split(line, " ")
data := dataAr[len(dataAr)-1]
// Verify created is in a known timestamp format
// Verify created
_, err := time.Parse(time.RFC3339, data)
_, err2 := time.Parse("2006-01-02T15:04:05-0700", data)
if err != nil && err2 != nil {
t.Errorf("Failed to validate Image created stamp (%v) - %v or %v", data, time.RFC3339, "2006-01-02T15:04:05-0700")
if err != nil {
t.Errorf("Failed to validate Image created (%v) - %v", data, 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");
you may not use this file except in compliance with the License.
@@ -43,18 +43,6 @@ import (
"github.com/docker/go-connections/nat"
)
type containerDetails struct {
ID string
Name string
Image string
Path string
Args []string
CapAdd []string
CapDrop []string
User string
Env []string
}
func imageName() string {
image, ok := os.LookupEnv("TEST_IMAGE")
if !ok {
@@ -71,29 +59,6 @@ func imageNameDevJMS() string {
return image
}
// baseImage returns the ID of the underlying base image (e.g. "ubuntu" or "rhel")
func baseImage(t *testing.T, cli *client.Client) string {
rc, out := runContainerOneShot(t, cli, "grep", "^ID=", "/etc/os-release")
if rc != 0 {
t.Fatal("Couldn't determine base image")
}
s := strings.Split(out, "=")
if len(s) < 2 {
t.Fatal("Couldn't determine base image string")
}
return s[1]
}
// devImage returns true if the image under test is a developer image,
// determined by use of the MQ_ADMIN_PASSWORD environment variable
func devImage(t *testing.T, cli *client.Client) bool {
rc, _ := runContainerOneShot(t, cli, "printenv", "MQ_ADMIN_PASSWORD")
if rc == 0 {
return true
}
return false
}
// isWSL return whether we are running in the Windows Subsystem for Linux
func isWSL(t *testing.T) bool {
if runtime.GOOS == "linux" {
@@ -159,79 +124,66 @@ func getTempDir(t *testing.T, unixStylePath bool) string {
return "/tmp/"
}
// terminationMessage return the termination message, or an empty string if not set
func terminationMessage(t *testing.T, cli *client.Client, ID string) string {
r, _, err := cli.CopyFromContainer(context.Background(), ID, "/run/termination-log")
if err != nil {
t.Log(err)
return ""
}
b, err := ioutil.ReadAll(r)
tr := tar.NewReader(bytes.NewReader(b))
_, err = tr.Next()
if err != nil {
t.Log(err)
return ""
}
// read the complete content of the file h.Name into the bs []byte
content, err := ioutil.ReadAll(tr)
if err != nil {
t.Log(err)
return ""
}
return string(content)
// terminationLogUnixPath returns the name of the file to use for the termination log message, with a UNIX path
func terminationLogUnixPath(t *testing.T) string {
// Warning: this directory must be accessible to the Docker daemon,
// in order to enable the bind mount
return getTempDir(t, true) + t.Name() + "-termination-log"
}
func expectTerminationMessage(t *testing.T, cli *client.Client, ID string) {
m := terminationMessage(t, cli, ID)
// terminationLogOSPath returns the name of the file to use for the termination log message, with an OS specific path
func terminationLogOSPath(t *testing.T) string {
// Warning: this directory must be accessible to the Docker daemon,
// in order to enable the bind mount
return getTempDir(t, false) + t.Name() + "-termination-log"
}
// terminationBind returns a string to use to bind-mount a termination log file.
// This is done using a bind, because you can't copy files from /dev out of the container.
func terminationBind(t *testing.T) string {
n := terminationLogUnixPath(t)
// Remove it if it already exists
os.Remove(n)
// Create the empty file
f, err := os.OpenFile(n, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
t.Fatal(err)
}
f.Close()
return terminationLogOSPath(t) + ":/dev/termination-log"
}
// terminationMessage return the termination message, or an empty string if not set
func terminationMessage(t *testing.T) string {
b, err := ioutil.ReadFile(terminationLogUnixPath(t))
if err != nil {
t.Log(err)
}
return string(b)
}
func expectTerminationMessage(t *testing.T) {
m := terminationMessage(t)
if m == "" {
t.Error("Expected termination message to be set")
}
}
// logContainerDetails logs selected details about the container
func logContainerDetails(t *testing.T, cli *client.Client, ID string) {
func cleanContainer(t *testing.T, cli *client.Client, ID string) {
i, err := cli.ContainerInspect(context.Background(), ID)
if err == nil {
d := containerDetails{
ID: ID,
Name: i.Name,
Image: i.Image,
Path: i.Path,
Args: i.Args,
CapAdd: i.HostConfig.CapAdd,
CapDrop: i.HostConfig.CapDrop,
User: i.Config.User,
Env: i.Config.Env,
// Log the results and continue
t.Logf("Inspected container %v: %#v", ID, i)
s, err := json.MarshalIndent(i, "", " ")
if err != nil {
t.Fatal(err)
}
// If you need more details, you can always just run `json.MarshalIndent(i, "", " ")` to see everything.
t.Logf("Container details: %+v", d)
t.Logf("Inspected container %v: %v", ID, string(s))
}
}
func cleanContainerQuiet(t *testing.T, cli *client.Client, ID string) {
timeout := 10 * time.Second
err := cli.ContainerStop(context.Background(), ID, &timeout)
if err != nil {
// Just log the error and continue
t.Log(err)
}
opts := types.ContainerRemoveOptions{
RemoveVolumes: true,
Force: true,
}
err = cli.ContainerRemove(context.Background(), ID, opts)
if err != nil {
t.Error(err)
}
}
func cleanContainer(t *testing.T, cli *client.Client, ID string) {
logContainerDetails(t, cli, ID)
t.Logf("Stopping container: %v", ID)
timeout := 10 * time.Second
// Stop the container. This allows the coverage output to be generated.
err := cli.ContainerStop(context.Background(), ID, &timeout)
err = cli.ContainerStop(context.Background(), ID, &timeout)
if err != nil {
// Just log the error and continue
t.Log(err)
@@ -243,10 +195,11 @@ func cleanContainer(t *testing.T, cli *client.Client, ID string) {
// Log the container output for any container we're about to delete
t.Logf("Console log from container %v:\n%v", ID, inspectTextLogs(t, cli, ID))
m := terminationMessage(t, cli, ID)
m := terminationMessage(t)
if m != "" {
t.Logf("Termination message: %v", m)
}
os.Remove(terminationLogUnixPath(t))
t.Logf("Removing container: %s", ID)
opts := types.ContainerRemoveOptions{
@@ -266,36 +219,15 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co
if containerConfig.Image == "" {
containerConfig.Image = imageName()
}
// Always run as the "mqm" user, unless the test has specified otherwise
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{
Binds: []string{
coverageBind(t),
terminationBind(t),
},
PortBindings: nat.PortMap{},
CapDrop: []string{
"ALL",
},
}
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
if baseImage(t, cli) != "ubuntu" {
hostConfig.CapAdd = append(hostConfig.CapAdd, "DAC_OVERRIDE")
}
} else {
t.Logf("Detected MQ Advanced image - dropping all capabilities")
}
for _, p := range ports {
port := nat.Port(fmt.Sprintf("%v/tcp", p))
@@ -322,62 +254,13 @@ func runContainer(t *testing.T, cli *client.Client, containerConfig *container.C
return runContainerWithPorts(t, cli, containerConfig, nil)
}
// runContainerOneShot runs a container with a custom entrypoint, as the root
// user and with default capabilities
func runContainerOneShot(t *testing.T, cli *client.Client, command ...string) (int64, string) {
containerConfig := container.Config{
Entrypoint: command,
User: "root",
Image: imageName(),
}
hostConfig := container.HostConfig{}
networkingConfig := network.NetworkingConfig{}
t.Logf("Running one shot container (%s): %v", containerConfig.Image, command)
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShot")
if err != nil {
t.Fatal(err)
}
startOptions := types.ContainerStartOptions{}
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
if err != nil {
t.Fatal(err)
}
defer cleanContainerQuiet(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
out := inspectLogs(t, cli, ctr.ID)
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
return rc, out
}
// runContainerOneShot runs a container with a custom entrypoint, as the root
// user, with default capabilities, and a volume mounted
func runContainerOneShotWithVolume(t *testing.T, cli *client.Client, bind string, command ...string) (int64, string) {
containerConfig := container.Config{
Entrypoint: command,
User: "root",
Image: imageName(),
}
hostConfig := container.HostConfig{
Binds: []string{
bind,
},
}
networkingConfig := network.NetworkingConfig{}
t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command)
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShotVolume")
if err != nil {
t.Fatal(err)
}
startOptions := types.ContainerStartOptions{}
err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
if err != nil {
t.Fatal(err)
}
defer cleanContainerQuiet(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
out := inspectLogs(t, cli, ctr.ID)
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
return rc, out
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
return waitForContainer(t, cli, id, 10), inspectLogs(t, cli, id)
}
func startContainer(t *testing.T, cli *client.Client, ID string) {
@@ -426,19 +309,19 @@ func getCoverageExitCode(t *testing.T, orig int64) int64 {
}
// waitForContainer waits until a container has exited
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.Duration) int64 {
c, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
rc, err := cli.ContainerWait(c, ID)
if err != nil {
t.Fatal(err)
}
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout int64) int64 {
rc, err := cli.ContainerWait(context.Background(), ID)
if coverage() {
// COVERAGE: When running coverage, the exit code is written to a file,
// to allow the coverage to be generated (which doesn't happen for non-zero
// exit codes)
rc = getCoverageExitCode(t, rc)
}
if err != nil {
t.Fatal(err)
}
return rc
}
@@ -512,7 +395,7 @@ func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd
}
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(), time.Minute)
defer cancel()
for {

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");
you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@ import (
func TestGoldenPathMetric(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -54,7 +53,6 @@ func TestGoldenPathMetric(t *testing.T) {
func TestMetricNames(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -98,7 +96,6 @@ func TestMetricNames(t *testing.T) {
func TestMetricLabels(t *testing.T) {
t.Parallel()
requiredLabels := []string{"qmgr"}
cli, err := client.NewEnvClient()
if err != nil {
@@ -147,7 +144,6 @@ func TestMetricLabels(t *testing.T) {
func TestRapidFirePrometheus(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -181,7 +177,6 @@ func TestRapidFirePrometheus(t *testing.T) {
func TestSlowPrometheus(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -212,7 +207,6 @@ func TestSlowPrometheus(t *testing.T) {
func TestContainerRestart(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -260,7 +254,6 @@ func TestContainerRestart(t *testing.T) {
func TestQMRestart(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -286,7 +279,7 @@ func TestQMRestart(t *testing.T) {
// Restart just the QM (to simulate a lost connection)
t.Log("Stopping queue manager\n")
rc, out := execContainer(t, cli, id, "mqm", []string{"endmqm", "-w", "-r", defaultMetricQMName})
rc, out := execContainer(t, cli, id, "mqm", []string{"endmqm", "-w", defaultMetricQMName})
if rc != 0 {
t.Fatalf("Failed to stop the queue manager. rc=%d, err=%s", rc, out)
}
@@ -318,7 +311,6 @@ func TestQMRestart(t *testing.T) {
func TestValidValues(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
@@ -354,7 +346,6 @@ func TestValidValues(t *testing.T) {
func TestChangingValues(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)

View File

@@ -1,84 +0,0 @@
#!/bin/bash
# © 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.
set -x
set -e
###############################################################################
# Setup MQ JMS Test container
###############################################################################
# Use a "scratch" container, so the resulting image has minimal files
# Resulting image won't have yum, for example
readonly ctr_mq=$(buildah from rhel7-minimal)
readonly mnt_mq=$(buildah mount $ctr_mq)
readonly imagename=$1
microdnf_opts="--nodocs"
# Check whether the host is registered with Red Hat
if subscription-manager status ; then
# Host is subscribed, but the minimal image has no enabled repos
# Note that the "bc" package is the only one in "extras"
microdnf_opts="${microdnf_opts} --enablerepo=rhel-7-server-rpms --enablerepo=rhel-7-server-extras-rpms"
else
# Use the Yum repositories configured on the host
cp -R /etc/yum.repos.d/* ${mnt_mq}/etc/yum.repos.d/
fi
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} install \
java-1.8.0-openjdk-devel \
java \
which \
wget
buildah run $ctr_mq -- sh -c "cd /tmp && wget https://www-eu.apache.org/dist/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz"
tar xvf $mnt_mq/tmp/apache-maven-3.6.0-bin.tar.gz -C $mnt_mq/tmp/
mkdir -p $mnt_mq/usr/src/mymaven
cp pom.xml $mnt_mq/usr/src/mymaven/
cp -R src $mnt_mq/usr/src/mymaven/src
buildah run $ctr_mq -- sh -c "cd /usr/src/mymaven && export M2_HOME=/tmp/apache-maven-3.6.0 && export M2=\$M2_HOME/bin && export PATH=\$M2:\$PATH && mvn --version && mvn dependency:go-offline install && mvn --offline install"
mkdir -p $mnt_mq/opt/app
cp $mnt_mq/usr/src/mymaven/target/*.jar $mnt_mq/opt/app/
cp $mnt_mq/usr/src/mymaven/target/lib/*.jar $mnt_mq/opt/app/
###############################################################################
# Post install tidy up
###############################################################################
rm -rf $mnt_mq/tmp/*
rm -rf $mnt_mq/usr/src/mymaven
# Clean up cached files
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} clean all
rm -rf ${mnt_mq}/etc/yum.repos.d/*
###############################################################################
# Contain image finalization
###############################################################################
buildah config \
--os linux \
--label architecture=x86_64 \
--label name="${imagename%:*}" \
--cmd "" \
--entrypoint '["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]' \
$ctr_mq
buildah unmount $ctr_mq
buildah commit $ctr_mq $imagename
buildah rm $ctr_mq

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");
you may not use this file except in compliance with the License.
@@ -32,19 +32,19 @@ limitations under the License.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.2</version>
<version>5.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.2</version>
<version>5.2.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-console-standalone</artifactId>
<version>1.3.2</version>
<version>1.2.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>

View File

@@ -84,15 +84,9 @@ class JMSTests {
else {
LOGGER.info(String.format("Using TLS. Trust store=%s", TRUSTSTORE));
SSLSocketFactory ssl = createSSLSocketFactory();
factory.setSSLSocketFactory(ssl);
boolean ibmjre = System.getenv("IBMJRE").equals("true");
if (ibmjre){
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
factory.setSSLCipherSuite("SSL_RSA_WITH_AES_128_CBC_SHA256");
} else {
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
factory.setSSLCipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA256");
}
factory.setSSLSocketFactory(ssl);
factory.setSSLCipherSuite("SSL_RSA_WITH_AES_128_CBC_SHA256");
// LOGGER.info(Arrays.toString(ssl.getSupportedCipherSuites()));
}
// Give up if unable to reconnect for 10 minutes
// factory.setClientReconnectTimeout(600);

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<server>
<featureManager>
<feature>appSecurity-2.0</feature>
</featureManager>
<enterpriseApplication id="com.ibm.mq.console">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebUI" realm="defaultRealm"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<enterpriseApplication id="com.ibm.mq.rest">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebUI" realm="defaultRealm"/>
</security-role>
<security-role name="MQWebUser">
<group name="MQWebMessaging" realm="defaultRealm"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<variable name="httpHost" value="*"/>
<include location="tls.xml"/>
</server>

View File

@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<server>
<featureManager>
<feature>openidConnectClient-1.0</feature>
<feature>ssl-1.0</feature>
</featureManager>
<enterpriseApplication id="com.ibm.mq.console">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebUI" realm="defaultRealm"/>
{{- range $index, $element := .AdminUser}}
<user name="admin{{$index}}" access-id="{{.}}"/>
{{- end}}
</security-role>
</application-bnd>
</enterpriseApplication>
<enterpriseApplication id="com.ibm.mq.rest">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebUI" realm="defaultRealm"/>
</security-role>
<security-role name="MQWebUser">
<group name="MQWebMessaging" realm="defaultRealm"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<openidConnectClient id="mqclient"
clientId="${env.MQ_OIDC_CLIENT_ID}"
clientSecret="${env.MQ_OIDC_CLIENT_SECRET}"
uniqueUserIdentifier="${env.MQ_OIDC_UNIQUE_USER_IDENTIFIER}"
authorizationEndpointUrl="${env.MQ_OIDC_AUTHORIZATION_ENDPOINT}"
tokenEndpointUrl="${env.MQ_OIDC_TOKEN_ENDPOINT}"
scope="openid profile email"
inboundPropagation="supported"
jwkEndpointUrl="${env.MQ_OIDC_JWK_ENDPOINT}"
signatureAlgorithm="RS256"
issuerIdentifier="${env.MQ_OIDC_ISSUER_IDENTIFIER}">
</openidConnectClient>
<variable name="httpHost" value="*"/>
<variable name="managementMode" value="externallyprovisioned"/>
<jndiEntry jndiName="xframeAllowedSourceList" value="${env.MQ_HOSTS}"/>
<keyStore id="MQWebKeyStore" location="/run/tls/key.jks" type="JKS" password="password"/>
<keyStore id="MQWebTrustStore" location="/run/tls/trust.jks" type="JKS" password="password"/>
<ssl id="thisSSLConfig" clientAuthenticationSupported="true" keyStoreRef="MQWebKeyStore" trustStoreRef="MQWebTrustStore" sslProtocol="TLSv1.2" serverKeyAlias="default"/>
<sslDefault sslRef="thisSSLConfig"/>
<httpDispatcher enableWelcomePage="false" appOrContextRootMissingMessage='&lt;script&gt;document.location.href="/ibmmq/console";&lt;/script&gt;' />
</server>