Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9718af565 | ||
|
|
f05a7d3eaf | ||
|
|
723fe2b998 | ||
|
|
44d0e0a432 | ||
|
|
33defc0fc9 | ||
|
|
d69befed71 | ||
|
|
0934289b61 | ||
|
|
f6231cd51c | ||
|
|
d5f04bc470 | ||
|
|
d8cbf4566e | ||
|
|
493bc7bfd4 | ||
|
|
1fa4f6f148 | ||
|
|
ce664dd654 | ||
|
|
f8e057a1d6 | ||
|
|
efd550822d | ||
|
|
d4df05fd2a | ||
|
|
194b04ac13 | ||
|
|
6848038165 | ||
|
|
0d3e177147 | ||
|
|
13f620f21a | ||
|
|
d4a81741cc | ||
|
|
0047301335 | ||
|
|
5ef532d2c1 | ||
|
|
281cdc4578 | ||
|
|
d68c051104 | ||
|
|
c5a52e616c | ||
|
|
c441de7d26 | ||
|
|
a194545f08 | ||
|
|
4f57d1bae2 | ||
|
|
cc0f072908 | ||
|
|
d834ac7c9c | ||
|
|
2dbee560fe | ||
|
|
17d3238161 | ||
|
|
c08ca2e79f | ||
|
|
84df0e8362 | ||
|
|
cc213f429f | ||
|
|
c29159dd38 | ||
|
|
f345ccf920 | ||
|
|
d1b1cfc5d8 | ||
|
|
a19c455ea4 | ||
|
|
694b31d6e8 | ||
|
|
33f82d76ff | ||
|
|
77319629fe | ||
|
|
d9c70c48c5 | ||
|
|
599f5f4b53 | ||
|
|
6840a575f9 | ||
|
|
1b8c816f57 | ||
|
|
9a8ff9b524 | ||
|
|
f3c858184f | ||
|
|
43676049b7 | ||
|
|
df6ce917c2 | ||
|
|
d3eb6e0d3d | ||
|
|
2bfdd51a01 | ||
|
|
be11b3cda1 | ||
|
|
525ff82fe7 | ||
|
|
3e07814bf6 | ||
|
|
b1daacf377 | ||
|
|
9c8b3825be | ||
|
|
4145f077b6 | ||
|
|
c063ddd67d |
36
.travis.yml
36
.travis.yml
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
dist: xenial
|
||||||
|
|
||||||
sudo: required
|
sudo: required
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
@@ -27,22 +29,26 @@ cache:
|
|||||||
directories:
|
directories:
|
||||||
- downloads
|
- downloads
|
||||||
|
|
||||||
env:
|
|
||||||
- BASE_IMAGE=ubuntu:16.04
|
|
||||||
- BASE_IMAGE=centos:latest
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- if: type IN (pull_request)
|
- stage: build and test
|
||||||
env: DOCKER_DOWNGRADE="docker save -o images.tar mqadvanced-server-dev mq-dev-jms-test &&
|
env:
|
||||||
sudo apt-get autoremove -y docker-ce &&
|
- BASE_IMAGE=ubuntu:16.04
|
||||||
curl -fsSL \"https://apt.dockerproject.org/gpg\" | sudo apt-key add - &&
|
- DOCKER_DOWNGRADE="echo nothing to be done"
|
||||||
sudo apt-add-repository \"deb https://apt.dockerproject.org/repo ubuntu-$(lsb_release -cs) main\" &&
|
- env:
|
||||||
sudo apt-get update &&
|
- BASE_IMAGE=centos:7
|
||||||
sudo apt-get install docker-engine=1.12.6-0~ubuntu-$(lsb_release -cs) &&
|
- DOCKER_DOWNGRADE="echo nothing to be done"
|
||||||
docker load -q -i images.tar &&
|
- if: type IN (pull_request) OR tag IS present
|
||||||
export DOCKER_API_VERSION=\"1.24\""
|
env:
|
||||||
- env: DOCKER_DOWNGRADE="echo nothing to be done"
|
- 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\""
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- ./install-build-deps-ubuntu.sh
|
- ./install-build-deps-ubuntu.sh
|
||||||
|
|||||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,11 +1,23 @@
|
|||||||
# Change log
|
# Change log
|
||||||
|
|
||||||
|
## 9.1.2.0 (2019-03-21)
|
||||||
|
|
||||||
|
* 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
|
||||||
|
* Building on subscribed and unsubscribed hosts ([#273](https://github.com/ibm-messaging/mq-container/pull/273))
|
||||||
|
* Gosec failures ([#286](https://github.com/ibm-messaging/mq-container/pull/286))
|
||||||
|
* Security fix for perl-base ([#253](https://github.com/ibm-messaging/mq-container/pull/253))
|
||||||
|
|
||||||
## 9.1.1.0 (2018-11-30)
|
## 9.1.1.0 (2018-11-30)
|
||||||
|
|
||||||
* Updated to MQ version 9.1.1.0
|
* Updated to MQ version 9.1.1.0
|
||||||
* Created seperate RedHat Makefile for building images on RedHat machines with buildah
|
* Created seperate RedHat Makefile for building images on RedHat machines with buildah
|
||||||
* Enabled REST messaging capability for app user.
|
* Enabled REST messaging capability for app user.
|
||||||
* Added support for container suplimentary groups
|
* Added support for container supplementary groups
|
||||||
* Removed IBM MQ version 9.0.5 details.
|
* Removed IBM MQ version 9.0.5 details.
|
||||||
* Added additional Diagnostics ([#203](https://github.com/ibm-messaging/mq-container/pull/203))
|
* 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)))
|
* Implementted GOSec to perform code scans for security vulnerabilities. (([#227](https://github.com/ibm-messaging/mq-container/pull/227)))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2015, 2018
|
# © Copyright IBM Corporation 2015, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
ARG BASE_IMAGE=ubuntu:16.04
|
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.1.2.0-x86_64-ubuntu-16.04
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build stage to build Go code
|
# Build stage to build Go code
|
||||||
@@ -22,10 +22,11 @@ FROM $BUILDER_IMAGE as builder
|
|||||||
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
|
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
|
||||||
ARG IMAGE_REVISION="Not specified"
|
ARG IMAGE_REVISION="Not specified"
|
||||||
ARG IMAGE_SOURCE="Not specified"
|
ARG IMAGE_SOURCE="Not specified"
|
||||||
|
ARG IMAGE_TAG="Not specified"
|
||||||
COPY cmd/ ./cmd
|
COPY cmd/ ./cmd
|
||||||
COPY internal/ ./internal
|
COPY internal/ ./internal
|
||||||
COPY vendor/ ./vendor
|
COPY vendor/ ./vendor
|
||||||
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 -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\" -X \"main.ImageTag=$IMAGE_TAG\"" ./cmd/runmqserver/
|
||||||
RUN go build ./cmd/chkmqready/
|
RUN go build ./cmd/chkmqready/
|
||||||
RUN go build ./cmd/chkmqhealthy/
|
RUN go build ./cmd/chkmqhealthy/
|
||||||
# Run all unit tests
|
# Run all unit tests
|
||||||
@@ -47,12 +48,15 @@ ARG MQ_URL
|
|||||||
# The MQ packages to install - see install-mq.sh for default value
|
# The MQ packages to install - see install-mq.sh for default value
|
||||||
ARG MQ_PACKAGES
|
ARG MQ_PACKAGES
|
||||||
|
|
||||||
|
# The UID to use for the "mqm" user
|
||||||
|
ARG MQM_UID=999
|
||||||
|
|
||||||
COPY install-mq.sh /usr/local/bin/
|
COPY install-mq.sh /usr/local/bin/
|
||||||
|
|
||||||
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
|
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
|
||||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
||||||
&& sleep 1 \
|
&& sleep 1 \
|
||||||
&& install-mq.sh
|
&& install-mq.sh $MQM_UID
|
||||||
|
|
||||||
# Create a directory for runtime data from runmqserver
|
# Create a directory for runtime data from runmqserver
|
||||||
RUN mkdir -p /run/runmqserver \
|
RUN mkdir -p /run/runmqserver \
|
||||||
@@ -64,11 +68,17 @@ COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
|||||||
|
|
||||||
RUN chmod ug+x /usr/local/bin/runmqserver \
|
RUN chmod ug+x /usr/local/bin/runmqserver \
|
||||||
&& chown mqm:mqm /usr/local/bin/*mq* \
|
&& chown mqm:mqm /usr/local/bin/*mq* \
|
||||||
&& chmod ug+xs /usr/local/bin/chkmq*
|
&& chmod ug+xs /usr/local/bin/chkmq* \
|
||||||
|
&& install --directory --mode 0775 --owner mqm --group root /run/runmqserver \
|
||||||
|
&& touch /run/termination-log \
|
||||||
|
&& chown mqm:root /run/termination-log \
|
||||||
|
&& chmod 0660 /run/termination-log
|
||||||
|
|
||||||
# Always use port 1414 for MQ & 9157 for the metrics
|
# Always use port 1414 for MQ & 9157 for the metrics
|
||||||
EXPOSE 1414 9157
|
EXPOSE 1414 9157
|
||||||
|
|
||||||
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic
|
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic
|
||||||
|
|
||||||
|
USER $MQM_UID
|
||||||
|
|
||||||
ENTRYPOINT ["runmqserver"]
|
ENTRYPOINT ["runmqserver"]
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -176,7 +176,7 @@
|
|||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
© Copyright IBM Corporation. 2015, 2018
|
© Copyright IBM Corporation. 2015, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -19,16 +19,16 @@
|
|||||||
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
|
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
|
||||||
BASE_IMAGE ?= rhel
|
BASE_IMAGE ?= rhel
|
||||||
# MQ_VERSION is the fully qualified MQ version number to build
|
# MQ_VERSION is the fully qualified MQ version number to build
|
||||||
MQ_VERSION ?= 9.1.1.0
|
MQ_VERSION ?= 9.1.2.0
|
||||||
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
|
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
|
||||||
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
|
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
|
||||||
# Does not apply to MQ Advanced for Developers.
|
# Does not apply to MQ Advanced for Developers.
|
||||||
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION)_LINUX_$(MQ_ARCHIVE_ARCH).tar.gz
|
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
|
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
|
||||||
# for Developers can be installed
|
# for Developers can be installed
|
||||||
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
# MQ_SDK_ARCHIVE specifies the archive to use for the MQ redistributable client, which is used for building the golang programs.
|
||||||
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
MQ_SDK_ARCHIVE ?= 9.1.2.0-IBM-MQC-Redist-LinuxX64.tar.gz
|
||||||
# Options to `go test` for the Docker tests
|
# Options to `go test` for the Docker tests
|
||||||
TEST_OPTS_DOCKER ?=
|
TEST_OPTS_DOCKER ?=
|
||||||
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
|
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
|
||||||
@@ -56,6 +56,10 @@ DEV_JMS_IMAGE=mq-dev-jms-test:latest
|
|||||||
IMAGE_REVISION=$(shell git rev-parse HEAD)
|
IMAGE_REVISION=$(shell git rev-parse HEAD)
|
||||||
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
|
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
|
||||||
MQDEV=
|
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.2 instead of 9.1.2.0
|
||||||
|
MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION))))
|
||||||
|
|
||||||
|
|
||||||
ifneq (,$(findstring Microsoft,$(shell uname -r)))
|
ifneq (,$(findstring Microsoft,$(shell uname -r)))
|
||||||
@@ -76,9 +80,9 @@ else ifeq "$(ARCH)" "s390x"
|
|||||||
MQ_DEV_ARCH=s390x
|
MQ_DEV_ARCH=s390x
|
||||||
endif
|
endif
|
||||||
# Archive names for IBM MQ Advanced for Developers
|
# 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.0.0=mqadv_dev910_linux_$(MQ_DEV_ARCH).tar.gz
|
||||||
MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev910_linux_$(MQ_DEV_ARCH).tar.gz
|
MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_linux_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
MQ_ARCHIVE_DEV_9.1.2.0=mqadv_dev912_linux_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build targets
|
# Build targets
|
||||||
@@ -113,9 +117,9 @@ downloads/$(MQ_ARCHIVE_DEV):
|
|||||||
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
|
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
|
||||||
|
|
||||||
downloads/$(MQ_SDK_ARCHIVE):
|
downloads/$(MQ_SDK_ARCHIVE):
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced redistributable client "$(MQ_VERSION)$(END)))
|
||||||
mkdir -p downloads
|
mkdir -p downloads
|
||||||
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_SDK_ARCHIVE)
|
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist/$(MQ_SDK_ARCHIVE)
|
||||||
|
|
||||||
.PHONY: downloads
|
.PHONY: downloads
|
||||||
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
||||||
@@ -133,7 +137,7 @@ check-prereqs:
|
|||||||
yum list | grep yum-utils || (echo "Missing required package yum-utils" && exit 1)
|
yum list | grep yum-utils || (echo "Missing required package yum-utils" && exit 1)
|
||||||
|
|
||||||
.PHONY: check-test-prereqs
|
.PHONY: check-test-prereqs
|
||||||
check-prereqs:
|
check-test-prereqs:
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Checking for prereqs"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Checking for prereqs"$(END)))
|
||||||
which buildah || (echo "Missing required program buildah" && exit 1)
|
which buildah || (echo "Missing required program buildah" && exit 1)
|
||||||
which docker || (echo "Missing required program docker" && exit 1)
|
which docker || (echo "Missing required program docker" && exit 1)
|
||||||
@@ -155,37 +159,29 @@ test-devserver: check-test-prereqs test/docker/vendor
|
|||||||
|
|
||||||
|
|
||||||
.PHONY: build-advancedserver
|
.PHONY: build-advancedserver
|
||||||
build-advancedserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE)
|
build-advancedserver: check-prereqs downloads/$(MQ_ARCHIVE) build-go-programs
|
||||||
build-advancedserver: check-prereqs downloads/$(MQ_ARCHIVE) build-go-programs-ex
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
|
$(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)"
|
sudo mq-advanced-server-rhel/mq-buildah.sh "$(MQ_ARCHIVE)" "$(MQ_PACKAGES)" "$(MQ_IMAGE_ADVANCEDSERVER)" "$(MQ_VERSION)" "$(MQDEV)"
|
||||||
|
|
||||||
|
|
||||||
.PHONY: build-devserver
|
.PHONY: build-devserver
|
||||||
build-devserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE_DEV)
|
|
||||||
build-devserver: MQDEV=TRUE
|
build-devserver: MQDEV=TRUE
|
||||||
build-devserver: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm MQSeriesWeb-*.rpm
|
build-devserver: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm MQSeriesWeb-*.rpm
|
||||||
build-devserver: check-prereqs downloads/$(MQ_ARCHIVE_DEV) build-go-programs-ex
|
build-devserver: check-prereqs downloads/$(MQ_ARCHIVE_DEV) build-go-programs
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER)"$(END)))
|
$(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/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)"
|
sudo mq-advanced-server-rhel/mqdev-buildah.sh "$(MQ_IMAGE_DEVSERVER_BASE)" "$(MQ_IMAGE_DEVSERVER)" "$(MQ_VERSION)"
|
||||||
|
|
||||||
|
|
||||||
.PHONY: build-mqgolang-sdk
|
.PHONY: build-mqgolang-sdk
|
||||||
build-mqgolang-sdk: check-prereqs downloads/$(MQ_SDK_ARCHIVE) build-mqgolang-sdk-ex
|
build-mqgolang-sdk: check-prereqs downloads/$(MQ_SDK_ARCHIVE)
|
||||||
|
|
||||||
.PHONY: build-mqgolang-sdk-ex
|
|
||||||
build-mqgolang-sdk-ex:
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build mq-golang SDK"$(END)))
|
$(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)"
|
sudo mq-advanced-server-rhel/mq-golang-sdk-buildah.sh "$(MQ_SDK_ARCHIVE)" "$(MQ_IMAGE_GOLANG_SDK)"
|
||||||
|
|
||||||
.PHONY: build-go-programs
|
.PHONY: build-go-programs
|
||||||
build-go-programs: check-prereqs downloads/$(MQ_SDK_ARCHIVE) build-go-programs-ex
|
build-go-programs: check-prereqs downloads/$(MQ_SDK_ARCHIVE) build-mqgolang-sdk
|
||||||
|
|
||||||
.PHONY: build-go-programs-ex
|
|
||||||
build-go-programs-ex: build-mqgolang-sdk-ex
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build go programs"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Build go programs"$(END)))
|
||||||
IMAGE_REVISION=$(IMAGE_REVISION) IMAGE_SOURCE=$(IMAGE_SOURCE) sudo mq-advanced-server-rhel/go-buildah.sh "$(MQ_IMAGE_GOLANG_SDK)" "$(MQDEV)"
|
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
|
.PHONY: build-devjmstest
|
||||||
build-devjmstest: check-test-prereqs
|
build-devjmstest: check-test-prereqs
|
||||||
@@ -194,4 +190,15 @@ build-devjmstest: check-test-prereqs
|
|||||||
sudo buildah push $(DEV_JMS_IMAGE) docker-daemon:$(DEV_JMS_IMAGE)
|
sudo buildah push $(DEV_JMS_IMAGE) docker-daemon:$(DEV_JMS_IMAGE)
|
||||||
docker tag docker.io/$(DEV_JMS_IMAGE) $(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
|
include formatting.mk
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2017, 2018
|
# © Copyright IBM Corporation 2017, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -19,11 +19,11 @@
|
|||||||
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
|
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
|
||||||
BASE_IMAGE ?= ubuntu:16.04
|
BASE_IMAGE ?= ubuntu:16.04
|
||||||
# MQ_VERSION is the fully qualified MQ version number to build
|
# MQ_VERSION is the fully qualified MQ version number to build
|
||||||
MQ_VERSION ?= 9.1.1.0
|
MQ_VERSION ?= 9.1.2.0
|
||||||
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
|
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
|
||||||
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
|
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
|
||||||
# Does not apply to MQ Advanced for Developers.
|
# Does not apply to MQ Advanced for Developers.
|
||||||
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH).tar.gz
|
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH).tar.gz
|
||||||
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
|
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
|
||||||
# for Developers can be installed
|
# for Developers can be installed
|
||||||
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
@@ -62,6 +62,10 @@ DEV_JMS_IMAGE=mq-dev-jms-test
|
|||||||
# Variables for versioning
|
# Variables for versioning
|
||||||
IMAGE_REVISION=$(shell git rev-parse HEAD)
|
IMAGE_REVISION=$(shell git rev-parse HEAD)
|
||||||
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
|
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
|
||||||
|
EMPTY:=
|
||||||
|
SPACE:= $(EMPTY) $(EMPTY)
|
||||||
|
# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.2 instead of 9.1.2.0
|
||||||
|
MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION))))
|
||||||
|
|
||||||
ifneq (,$(findstring Microsoft,$(shell uname -r)))
|
ifneq (,$(findstring Microsoft,$(shell uname -r)))
|
||||||
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
|
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
|
||||||
@@ -73,9 +77,11 @@ endif
|
|||||||
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
||||||
MQ_ARCHIVE_TYPE=UBUNTU
|
MQ_ARCHIVE_TYPE=UBUNTU
|
||||||
MQ_ARCHIVE_DEV_PLATFORM=ubuntu
|
MQ_ARCHIVE_DEV_PLATFORM=ubuntu
|
||||||
|
MQM_UID=999
|
||||||
else
|
else
|
||||||
MQ_ARCHIVE_TYPE=LINUX
|
MQ_ARCHIVE_TYPE=LINUX
|
||||||
MQ_ARCHIVE_DEV_PLATFORM=linux
|
MQ_ARCHIVE_DEV_PLATFORM=linux
|
||||||
|
MQM_UID=888
|
||||||
endif
|
endif
|
||||||
# Try to figure out which archive to use from the architecture
|
# Try to figure out which archive to use from the architecture
|
||||||
ifeq "$(ARCH)" "x86_64"
|
ifeq "$(ARCH)" "x86_64"
|
||||||
@@ -89,9 +95,9 @@ else ifeq "$(ARCH)" "s390x"
|
|||||||
MQ_DEV_ARCH=s390x
|
MQ_DEV_ARCH=s390x
|
||||||
endif
|
endif
|
||||||
# Archive names for IBM MQ Advanced for Developers
|
# 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.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
|
MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
MQ_ARCHIVE_DEV_9.1.2.0=mqadv_dev912_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build targets
|
# Build targets
|
||||||
@@ -145,6 +151,7 @@ test-unit:
|
|||||||
.PHONY: test-advancedserver
|
.PHONY: test-advancedserver
|
||||||
test-advancedserver: test/docker/vendor
|
test-advancedserver: test/docker/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on $(shell docker --version)"$(END)))
|
$(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)
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
.PHONY: build-devjmstest
|
.PHONY: build-devjmstest
|
||||||
@@ -155,6 +162,7 @@ build-devjmstest:
|
|||||||
.PHONY: test-devserver
|
.PHONY: test-devserver
|
||||||
test-devserver: test/docker/vendor
|
test-devserver: test/docker/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on $(shell docker --version)"$(END)))
|
$(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)
|
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:
|
coverage:
|
||||||
@@ -205,6 +213,8 @@ define docker-build-mq
|
|||||||
--build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) \
|
--build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) \
|
||||||
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
||||||
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
||||||
|
--build-arg IMAGE_TAG="$1" \
|
||||||
|
--build-arg MQM_UID=$(MQM_UID) \
|
||||||
--label IBM_PRODUCT_ID=$4 \
|
--label IBM_PRODUCT_ID=$4 \
|
||||||
--label IBM_PRODUCT_NAME=$5 \
|
--label IBM_PRODUCT_NAME=$5 \
|
||||||
--label IBM_PRODUCT_VERSION=$6 \
|
--label IBM_PRODUCT_VERSION=$6 \
|
||||||
@@ -236,15 +246,20 @@ build-devserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE_DEV)
|
|||||||
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version build-golang-sdk-ex
|
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version build-golang-sdk-ex
|
||||||
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER_BASE)"$(END)))
|
$(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))
|
$(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 .
|
$(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
|
.PHONY: build-advancedserver-cover
|
||||||
build-advancedserver-cover: docker-version
|
build-advancedserver-cover: docker-version
|
||||||
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_IMAGE_ADVANCEDSERVER)-cover -f Dockerfile-server.cover .
|
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_IMAGE_ADVANCEDSERVER)-cover -f Dockerfile-server.cover .
|
||||||
|
|
||||||
.PHONY: build-explorer
|
.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
|
build-explorer: downloads/$(MQ_ARCHIVE_DEV) docker-pull
|
||||||
$(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))
|
$(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
|
.PHONY: build-sdk
|
||||||
build-sdk: downloads/$(MQ_SDK_ARCHIVE) build-sdk-ex
|
build-sdk: downloads/$(MQ_SDK_ARCHIVE) build-sdk-ex
|
||||||
@@ -256,6 +271,7 @@ else
|
|||||||
build-sdk-ex: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm
|
build-sdk-ex: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm
|
||||||
endif
|
endif
|
||||||
build-sdk-ex: docker-version docker-pull
|
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))
|
$(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
|
.PHONY: build-golang-sdk
|
||||||
@@ -263,8 +279,10 @@ build-golang-sdk: downloads/$(MQ_SDK_ARCHIVE) build-golang-sdk-ex
|
|||||||
|
|
||||||
.PHONY: build-golang-sdk-ex
|
.PHONY: build-golang-sdk-ex
|
||||||
build-golang-sdk-ex: docker-version build-sdk-ex
|
build-golang-sdk-ex: docker-version build-sdk-ex
|
||||||
|
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_GOLANG_SDK)"$(END)))
|
||||||
|
@echo hello
|
||||||
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_SDK) -t $(MQ_IMAGE_GOLANG_SDK) -f incubating/mq-golang-sdk/Dockerfile .
|
$(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))
|
@echo goodbye
|
||||||
|
|
||||||
.PHONY: docker-pull
|
.PHONY: docker-pull
|
||||||
docker-pull:
|
docker-pull:
|
||||||
|
|||||||
68
cmd/runmqdevserver/logruntime.go
Normal file
68
cmd/runmqdevserver/logruntime.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
© 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())
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -31,7 +31,7 @@ var log *logger.Logger
|
|||||||
|
|
||||||
func setPassword(user string, password string) error {
|
func setPassword(user string, password string) error {
|
||||||
// #nosec G204
|
// #nosec G204
|
||||||
cmd := exec.Command("chpasswd")
|
cmd := exec.Command("sudo", "chpasswd")
|
||||||
stdin, err := cmd.StdinPipe()
|
stdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -41,9 +41,10 @@ func setPassword(user string, password string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error closing password stdin: %v", err)
|
log.Errorf("Error closing password stdin: %v", err)
|
||||||
}
|
}
|
||||||
_, _, err = command.RunCmd(cmd)
|
out, _, err := command.RunCmd(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
// Include the command output in the error
|
||||||
|
return fmt.Errorf("%v: %v", err.Error(), out)
|
||||||
}
|
}
|
||||||
log.Printf("Set password for \"%v\" user", user)
|
log.Printf("Set password for \"%v\" user", user)
|
||||||
return nil
|
return nil
|
||||||
@@ -93,16 +94,16 @@ func configureWeb(qmName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func logTerminationf(format string, args ...interface{}) {
|
func logTerminationf(format string, args ...interface{}) {
|
||||||
logTermination(fmt.Sprintf(format, args))
|
logTermination(fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Duplicated code
|
// TODO: Duplicated code
|
||||||
func logTermination(args ...interface{}) {
|
func logTermination(args ...interface{}) {
|
||||||
msg := fmt.Sprint(args)
|
msg := fmt.Sprint(args...)
|
||||||
// Write the message to the termination log. This is the default place
|
// Write the message to the termination log. This is not the default place
|
||||||
// that Kubernetes will look for termination information.
|
// that Kubernetes will look for termination information.
|
||||||
log.Debugf("Writing termination message: %v", msg)
|
log.Debugf("Writing termination message: %v", msg)
|
||||||
err := ioutil.WriteFile("/dev/termination-log", []byte(msg), 0660)
|
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
@@ -115,6 +116,9 @@ func doMain() error {
|
|||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logContainerDetails()
|
||||||
|
|
||||||
adminPassword, set := os.LookupEnv("MQ_ADMIN_PASSWORD")
|
adminPassword, set := os.LookupEnv("MQ_ADMIN_PASSWORD")
|
||||||
if set {
|
if set {
|
||||||
err = setPassword("admin", adminPassword)
|
err = setPassword("admin", adminPassword)
|
||||||
@@ -170,7 +174,7 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
// Replace this process with runmqserver
|
// Replace this process with runmqserver
|
||||||
// #nosec G204
|
// #nosec G204
|
||||||
err = syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver"}, os.Environ())
|
err = syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver", "-dev"}, os.Environ())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error replacing this process with runmqserver: %v", err)
|
log.Errorf("Error replacing this process with runmqserver: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -36,7 +36,8 @@ func processTemplateFile(templateFile, destFile string, data interface{}) error
|
|||||||
_, err = os.Stat(dir)
|
_, err = os.Stat(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
err = os.MkdirAll(dir, 0660)
|
// #nosec G301
|
||||||
|
err = os.MkdirAll(dir, 0770)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2018
|
© Copyright IBM Corporation 2017, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -36,15 +36,15 @@ var log *logger.Logger
|
|||||||
var collectDiagOnFail = false
|
var collectDiagOnFail = false
|
||||||
|
|
||||||
func logTerminationf(format string, args ...interface{}) {
|
func logTerminationf(format string, args ...interface{}) {
|
||||||
logTermination(fmt.Sprintf(format, args))
|
logTermination(fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func logTermination(args ...interface{}) {
|
func logTermination(args ...interface{}) {
|
||||||
msg := fmt.Sprint(args)
|
msg := fmt.Sprint(args...)
|
||||||
// Write the message to the termination log. This is the default place
|
// Write the message to the termination log. This is not the default place
|
||||||
// that Kubernetes will look for termination information.
|
// that Kubernetes will look for termination information.
|
||||||
log.Debugf("Writing termination message: %v", msg)
|
log.Debugf("Writing termination message: %v", msg)
|
||||||
err := ioutil.WriteFile("/dev/termination-log", []byte(msg), 0660)
|
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
|
|||||||
86
cmd/runmqserver/logruntime.go
Normal file
86
cmd/runmqserver/logruntime.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
© 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
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2018
|
© Copyright IBM Corporation 2017, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -29,12 +30,35 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func doMain() error {
|
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()
|
name, nameErr := name.GetQueueManagerName()
|
||||||
mf, err := configureLogger(name)
|
mf, err := configureLogger(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return 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 {
|
if nameErr != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
@@ -61,16 +85,12 @@ func doMain() error {
|
|||||||
// Enable diagnostic collecting on failure
|
// Enable diagnostic collecting on failure
|
||||||
collectDiagOnFail = true
|
collectDiagOnFail = true
|
||||||
|
|
||||||
err = verifyCurrentUser()
|
if *devFlag == false {
|
||||||
if err != nil {
|
err = logContainerDetails()
|
||||||
logTermination(err)
|
if err != nil {
|
||||||
return err
|
logTermination(err)
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
err = logConfig()
|
|
||||||
if err != nil {
|
|
||||||
logTermination(err)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = createVolume("/mnt/mqm")
|
err = createVolume("/mnt/mqm")
|
||||||
@@ -84,6 +104,11 @@ func doMain() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If init flag is set, exit now
|
||||||
|
if *initFlag {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Print out versioning information
|
// Print out versioning information
|
||||||
logVersionInfo()
|
logVersionInfo()
|
||||||
|
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
/*
|
|
||||||
© 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"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/genuinetools/amicontained/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
func logContainerRuntime() {
|
|
||||||
r, err := container.DetectRuntime()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to get container runtime: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("Container runtime: %v", r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func logBaseImage() {
|
|
||||||
buf, err := ioutil.ReadFile("/etc/os-release")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to read /etc/os-release: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// logCapabilities logs the Linux capabilities (e.g. setuid, setgid). See https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
|
|
||||||
func logCapabilities() {
|
|
||||||
caps, err := container.Capabilities()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to get container capabilities: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for k, v := range caps {
|
|
||||||
if len(v) > 0 {
|
|
||||||
log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// logSeccomp logs the seccomp enforcing mode, which affects which kernel calls can be made
|
|
||||||
func logSeccomp() {
|
|
||||||
s, err := container.SeccompEnforcingMode()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to get container SeccompEnforcingMode: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("seccomp enforcing mode: %v", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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
|
|
||||||
}
|
|
||||||
64
cmd/runmqserver/process.go
Normal file
64
cmd/runmqserver/process.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
© 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
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2018
|
© Copyright IBM Corporation 2017, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -16,11 +16,12 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
@@ -86,43 +87,35 @@ func configureQueueManager() error {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if strings.HasSuffix(file.Name(), ".mqsc") {
|
if strings.HasSuffix(file.Name(), ".mqsc") {
|
||||||
abs := filepath.Join(configDir, file.Name())
|
abs := filepath.Join(configDir, file.Name())
|
||||||
// #nosec G204
|
// #nosec G204
|
||||||
cmd := exec.Command("runmqsc")
|
cmd := exec.Command("runmqsc")
|
||||||
stdin, err := cmd.StdinPipe()
|
// Read mqsc file into variable
|
||||||
|
mqsc, err := ioutil.ReadFile(abs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Printf("Error reading file %v: %v", abs, err)
|
||||||
return err
|
continue
|
||||||
}
|
}
|
||||||
// Open the MQSC file for reading
|
// Write mqsc to buffer
|
||||||
// #nosec G304
|
var buffer bytes.Buffer
|
||||||
f, err := os.Open(abs)
|
_, err = buffer.Write(mqsc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error opening %v: %v", abs, err)
|
log.Printf("Error writing MQSC file %v to buffer: %v", abs, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
// Copy the contents to stdin of the runmqsc process
|
// Buffer mqsc to stdin of runmqsc
|
||||||
_, err = io.Copy(stdin, f)
|
cmd.Stdin = &buffer
|
||||||
if err != nil {
|
// Run runmqsc command
|
||||||
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)
|
|
||||||
}
|
|
||||||
// Run the command and wait for completion
|
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Errorf("Error running MQSC file %v (%v):\n\t%v", file.Name(), err, formatMQSCOutput(string(out)))
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
// Print the runmqsc output, adding tab characters to make it more readable as part of the log
|
||||||
|
log.Printf("Output for \"runmqsc\" with %v:\n\t%v", abs, formatMQSCOutput(string(out)))
|
||||||
}
|
}
|
||||||
// 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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -130,7 +123,7 @@ func configureQueueManager() error {
|
|||||||
|
|
||||||
func stopQueueManager(name string) error {
|
func stopQueueManager(name string) error {
|
||||||
log.Println("Stopping queue manager")
|
log.Println("Stopping queue manager")
|
||||||
out, _, err := command.Run("endmqm", "-w", name)
|
out, _, err := command.Run("endmqm", "-w", "-r", name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error stopping queue manager: %v", string(out))
|
log.Printf("Error stopping queue manager: %v", string(out))
|
||||||
return err
|
return err
|
||||||
@@ -138,3 +131,16 @@ func stopQueueManager(name string) error {
|
|||||||
log.Println("Stopped queue manager")
|
log.Println("Stopped queue manager")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatMQSCOutput(out string) string {
|
||||||
|
// redact sensitive information
|
||||||
|
pattern, _ := regexp.Compile("(?i)LDAPPWD\\s*?\\((.*?)\\)")
|
||||||
|
out = pattern.ReplaceAllString(out, "LDAPPWD(*********)")
|
||||||
|
pattern, _ = regexp.Compile("(?i)PASSWORD\\s*?\\((.*?)\\)")
|
||||||
|
out = pattern.ReplaceAllString(out, "PASSWORD(*********)")
|
||||||
|
pattern, _ = regexp.Compile("(?i)SSLCRYP\\s*?\\((.*?)\\)")
|
||||||
|
out = pattern.ReplaceAllString(out, "SSLCRYP(*********)")
|
||||||
|
|
||||||
|
// add tab characters to make it more readable as part of the log
|
||||||
|
return strings.Replace(string(out), "\n", "\n\t", -1)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,137 +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.
|
|
||||||
*/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os/user"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
|
||||||
)
|
|
||||||
|
|
||||||
const groupName string = "supplgrp"
|
|
||||||
|
|
||||||
func verifyCurrentUser() error {
|
|
||||||
log.Debug("Verifying current user information")
|
|
||||||
curUser, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Debugf("Detected current user as: %v+", curUser)
|
|
||||||
if curUser.Username == "mqm" {
|
|
||||||
// Not supported yet
|
|
||||||
return fmt.Errorf("Container is running as mqm user which is not supported. Please run this container as root")
|
|
||||||
} else if curUser.Username == "root" {
|
|
||||||
// We're running as root so need to check for supplementary groups.
|
|
||||||
// We can't use the golang User.GroupIDs as it doesn't seem to detect container supplementary groups..
|
|
||||||
groups, err := getCurrentUserGroups()
|
|
||||||
for _, e := range groups {
|
|
||||||
_, _, testGroup := command.Run("getent", "group", e)
|
|
||||||
if testGroup != nil {
|
|
||||||
log.Printf("Group %s does not exist on the system... Adding to system and MQM user", e)
|
|
||||||
_, _, err = command.Run("groupadd", "-g", e, groupName)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to create group %s as %s", e, groupName)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, _, err = command.Run("usermod", "-aG", groupName, "mqm")
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to add group %s(%s) to the mqm user.", groupName, e)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We're running as an unknown user...
|
|
||||||
return fmt.Errorf("Container is running as %s user which is not supported. Please run this container as root", curUser.Username)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func logUser() {
|
|
||||||
u, usererr := user.Current()
|
|
||||||
if usererr == nil {
|
|
||||||
g, err := getCurrentUserGroups()
|
|
||||||
if err != nil && len(g) == 0 {
|
|
||||||
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 supplementary groups %v", u.Uid, u.Name, u.Gid, strings.Join(g, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if usererr == nil && u.Username != "mqm" {
|
|
||||||
mqm, err := user.Lookup("mqm")
|
|
||||||
// Need to print out mqm user details as well.
|
|
||||||
g, err := getUserGroups(mqm)
|
|
||||||
if err != nil && len(g) == 0 {
|
|
||||||
log.Printf("MQM user ID %v (%v) has primary group %v", mqm.Uid, "mqm", mqm.Gid)
|
|
||||||
} else {
|
|
||||||
// Look for the primary group in the list of group IDs
|
|
||||||
for i, v := range g {
|
|
||||||
if v == mqm.Gid {
|
|
||||||
// Remove the element from the slice
|
|
||||||
g = append(g[:i], g[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Printf("MQM user ID %v (%v) has primary group %v, and supplementary groups %v", mqm.Uid, "mqm", mqm.Gid, strings.Join(g, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCurrentUserGroups() ([]string, error) {
|
|
||||||
var nilArray []string
|
|
||||||
out, _, err := command.Run("id", "--groups")
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Unable to get current user groups")
|
|
||||||
return nilArray, err
|
|
||||||
}
|
|
||||||
|
|
||||||
out = strings.TrimSpace(out)
|
|
||||||
if out == "" {
|
|
||||||
// we don't have any groups?
|
|
||||||
return nilArray, fmt.Errorf("Unable to determine groups for current user")
|
|
||||||
}
|
|
||||||
|
|
||||||
groups := strings.Split(out, " ")
|
|
||||||
return groups, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUserGroups(usr *user.User) ([]string, error) {
|
|
||||||
var nilArray []string
|
|
||||||
out, _, err := command.Run("id", "--groups", usr.Uid)
|
|
||||||
if err != nil {
|
|
||||||
log.Debugf("Unable to get user %s groups", usr.Uid)
|
|
||||||
return nilArray, err
|
|
||||||
}
|
|
||||||
|
|
||||||
out = strings.TrimSpace(out)
|
|
||||||
if out == "" {
|
|
||||||
// we don't have any groups?
|
|
||||||
return nilArray, fmt.Errorf("Unable to determine groups for user %s", usr.Uid)
|
|
||||||
}
|
|
||||||
|
|
||||||
groups := strings.Split(out, " ")
|
|
||||||
return groups, nil
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,8 @@ var (
|
|||||||
ImageRevision = "Not specified"
|
ImageRevision = "Not specified"
|
||||||
// ImageSource is the URL to get source code for building the image
|
// ImageSource is the URL to get source code for building the image
|
||||||
ImageSource = "Not specified"
|
ImageSource = "Not specified"
|
||||||
|
// ImageTag is the tag of the image
|
||||||
|
ImageTag = "Not specified"
|
||||||
)
|
)
|
||||||
|
|
||||||
func logDateStamp() {
|
func logDateStamp() {
|
||||||
@@ -43,6 +45,10 @@ func logGitCommit() {
|
|||||||
log.Printf("Image source: %v", ImageSource)
|
log.Printf("Image source: %v", ImageSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logImageTag() {
|
||||||
|
log.Printf("Image tag: %v", ImageTag)
|
||||||
|
}
|
||||||
|
|
||||||
func logMQVersion() {
|
func logMQVersion() {
|
||||||
mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
|
mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,5 +73,6 @@ func logVersionInfo() {
|
|||||||
logDateStamp()
|
logDateStamp()
|
||||||
logGitRepo()
|
logGitRepo()
|
||||||
logGitCommit()
|
logGitCommit()
|
||||||
|
logImageTag()
|
||||||
logMQVersion()
|
logMQVersion()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -22,7 +22,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
@@ -42,12 +44,23 @@ func startWebServer() error {
|
|||||||
// Take all current environment variables, and add the app password
|
// Take all current environment variables, and add the app password
|
||||||
cmd.Env = append(os.Environ(), "MQ_APP_PASSWORD=passw0rd")
|
cmd.Env = append(os.Environ(), "MQ_APP_PASSWORD=passw0rd")
|
||||||
}
|
}
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
|
||||||
uid, gid, err := command.LookupMQM()
|
uid, gid, err := command.LookupMQM()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
currentUID, err := strconv.Atoi(u.Uid)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error converting UID to string: %v", err)
|
||||||
|
}
|
||||||
|
// Add credentials to run as 'mqm', only if we aren't already 'mqm'
|
||||||
|
if currentUID != uid {
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
|
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||||
|
}
|
||||||
out, rc, err := command.RunCmd(cmd)
|
out, rc, err := command.RunCmd(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error %v starting web server: %v", rc, string(out))
|
log.Printf("Error %v starting web server: %v", rc, string(out))
|
||||||
|
|||||||
39
docs/security.md
Normal file
39
docs/security.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# 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.2.0-x86_64-ubuntu-16.04
|
||||||
|
```
|
||||||
|
|
||||||
|
The MQ Advanced for Developers image does require the "chown", "setuid", "setgid" and "audit_write" capabilities (plus "dac_override" if you're using an image based on Red Hat Enterprise Linux). This is because it uses the "sudo" command to change passwords inside the container. For example, in Docker, you could do the following:
|
||||||
|
|
||||||
|
```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.2.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.
|
||||||
@@ -8,6 +8,12 @@ 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
|
* [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
|
* [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
|
## Running the tests
|
||||||
There are two main sets of tests:
|
There are two main sets of tests:
|
||||||
|
|
||||||
@@ -25,7 +31,7 @@ make test-advancedserver
|
|||||||
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
||||||
|
|
||||||
```
|
```
|
||||||
MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server:9.1.1.0-x86_64-ubuntu-16.04 make test-advancedserver
|
MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server:9.1.2.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::
|
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command::
|
||||||
@@ -34,10 +40,10 @@ You can pass parameters to `go test` with an environment variable. For example,
|
|||||||
TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver
|
TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `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.1.2.0-x86_64-ubuntu-16.04`:
|
||||||
|
|
||||||
```
|
```
|
||||||
MQ_VERSION=9.1.0.0 make test-advancedserver
|
MQ_VERSION=9.1.2.0 make test-advancedserver
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running the Docker tests with code coverage
|
### Running the Docker tests with code coverage
|
||||||
|
|||||||
@@ -66,20 +66,20 @@ The following is an *example* `Dockerfile` for creating your own pre-configured
|
|||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM ibmcom/mq
|
FROM ibmcom/mq
|
||||||
|
USER root
|
||||||
RUN useradd alice -G mqm && \
|
RUN useradd alice -G mqm && \
|
||||||
echo alice:passw0rd | chpasswd
|
echo alice:passw0rd | chpasswd
|
||||||
|
USER mqm
|
||||||
COPY 20-config.mqsc /etc/mqm/
|
COPY 20-config.mqsc /etc/mqm/
|
||||||
```
|
```
|
||||||
|
|
||||||
Here is an example corresponding `20-config.mqsc` script from the [mqdev blog](https://developer.ibm.com/messaging/2018/10/01/archives-getting-going-without-turning-off-ibm-mq-security/), which allows users with passwords to connect on the `PASSWORD.SVRCONN` channel:
|
The `USER` instructions are necessary to ensure that the `useradd` and `chpasswd` commands are run as the root user.
|
||||||
|
|
||||||
|
Here is an example corresponding `20-config.mqsc` script, which creates two local queues:
|
||||||
|
|
||||||
```mqsc
|
```mqsc
|
||||||
DEFINE CHANNEL(PASSWORD.SVRCONN) CHLTYPE(SVRCONN) REPLACE
|
DEFINE QLOCAL(MY.QUEUE.1) REPLACE
|
||||||
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allow privileged users on this channel')
|
DEFINE QLOCAL(MY.QUEUE.2) REPLACE
|
||||||
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)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The file `20-config.mqsc` should be saved into the same directory as the `Dockerfile`.
|
The file `20-config.mqsc` should be saved into the same directory as the `Dockerfile`.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2015, 2017
|
# © Copyright IBM Corporation 2015, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -20,9 +20,11 @@ ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messag
|
|||||||
# The MQ packages to install
|
# The MQ packages to install
|
||||||
ARG MQ_PACKAGES="ibmmq-sfbridge"
|
ARG MQ_PACKAGES="ibmmq-sfbridge"
|
||||||
|
|
||||||
|
ARG MQM_UID=999
|
||||||
|
|
||||||
ADD install-mq.sh /usr/local/bin/
|
ADD install-mq.sh /usr/local/bin/
|
||||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
||||||
&& install-mq.sh
|
&& install-mq.sh $MQM_UID
|
||||||
|
|
||||||
ENV LANG=en_US.UTF-8
|
ENV LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2015, 2017
|
# © Copyright IBM Corporation 2015, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -18,7 +18,9 @@ FROM ubuntu:16.04
|
|||||||
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev911_ubuntu_x86-64.tar.gz
|
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev911_ubuntu_x86-64.tar.gz
|
||||||
|
|
||||||
# The MQ packages to install
|
# The MQ packages to install
|
||||||
ARG MQ_PACKAGES="ibmmq-explorer"
|
ARG MQ_PACKAGES
|
||||||
|
|
||||||
|
ARG MQM_UID=999
|
||||||
|
|
||||||
RUN export DEBIAN_FRONTEND=noninteractive \
|
RUN export DEBIAN_FRONTEND=noninteractive \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
ARG BASE_IMAGE=mq-sdk:9.1.1.0-x86_64-ubuntu-16.04
|
ARG BASE_IMAGE=mq-sdk:9.1.1.0-x86_64-ubuntu-16.04
|
||||||
|
|
||||||
FROM $BASE_IMAGE
|
FROM $BASE_IMAGE
|
||||||
@@ -30,4 +30,4 @@ RUN chmod +x /usr/local/bin/install-golang.sh \
|
|||||||
&& sleep 1 \
|
&& sleep 1 \
|
||||||
&& install-golang.sh
|
&& install-golang.sh
|
||||||
|
|
||||||
WORKDIR $GOPATH
|
WORKDIR $GOPATH
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -23,6 +23,8 @@ ARG MQ_URL
|
|||||||
# The packages to install in install-mq.sh
|
# The packages to install in install-mq.sh
|
||||||
ARG MQ_PACKAGES
|
ARG MQ_PACKAGES
|
||||||
|
|
||||||
|
ARG MQM_UID=999
|
||||||
|
|
||||||
COPY install-mq.sh /usr/local/bin/
|
COPY install-mq.sh /usr/local/bin/
|
||||||
|
|
||||||
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
|
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
|
||||||
@@ -30,6 +32,6 @@ COPY install-mq.sh /usr/local/bin/
|
|||||||
# errors with some commands (e.g. `dspmqver`)
|
# errors with some commands (e.g. `dspmqver`)
|
||||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
||||||
&& sleep 1 \
|
&& sleep 1 \
|
||||||
&& install-mq.sh \
|
&& install-mq.sh $MQM_UID \
|
||||||
&& rm -rf /var/mqm \
|
&& rm -rf /var/mqm \
|
||||||
&& /opt/mqm/bin/crtmqdir -f -s
|
&& /opt/mqm/bin/crtmqdir -f -s
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
* © Copyright IBM Corporation 2017, 2018
|
* © Copyright IBM Corporation 2017, 2019
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
|
||||||
STOP LISTENER('SYSTEM.LISTENER.TCP.1')
|
STOP LISTENER('SYSTEM.LISTENER.TCP.1') IGNSTATE(YES)
|
||||||
|
|
||||||
* Developer queues
|
* Developer queues
|
||||||
DEFINE QLOCAL('DEV.QUEUE.1') REPLACE
|
DEFINE QLOCAL('DEV.QUEUE.1') REPLACE
|
||||||
@@ -50,4 +50,4 @@ SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(TOPIC) AUTHADD(PUB,SUB)
|
|||||||
|
|
||||||
* Developer listener
|
* Developer listener
|
||||||
DEFINE LISTENER('DEV.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE
|
DEFINE LISTENER('DEV.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE
|
||||||
START LISTENER('DEV.LISTENER.TCP')
|
START LISTENER('DEV.LISTENER.TCP') IGNSTATE(YES)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2015, 2018
|
# © Copyright IBM Corporation 2015, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
ARG BASE_IMAGE=mqadvanced-server-dev-base:9.1.1.0-x86_64-ubuntu-16.04
|
ARG BASE_IMAGE=mqadvanced-server-dev-base:9.1.2.0-x86_64-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.1.2.0-x86_64-ubuntu-16.04
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build stage to build Go code
|
# Build stage to build Go code
|
||||||
@@ -21,12 +21,13 @@ ARG BUILDER_IMAGE=mq-golang-sdk:9.1.1.0-x86_64-ubuntu-16.04
|
|||||||
FROM $BUILDER_IMAGE as builder
|
FROM $BUILDER_IMAGE as builder
|
||||||
ARG IMAGE_REVISION="Not specified"
|
ARG IMAGE_REVISION="Not specified"
|
||||||
ARG IMAGE_SOURCE="Not specified"
|
ARG IMAGE_SOURCE="Not specified"
|
||||||
|
ARG IMAGE_TAG="Not specified"
|
||||||
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
|
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
|
||||||
COPY cmd/ ./cmd
|
COPY cmd/ ./cmd
|
||||||
COPY internal/ ./internal
|
COPY internal/ ./internal
|
||||||
COPY vendor/ ./vendor
|
COPY vendor/ ./vendor
|
||||||
# Re-build runmqserver, with code tagged with 'mqdev' enabled
|
# 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\"" --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\" -X \"main.ImageTag=$IMAGE_TAG\"" --tags 'mqdev' ./cmd/runmqserver
|
||||||
RUN go build ./cmd/runmqdevserver/
|
RUN go build ./cmd/runmqdevserver/
|
||||||
# Run all unit tests
|
# Run all unit tests
|
||||||
RUN go test -v ./cmd/runmqdevserver/...
|
RUN go test -v ./cmd/runmqdevserver/...
|
||||||
@@ -42,6 +43,20 @@ ENV MQ_DEV=true
|
|||||||
# Default administrator password
|
# Default administrator password
|
||||||
ENV MQ_ADMIN_PASSWORD=passw0rd
|
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
|
## Add admin and app users, and set a default password for admin
|
||||||
RUN useradd admin -G mqm \
|
RUN useradd admin -G mqm \
|
||||||
&& groupadd mqclient \
|
&& groupadd mqclient \
|
||||||
@@ -54,12 +69,18 @@ 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/runmqserver /usr/local/bin/
|
||||||
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/
|
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/
|
||||||
|
|
||||||
# Copy template files
|
# Copy template files
|
||||||
COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/
|
COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/
|
||||||
# Copy web XML files for default developer configuration
|
# Copy web XML files for default developer configuration
|
||||||
COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
|
COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
|
||||||
RUN 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
|
||||||
|
|
||||||
EXPOSE 9443
|
EXPOSE 9443
|
||||||
|
|
||||||
|
USER $MQM_UID
|
||||||
|
|
||||||
ENTRYPOINT ["runmqdevserver"]
|
ENTRYPOINT ["runmqdevserver"]
|
||||||
|
|||||||
32
incubating/mqadvanced-server-dev/install-extra-packages.sh
Normal file
32
incubating/mqadvanced-server-dev/install-extra-packages.sh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/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
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2015, 2018
|
# © Copyright IBM Corporation 2015, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
curl https://glide.sh/get | sh
|
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 curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64
|
||||||
sudo chmod +x /usr/local/bin/dep
|
sudo chmod +x /usr/local/bin/dep
|
||||||
|
|
||||||
go get golang.org/x/lint/golint
|
go get -u golang.org/x/lint/golint
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2015, 2018
|
# © Copyright IBM Corporation 2015, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
# Fail on any non-zero return code
|
# Fail on any non-zero return code
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
mqm_uid=${1:-999}
|
||||||
|
|
||||||
test -f /usr/bin/yum && RHEL=true || RHEL=false
|
test -f /usr/bin/yum && RHEL=true || RHEL=false
|
||||||
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
|
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
|
||||||
|
|
||||||
@@ -102,11 +104,8 @@ $UBUNTU && apt-get purge -y \
|
|||||||
$UBUNTU && apt-get autoremove -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
|
# Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images
|
||||||
$UBUNTU && groupadd --system --gid 999 mqm
|
groupadd --system --gid ${mqm_uid} mqm
|
||||||
$UBUNTU && useradd --system --uid 999 --gid mqm mqm
|
useradd --system --uid ${mqm_uid} --gid mqm --groups 0 mqm
|
||||||
$RHEL && groupadd --system --gid 888 mqm
|
|
||||||
$RHEL && useradd --system --uid 888 --gid mqm mqm
|
|
||||||
usermod -aG mqm root
|
|
||||||
|
|
||||||
# Find directory containing .deb files
|
# Find directory containing .deb files
|
||||||
$UBUNTU && DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1)
|
$UBUNTU && DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1)
|
||||||
@@ -139,7 +138,7 @@ rm -rf ${DIR_EXTRACT}
|
|||||||
|
|
||||||
# Apply any bug fixes not included in base Ubuntu or MQ image.
|
# 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
|
# 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 --only-upgrade
|
$UBUNTU && apt-get install -y libapparmor1 libsystemd0 systemd systemd-sysv libudev1 perl-base --only-upgrade
|
||||||
# End of bug fixes
|
# End of bug fixes
|
||||||
|
|
||||||
# Clean up cached files
|
# Clean up cached files
|
||||||
@@ -153,16 +152,18 @@ $UBUNTU && echo "mq:$(dspmqver -b -f 2)" > /etc/debian_chroot
|
|||||||
# Remove the directory structure under /var/mqm which was created by the installer
|
# Remove the directory structure under /var/mqm which was created by the installer
|
||||||
rm -rf /var/mqm
|
rm -rf /var/mqm
|
||||||
|
|
||||||
# Create the mount point for volumes
|
# Create the mount point for volumes, ensuring MQ has permissions to all directories
|
||||||
mkdir -p /mnt/mqm
|
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 directory for MQ configuration files
|
# Create the directory for MQ configuration files
|
||||||
mkdir -p /etc/mqm
|
install --directory --mode 0775 --owner mqm --group root /etc/mqm
|
||||||
|
|
||||||
# Create a symlink for /var/mqm -> /mnt/mqm/data
|
# Create a symlink for /var/mqm -> /mnt/mqm/data
|
||||||
ln -s /mnt/mqm/data /var/mqm
|
ln -s /mnt/mqm/data /var/mqm
|
||||||
|
|
||||||
# Optional: Set these values for the Bluemix Vulnerability Report
|
# Optional: Ensure any passwords expire in a timely manner
|
||||||
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' /etc/login.defs
|
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' /etc/login.defs
|
||||||
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' /etc/login.defs
|
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' /etc/login.defs
|
||||||
|
|
||||||
|
|||||||
109
internal/containerruntime/runtime.go
Normal file
109
internal/containerruntime/runtime.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
© 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")
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2018
|
© Copyright IBM Corporation 2017, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -15,11 +15,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
package main
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -101,24 +99,27 @@ var fsTypes = map[int64]string{
|
|||||||
0x58295829: "zsmalloc",
|
0x58295829: "zsmalloc",
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFS(path string) error {
|
// GetFilesystem returns the filesystem type for the specified path
|
||||||
|
func GetFilesystem(path string) (string, error) {
|
||||||
statfs := &unix.Statfs_t{}
|
statfs := &unix.Statfs_t{}
|
||||||
err := unix.Statfs(path, statfs)
|
err := unix.Statfs(path, statfs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
return "", err
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
// Use a type conversion to make type an int64. On s390x it's a uint32.
|
// Use a type conversion to make type an int64. On s390x it's a uint32.
|
||||||
t, ok := fsTypes[int64(statfs.Type)]
|
t, ok := fsTypes[int64(statfs.Type)]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Printf("WARNING: detected %v has unknown filesystem type %x", path, statfs.Type)
|
return "unknown", nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
switch t {
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedFilesystem returns true if the supplied filesystem type is supported for MQ data
|
||||||
|
func SupportedFilesystem(fsType string) bool {
|
||||||
|
switch fsType {
|
||||||
case "aufs", "overlayfs", "tmpfs":
|
case "aufs", "overlayfs", "tmpfs":
|
||||||
return fmt.Errorf("%v uses unsupported filesystem type: %v", path, t)
|
return false
|
||||||
default:
|
default:
|
||||||
log.Printf("Detected %v has filesystem type '%v'", path, t)
|
return true
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// +build !linux
|
// +build !linux
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
package main
|
package runtime
|
||||||
|
|
||||||
// Dummy version of this function, only for non-Linux systems.
|
// Dummy version of this function, only for non-Linux systems.
|
||||||
// Having this allows unit tests to be run on other platforms (e.g. macOS)
|
// Having this allows unit tests to be run on other platforms (e.g. macOS)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -44,7 +44,7 @@ type Logger struct {
|
|||||||
pid string
|
pid string
|
||||||
serverName string
|
serverName string
|
||||||
host string
|
host string
|
||||||
user *user.User
|
userName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogger creates a new logger
|
// NewLogger creates a new logger
|
||||||
@@ -53,9 +53,13 @@ func NewLogger(writer io.Writer, debug bool, json bool, serverName string) (*Log
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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()
|
user, err := user.Current()
|
||||||
if err != nil {
|
userName := ""
|
||||||
return nil, err
|
if err == nil {
|
||||||
|
userName = user.Username
|
||||||
}
|
}
|
||||||
return &Logger{
|
return &Logger{
|
||||||
mutex: sync.Mutex{},
|
mutex: sync.Mutex{},
|
||||||
@@ -66,7 +70,7 @@ func NewLogger(writer io.Writer, debug bool, json bool, serverName string) (*Log
|
|||||||
pid: strconv.Itoa(os.Getpid()),
|
pid: strconv.Itoa(os.Getpid()),
|
||||||
serverName: serverName,
|
serverName: serverName,
|
||||||
host: hostname,
|
host: hostname,
|
||||||
user: user,
|
userName: userName,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +97,7 @@ func (l *Logger) log(level string, msg string) {
|
|||||||
"ibm_serverName": l.serverName,
|
"ibm_serverName": l.serverName,
|
||||||
"ibm_processName": l.processName,
|
"ibm_processName": l.processName,
|
||||||
"ibm_processId": l.pid,
|
"ibm_processId": l.pid,
|
||||||
"ibm_userName": l.user.Username,
|
"ibm_userName": l.userName,
|
||||||
"type": "mq_containerlog",
|
"type": "mq_containerlog",
|
||||||
}
|
}
|
||||||
s, err := l.format(entry)
|
s, err := l.format(entry)
|
||||||
|
|||||||
81
internal/user/user.go
Normal file
81
internal/user/user.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
© 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
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -12,17 +12,17 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
image: ibmcom/mq:9
|
image: ibmcom/mq:9.1.2.0
|
||||||
manifests:
|
manifests:
|
||||||
- image: ibmcom/mq:9.1.1.0-x86_64
|
- image: ibmcom/mq:9.1.2.0-x86_64
|
||||||
platform:
|
platform:
|
||||||
architecture: amd64
|
architecture: amd64
|
||||||
os: linux
|
os: linux
|
||||||
- image: ibmcom/mq:9.1.1.0-ppc64le
|
- image: ibmcom/mq:9.1.2.0-ppc64le
|
||||||
platform:
|
platform:
|
||||||
architecture: ppc64le
|
architecture: ppc64le
|
||||||
os: linux
|
os: linux
|
||||||
- image: ibmcom/mq:9.1.1.0-s390x
|
- image: ibmcom/mq:9.1.2.0-s390x
|
||||||
platform:
|
platform:
|
||||||
architecture: s390x
|
architecture: s390x
|
||||||
os: linux
|
os: linux
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -14,15 +14,15 @@
|
|||||||
|
|
||||||
image: ibmcom/mq:latest
|
image: ibmcom/mq:latest
|
||||||
manifests:
|
manifests:
|
||||||
- image: ibmcom/mq:9.1.1.0-x86_64
|
- image: ibmcom/mq:9.1.2.0-x86_64
|
||||||
platform:
|
platform:
|
||||||
architecture: amd64
|
architecture: amd64
|
||||||
os: linux
|
os: linux
|
||||||
- image: ibmcom/mq:9.1.1.0-ppc64le
|
- image: ibmcom/mq:9.1.2.0-ppc64le
|
||||||
platform:
|
platform:
|
||||||
architecture: ppc64le
|
architecture: ppc64le
|
||||||
os: linux
|
os: linux
|
||||||
- image: ibmcom/mq:9.1.1.0-s390x
|
- image: ibmcom/mq:9.1.2.0-s390x
|
||||||
platform:
|
platform:
|
||||||
architecture: s390x
|
architecture: s390x
|
||||||
os: linux
|
os: linux
|
||||||
|
|||||||
29
manifests/dockerstore/manifest-9.1.2.yaml
Normal file
29
manifests/dockerstore/manifest-9.1.2.yaml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
image: ibmcorp/mqadvanced-server-dev:9.1.2.0
|
||||||
|
manifests:
|
||||||
|
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-x86_64
|
||||||
|
platform:
|
||||||
|
architecture: amd64
|
||||||
|
os: linux
|
||||||
|
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-ppc64le
|
||||||
|
platform:
|
||||||
|
architecture: ppc64le
|
||||||
|
os: linux
|
||||||
|
- image: ibmcorp/mqadvanced-server-dev:9.1.2.0-s390x
|
||||||
|
platform:
|
||||||
|
architecture: s390x
|
||||||
|
os: linux
|
||||||
|
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
This is a work-in-progress for a Docker image based on Red Hat Enterprise Linux (RHEL).
|
# RHEL-based container build
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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.
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -17,9 +17,11 @@
|
|||||||
|
|
||||||
# Builds and tests the golang programs used by the MQ image.
|
# Builds and tests the golang programs used by the MQ image.
|
||||||
|
|
||||||
set -e
|
set -ex
|
||||||
|
|
||||||
cd $GOPATH/src/github.com/ibm-messaging/mq-container/
|
# 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
|
# Build and test the Go code
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -34,12 +34,16 @@ readonly dev=$2
|
|||||||
IMAGE_REVISION=${IMAGE_REVISION:="Not Applicable"}
|
IMAGE_REVISION=${IMAGE_REVISION:="Not Applicable"}
|
||||||
IMAGE_SOURCE=${IMAGE_SOURCE:="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 \
|
podman run \
|
||||||
--volume ${PWD}:/go/src/github.com/ibm-messaging/mq-container/ \
|
--volume ${PWD}:/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/:Z \
|
||||||
--env GOPATH=/go \
|
|
||||||
--env IMAGE_REVISION="$IMAGE_REVISION" \
|
--env IMAGE_REVISION="$IMAGE_REVISION" \
|
||||||
--env IMAGE_SOURCE="$IMAGE_SOURCE" \
|
--env IMAGE_SOURCE="$IMAGE_SOURCE" \
|
||||||
--env MQDEV=${dev} \
|
--env MQDEV=${dev} \
|
||||||
|
--user $(id -u) \
|
||||||
--rm \
|
--rm \
|
||||||
|
--network podman \
|
||||||
${tag} \
|
${tag} \
|
||||||
bash -c "cd /go/src/github.com/ibm-messaging/mq-container/ && ./mq-advanced-server-rhel/go-build.sh"
|
bash -c "cd /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/ && ./mq-advanced-server-rhel/go-build.sh"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -34,6 +34,8 @@ readonly mnt_mq=$2
|
|||||||
readonly archive=$3
|
readonly archive=$3
|
||||||
readonly mq_packages=$4
|
readonly mq_packages=$4
|
||||||
readonly dir_extract=/tmp/extract
|
readonly dir_extract=/tmp/extract
|
||||||
|
readonly mqm_uid=888
|
||||||
|
readonly mqm_gid=888
|
||||||
|
|
||||||
if [ ! -d ${dir_extract}/MQServer ]; then
|
if [ ! -d ${dir_extract}/MQServer ]; then
|
||||||
mkdir -p ${dir_extract}
|
mkdir -p ${dir_extract}
|
||||||
@@ -42,13 +44,11 @@ if [ ! -d ${dir_extract}/MQServer ]; then
|
|||||||
echo Extracting finished
|
echo Extracting finished
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If MQ_PACKAGES isn't specifically set, then choose a valid set of defaults
|
|
||||||
|
|
||||||
|
|
||||||
# Accept the MQ license
|
# Accept the MQ license
|
||||||
buildah run --volume ${dir_extract}:/mnt/mq-download $ctr_mq -- /mnt/mq-download/MQServer/mqlicense.sh -text_only -accept
|
buildah run --user root --volume ${dir_extract}:/mnt/mq-download:Z $ctr_mq -- /mnt/mq-download/MQServer/mqlicense.sh -text_only -accept
|
||||||
|
|
||||||
buildah run --volume ${dir_extract}:/mnt/mq-download $ctr_mq -- bash -c "cd /mnt/mq-download/MQServer && rpm -ivh $mq_packages"
|
# 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
|
rm -rf ${dir_extract}/MQServer
|
||||||
|
|
||||||
@@ -62,16 +62,23 @@ find $mnt_mq/opt/mqm -name '*.tar.gz' -delete
|
|||||||
buildah run $ctr_mq -- /opt/mqm/bin/setmqinst -p /opt/mqm -i
|
buildah run $ctr_mq -- /opt/mqm/bin/setmqinst -p /opt/mqm -i
|
||||||
|
|
||||||
mkdir -p $mnt_mq/run/runmqserver
|
mkdir -p $mnt_mq/run/runmqserver
|
||||||
chown 888:888 $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
|
# Remove the directory structure under /var/mqm which was created by the installer
|
||||||
rm -rf $mnt_mq/var/mqm
|
rm -rf $mnt_mq/var/mqm
|
||||||
|
|
||||||
# Create the mount point for volumes
|
# Create the mount point for volumes, ensuring MQ has permissions to all directories
|
||||||
mkdir -p $mnt_mq/mnt/mqm
|
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
|
# Create a symlink for /var/mqm -> /mnt/mqm/data
|
||||||
buildah run $ctr_mq -- ln -s /mnt/mqm/data /var/mqm
|
buildah run --user root $ctr_mq -- ln -s /mnt/mqm/data /var/mqm
|
||||||
|
|
||||||
# Optional: Set these values for the IBM Cloud Vulnerability Report
|
# 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_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' $mnt_mq/etc/login.defs
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -16,14 +16,12 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
# Build a RHEL image, using the buildah tool
|
# Build a RHEL image, using the buildah tool
|
||||||
# Usage
|
|
||||||
# mq-buildah.sh ARCHIVEFILE PACKAGES
|
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
function usage {
|
function usage {
|
||||||
echo "Usage: $0 ARCHIVENAME PACKAGES TAG VERSION MQDevFlag"
|
echo "Usage: $0 ARCHIVE-NAME PACKAGES TAG VERSION MQDevFlag"
|
||||||
exit 20
|
exit 20
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +34,8 @@ fi
|
|||||||
# Setup MQ server working container
|
# Setup MQ server working container
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
readonly ctr_mq=$(buildah from rhel7)
|
# 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" ]
|
if [ -z "$ctr_mq" ]
|
||||||
then
|
then
|
||||||
echo "ERROR: ctr_mq is empty. Check above output for errors"
|
echo "ERROR: ctr_mq is empty. Check above output for errors"
|
||||||
@@ -55,18 +54,24 @@ readonly packages=$2
|
|||||||
readonly tag=$3
|
readonly tag=$3
|
||||||
readonly version=$4
|
readonly version=$4
|
||||||
readonly mqdev=$5
|
readonly mqdev=$5
|
||||||
|
readonly mqm_uid=888
|
||||||
|
readonly mqm_gid=888
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Install MQ server
|
# Install MQ server
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
groupadd --root ${mnt_mq} --system --gid 888 mqm
|
microdnf_opts="--nodocs"
|
||||||
useradd --root ${mnt_mq} --system --uid 888 --gid mqm mqm
|
# Check whether the host is registered with Red Hat
|
||||||
usermod --root ${mnt_mq} -aG root mqm
|
if subscription-manager status ; then
|
||||||
usermod --root ${mnt_mq} -aG mqm root
|
# Host is subscribed, but the minimal image has no enabled repos
|
||||||
|
# Note that the "bc" package is the only one in "extras"
|
||||||
# Install the packages required by MQ
|
microdnf_opts="${microdnf_opts} --enablerepo=rhel-7-server-rpms --enablerepo=rhel-7-server-extras-rpms"
|
||||||
buildah run $ctr_mq -- yum install -y --setopt install_weak_deps=false --setopt=tsflags=nodocs --setopt=override_install_langs=en_US.utf8 \
|
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 \
|
bash \
|
||||||
bc \
|
bc \
|
||||||
coreutils \
|
coreutils \
|
||||||
@@ -78,24 +83,43 @@ buildah run $ctr_mq -- yum install -y --setopt install_weak_deps=false --setopt=
|
|||||||
passwd \
|
passwd \
|
||||||
procps-ng \
|
procps-ng \
|
||||||
sed \
|
sed \
|
||||||
|
shadow-utils \
|
||||||
tar \
|
tar \
|
||||||
util-linux
|
util-linux \
|
||||||
|
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
|
# Clean up cached files
|
||||||
buildah run $ctr_mq -- yum clean all
|
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} clean all
|
||||||
rm -rf ${mnt_mq}/var/cache/yum/*
|
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
|
# Install MQ server packages into the MQ builder image
|
||||||
./mq-advanced-server-rhel/install-mq-rhel.sh ${ctr_mq} "${mnt_mq}" "${archive}" "${packages}"
|
./mq-advanced-server-rhel/install-mq-rhel.sh ${ctr_mq} "${mnt_mq}" "${archive}" "${packages}"
|
||||||
|
|
||||||
# Create the directory for MQ configuration files
|
# Create the directory for MQ configuration files
|
||||||
mkdir -p ${mnt_mq}/etc/mqm
|
mkdir -p ${mnt_mq}/etc/mqm
|
||||||
chown 888:888 ${mnt_mq}/etc/mqm
|
chown ${mqm_uid}:${mqm_gid} ${mnt_mq}/etc/mqm
|
||||||
|
|
||||||
# Install the Go binaries into the image
|
# Install the Go binaries into the image
|
||||||
install --mode 0750 --owner 888 --group 888 ./build/runmqserver ${mnt_mq}/usr/local/bin/
|
install --mode 0750 --owner ${mqm_uid} --group 0 ./build/runmqserver ${mnt_mq}/usr/local/bin/
|
||||||
install --mode 6750 --owner 888 --group 888 ./build/chk* ${mnt_mq}/usr/local/bin/
|
install --mode 6750 --owner ${mqm_uid} --group 0 ./build/chk* ${mnt_mq}/usr/local/bin/
|
||||||
install --mode 0750 --owner 888 --group 888 ./NOTICES.txt ${mnt_mq}/opt/mqm/licenses/notices-container.txt
|
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
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Final Buildah commands
|
# Final Buildah commands
|
||||||
@@ -133,7 +157,7 @@ buildah config \
|
|||||||
--env LANG=en_US.UTF-8 \
|
--env LANG=en_US.UTF-8 \
|
||||||
--env LOG_FORMAT=basic \
|
--env LOG_FORMAT=basic \
|
||||||
--entrypoint runmqserver \
|
--entrypoint runmqserver \
|
||||||
--user root \
|
--user ${mqm_uid} \
|
||||||
$ctr_mq
|
$ctr_mq
|
||||||
buildah unmount $ctr_mq
|
buildah unmount $ctr_mq
|
||||||
buildah commit $ctr_mq $tag
|
buildah commit $ctr_mq $tag
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
function usage {
|
function usage {
|
||||||
echo "Usage: $0 ARCHIVENAME TAG"
|
echo "Usage: $0 REDIST-ARCHIVE-NAME TAG"
|
||||||
exit 20
|
exit 20
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,41 +29,30 @@ if [ "$#" -ne 2 ]; then
|
|||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
|
|
||||||
readonly mq_archive=downloads/$1
|
readonly mq_redist_archive=downloads/$1
|
||||||
readonly tag=$2
|
readonly tag=$2
|
||||||
# Use plain RHEL 7 container
|
# Use Red Hat's Go toolset image as the base
|
||||||
# Note: Red Hat's devtools/go-toolset-7-rhel7 image doesn't allow use of 'root'
|
readonly ctr_mq=$(buildah from devtools/go-toolset-7-rhel7)
|
||||||
# user required for installing the MQ SDK
|
|
||||||
readonly ctr_mq=$(buildah from rhel7)
|
|
||||||
if [ -z "$ctr_mq" ]
|
if [ -z "$ctr_mq" ]
|
||||||
then
|
then
|
||||||
echo "ERROR: ctr_mq is empty. Check above output for errors"
|
echo "ERROR: ctr_mq is empty. Check above output for errors"
|
||||||
exit 50
|
exit 50
|
||||||
fi
|
fi
|
||||||
|
|
||||||
readonly mnt_mq=$(buildah mount $ctr_mq)
|
readonly mnt_mq_go=$(buildah mount $ctr_mq)
|
||||||
if [ -z "$mnt_mq" ]
|
if [ -z "$mnt_mq_go" ]
|
||||||
then
|
then
|
||||||
echo "ERROR: mnt_mq is empty. Check above output for errors"
|
echo "ERROR: mnt_mq_go is empty. Check above output for errors"
|
||||||
exit 50
|
exit 50
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add mqm user
|
# Install the MQ redistributable client (including header files) into the Go builder image
|
||||||
sudo groupadd --root $mnt_mq --system --gid 888 mqm
|
mkdir -p ${mnt_mq_go}/opt/mqm
|
||||||
sudo useradd --root $mnt_mq --system --uid 888 --gid mqm mqm
|
tar -xzf ${mq_redist_archive} -C ${mnt_mq_go}/opt/mqm
|
||||||
sudo usermod --root $mnt_mq -aG root mqm
|
|
||||||
sudo usermod --root $mnt_mq -aG mqm root
|
|
||||||
|
|
||||||
# Enable Yum repository for "optional" RPMs, which is needed for "golang"
|
|
||||||
buildah run ${ctr_mq} -- yum-config-manager --enable rhel-7-server-optional-rpms
|
|
||||||
# Install Go compiler
|
|
||||||
buildah run ${ctr_mq} -- yum install -y golang git gcc
|
|
||||||
|
|
||||||
# Install the MQ SDK into the Go builder image
|
|
||||||
./mq-advanced-server-rhel/install-mq-rhel.sh ${ctr_mq} "${mnt_mq}" "${mq_archive}" "MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm"
|
|
||||||
# Clean up Yum files
|
# Clean up Yum files
|
||||||
buildah run ${ctr_mq} -- yum clean all --releasever 7
|
rm -rf ${mnt_mq_go}/etc/yum.repos.d/*
|
||||||
rm -rf ${mnt_mq}/var/cache/yum/*
|
|
||||||
buildah unmount ${ctr_mq}
|
buildah unmount ${ctr_mq}
|
||||||
# Set environment variables for MQ/Go compilation
|
# Set environment variables for MQ/Go compilation
|
||||||
buildah config \
|
buildah config \
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -15,9 +15,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
# Build a RHEL image, using the buildah tool
|
# Build a RHEL image of MQ Advanced for Developers, using the buildah tool
|
||||||
# Usage
|
|
||||||
# mq-buildah.sh ARCHIVEFILE PACKAGES
|
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
set -e
|
set -e
|
||||||
@@ -55,26 +53,37 @@ fi
|
|||||||
|
|
||||||
readonly tag=$2
|
readonly tag=$2
|
||||||
readonly version=$3
|
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
|
||||||
|
|
||||||
useradd --root $mnt_mq --gid mqm admin
|
# Run these commands inside the container so that the SELinux context is handled correctly
|
||||||
groupadd --root $mnt_mq --system mqclient
|
buildah run --user root $ctr_mq -- useradd --gid mqm admin
|
||||||
useradd --root $mnt_mq --gid mqclient app
|
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"
|
||||||
|
|
||||||
buildah run $ctr_mq -- id admin
|
mkdir --parents $mnt_mq/run/runmqdevserver
|
||||||
buildah run $ctr_mq -- sh -c "echo admin:passw0rd | chpasswd"
|
chown ${mqm_uid}:${mqm_gid} $mnt_mq/run/runmqdevserver
|
||||||
|
|
||||||
mkdir -p $mnt_mq/run/runmqdevserver
|
|
||||||
chown 888:888 $mnt_mq/run/runmqdevserver
|
|
||||||
|
|
||||||
# Copy runmqdevserver program
|
# Copy runmqdevserver program
|
||||||
install --mode 0750 --owner 888 --group 888 ./build/runmqdevserver ${mnt_mq}/usr/local/bin/
|
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
|
# Copy template files
|
||||||
cp incubating/mqadvanced-server-dev/*.tpl ${mnt_mq}/etc/mqm/
|
cp ./incubating/mqadvanced-server-dev/*.tpl ${mnt_mq}/etc/mqm/
|
||||||
|
|
||||||
# Copy web XML files for default developer configuration
|
# Copy web XML files for default developer configuration
|
||||||
cp -R incubating/mqadvanced-server-dev/web ${mnt_mq}/etc/mqm/web
|
mkdir --parents ${mnt_mq}/etc/mqm/web
|
||||||
|
cp --recursive ./incubating/mqadvanced-server-dev/web/* ${mnt_mq}/etc/mqm/web/
|
||||||
|
|
||||||
|
# Make "mqm" the owner of all the config files
|
||||||
|
chown --recursive ${mqm_uid}:${mqm_gid} ${mnt_mq}/etc/mqm/*
|
||||||
|
chmod --recursive 0750 ${mnt_mq}/etc/mqm/*
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Final Buildah commands
|
# Final Buildah commands
|
||||||
@@ -105,7 +114,7 @@ buildah config \
|
|||||||
--env MQ_ADMIN_PASSWORD=passw0rd \
|
--env MQ_ADMIN_PASSWORD=passw0rd \
|
||||||
--env MQ_DEV=true \
|
--env MQ_DEV=true \
|
||||||
--entrypoint runmqdevserver \
|
--entrypoint runmqdevserver \
|
||||||
--user root \
|
--user ${mqm_uid} \
|
||||||
$ctr_mq
|
$ctr_mq
|
||||||
buildah unmount $ctr_mq
|
buildah unmount $ctr_mq
|
||||||
buildah commit $ctr_mq $tag
|
buildah commit $ctr_mq $tag
|
||||||
|
|||||||
30
mq-advanced-server-rhel/writePackages.sh
Executable file
30
mq-advanced-server-rhel/writePackages.sh
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/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
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/docker/go-connections"
|
name = "github.com/docker/go-connections"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import (
|
|||||||
// Note: This test requires a separate container image to be available for the JMS tests.
|
// Note: This test requires a separate container image to be available for the JMS tests.
|
||||||
func TestDevGoldenPath(t *testing.T) {
|
func TestDevGoldenPath(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -66,6 +67,7 @@ func TestDevGoldenPath(t *testing.T) {
|
|||||||
// Note: This test requires a separate container image to be available for the JMS tests
|
// Note: This test requires a separate container image to be available for the JMS tests
|
||||||
func TestDevSecure(t *testing.T) {
|
func TestDevSecure(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -127,6 +129,7 @@ func TestDevSecure(t *testing.T) {
|
|||||||
|
|
||||||
func TestDevWebDisabled(t *testing.T) {
|
func TestDevWebDisabled(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -157,6 +160,7 @@ func TestDevWebDisabled(t *testing.T) {
|
|||||||
|
|
||||||
func TestDevConfigDisabled(t *testing.T) {
|
func TestDevConfigDisabled(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -114,7 +114,7 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
startContainer(t, cli, ctr.ID)
|
startContainer(t, cli, ctr.ID)
|
||||||
rc := waitForContainer(t, cli, ctr.ID, 10)
|
rc := waitForContainer(t, cli, ctr.ID, 2*time.Minute)
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
t.Errorf("JUnit container failed with rc=%v", rc)
|
t.Errorf("JUnit container failed with rc=%v", rc)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2018
|
© Copyright IBM Corporation 2017, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -34,10 +34,13 @@ import (
|
|||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLicenseNotSet(t *testing.T) {
|
func TestLicenseNotSet(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -45,15 +48,16 @@ func TestLicenseNotSet(t *testing.T) {
|
|||||||
containerConfig := container.Config{}
|
containerConfig := container.Config{}
|
||||||
id := runContainer(t, cli, &containerConfig)
|
id := runContainer(t, cli, &containerConfig)
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
rc := waitForContainer(t, cli, id, 5)
|
rc := waitForContainer(t, cli, id, 20*time.Second)
|
||||||
if rc != 1 {
|
if rc != 1 {
|
||||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||||
}
|
}
|
||||||
expectTerminationMessage(t)
|
expectTerminationMessage(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLicenseView(t *testing.T) {
|
func TestLicenseView(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -63,7 +67,7 @@ func TestLicenseView(t *testing.T) {
|
|||||||
}
|
}
|
||||||
id := runContainer(t, cli, &containerConfig)
|
id := runContainer(t, cli, &containerConfig)
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
rc := waitForContainer(t, cli, id, 5)
|
rc := waitForContainer(t, cli, id, 20*time.Second)
|
||||||
if rc != 1 {
|
if rc != 1 {
|
||||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||||
}
|
}
|
||||||
@@ -77,12 +81,14 @@ func TestLicenseView(t *testing.T) {
|
|||||||
// TestGoldenPath starts a queue manager successfully when metrics are enabled
|
// TestGoldenPath starts a queue manager successfully when metrics are enabled
|
||||||
func TestGoldenPathWithMetrics(t *testing.T) {
|
func TestGoldenPathWithMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
goldenPath(t, true)
|
goldenPath(t, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestGoldenPath starts a queue manager successfully when metrics are disabled
|
// TestGoldenPath starts a queue manager successfully when metrics are disabled
|
||||||
func TestGoldenPathNoMetrics(t *testing.T) {
|
func TestGoldenPathNoMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
goldenPath(t, false)
|
goldenPath(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,10 +112,11 @@ func goldenPath(t *testing.T, metric bool) {
|
|||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSecurityVulnerabilities checks for any vulnerabilities in the image, as reported
|
// TestSecurityVulnerabilitiesUbuntu checks for any vulnerabilities in the image, as reported
|
||||||
// by Ubuntu
|
// by Ubuntu
|
||||||
func TestSecurityVulnerabilities(t *testing.T) {
|
func TestSecurityVulnerabilitiesUbuntu(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -135,6 +142,47 @@ func TestSecurityVulnerabilities(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) {
|
func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName string) {
|
||||||
search := "QMNAME(" + expectedName + ")"
|
search := "QMNAME(" + expectedName + ")"
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
@@ -155,11 +203,13 @@ func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName stri
|
|||||||
}
|
}
|
||||||
func TestNoQueueManagerName(t *testing.T) {
|
func TestNoQueueManagerName(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
utilTestNoQueueManagerName(t, "test", "test")
|
utilTestNoQueueManagerName(t, "test", "test")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNoQueueManagerNameInvalidHostname(t *testing.T) {
|
func TestNoQueueManagerNameInvalidHostname(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
utilTestNoQueueManagerName(t, "test-1", "test1")
|
utilTestNoQueueManagerName(t, "test-1", "test1")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +217,7 @@ func TestNoQueueManagerNameInvalidHostname(t *testing.T) {
|
|||||||
// container and starts a new one with same volume. With metrics enabled
|
// container and starts a new one with same volume. With metrics enabled
|
||||||
func TestWithVolumeAndMetrics(t *testing.T) {
|
func TestWithVolumeAndMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
withVolume(t, true)
|
withVolume(t, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +225,7 @@ func TestWithVolumeAndMetrics(t *testing.T) {
|
|||||||
// container and starts a new one with same volume. With metrics disabled
|
// container and starts a new one with same volume. With metrics disabled
|
||||||
func TestWithVolumeNoMetrics(t *testing.T) {
|
func TestWithVolumeNoMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
withVolume(t, false)
|
withVolume(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +277,7 @@ func withVolume(t *testing.T, metric bool) {
|
|||||||
// and restarted cleanly
|
// and restarted cleanly
|
||||||
func TestNoVolumeWithRestart(t *testing.T) {
|
func TestNoVolumeWithRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -240,58 +293,139 @@ func TestNoVolumeWithRestart(t *testing.T) {
|
|||||||
waitForReady(t, cli, id)
|
waitForReady(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestCreateQueueManagerFail causes a failure of `crtmqm`
|
// TestVolumeRequiresRoot tests the case where only the root user can write
|
||||||
func TestCreateQueueManagerFail(t *testing.T) {
|
// to the persistent volume. In this case, an "init container" is needed,
|
||||||
t.Parallel()
|
// 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()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
img, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
|
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())},
|
||||||
|
}
|
||||||
|
tag := createImage(t, cli, files)
|
||||||
|
defer deleteImage(t, cli, tag)
|
||||||
|
|
||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||||
// Override the entrypoint to create the queue manager directory, but leave it empty.
|
Image: tag,
|
||||||
// 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)
|
id := runContainer(t, cli, &containerConfig)
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
rc := waitForContainer(t, cli, id, 10)
|
rc := waitForContainer(t, cli, id, 10*time.Second)
|
||||||
if rc != 1 {
|
if rc != 1 {
|
||||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||||
}
|
}
|
||||||
expectTerminationMessage(t)
|
expectTerminationMessage(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStartQueueManagerFail causes a failure of `strmqm`
|
// TestStartQueueManagerFail causes a failure of `strmqm`
|
||||||
func TestStartQueueManagerFail(t *testing.T) {
|
func TestStartQueueManagerFail(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
img, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
|
var files = []struct {
|
||||||
if err != nil {
|
Name, Body string
|
||||||
t.Fatal(err)
|
}{
|
||||||
|
{"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())},
|
||||||
}
|
}
|
||||||
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
|
tag := createImage(t, cli, files)
|
||||||
|
defer deleteImage(t, cli, tag)
|
||||||
|
|
||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1", "DEBUG=1"},
|
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||||
// Override the entrypoint to replace `strmqm` with a script which deletes the queue manager.
|
Image: tag,
|
||||||
// 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)
|
id := runContainer(t, cli, &containerConfig)
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
rc := waitForContainer(t, cli, id, 10)
|
rc := waitForContainer(t, cli, id, 20*time.Second)
|
||||||
if rc != 1 {
|
if rc != 1 {
|
||||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||||
}
|
}
|
||||||
expectTerminationMessage(t)
|
expectTerminationMessage(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestVolumeUnmount runs a queue manager with a volume, and then forces an
|
// TestVolumeUnmount runs a queue manager with a volume, and then forces an
|
||||||
@@ -300,6 +434,7 @@ func TestStartQueueManagerFail(t *testing.T) {
|
|||||||
// attached storage gets unmounted.
|
// attached storage gets unmounted.
|
||||||
func TestVolumeUnmount(t *testing.T) {
|
func TestVolumeUnmount(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -348,6 +483,7 @@ func TestVolumeUnmount(t *testing.T) {
|
|||||||
// created, then checks that no zombies exist (runmqserver should reap them)
|
// created, then checks that no zombies exist (runmqserver should reap them)
|
||||||
func TestZombies(t *testing.T) {
|
func TestZombies(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -384,6 +520,7 @@ func TestZombies(t *testing.T) {
|
|||||||
// on that image, and checks that the MQSC has been applied correctly.
|
// on that image, and checks that the MQSC has been applied correctly.
|
||||||
func TestMQSC(t *testing.T) {
|
func TestMQSC(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -391,7 +528,13 @@ func TestMQSC(t *testing.T) {
|
|||||||
var files = []struct {
|
var files = []struct {
|
||||||
Name, Body string
|
Name, Body string
|
||||||
}{
|
}{
|
||||||
{"Dockerfile", fmt.Sprintf("FROM %v\nRUN rm -f /etc/mqm/*.mqsc\nADD test.mqsc /etc/mqm/", imageName())},
|
{"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())},
|
||||||
{"test.mqsc", "DEFINE QLOCAL(test)"},
|
{"test.mqsc", "DEFINE QLOCAL(test)"},
|
||||||
}
|
}
|
||||||
tag := createImage(t, cli, files)
|
tag := createImage(t, cli, files)
|
||||||
@@ -411,11 +554,144 @@ func TestMQSC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestLargeMQSC creates a new image with a large MQSC file in, starts a container based
|
||||||
|
// on that image, and checks that the MQSC has been applied correctly.
|
||||||
|
func TestLargeMQSC(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewEnvClient()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
const numQueues = 1000
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i := 1; i <= numQueues; i++ {
|
||||||
|
fmt.Fprintf(&buf, "* Test processing of a large MQSC file, defining queue test%v\nDEFINE QLOCAL(test%v)\n", i, i)
|
||||||
|
}
|
||||||
|
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())},
|
||||||
|
{"test.mqsc", buf.String()},
|
||||||
|
}
|
||||||
|
tag := createImage(t, cli, files)
|
||||||
|
defer deleteImage(t, cli, tag)
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||||
|
Image: tag,
|
||||||
|
}
|
||||||
|
id := runContainer(t, cli, &containerConfig)
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
waitForReady(t, cli, id)
|
||||||
|
|
||||||
|
rc, mqscOutput := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test" + strconv.Itoa(numQueues) + ")' | runmqsc"})
|
||||||
|
if rc != 0 {
|
||||||
|
r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E")
|
||||||
|
t.Fatalf("Expected runmqsc to exit with rc=0, got %v with error %v", rc, r.FindString(mqscOutput))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRedactMQSC creates a new image with a MQSC file that contains sensitive information, starts a container based
|
||||||
|
// on that image, and checks that the MQSC has been redacted in the logs.
|
||||||
|
func TestRedactMQSC(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewEnvClient()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
sslcryp := "GSK_PKCS11=/usr/lib/pkcs11/PKCS11_API.so;token-label;token-password;SYMMETRIC_CIPHER_ON;"
|
||||||
|
fmt.Fprintf(&buf, "*TEST-REDACT-MQSC: A(1) LDAPPWD(abcdefgh) B(2) PASSWORD(abcdefgh) C(3) SSLCRYP(%v) D(4)\n", sslcryp)
|
||||||
|
fmt.Fprintf(&buf, "*TEST-REDACT-MQSC: A(1) ldappwd(12345678) B(2) password(12345678) C(3) sslcryp(%v) D(4)\n", sslcryp)
|
||||||
|
fmt.Fprintf(&buf, "*TEST-REDACT-MQSC: A(1) LdapPwd('12?@!$Gh') B(2) Password('12?@!$Gh') C(3) SSLCryp(%v) D(4)\n", sslcryp)
|
||||||
|
fmt.Fprintf(&buf, "*TEST-REDACT-MQSC: A(1) LDAPPWD (abcdefgh) B(2) PASSWORD\t(abcdefgh) C(3) SSLCRYP \t (%v) D(4)", sslcryp)
|
||||||
|
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())},
|
||||||
|
{"test.mqsc", buf.String()},
|
||||||
|
}
|
||||||
|
tag := createImage(t, cli, files)
|
||||||
|
defer deleteImage(t, cli, tag)
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||||
|
Image: tag,
|
||||||
|
}
|
||||||
|
id := runContainer(t, cli, &containerConfig)
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
waitForReady(t, cli, id)
|
||||||
|
stopContainer(t, cli, id)
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(inspectLogs(t, cli, id)))
|
||||||
|
expectedOutput := "*TEST-REDACT-MQSC: A(1) LDAPPWD(*********) B(2) PASSWORD(*********) C(3) SSLCRYP(*********) D(4)"
|
||||||
|
for scanner.Scan() {
|
||||||
|
s := scanner.Text()
|
||||||
|
if strings.Contains(s, "*TEST-REDACT-MQSC:") && !strings.Contains(s, expectedOutput) {
|
||||||
|
t.Fatalf("Expected redacted MQSC output, got: %v", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = scanner.Err()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// TestReadiness creates a new image with large amounts of MQSC in, to
|
||||||
// ensure that the readiness check doesn't pass until configuration has finished.
|
// ensure that the readiness check doesn't pass until configuration has finished.
|
||||||
// WARNING: This test is sensitive to the speed of the machine it's running on.
|
// WARNING: This test is sensitive to the speed of the machine it's running on.
|
||||||
func TestReadiness(t *testing.T) {
|
func TestReadiness(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -428,7 +704,13 @@ func TestReadiness(t *testing.T) {
|
|||||||
var files = []struct {
|
var files = []struct {
|
||||||
Name, Body string
|
Name, Body string
|
||||||
}{
|
}{
|
||||||
{"Dockerfile", fmt.Sprintf("FROM %v\nRUN rm -f /etc/mqm/*.mqsc\nADD test.mqsc /etc/mqm/", imageName())},
|
{"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())},
|
||||||
{"test.mqsc", buf.String()},
|
{"test.mqsc", buf.String()},
|
||||||
}
|
}
|
||||||
tag := createImage(t, cli, files)
|
tag := createImage(t, cli, files)
|
||||||
@@ -464,22 +746,34 @@ func TestReadiness(t *testing.T) {
|
|||||||
|
|
||||||
func TestErrorLogRotation(t *testing.T) {
|
func TestErrorLogRotation(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logsize := 65536
|
||||||
|
|
||||||
|
rc, _ := runContainerOneShot(t, cli, "bash", "-c", "test -d /etc/apt")
|
||||||
|
if rc != 0 {
|
||||||
|
// RHEL
|
||||||
|
logsize = 32768
|
||||||
|
}
|
||||||
|
|
||||||
qmName := "qm1"
|
qmName := "qm1"
|
||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + qmName,
|
"MQ_QMGR_NAME=" + qmName,
|
||||||
"MQMAXERRORLOGSIZE=65536",
|
fmt.Sprintf("MQMAXERRORLOGSIZE=%d", logsize),
|
||||||
"LOG_FORMAT=json",
|
"LOG_FORMAT=json",
|
||||||
|
fmt.Sprintf("AMQ_EXTRA_QM_STANZAS=QMErrorLog:ErrorLogSize=%d", logsize),
|
||||||
},
|
},
|
||||||
ExposedPorts: nat.PortSet{
|
ExposedPorts: nat.PortSet{
|
||||||
"1414/tcp": struct{}{},
|
"1414/tcp": struct{}{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
id := runContainer(t, cli, &containerConfig)
|
id := runContainer(t, cli, &containerConfig)
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
waitForReady(t, cli, id)
|
waitForReady(t, cli, id)
|
||||||
@@ -487,6 +781,7 @@ func TestErrorLogRotation(t *testing.T) {
|
|||||||
// Generate some content for the error logs, by trying to put messages under an unauthorized user
|
// 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, "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"})
|
execContainer(t, cli, id, "root", []string{"useradd", "fred"})
|
||||||
|
|
||||||
for {
|
for {
|
||||||
execContainer(t, cli, id, "fred", []string{"bash", "-c", "/opt/mqm/samp/bin/amqsput FAKE"})
|
execContainer(t, cli, id, "fred", []string{"bash", "-c", "/opt/mqm/samp/bin/amqsput FAKE"})
|
||||||
|
|
||||||
@@ -529,12 +824,14 @@ func TestErrorLogRotation(t *testing.T) {
|
|||||||
// Tests the log comes out in JSON format when JSON format is enabled. With metrics enabled
|
// Tests the log comes out in JSON format when JSON format is enabled. With metrics enabled
|
||||||
func TestJSONLogFormatWithMetrics(t *testing.T) {
|
func TestJSONLogFormatWithMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
jsonLogFormat(t, true)
|
jsonLogFormat(t, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests the log comes out in JSON format when JSON format is enabled. With metrics disabled
|
// Tests the log comes out in JSON format when JSON format is enabled. With metrics disabled
|
||||||
func TestJSONLogFormatNoMetrics(t *testing.T) {
|
func TestJSONLogFormatNoMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
jsonLogFormat(t, false)
|
jsonLogFormat(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,6 +872,7 @@ func jsonLogFormat(t *testing.T, metric bool) {
|
|||||||
|
|
||||||
func TestBadLogFormat(t *testing.T) {
|
func TestBadLogFormat(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -587,11 +885,11 @@ func TestBadLogFormat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
id := runContainer(t, cli, &containerConfig)
|
id := runContainer(t, cli, &containerConfig)
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
rc := waitForContainer(t, cli, id, 5)
|
rc := waitForContainer(t, cli, id, 20*time.Second)
|
||||||
if rc != 1 {
|
if rc != 1 {
|
||||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||||
}
|
}
|
||||||
expectTerminationMessage(t)
|
expectTerminationMessage(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestMQJSONDisabled tests the case where MQ's JSON logging feature is
|
// TestMQJSONDisabled tests the case where MQ's JSON logging feature is
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2018
|
© Copyright IBM Corporation 2017, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -43,6 +43,18 @@ import (
|
|||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type containerDetails struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Image string
|
||||||
|
Path string
|
||||||
|
Args []string
|
||||||
|
CapAdd []string
|
||||||
|
CapDrop []string
|
||||||
|
User string
|
||||||
|
Env []string
|
||||||
|
}
|
||||||
|
|
||||||
func imageName() string {
|
func imageName() string {
|
||||||
image, ok := os.LookupEnv("TEST_IMAGE")
|
image, ok := os.LookupEnv("TEST_IMAGE")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -59,6 +71,29 @@ func imageNameDevJMS() string {
|
|||||||
return image
|
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
|
// isWSL return whether we are running in the Windows Subsystem for Linux
|
||||||
func isWSL(t *testing.T) bool {
|
func isWSL(t *testing.T) bool {
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
@@ -124,66 +159,79 @@ func getTempDir(t *testing.T, unixStylePath bool) string {
|
|||||||
return "/tmp/"
|
return "/tmp/"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
// terminationMessage return the termination message, or an empty string if not set
|
||||||
func terminationMessage(t *testing.T) string {
|
func terminationMessage(t *testing.T, cli *client.Client, ID string) string {
|
||||||
b, err := ioutil.ReadFile(terminationLogUnixPath(t))
|
r, _, err := cli.CopyFromContainer(context.Background(), ID, "/run/termination-log")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return string(b)
|
b, err := ioutil.ReadAll(r)
|
||||||
|
tr := tar.NewReader(bytes.NewReader(b))
|
||||||
|
_, err = tr.Next()
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// read the complete content of the file h.Name into the bs []byte
|
||||||
|
content, err := ioutil.ReadAll(tr)
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectTerminationMessage(t *testing.T) {
|
func expectTerminationMessage(t *testing.T, cli *client.Client, ID string) {
|
||||||
m := terminationMessage(t)
|
m := terminationMessage(t, cli, ID)
|
||||||
if m == "" {
|
if m == "" {
|
||||||
t.Error("Expected termination message to be set")
|
t.Error("Expected termination message to be set")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanContainer(t *testing.T, cli *client.Client, ID string) {
|
// logContainerDetails logs selected details about the container
|
||||||
|
func logContainerDetails(t *testing.T, cli *client.Client, ID string) {
|
||||||
i, err := cli.ContainerInspect(context.Background(), ID)
|
i, err := cli.ContainerInspect(context.Background(), ID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Log the results and continue
|
d := containerDetails{
|
||||||
t.Logf("Inspected container %v: %#v", ID, i)
|
ID: ID,
|
||||||
s, err := json.MarshalIndent(i, "", " ")
|
Name: i.Name,
|
||||||
if err != nil {
|
Image: i.Image,
|
||||||
t.Fatal(err)
|
Path: i.Path,
|
||||||
|
Args: i.Args,
|
||||||
|
CapAdd: i.HostConfig.CapAdd,
|
||||||
|
CapDrop: i.HostConfig.CapDrop,
|
||||||
|
User: i.Config.User,
|
||||||
|
Env: i.Config.Env,
|
||||||
}
|
}
|
||||||
t.Logf("Inspected container %v: %v", ID, string(s))
|
// If you need more details, you can always just run `json.MarshalIndent(i, "", " ")` to see everything.
|
||||||
|
t.Logf("Container details: %+v", d)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
t.Logf("Stopping container: %v", ID)
|
||||||
timeout := 10 * time.Second
|
timeout := 10 * time.Second
|
||||||
// Stop the container. This allows the coverage output to be generated.
|
// Stop the container. This allows the coverage output to be generated.
|
||||||
err = cli.ContainerStop(context.Background(), ID, &timeout)
|
err := cli.ContainerStop(context.Background(), ID, &timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Just log the error and continue
|
// Just log the error and continue
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@@ -195,11 +243,10 @@ func cleanContainer(t *testing.T, cli *client.Client, ID string) {
|
|||||||
// Log the container output for any container we're about to delete
|
// 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))
|
t.Logf("Console log from container %v:\n%v", ID, inspectTextLogs(t, cli, ID))
|
||||||
|
|
||||||
m := terminationMessage(t)
|
m := terminationMessage(t, cli, ID)
|
||||||
if m != "" {
|
if m != "" {
|
||||||
t.Logf("Termination message: %v", m)
|
t.Logf("Termination message: %v", m)
|
||||||
}
|
}
|
||||||
os.Remove(terminationLogUnixPath(t))
|
|
||||||
|
|
||||||
t.Logf("Removing container: %s", ID)
|
t.Logf("Removing container: %s", ID)
|
||||||
opts := types.ContainerRemoveOptions{
|
opts := types.ContainerRemoveOptions{
|
||||||
@@ -219,15 +266,36 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co
|
|||||||
if containerConfig.Image == "" {
|
if containerConfig.Image == "" {
|
||||||
containerConfig.Image = imageName()
|
containerConfig.Image = imageName()
|
||||||
}
|
}
|
||||||
|
// Always run as the "mqm" user, unless the test has specified otherwise
|
||||||
|
if containerConfig.User == "" {
|
||||||
|
containerConfig.User = "mqm"
|
||||||
|
}
|
||||||
// if coverage
|
// if coverage
|
||||||
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
hostConfig := container.HostConfig{
|
hostConfig := container.HostConfig{
|
||||||
Binds: []string{
|
Binds: []string{
|
||||||
coverageBind(t),
|
coverageBind(t),
|
||||||
terminationBind(t),
|
|
||||||
},
|
},
|
||||||
PortBindings: nat.PortMap{},
|
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 {
|
for _, p := range ports {
|
||||||
port := nat.Port(fmt.Sprintf("%v/tcp", p))
|
port := nat.Port(fmt.Sprintf("%v/tcp", p))
|
||||||
@@ -254,13 +322,62 @@ func runContainer(t *testing.T, cli *client.Client, containerConfig *container.C
|
|||||||
return runContainerWithPorts(t, cli, containerConfig, nil)
|
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) {
|
func runContainerOneShot(t *testing.T, cli *client.Client, command ...string) (int64, string) {
|
||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
Entrypoint: command,
|
Entrypoint: command,
|
||||||
|
User: "root",
|
||||||
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
id := runContainer(t, cli, &containerConfig)
|
hostConfig := container.HostConfig{}
|
||||||
defer cleanContainer(t, cli, id)
|
networkingConfig := network.NetworkingConfig{}
|
||||||
return waitForContainer(t, cli, id, 10), inspectLogs(t, cli, id)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func startContainer(t *testing.T, cli *client.Client, ID string) {
|
func startContainer(t *testing.T, cli *client.Client, ID string) {
|
||||||
@@ -309,19 +426,19 @@ func getCoverageExitCode(t *testing.T, orig int64) int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// waitForContainer waits until a container has exited
|
// waitForContainer waits until a container has exited
|
||||||
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout int64) int64 {
|
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.Duration) int64 {
|
||||||
rc, err := cli.ContainerWait(context.Background(), ID)
|
c, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
rc, err := cli.ContainerWait(c, ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
if coverage() {
|
if coverage() {
|
||||||
// COVERAGE: When running coverage, the exit code is written to a file,
|
// COVERAGE: When running coverage, the exit code is written to a file,
|
||||||
// to allow the coverage to be generated (which doesn't happen for non-zero
|
// to allow the coverage to be generated (which doesn't happen for non-zero
|
||||||
// exit codes)
|
// exit codes)
|
||||||
rc = getCoverageExitCode(t, rc)
|
rc = getCoverageExitCode(t, rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +512,7 @@ func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd
|
|||||||
}
|
}
|
||||||
|
|
||||||
func waitForReady(t *testing.T, cli *client.Client, ID string) {
|
func waitForReady(t *testing.T, cli *client.Client, ID string) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2019
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
|
|
||||||
func TestGoldenPathMetric(t *testing.T) {
|
func TestGoldenPathMetric(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -53,6 +54,7 @@ func TestGoldenPathMetric(t *testing.T) {
|
|||||||
|
|
||||||
func TestMetricNames(t *testing.T) {
|
func TestMetricNames(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -96,6 +98,7 @@ func TestMetricNames(t *testing.T) {
|
|||||||
|
|
||||||
func TestMetricLabels(t *testing.T) {
|
func TestMetricLabels(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
requiredLabels := []string{"qmgr"}
|
requiredLabels := []string{"qmgr"}
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -144,6 +147,7 @@ func TestMetricLabels(t *testing.T) {
|
|||||||
|
|
||||||
func TestRapidFirePrometheus(t *testing.T) {
|
func TestRapidFirePrometheus(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -177,6 +181,7 @@ func TestRapidFirePrometheus(t *testing.T) {
|
|||||||
|
|
||||||
func TestSlowPrometheus(t *testing.T) {
|
func TestSlowPrometheus(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -207,6 +212,7 @@ func TestSlowPrometheus(t *testing.T) {
|
|||||||
|
|
||||||
func TestContainerRestart(t *testing.T) {
|
func TestContainerRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -254,6 +260,7 @@ func TestContainerRestart(t *testing.T) {
|
|||||||
|
|
||||||
func TestQMRestart(t *testing.T) {
|
func TestQMRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -279,7 +286,7 @@ func TestQMRestart(t *testing.T) {
|
|||||||
|
|
||||||
// Restart just the QM (to simulate a lost connection)
|
// Restart just the QM (to simulate a lost connection)
|
||||||
t.Log("Stopping queue manager\n")
|
t.Log("Stopping queue manager\n")
|
||||||
rc, out := execContainer(t, cli, id, "mqm", []string{"endmqm", "-w", defaultMetricQMName})
|
rc, out := execContainer(t, cli, id, "mqm", []string{"endmqm", "-w", "-r", defaultMetricQMName})
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
t.Fatalf("Failed to stop the queue manager. rc=%d, err=%s", rc, out)
|
t.Fatalf("Failed to stop the queue manager. rc=%d, err=%s", rc, out)
|
||||||
}
|
}
|
||||||
@@ -311,6 +318,7 @@ func TestQMRestart(t *testing.T) {
|
|||||||
|
|
||||||
func TestValidValues(t *testing.T) {
|
func TestValidValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -346,6 +354,7 @@ func TestValidValues(t *testing.T) {
|
|||||||
|
|
||||||
func TestChangingValues(t *testing.T) {
|
func TestChangingValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewEnvClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -22,24 +22,34 @@ set -e
|
|||||||
|
|
||||||
# Use a "scratch" container, so the resulting image has minimal files
|
# Use a "scratch" container, so the resulting image has minimal files
|
||||||
# Resulting image won't have yum, for example
|
# Resulting image won't have yum, for example
|
||||||
readonly ctr_mq=$(buildah from rhel7)
|
readonly ctr_mq=$(buildah from rhel7-minimal)
|
||||||
readonly mnt_mq=$(buildah mount $ctr_mq)
|
readonly mnt_mq=$(buildah mount $ctr_mq)
|
||||||
readonly imagename=$1
|
readonly imagename=$1
|
||||||
|
|
||||||
buildah run $ctr_mq -- yum install -y \
|
microdnf_opts="--nodocs"
|
||||||
java-1.7.0-openjdk-devel \
|
# Check whether the host is registered with Red Hat
|
||||||
java \
|
if subscription-manager status ; then
|
||||||
which \
|
# Host is subscribed, but the minimal image has no enabled repos
|
||||||
wget
|
# 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 http://mirror.olnevhost.net/pub/apache/maven/binaries/apache-maven-3.2.2-bin.tar.gz"
|
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.2.2-bin.tar.gz -C $mnt_mq/tmp/
|
tar xvf $mnt_mq/tmp/apache-maven-3.6.0-bin.tar.gz -C $mnt_mq/tmp/
|
||||||
|
|
||||||
mkdir -p $mnt_mq/usr/src/mymaven
|
mkdir -p $mnt_mq/usr/src/mymaven
|
||||||
cp pom.xml $mnt_mq/usr/src/mymaven/
|
cp pom.xml $mnt_mq/usr/src/mymaven/
|
||||||
cp -R src $mnt_mq/usr/src/mymaven/src
|
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.2.2 && export M2=\$M2_HOME/bin && export PATH=\$M2:\$PATH && mvn --version && mvn dependency:go-offline install && mvn --offline install"
|
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
|
mkdir -p $mnt_mq/opt/app
|
||||||
|
|
||||||
@@ -53,13 +63,9 @@ cp $mnt_mq/usr/src/mymaven/target/lib/*.jar $mnt_mq/opt/app/
|
|||||||
rm -rf $mnt_mq/tmp/*
|
rm -rf $mnt_mq/tmp/*
|
||||||
rm -rf $mnt_mq/usr/src/mymaven
|
rm -rf $mnt_mq/usr/src/mymaven
|
||||||
|
|
||||||
# We can't uninstall tar or gzip because they are required
|
|
||||||
buildah run $ctr_mq -- yum remove -y \
|
|
||||||
wget
|
|
||||||
|
|
||||||
# Clean up cached files
|
# Clean up cached files
|
||||||
buildah run $ctr_mq -- yum clean all
|
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} clean all
|
||||||
rm -rf ${mnt_mq}/var/cache/yum/*
|
rm -rf ${mnt_mq}/etc/yum.repos.d/*
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Contain image finalization
|
# Contain image finalization
|
||||||
@@ -69,6 +75,7 @@ buildah config \
|
|||||||
--os linux \
|
--os linux \
|
||||||
--label architecture=x86_64 \
|
--label architecture=x86_64 \
|
||||||
--label name="${imagename%:*}" \
|
--label name="${imagename%:*}" \
|
||||||
|
--cmd "" \
|
||||||
--entrypoint '["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]' \
|
--entrypoint '["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]' \
|
||||||
$ctr_mq
|
$ctr_mq
|
||||||
buildah unmount $ctr_mq
|
buildah unmount $ctr_mq
|
||||||
|
|||||||
@@ -32,19 +32,19 @@ limitations under the License.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<version>5.2.0</version>
|
<version>5.3.2</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<version>5.2.0</version>
|
<version>5.3.2</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.platform</groupId>
|
<groupId>org.junit.platform</groupId>
|
||||||
<artifactId>junit-platform-console-standalone</artifactId>
|
<artifactId>junit-platform-console-standalone</artifactId>
|
||||||
<version>1.2.0</version>
|
<version>1.3.2</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
Binary file not shown.
@@ -23,7 +23,7 @@ PASSWORD=passw0rd
|
|||||||
openssl req \
|
openssl req \
|
||||||
-newkey rsa:2048 -nodes -keyout ${KEY} \
|
-newkey rsa:2048 -nodes -keyout ${KEY} \
|
||||||
-subj "/CN=localhost" \
|
-subj "/CN=localhost" \
|
||||||
-x509 -days 365 -out ${CERT}
|
-x509 -days 3650 -out ${CERT}
|
||||||
|
|
||||||
# Add the key and certificate to a PKCS #12 key store, for the server to use
|
# Add the key and certificate to a PKCS #12 key store, for the server to use
|
||||||
openssl pkcs12 \
|
openssl pkcs12 \
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIICpDCCAYwCCQDft9xlN4fNFTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
MIICpDCCAYwCCQC6vpJFnfYO6TANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
||||||
b2NhbGhvc3QwHhcNMTgwMzIwMTUxODMwWhcNMTkwMzIwMTUxODMwWjAUMRIwEAYD
|
b2NhbGhvc3QwHhcNMTkwMzIxMTYxMzUxWhcNMjkwMzE4MTYxMzUxWjAUMRIwEAYD
|
||||||
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDk
|
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCu
|
||||||
XzX0xQIZzKVX8/lDQh5lSHr5U9cBL+kURA3fEgl3ks9KjZPggfxWl4Y5dekChW/s
|
48qtIDwmihFqj2HY3dZjPfROA1MJ+D0c6aEA08ooOczthLB7XdZBQDapj8LFldyt
|
||||||
iknVssoNw9vI1W25qtQ81zRFQbHbpej0lLdYsS8/yZCuAVjMTp6Q9IswTwhVA6OD
|
4ZMbTkqtF5QtPXmJY0wi39foLYlcGXPL1b7y3mypaFou88BcSM3VmfILKXhNeAlt
|
||||||
5orag5dH3XQH+GsnmGXRCY7Gs93onAe3i3ShX9qpUFOJXyxCX+pLAC6kWQ3f/HI8
|
rXevnuT5kDU7sLVgKGhGwas20T1MU7d0I3bQ5z5c7egL76Hk9fYucjN6RkbwlrJ3
|
||||||
dujVXKsg1vHgOgGqQGwnh8gm5OeWUeuTMdD2v7Hn1OxilgNMbcewA7bpvipgm2xt
|
TrCXrGIziofn3Zq1t51ygv21c80JD3XJ44YmuCrede4rhOS/4NpwRuZyiwpJ6tlv
|
||||||
ZD0PKFDmtQ4comr25Oo+eUf1N7jSpRPOWJNxoyS9/coQUPp1Gpbk7khYHjGn7f5a
|
0L0QSDGCmt2JT3ty28UAsGznFzC5Qu9KyaR+9Gk4aftiyKxrYWZkgtJmMRU+C1X2
|
||||||
EZqQ4Hmwwh50uT+vKVxDAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAHaywC7ZLOi
|
kFLOHsucGmJswjwubSR7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEdlmXVGy86P
|
||||||
3PKlidj6PWe33dEVsDL6RRb3cOqR86Ld2aD91oLrpELRhz4v2mt/GfQMIg7rc6z7
|
XIX5a4ZmHQ5Ns4wm7rY8vzUxlymEQ86En1PN1zAO9gV94tLyNeMptjsFEEo/uJhC
|
||||||
26SuPzV/7zZAv1N/vGoIFyvBXWLYP5qCwUrmykcH/wfFM80S6FJxz5Wy5MA5UzTB
|
Yvg3l5TIr/WCiY2+2XsSHvnbXrlbF3S0fRHa9VaCMRKjzRT68uq2Y891906YGtUE
|
||||||
HdpiQCPu4U0IKgATLDraz0xlQ61Rog56YhgJI8ulHuav5iYxqV2mwU09Hs0kXPJ7
|
m6fCjHqVzX8qaplDf79aVkPydYaYOIZ1a/mCfQcD9XMZ/v5zI9IUDhdoq97bgPhB
|
||||||
g0PLRaSyidsXafxBKukeM9QHl8z8HN8er23oqecYo59b/Bt0c6jSrJCK39EUcoLP
|
gBOzWLI+hkzyU8jxKAFw1Hwi9lD/P6RXL5arNb/+arOgA3vTW+xGWGevgjVK1Ay9
|
||||||
HxR+Ma1SPhVKGqa3lPmaoAzsFTqaJ6fsIcbp+oEFAq0LPeqMPK7u3ygT4iTblAl8
|
81beWiQmn0KbeLZxj+WJ9Nntlf1M4EqPYgsSYs/IlJTYS8W1B0mDJEoovPdFTryY
|
||||||
q3isCz4Ytx4=
|
GyIuQEVcjUE=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDkXzX0xQIZzKVX
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu48qtIDwmihFq
|
||||||
8/lDQh5lSHr5U9cBL+kURA3fEgl3ks9KjZPggfxWl4Y5dekChW/siknVssoNw9vI
|
j2HY3dZjPfROA1MJ+D0c6aEA08ooOczthLB7XdZBQDapj8LFldyt4ZMbTkqtF5Qt
|
||||||
1W25qtQ81zRFQbHbpej0lLdYsS8/yZCuAVjMTp6Q9IswTwhVA6OD5orag5dH3XQH
|
PXmJY0wi39foLYlcGXPL1b7y3mypaFou88BcSM3VmfILKXhNeAltrXevnuT5kDU7
|
||||||
+GsnmGXRCY7Gs93onAe3i3ShX9qpUFOJXyxCX+pLAC6kWQ3f/HI8dujVXKsg1vHg
|
sLVgKGhGwas20T1MU7d0I3bQ5z5c7egL76Hk9fYucjN6RkbwlrJ3TrCXrGIziofn
|
||||||
OgGqQGwnh8gm5OeWUeuTMdD2v7Hn1OxilgNMbcewA7bpvipgm2xtZD0PKFDmtQ4c
|
3Zq1t51ygv21c80JD3XJ44YmuCrede4rhOS/4NpwRuZyiwpJ6tlv0L0QSDGCmt2J
|
||||||
omr25Oo+eUf1N7jSpRPOWJNxoyS9/coQUPp1Gpbk7khYHjGn7f5aEZqQ4Hmwwh50
|
T3ty28UAsGznFzC5Qu9KyaR+9Gk4aftiyKxrYWZkgtJmMRU+C1X2kFLOHsucGmJs
|
||||||
uT+vKVxDAgMBAAECggEBAL91kybChCBdEcHLKQ7aP+FqAq9FOtwj7qSu6XI7DPTS
|
wjwubSR7AgMBAAECggEAH9t6teKjUlngJksMBdcTEGzerb9JRw2jBDtCisYJkx5E
|
||||||
gDdgurleQM/X+Q/zaoZSmKMWzQ/79KnVqk2VoYgnUAgx5ACsMxCS59slUxFoetRf
|
SBfdlftX5fbufiCj2B4eXsYyZ8zxKWqcIUmLdA1Udx3TVIXG+bHhOAYtjEwb+xf5
|
||||||
iIxZVLj0sLuWSZsWp0We51eN0Juh9xKo9r435p4rhjDacnjkEwcQyOd4Yy9nzUpk
|
JYhdR/IzHG+4eXQKaAIvpXztyl3lU9iC+eaMg4GYzRrGN2wSAG9XgZ5cLF2TLJYU
|
||||||
GDD5Vu1J9bOOKUQZ0qgjPyl/xWiwD1yfGJ0nHpQ5ucfrCO9p+n7SYsx01WcAkC8J
|
jPxp7goz9X6V57aL2G/EFlbFsMaI/6cW7+XoRdo0I4N2Z766gz7GgyxtTVwR5Peq
|
||||||
WP9XSXgi5uIefTWb/4m2b32jzjIgzAHkNx6yktRTjBJ7QILnKq1P8JjkNA/Awj4P
|
LjOpqSNS0W57KJxReURfySok9CP1DfyigopsYW8O4jGVDDRLdiN3I8+JhWya2E0j
|
||||||
OxAz9hHHnVRuq4ZlEqfvo9p9YAbN2IH5TnmN3rGCXwECgYEA9JitVIeXCS0qIMFA
|
96hHpN04Oz6HnMm7bdZDVtkZCOiu6xIzLJJxZ4o+kQKBgQDYqOA/hSod7s7w4LBE
|
||||||
dKCmm9CT7JXccdpVllwaaYCNTb+G2RBrJqAvQEetoYJodWTIm1mNwSEORFFw0W+N
|
A6Mp+e0//PYH6/N9SKmSIgQNec9bMGI4yanoblMbg4GM1g7pkvjlC0nTdjnUbLkB
|
||||||
eaMzibJoJ+MZHRhiulDJaY0vwAKHkSJjDPJrPLgGMCUOLiWSAAnR4z35WfeY0e//
|
vIvtVh3XwTIlrZ/4lc7VB23/hmKU+lRc+NJP5fgasAQu0W3+qp2cXo0pnHVwBEku
|
||||||
JbdZZemrJRyzy3o6rkRN9TQcUMUCgYEA7wTj5w5GZ8NQ7Nn8nIS2ayk+woIMHS+g
|
Z7FwDPX0JNDIi/Or2I7dt8JojQKBgQDOpU1AnIXv1/cToYK4nz8BWLxRxwLTxy5A
|
||||||
RVFufJoBeopsNJfNzGak0s+nz5q0nMGMzQsxXkbmAOLMTU3woQ7cEGjkLAfoch23
|
ucafNKacPlxb5luZRCExiPZwAM8Z3zI9o99rYXOPQmsnknZWJV66Zx0Vo0yTD1CT
|
||||||
ACOe7M4rZbIk6kVNOlFESWdVdWViVd/B2a7oBqOIykoqX6VSqqrw+xghAUmd/2W1
|
DWMUj0ugI1wORNMhwZP6YBYWjAeupyU9a7FyU1Geg4sdQt5rMyAEQOoECc8x8foP
|
||||||
uxjg9v01OWcCgYApE5LYRUUKF3mhspKeg3Q3apnM+4Xf4OjKrYEKArq4OdftkCJO
|
rySHuO/TJwKBgBjMM2ZxymFErQDa5rHSLMGoLmRtgodjlSnYwDfOluIn9/i67/MJ
|
||||||
hEwrIV55Zysfu+Mso6d4rZJ1yq+FnJRHvy6ii0GOoUbQag36eCK7BSjluAcISpwT
|
+d11iyOSCKji8y/+t2gXw6plVLcgfohZWTaf7ah9H006sx2Tn+m4APoHGo9sm21M
|
||||||
yopT0hvH7hEpksmoE/4ZiYjcoQYbC5DvxpDO2qURQHa5TzeXmIT3Dt9KeQKBgQC6
|
uV2Vt7DuRnxJUiqcwo9cLxH9K1/Xzbx299MYWKpJ8G+TvR8FGUz9NE4dAoGAM5gs
|
||||||
UKeOXrRHAhs85ZdiMpk340jGujTTM2LNZfKoMixg5zH9tS9427IzmicHT2LmpoEo
|
KKSsAE1QwFMEG2qPRZvNMTHaL9w8XSbFQ7zWmI4tazihyCutifujZCWfj9sdZSyE
|
||||||
/EaZZM65dhEnWU/vW/Py3rCuGeP5wGv8Mcgac4OknD7mVusiQGLojSIyhrsmkWs8
|
PQBQ5QT1UiUMbMfZ1fqm1V83YERjnsOp6Fk6zZnmgx2GBZiahNn2ydxekqni72nz
|
||||||
UnkPY76nYTSypd5Qpzt9n4tqw4XjpdcJZxVFso8glQKBgQCHlb15As73En/Q2AxL
|
HRNWfphjZIPsmqFiLg2zIBz+4X6EK+RT35s6LeMCgYEAwF/9jX8kONW5KKZdoNHa
|
||||||
5FY1Q1lLuO8y33ZZIRK4eynOKkbiuAh7X+ONZ4T9NtTm2J7mnltvTHZ7yeOI+VLS
|
opkLpa9qkwTGQ9M3AZiRUjM4rtvggYt8FBEP+3BLDLHqfUOkPq82MCRXm+6Cz+sT
|
||||||
LrTTBwnnNfdpp8UVPQlwzeizoDqSbr1sjFYvKOfdDDfxuzieT/4tfW9VTAxn4uOg
|
gyPnsPlAh/sr3Pys3olJbUDE9H24k1LU0CI/sSwAFkka0+Q7PVTTe/Dcavitrcrm
|
||||||
qpg7aRMUYUuLAH+S5atdOqXB+g==
|
+fyiT2oSPZeHSjQE9iIW3OY=
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user