Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
5f000ff891 | ||
|
|
e33710eb00 | ||
|
|
2fdd2c51ff | ||
|
|
b73ad12011 | ||
|
|
b276e0b4ef | ||
|
|
a3c0af9648 | ||
|
|
1208a5d08b | ||
|
|
fe8a87b39f | ||
|
|
9a34e9b15c | ||
|
|
78ce84b3a1 | ||
|
|
6d11b0d8ae | ||
|
|
d0fce28ef3 | ||
|
|
31f604cc47 | ||
|
|
c6a921efee | ||
|
|
822a073c4e | ||
|
|
a854c4c627 | ||
|
|
3989661778 | ||
|
|
9a7d44fef6 | ||
|
|
f73347a9cf | ||
|
|
ad1b2db1fd | ||
|
|
11b94de1c0 | ||
|
|
1906896038 | ||
|
|
d5ec1fa505 | ||
|
|
e03ceff7c9 | ||
|
|
64f5ce3624 | ||
|
|
b921bb82d3 | ||
|
|
92e57f2cb1 | ||
|
|
0281e52b47 | ||
|
|
8bdba41f75 | ||
|
|
aa04229d85 | ||
|
|
9e04bfc68a | ||
|
|
8fcdfeb1c4 | ||
|
|
a2d3abfb86 | ||
|
|
e66bcfd77f | ||
|
|
d2ea8d4f06 | ||
|
|
fc19776c04 | ||
|
|
3f07b1e77f | ||
|
|
00568adc6d | ||
|
|
ba1b4f8ef9 | ||
|
|
9b98555886 | ||
|
|
dbfc47591e | ||
|
|
b087f37505 | ||
|
|
08299dd0d1 | ||
|
|
b8f96d0148 | ||
|
|
6bb669d6ac | ||
|
|
80384a65a2 | ||
|
|
c11c0a2bf4 | ||
|
|
29dfe38d32 | ||
|
|
89eae35724 | ||
|
|
b751640b79 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,3 +7,8 @@ build
|
|||||||
coverage
|
coverage
|
||||||
downloads
|
downloads
|
||||||
incubating/mqipt/ms81*
|
incubating/mqipt/ms81*
|
||||||
|
vendor/github.com/prometheus/client_model/bin/
|
||||||
|
vendor/github.com/prometheus/client_model/.classpath
|
||||||
|
vendor/github.com/prometheus/client_model/.project
|
||||||
|
vendor/github.com/prometheus/client_model/.settings*
|
||||||
|
gosec_results.json
|
||||||
|
|||||||
60
.travis.yml
60
.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,43 +29,51 @@ cache:
|
|||||||
directories:
|
directories:
|
||||||
- downloads
|
- downloads
|
||||||
|
|
||||||
env:
|
|
||||||
- BASE_IMAGE=ubuntu:16.04
|
|
||||||
# Commented out temporarily until Issue 166 is resolved
|
|
||||||
# - 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:
|
||||||
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
- ./install-build-deps-ubuntu.sh
|
||||||
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
|
||||||
- sudo apt-get update
|
|
||||||
- sudo apt-get -y install docker-ce
|
|
||||||
- curl https://glide.sh/get | sh
|
|
||||||
- sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64
|
|
||||||
- sudo chmod +x /usr/local/bin/dep
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- echo nothing
|
- echo nothing
|
||||||
|
|
||||||
script:
|
before_script:
|
||||||
|
- echo 'Downloading Go dependencies...' && echo -en 'travis_fold:start:deps\\r'
|
||||||
- make deps
|
- make deps
|
||||||
|
- echo -en 'travis_fold:end:deps\\r'
|
||||||
|
- echo 'Building Developer image...' && echo -en 'travis_fold:start:build-devserver\\r'
|
||||||
- make build-devserver
|
- make build-devserver
|
||||||
|
- echo -en 'travis_fold:end:build-devserver\\r'
|
||||||
|
- echo 'Building Developer JMS test image...' && echo -en 'travis_fold:start:build-devjmstest\\r'
|
||||||
- make build-devjmstest
|
- make build-devjmstest
|
||||||
|
- echo -en 'travis_fold:end:build-devjmstest\\r'
|
||||||
|
|
||||||
|
script:
|
||||||
|
- echo 'Downgrading Docker (if necessary)...' && echo -en 'travis_fold:start:docker-downgrade\\r'
|
||||||
- eval "$DOCKER_DOWNGRADE"
|
- eval "$DOCKER_DOWNGRADE"
|
||||||
|
- echo -en 'travis_fold:end:docker-downgrade\\r'
|
||||||
|
- echo 'Testing Developer image...' && echo -en 'travis_fold:start:test-devserver\\r'
|
||||||
- make test-devserver
|
- make test-devserver
|
||||||
|
- echo -en 'travis_fold:end:test-devserver\\r'
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- go get golang.org/x/lint/golint
|
|
||||||
- make lint
|
- make lint
|
||||||
|
|||||||
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,5 +1,33 @@
|
|||||||
# 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)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.1.1.0
|
||||||
|
* Created seperate RedHat Makefile for building images on RedHat machines with buildah
|
||||||
|
* Enabled REST messaging capability for app user.
|
||||||
|
* Added support for container supplementary groups
|
||||||
|
* Removed IBM MQ version 9.0.5 details.
|
||||||
|
* Added additional Diagnostics ([#203](https://github.com/ibm-messaging/mq-container/pull/203))
|
||||||
|
* Implementted GOSec to perform code scans for security vulnerabilities. (([#227](https://github.com/ibm-messaging/mq-container/pull/227)))
|
||||||
|
* Removed Queue manager create option from the MQ Console.
|
||||||
|
* Fixes for the following issues:
|
||||||
|
* Check explicitly for `/mnt/mqm` ([#175](https://github.com/ibm-messaging/mq-container/pull/175))
|
||||||
|
* Force string output in chkmqhealthy ([#174](https://github.com/ibm-messaging/mq-container/pull/174))
|
||||||
|
* Use -aG not -G when adding a group for a user
|
||||||
|
* Security fixes for libsystemd0 systemd systemd-sysv & libudev1
|
||||||
|
|
||||||
## 9.1.0.0 (2018-07-23)
|
## 9.1.0.0 (2018-07-23)
|
||||||
|
|
||||||
* Updated to MQ version 9.1.0.0
|
* Updated to MQ version 9.1.0.0
|
||||||
|
|||||||
@@ -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.0.5.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,12 @@ ARG BUILDER_IMAGE=mq-golang-sdk:9.0.5.0-x86_64-ubuntu-16.04
|
|||||||
FROM $BUILDER_IMAGE as builder
|
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_CREATED="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=$IMAGE_CREATED\" -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
|
||||||
@@ -48,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 \
|
||||||
@@ -65,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.
|
||||||
|
|||||||
361
Makefile
361
Makefile
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2017, 2018
|
# © Copyright IBM Corporation 2018
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -13,282 +13,163 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Conditional variables - you can override the values of these variables from
|
# Variables
|
||||||
# the command line
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
|
GO_PKG_DIRS = ./cmd ./internal ./test
|
||||||
BASE_IMAGE ?= ubuntu:16.04
|
|
||||||
# MQ_VERSION is the fully qualified MQ version number to build
|
|
||||||
MQ_VERSION ?= 9.1.0.0
|
|
||||||
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
|
|
||||||
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
|
|
||||||
# Does not apply to MQ Advanced for Developers.
|
|
||||||
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH).tar.gz
|
|
||||||
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
|
|
||||||
# for Developers can be installed
|
|
||||||
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
|
||||||
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
|
||||||
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
|
||||||
# Options to `go test` for the Docker tests
|
|
||||||
TEST_OPTS_DOCKER ?=
|
|
||||||
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
|
|
||||||
MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
|
||||||
# MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image
|
|
||||||
MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
|
||||||
# MQ_IMAGE_SDK is the name and tag of the built MQ Advanced for Developers SDK image
|
|
||||||
MQ_IMAGE_SDK ?=mq-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
|
||||||
# MQ_IMAGE_GOLANG_SDK is the name and tag of the built MQ Advanced for Developers SDK image, plus Go tools
|
|
||||||
MQ_IMAGE_GOLANG_SDK ?=mq-golang-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
|
||||||
# DOCKER is the Docker command to run
|
|
||||||
DOCKER ?= docker
|
|
||||||
# MQ_PACKAGES specifies the MQ packages (.deb or .rpm) to install. Defaults vary on base image.
|
|
||||||
MQ_PACKAGES ?=
|
|
||||||
|
|
||||||
###############################################################################
|
# Set variable if running on a Red Hat Enterprise Linux host
|
||||||
# Other variables
|
ifneq ($(wildcard /etc/redhat-release),)
|
||||||
###############################################################################
|
REDHAT_RELEASE = $(shell cat /etc/redhat-release)
|
||||||
# ARCH is the platform architecture (e.g. x86_64, ppc64le or s390x)
|
ifeq "$(findstring Red Hat,$(REDHAT_RELEASE))" "Red Hat"
|
||||||
ARCH = $(shell uname -m)
|
RHEL_HOST = "true"
|
||||||
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
|
|
||||||
BUILD_SERVER_CONTAINER=build-server
|
|
||||||
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
|
|
||||||
# test run in parallel
|
|
||||||
NUM_CPU = $(or $(shell docker info --format "{{ .NCPU }}"),2)
|
|
||||||
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
|
|
||||||
BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
|
|
||||||
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
|
||||||
# Docker image name to use for JMS tests
|
|
||||||
DEV_JMS_IMAGE=mq-dev-jms-test
|
|
||||||
# Variables for versioning
|
|
||||||
IMAGE_REVISION=$(shell git rev-parse HEAD)
|
|
||||||
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
|
|
||||||
IMAGE_CREATED=$(shell date -u +%Y-%m-%dT%H:%M:%S%:z)
|
|
||||||
|
|
||||||
|
|
||||||
ifneq (,$(findstring Microsoft,$(shell uname -r)))
|
|
||||||
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
|
|
||||||
else
|
|
||||||
DOWNLOADS_DIR=$(realpath ./downloads/)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Try to figure out which archive to use from the BASE_IMAGE
|
|
||||||
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
|
||||||
MQ_ARCHIVE_TYPE=UBUNTU
|
|
||||||
MQ_ARCHIVE_DEV_PLATFORM=ubuntu
|
|
||||||
else
|
|
||||||
MQ_ARCHIVE_TYPE=LINUX
|
|
||||||
MQ_ARCHIVE_DEV_PLATFORM=linux
|
|
||||||
endif
|
endif
|
||||||
# Try to figure out which archive to use from the architecture
|
|
||||||
ifeq "$(ARCH)" "x86_64"
|
|
||||||
MQ_ARCHIVE_ARCH=X86-64
|
|
||||||
MQ_DEV_ARCH=x86-64
|
|
||||||
else ifeq "$(ARCH)" "ppc64le"
|
|
||||||
MQ_ARCHIVE_ARCH=LE_POWER
|
|
||||||
MQ_DEV_ARCH=ppcle
|
|
||||||
else ifeq "$(ARCH)" "s390x"
|
|
||||||
MQ_ARCHIVE_ARCH=SYSTEM_Z
|
|
||||||
MQ_DEV_ARCH=s390x
|
|
||||||
endif
|
|
||||||
# Archive names for IBM MQ Advanced for Developers
|
|
||||||
MQ_ARCHIVE_DEV_9.0.5.0=mqadv_dev905_$(MQ_ARCHIVE_DEV_PLATFORM)_x86-64.tar.gz
|
|
||||||
MQ_ARCHIVE_DEV_9.1.0.0=mqadv_dev910_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build targets
|
# Build targets
|
||||||
###############################################################################
|
###############################################################################
|
||||||
.PHONY: vars
|
|
||||||
vars:
|
|
||||||
#ifeq "$(findstring ubuntu,$(BASE_IMAGE))","ubuntu"
|
|
||||||
@echo $(MQ_ARCHIVE_ARCH)
|
|
||||||
@echo $(MQ_ARCHIVE_TYPE)
|
|
||||||
@echo $(MQ_ARCHIVE)
|
|
||||||
|
|
||||||
.PHONY: default
|
# Targets default to a RHEL image on a RHEL host, or an Ubuntu image everywhere else
|
||||||
default: build-devserver test
|
|
||||||
|
|
||||||
# Build all components (except incubating ones)
|
.PHONY: build-devserver
|
||||||
.PHONY: all
|
ifdef RHEL_HOST
|
||||||
all: build-devserver build-advancedserver
|
build-devserver: build-devserver-rhel
|
||||||
|
else
|
||||||
|
build-devserver: build-devserver-ubuntu
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: test-all
|
.PHONY: build-advancedserver
|
||||||
test-all: test-devserver test-advancedserver
|
ifdef RHEL_HOST
|
||||||
|
build-advancedserver: build-advancedserver-rhel
|
||||||
|
else
|
||||||
|
build-advancedserver: build-advancedserver-ubuntu
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: precommit
|
|
||||||
precommit: fmt lint all test-all
|
|
||||||
|
|
||||||
.PHONY: devserver
|
.PHONY: test-devserver
|
||||||
devserver: build-devserver test-devserver
|
ifdef RHEL_HOST
|
||||||
|
test-devserver: test-devserver-rhel
|
||||||
|
else
|
||||||
|
test-devserver: test-devserver-ubuntu
|
||||||
|
endif
|
||||||
|
|
||||||
# Build incubating components
|
.PHONY: test-advancedserver
|
||||||
.PHONY: incubating
|
ifdef RHEL_HOST
|
||||||
incubating: build-explorer
|
test-advancedserver: test-advancedserver-rhel
|
||||||
|
else
|
||||||
|
test-advancedserver: test-advancedserver-ubuntu
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: build-devjmstest
|
||||||
|
ifdef RHEL_HOST
|
||||||
|
build-devjmstest: build-devjmstest-rhel
|
||||||
|
else
|
||||||
|
build-devjmstest: build-devjmstest-ubuntu
|
||||||
|
endif
|
||||||
|
|
||||||
|
# UBUNTU building targets
|
||||||
|
.PHONY: build-devserver-ubuntu
|
||||||
|
build-devserver-ubuntu:
|
||||||
|
$(MAKE) -f Makefile-UBUNTU build-devserver
|
||||||
|
|
||||||
|
.PHONY: test-devserver-ubuntu
|
||||||
|
test-devserver-ubuntu:
|
||||||
|
$(MAKE) -f Makefile-UBUNTU test-devserver
|
||||||
|
|
||||||
|
.PHONY: build-devjmstest-ubuntu
|
||||||
|
$(MAKE) -f Makefile-UBUNTU build-devjmstest
|
||||||
|
|
||||||
|
.PHONY: build-advancedserver-ubuntu
|
||||||
|
build-advancedserver-ubuntu:
|
||||||
|
$(MAKE) -f Makefile-UBUNTU build-advancedserver
|
||||||
|
|
||||||
|
.PHONY: test-advancedserver-ubuntu
|
||||||
|
test-advancedserver-ubuntu:
|
||||||
|
$(MAKE) -f Makefile-UBUNTU test-advancedserver
|
||||||
|
|
||||||
|
.PHONY: build-devjmstest-ubuntu
|
||||||
|
build-devjmstest-ubuntu:
|
||||||
|
$(MAKE) -f Makefile-UBUNTU build-devjmstest
|
||||||
|
|
||||||
|
# RHEL building targets
|
||||||
|
.PHONY: build-devserver-rhel
|
||||||
|
build-devserver-rhel:
|
||||||
|
$(MAKE) -f Makefile-RHEL build-devserver
|
||||||
|
|
||||||
|
.PHONY: test-devserver-rhel
|
||||||
|
test-devserver-rhel:
|
||||||
|
$(MAKE) -f Makefile-RHEL test-devserver
|
||||||
|
|
||||||
|
.PHONY: build-advancedserver-rhel
|
||||||
|
build-advancedserver-rhel:
|
||||||
|
$(MAKE) -f Makefile-RHEL build-advancedserver
|
||||||
|
|
||||||
|
.PHONY: test-advancedserver-rhel
|
||||||
|
test-advancedserver-rhel:
|
||||||
|
$(MAKE) -f Makefile-RHEL test-advancedserver
|
||||||
|
|
||||||
|
.PHONY: build-devjmstest-rhel
|
||||||
|
build-devjmstest-rhel:
|
||||||
|
$(MAKE) -f Makefile-RHEL build-devjmstest
|
||||||
|
|
||||||
|
# Common targets
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf ./coverage
|
rm -rf ./coverage
|
||||||
rm -rf ./build
|
rm -rf ./build
|
||||||
rm -rf ./deps
|
rm -rf ./deps
|
||||||
|
|
||||||
downloads/$(MQ_ARCHIVE_DEV):
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
|
||||||
mkdir -p downloads
|
|
||||||
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
|
|
||||||
|
|
||||||
downloads/$(MQ_SDK_ARCHIVE):
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
|
||||||
mkdir -p downloads
|
|
||||||
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_SDK_ARCHIVE)
|
|
||||||
|
|
||||||
.PHONY: downloads
|
|
||||||
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
|
||||||
|
|
||||||
.PHONY: deps
|
.PHONY: deps
|
||||||
deps:
|
deps:
|
||||||
glide install --strip-vendor
|
glide install --strip-vendor
|
||||||
|
|
||||||
# Vendor Go dependencies for the Docker tests
|
|
||||||
test/docker/vendor:
|
|
||||||
cd test/docker && dep ensure -vendor-only
|
|
||||||
|
|
||||||
.PHONY: build-cov
|
.PHONY: build-cov
|
||||||
build-cov:
|
build-cov:
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build; go test -c -covermode=count ../cmd/runmqserver
|
cd build; go test -c -covermode=count ../cmd/runmqserver
|
||||||
|
|
||||||
# Shortcut to just run the unit tests
|
.PHONY: precommit
|
||||||
.PHONY: test-unit
|
precommit: fmt lint
|
||||||
test-unit:
|
|
||||||
docker build --target builder --file Dockerfile-server .
|
|
||||||
|
|
||||||
.PHONY: test-advancedserver
|
|
||||||
test-advancedserver: test/docker/vendor
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on $(shell docker --version)"$(END)))
|
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
|
|
||||||
|
|
||||||
.PHONY: build-devjmstest
|
|
||||||
build-devjmstest:
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
|
||||||
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
|
|
||||||
|
|
||||||
.PHONY: test-devserver
|
|
||||||
test-devserver: test/docker/vendor
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on $(shell docker --version)"$(END)))
|
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER)
|
|
||||||
|
|
||||||
coverage:
|
|
||||||
mkdir coverage
|
|
||||||
|
|
||||||
.PHONY: test-advancedserver-cover
|
|
||||||
test-advancedserver-cover: test/docker/vendor coverage
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) with code coverage on $(shell docker --version)"$(END)))
|
|
||||||
rm -f ./coverage/unit*.cov
|
|
||||||
# Run unit tests with coverage, for each package under 'internal'
|
|
||||||
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
|
|
||||||
# ls -1 ./cmd | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./cmd/{}/...
|
|
||||||
echo 'mode: count' > ./coverage/unit.cov
|
|
||||||
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
|
|
||||||
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
|
|
||||||
|
|
||||||
rm -f ./test/docker/coverage/*.cov
|
|
||||||
rm -f ./coverage/docker.*
|
|
||||||
mkdir -p ./test/docker/coverage/
|
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER)-cover TEST_COVER=true go test $(TEST_OPTS_DOCKER)
|
|
||||||
echo 'mode: count' > ./coverage/docker.cov
|
|
||||||
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
|
|
||||||
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
|
|
||||||
|
|
||||||
echo 'mode: count' > ./coverage/combined.cov
|
|
||||||
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
|
|
||||||
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
|
||||||
|
|
||||||
define docker-build-mq
|
|
||||||
# Create a temporary network to use for the build
|
|
||||||
$(DOCKER) network create build
|
|
||||||
# Start a web server to host the MQ downloadable (tar.gz) file
|
|
||||||
$(DOCKER) run \
|
|
||||||
--rm \
|
|
||||||
--name $(BUILD_SERVER_CONTAINER) \
|
|
||||||
--network build \
|
|
||||||
--network-alias build \
|
|
||||||
--volume $(DOWNLOADS_DIR):/usr/share/nginx/html:ro \
|
|
||||||
--detach \
|
|
||||||
nginx:alpine
|
|
||||||
# Build the new image
|
|
||||||
$(DOCKER) build \
|
|
||||||
--tag $1 \
|
|
||||||
--file $2 \
|
|
||||||
--network build \
|
|
||||||
--build-arg MQ_URL=http://build:80/$3 \
|
|
||||||
--build-arg BASE_IMAGE=$(BASE_IMAGE) \
|
|
||||||
--build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) \
|
|
||||||
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
|
||||||
--build-arg IMAGE_CREATED="$(IMAGE_CREATED)" \
|
|
||||||
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
|
||||||
--label IBM_PRODUCT_ID=$4 \
|
|
||||||
--label IBM_PRODUCT_NAME=$5 \
|
|
||||||
--label IBM_PRODUCT_VERSION=$6 \
|
|
||||||
--build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \
|
|
||||||
. ; $(DOCKER) kill $(BUILD_SERVER_CONTAINER) && $(DOCKER) network rm build
|
|
||||||
endef
|
|
||||||
|
|
||||||
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
|
|
||||||
DOCKER_CLIENT_VERSION=$(shell docker version --format "{{ .Client.Version }}")
|
|
||||||
.PHONY: docker-version
|
|
||||||
docker-version:
|
|
||||||
@test "$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
|
|
||||||
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
|
|
||||||
|
|
||||||
.PHONY: build-advancedserver
|
|
||||||
build-advancedserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE)
|
|
||||||
build-advancedserver: downloads/$(MQ_ARCHIVE) docker-version build-golang-sdk
|
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
|
|
||||||
$(call docker-build-mq,$(MQ_IMAGE_ADVANCEDSERVER),Dockerfile-server,$(MQ_ARCHIVE),"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced",$(MQ_VERSION))
|
|
||||||
|
|
||||||
.PHONY: build-devserver
|
|
||||||
# Target-specific variable to add web server into devserver image
|
|
||||||
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
|
||||||
build-devserver: MQ_PACKAGES=ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams ibmmq-web
|
|
||||||
else
|
|
||||||
build-devserver: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm MQSeriesWeb-*.rpm
|
|
||||||
endif
|
|
||||||
build-devserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE_DEV)
|
|
||||||
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version build-golang-sdk
|
|
||||||
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER_BASE)"$(END)))
|
|
||||||
$(call docker-build-mq,$(MQ_IMAGE_DEVSERVER_BASE),Dockerfile-server,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
|
|
||||||
$(DOCKER) build --tag $(MQ_IMAGE_DEVSERVER) --build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" --build-arg IMAGE_REVISION="$(IMAGE_REVISION)" --build-arg IMAGE_CREATED="$(IMAGE_CREATED)" --build-arg BASE_IMAGE=$(MQ_IMAGE_DEVSERVER_BASE) --build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) --file incubating/mqadvanced-server-dev/Dockerfile .
|
|
||||||
|
|
||||||
.PHONY: build-advancedserver-cover
|
|
||||||
build-advancedserver-cover: docker-version
|
|
||||||
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_IMAGE_ADVANCEDSERVER)-cover -f Dockerfile-server.cover .
|
|
||||||
|
|
||||||
.PHONY: build-explorer docker-pull
|
|
||||||
build-explorer: downloads/$(MQ_ARCHIVE_DEV)
|
|
||||||
$(call docker-build-mq,mq-explorer:latest-$(ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
|
|
||||||
|
|
||||||
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
|
||||||
build-sdk: MQ_PACKAGES=ibmmq-sdk ibmmq-samples build-essential
|
|
||||||
else
|
|
||||||
build-sdk: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm
|
|
||||||
endif
|
|
||||||
build-sdk: downloads/$(MQ_SDK_ARCHIVE) docker-version docker-pull
|
|
||||||
$(call docker-build-mq,$(MQ_IMAGE_SDK),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))
|
|
||||||
|
|
||||||
build-golang-sdk: downloads/$(MQ_SDK_ARCHIVE) docker-version build-sdk
|
|
||||||
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_SDK) -t $(MQ_IMAGE_GOLANG_SDK) -f incubating/mq-golang-sdk/Dockerfile .
|
|
||||||
# $(call docker-build-mq,$(MQ_IMAGE_GOLANG_SDK),incubating/mq-golang-sdk/Dockerfile,$(MQ_IMAGE_SDK),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))
|
|
||||||
|
|
||||||
docker-pull:
|
|
||||||
$(DOCKER) pull $(BASE_IMAGE)
|
|
||||||
|
|
||||||
GO_PKG_DIRS = ./cmd ./internal ./test
|
|
||||||
|
|
||||||
|
.PHONY: fmt
|
||||||
fmt: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
fmt: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
||||||
go fmt $(addsuffix /..., $(GO_PKG_DIRS))
|
go fmt $(addsuffix /..., $(GO_PKG_DIRS))
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
||||||
@# This expression is necessary because /... includes the vendor directory in golint
|
@# This expression is necessary because /... includes the vendor directory in golint
|
||||||
@# As of 11/04/2018 there is an open issue to fix it: https://github.com/golang/lint/issues/320
|
@# As of 11/04/2018 there is an open issue to fix it: https://github.com/golang/lint/issues/320
|
||||||
golint -set_exit_status $(sort $(dir $(wildcard $(addsuffix /*/*.go, $(GO_PKG_DIRS)))))
|
golint -set_exit_status $(sort $(dir $(wildcard $(addsuffix /*/*.go, $(GO_PKG_DIRS)))))
|
||||||
|
|
||||||
|
.PHONY: gosec
|
||||||
|
gosec: $(info $(SPACER)$(shell printf "Running gosec test"$(END)))
|
||||||
|
@gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\
|
||||||
|
cat "gosec_results.json" ;\
|
||||||
|
cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\
|
||||||
|
if [ $$? -eq 0 ]; then \
|
||||||
|
printf "\nFAILURE: gosec found files containing HIGH severity issues - see results.json\n" ;\
|
||||||
|
exit 1 ;\
|
||||||
|
else \
|
||||||
|
printf "\ngosec found no HIGH severity issues\n" ;\
|
||||||
|
fi ;\
|
||||||
|
cat gosec_results.json | grep MEDIUM | grep severity > /dev/null ;\
|
||||||
|
if [ $$? -eq 0 ]; then \
|
||||||
|
printf "\nFAILURE: gosec found files containing MEDIUM severity issues - see results.json\n" ;\
|
||||||
|
exit 1 ;\
|
||||||
|
else \
|
||||||
|
printf "\ngosec found no MEDIUM severity issues\n" ;\
|
||||||
|
fi ;\
|
||||||
|
cat gosec_results.json | grep LOW | grep severity > /dev/null;\
|
||||||
|
if [ $$? -eq 0 ]; then \
|
||||||
|
printf "\nFAILURE: gosec found files containing LOW severity issues - see results.json\n" ;\
|
||||||
|
exit 1;\
|
||||||
|
else \
|
||||||
|
printf "\ngosec found no LOW severity issues\n" ;\
|
||||||
|
fi ;\
|
||||||
|
|
||||||
|
.PHONY: unknownos
|
||||||
|
unknownos:
|
||||||
|
$(info $(SPACER)$(shell printf "ERROR: Unknown OS ("$(BASE_OS)") please run specific make targets"$(END)))
|
||||||
|
exit 1
|
||||||
|
|
||||||
include formatting.mk
|
include formatting.mk
|
||||||
|
|||||||
204
Makefile-RHEL
Normal file
204
Makefile-RHEL
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Conditional variables - you can override the values of these variables from
|
||||||
|
# the command line
|
||||||
|
###############################################################################
|
||||||
|
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
|
||||||
|
BASE_IMAGE ?= rhel
|
||||||
|
# MQ_VERSION is the fully qualified MQ version number to build
|
||||||
|
MQ_VERSION ?= 9.1.2.0
|
||||||
|
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
|
||||||
|
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
|
||||||
|
# Does not apply to MQ Advanced for Developers.
|
||||||
|
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_LINUX_$(MQ_ARCHIVE_ARCH).tar.gz
|
||||||
|
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
|
||||||
|
# for Developers can be installed
|
||||||
|
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
|
# MQ_SDK_ARCHIVE specifies the archive to use for the MQ redistributable client, which is used for building the golang programs.
|
||||||
|
MQ_SDK_ARCHIVE ?= 9.1.2.0-IBM-MQC-Redist-LinuxX64.tar.gz
|
||||||
|
# Options to `go test` for the Docker tests
|
||||||
|
TEST_OPTS_DOCKER ?=
|
||||||
|
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
|
||||||
|
MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-RHEL-$(ARCH)
|
||||||
|
# MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image
|
||||||
|
MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev:$(MQ_VERSION)-RHEL-$(ARCH)
|
||||||
|
# MQ_IMAGE_SDK is the name and tag of the built MQ Advanced for Developers SDK image
|
||||||
|
MQ_IMAGE_SDK ?=mq-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# MQ_IMAGE_GOLANG_SDK is the name and tag of the built MQ Advanced for Developers SDK image, plus Go tools
|
||||||
|
MQ_IMAGE_GOLANG_SDK ?=mq-golang-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# MQ_PACKAGES specifies the MQ packages to install. Defaults vary on base image.
|
||||||
|
MQ_PACKAGES ?= MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Other variables
|
||||||
|
###############################################################################
|
||||||
|
# ARCH is the platform architecture (e.g. x86_64, ppc64le or s390x)
|
||||||
|
ARCH = $(shell uname -m)
|
||||||
|
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
|
||||||
|
BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
|
||||||
|
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# Docker image name to use for JMS tests
|
||||||
|
DEV_JMS_IMAGE=mq-dev-jms-test:latest
|
||||||
|
# Variables for versioning
|
||||||
|
IMAGE_REVISION=$(shell git rev-parse HEAD)
|
||||||
|
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
|
||||||
|
MQDEV=
|
||||||
|
EMPTY:=
|
||||||
|
SPACE:= $(EMPTY) $(EMPTY)
|
||||||
|
# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.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)))
|
||||||
|
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
|
||||||
|
else
|
||||||
|
DOWNLOADS_DIR=$(realpath ./downloads/)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Try to figure out which archive to use from the architecture
|
||||||
|
ifeq "$(ARCH)" "x86_64"
|
||||||
|
MQ_ARCHIVE_ARCH=X86-64
|
||||||
|
MQ_DEV_ARCH=x86-64
|
||||||
|
else ifeq "$(ARCH)" "ppc64le"
|
||||||
|
MQ_ARCHIVE_ARCH=LE_POWER
|
||||||
|
MQ_DEV_ARCH=ppcle
|
||||||
|
else ifeq "$(ARCH)" "s390x"
|
||||||
|
MQ_ARCHIVE_ARCH=SYSTEM_Z
|
||||||
|
MQ_DEV_ARCH=s390x
|
||||||
|
endif
|
||||||
|
# Archive names for IBM MQ Advanced for Developers
|
||||||
|
MQ_ARCHIVE_DEV_9.1.0.0=mqadv_dev910_linux_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_linux_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
MQ_ARCHIVE_DEV_9.1.2.0=mqadv_dev912_linux_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Build targets
|
||||||
|
###############################################################################
|
||||||
|
.PHONY: vars
|
||||||
|
vars:
|
||||||
|
#ifeq "$(findstring ubuntu,$(BASE_IMAGE))","ubuntu"
|
||||||
|
@echo $(MQ_ARCHIVE_ARCH)
|
||||||
|
@echo $(MQ_ARCHIVE_TYPE)
|
||||||
|
@echo $(MQ_ARCHIVE)
|
||||||
|
|
||||||
|
.PHONY: default
|
||||||
|
default: build-devserver test-devserver
|
||||||
|
|
||||||
|
# Build all components (except incubating ones)
|
||||||
|
.PHONY: all
|
||||||
|
all: build-devserver build-advancedserver
|
||||||
|
|
||||||
|
.PHONY: test-all
|
||||||
|
test-all: build-devjmstest test-devserver test-advancedserver
|
||||||
|
|
||||||
|
.PHONY: devserver
|
||||||
|
devserver: build-devserver build-devjmstest test-devserver
|
||||||
|
|
||||||
|
# Build incubating components
|
||||||
|
.PHONY: incubating
|
||||||
|
incubating: build-explorer
|
||||||
|
|
||||||
|
downloads/$(MQ_ARCHIVE_DEV):
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
||||||
|
mkdir -p downloads
|
||||||
|
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
|
||||||
|
|
||||||
|
downloads/$(MQ_SDK_ARCHIVE):
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced redistributable client "$(MQ_VERSION)$(END)))
|
||||||
|
mkdir -p downloads
|
||||||
|
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist/$(MQ_SDK_ARCHIVE)
|
||||||
|
|
||||||
|
.PHONY: downloads
|
||||||
|
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
||||||
|
|
||||||
|
# Vendor Go dependencies for the Docker tests
|
||||||
|
test/docker/vendor:
|
||||||
|
cd test/docker && dep ensure -vendor-only
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: check-prereqs
|
||||||
|
check-prereqs:
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Checking for prereqs"$(END)))
|
||||||
|
which buildah || (echo "Missing required program buildah" && exit 1)
|
||||||
|
which podman || (echo "Missing required program podman" && exit 1)
|
||||||
|
yum list | grep yum-utils || (echo "Missing required package yum-utils" && exit 1)
|
||||||
|
|
||||||
|
.PHONY: check-test-prereqs
|
||||||
|
check-test-prereqs:
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Checking for prereqs"$(END)))
|
||||||
|
which buildah || (echo "Missing required program buildah" && exit 1)
|
||||||
|
which docker || (echo "Missing required program docker" && exit 1)
|
||||||
|
|
||||||
|
.PHONY: test-advancedserver
|
||||||
|
test-advancedserver: check-test-prereqs test/docker/vendor
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on $(shell docker --version)"$(END)))
|
||||||
|
sudo buildah push $(MQ_IMAGE_ADVANCEDSERVER) docker-daemon:$(MQ_IMAGE_ADVANCEDSERVER)
|
||||||
|
docker tag docker.io/$(MQ_IMAGE_ADVANCEDSERVER) $(MQ_IMAGE_ADVANCEDSERVER)
|
||||||
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) EXPECTED_LICENSE=Production go test $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: test-devserver
|
||||||
|
test-devserver: check-test-prereqs test/docker/vendor
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on $(shell docker --version)"$(END)))
|
||||||
|
sudo buildah push $(MQ_IMAGE_DEVSERVER) docker-daemon:$(MQ_IMAGE_DEVSERVER)
|
||||||
|
docker tag docker.io/$(MQ_IMAGE_DEVSERVER) $(MQ_IMAGE_DEVSERVER)
|
||||||
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) go test -tags mqdev $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: build-advancedserver
|
||||||
|
build-advancedserver: check-prereqs downloads/$(MQ_ARCHIVE) build-go-programs
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
|
||||||
|
sudo mq-advanced-server-rhel/mq-buildah.sh "$(MQ_ARCHIVE)" "$(MQ_PACKAGES)" "$(MQ_IMAGE_ADVANCEDSERVER)" "$(MQ_VERSION)" "$(MQDEV)"
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: build-devserver
|
||||||
|
build-devserver: MQDEV=TRUE
|
||||||
|
build-devserver: 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
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER)"$(END)))
|
||||||
|
sudo mq-advanced-server-rhel/mq-buildah.sh "$(MQ_ARCHIVE_DEV)" "$(MQ_PACKAGES)" "$(MQ_IMAGE_DEVSERVER_BASE)" "$(MQ_VERSION)" "$(MQDEV)"
|
||||||
|
sudo mq-advanced-server-rhel/mqdev-buildah.sh "$(MQ_IMAGE_DEVSERVER_BASE)" "$(MQ_IMAGE_DEVSERVER)" "$(MQ_VERSION)"
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: build-mqgolang-sdk
|
||||||
|
build-mqgolang-sdk: check-prereqs downloads/$(MQ_SDK_ARCHIVE)
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Build mq-golang SDK"$(END)))
|
||||||
|
sudo mq-advanced-server-rhel/mq-golang-sdk-buildah.sh "$(MQ_SDK_ARCHIVE)" "$(MQ_IMAGE_GOLANG_SDK)"
|
||||||
|
|
||||||
|
.PHONY: build-go-programs
|
||||||
|
build-go-programs: check-prereqs downloads/$(MQ_SDK_ARCHIVE) build-mqgolang-sdk
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Build go programs"$(END)))
|
||||||
|
IMAGE_REVISION=$(IMAGE_REVISION) IMAGE_SOURCE=$(IMAGE_SOURCE) sudo --preserve-env mq-advanced-server-rhel/go-buildah.sh "$(MQ_IMAGE_GOLANG_SDK)" "$(MQDEV)"
|
||||||
|
|
||||||
|
.PHONY: build-devjmstest
|
||||||
|
build-devjmstest: check-test-prereqs
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
||||||
|
cd test/messaging && sudo ./buildah.sh $(DEV_JMS_IMAGE)
|
||||||
|
sudo buildah push $(DEV_JMS_IMAGE) docker-daemon:$(DEV_JMS_IMAGE)
|
||||||
|
docker tag docker.io/$(DEV_JMS_IMAGE) $(DEV_JMS_IMAGE)
|
||||||
|
|
||||||
|
.PHONY: debug-vars
|
||||||
|
debug-vars:
|
||||||
|
@echo MQ_VERSION=$(MQ_VERSION)
|
||||||
|
@echo MQ_VERSION_VRM=$(MQ_VERSION_VRM)
|
||||||
|
@echo MQ_ARCHIVE=$(MQ_ARCHIVE)
|
||||||
|
@echo MQ_SDK_ARCHIVE=$(MQ_SDK_ARCHIVE)
|
||||||
|
@echo MQ_IMAGE_GOLANG_SDK=$(MQ_IMAGE_GOLANG_SDK)
|
||||||
|
@echo MQ_IMAGE_DEVSERVER_BASE=$(MQ_IMAGE_DEVSERVER_BASE)
|
||||||
|
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
|
||||||
|
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
|
||||||
|
|
||||||
|
include formatting.mk
|
||||||
291
Makefile-UBUNTU
Normal file
291
Makefile-UBUNTU
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
# © Copyright IBM Corporation 2017, 2019
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Conditional variables - you can override the values of these variables from
|
||||||
|
# the command line
|
||||||
|
###############################################################################
|
||||||
|
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
|
||||||
|
BASE_IMAGE ?= ubuntu:16.04
|
||||||
|
# MQ_VERSION is the fully qualified MQ version number to build
|
||||||
|
MQ_VERSION ?= 9.1.2.0
|
||||||
|
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
|
||||||
|
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
|
||||||
|
# Does not apply to MQ Advanced for Developers.
|
||||||
|
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH).tar.gz
|
||||||
|
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
|
||||||
|
# for Developers can be installed
|
||||||
|
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
|
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
||||||
|
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
|
# Options to `go test` for the Docker tests
|
||||||
|
TEST_OPTS_DOCKER ?=
|
||||||
|
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
|
||||||
|
MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image
|
||||||
|
MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# MQ_IMAGE_SDK is the name and tag of the built MQ Advanced for Developers SDK image
|
||||||
|
MQ_IMAGE_SDK ?=mq-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# MQ_IMAGE_GOLANG_SDK is the name and tag of the built MQ Advanced for Developers SDK image, plus Go tools
|
||||||
|
MQ_IMAGE_GOLANG_SDK ?=mq-golang-sdk:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# DOCKER is the Docker command to run
|
||||||
|
DOCKER ?= docker
|
||||||
|
# MQ_PACKAGES specifies the MQ packages (.deb or .rpm) to install. Defaults vary on base image.
|
||||||
|
MQ_PACKAGES ?=
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Other variables
|
||||||
|
###############################################################################
|
||||||
|
# ARCH is the platform architecture (e.g. x86_64, ppc64le or s390x)
|
||||||
|
ARCH = $(shell uname -m)
|
||||||
|
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
|
||||||
|
BUILD_SERVER_CONTAINER=build-server
|
||||||
|
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
|
||||||
|
# test run in parallel
|
||||||
|
NUM_CPU = $(or $(shell docker info --format "{{ .NCPU }}"),2)
|
||||||
|
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
|
||||||
|
BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
|
||||||
|
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
|
||||||
|
# Docker image name to use for JMS tests
|
||||||
|
DEV_JMS_IMAGE=mq-dev-jms-test
|
||||||
|
# Variables for versioning
|
||||||
|
IMAGE_REVISION=$(shell git rev-parse HEAD)
|
||||||
|
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
|
||||||
|
EMPTY:=
|
||||||
|
SPACE:= $(EMPTY) $(EMPTY)
|
||||||
|
# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.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)))
|
||||||
|
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
|
||||||
|
else
|
||||||
|
DOWNLOADS_DIR=$(realpath ./downloads/)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Try to figure out which archive to use from the BASE_IMAGE
|
||||||
|
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
||||||
|
MQ_ARCHIVE_TYPE=UBUNTU
|
||||||
|
MQ_ARCHIVE_DEV_PLATFORM=ubuntu
|
||||||
|
MQM_UID=999
|
||||||
|
else
|
||||||
|
MQ_ARCHIVE_TYPE=LINUX
|
||||||
|
MQ_ARCHIVE_DEV_PLATFORM=linux
|
||||||
|
MQM_UID=888
|
||||||
|
endif
|
||||||
|
# Try to figure out which archive to use from the architecture
|
||||||
|
ifeq "$(ARCH)" "x86_64"
|
||||||
|
MQ_ARCHIVE_ARCH=X86-64
|
||||||
|
MQ_DEV_ARCH=x86-64
|
||||||
|
else ifeq "$(ARCH)" "ppc64le"
|
||||||
|
MQ_ARCHIVE_ARCH=LE_POWER
|
||||||
|
MQ_DEV_ARCH=ppcle
|
||||||
|
else ifeq "$(ARCH)" "s390x"
|
||||||
|
MQ_ARCHIVE_ARCH=SYSTEM_Z
|
||||||
|
MQ_DEV_ARCH=s390x
|
||||||
|
endif
|
||||||
|
# Archive names for IBM MQ Advanced for Developers
|
||||||
|
MQ_ARCHIVE_DEV_9.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.2.0=mqadv_dev912_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Build targets
|
||||||
|
###############################################################################
|
||||||
|
.PHONY: vars
|
||||||
|
vars:
|
||||||
|
#ifeq "$(findstring ubuntu,$(BASE_IMAGE))","ubuntu"
|
||||||
|
@echo $(MQ_ARCHIVE_ARCH)
|
||||||
|
@echo $(MQ_ARCHIVE_TYPE)
|
||||||
|
@echo $(MQ_ARCHIVE)
|
||||||
|
|
||||||
|
.PHONY: default
|
||||||
|
default: build-devserver test
|
||||||
|
|
||||||
|
# Build all components (except incubating ones)
|
||||||
|
.PHONY: all
|
||||||
|
all: build-devserver build-advancedserver
|
||||||
|
|
||||||
|
.PHONY: test-all
|
||||||
|
test-all: build-devjmstest test-devserver test-advancedserver
|
||||||
|
|
||||||
|
.PHONY: devserver
|
||||||
|
devserver: build-devserver build-devjmstest test-devserver
|
||||||
|
|
||||||
|
# Build incubating components
|
||||||
|
.PHONY: incubating
|
||||||
|
incubating: build-explorer
|
||||||
|
|
||||||
|
downloads/$(MQ_ARCHIVE_DEV):
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
||||||
|
mkdir -p downloads
|
||||||
|
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
|
||||||
|
|
||||||
|
downloads/$(MQ_SDK_ARCHIVE):
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
||||||
|
mkdir -p downloads
|
||||||
|
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_SDK_ARCHIVE)
|
||||||
|
|
||||||
|
.PHONY: downloads
|
||||||
|
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
||||||
|
|
||||||
|
# Vendor Go dependencies for the Docker tests
|
||||||
|
test/docker/vendor:
|
||||||
|
cd test/docker && dep ensure -vendor-only
|
||||||
|
|
||||||
|
# Shortcut to just run the unit tests
|
||||||
|
.PHONY: test-unit
|
||||||
|
test-unit:
|
||||||
|
docker build --target builder --file Dockerfile-server .
|
||||||
|
|
||||||
|
.PHONY: test-advancedserver
|
||||||
|
test-advancedserver: test/docker/vendor
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on $(shell docker --version)"$(END)))
|
||||||
|
docker inspect $(MQ_IMAGE_ADVANCEDSERVER)
|
||||||
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
|
.PHONY: build-devjmstest
|
||||||
|
build-devjmstest:
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
||||||
|
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
|
||||||
|
|
||||||
|
.PHONY: test-devserver
|
||||||
|
test-devserver: test/docker/vendor
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on $(shell docker --version)"$(END)))
|
||||||
|
docker inspect $(MQ_IMAGE_DEVSERVER)
|
||||||
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=true go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
mkdir coverage
|
||||||
|
|
||||||
|
.PHONY: test-advancedserver-cover
|
||||||
|
test-advancedserver-cover: test/docker/vendor coverage
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) with code coverage on $(shell docker --version)"$(END)))
|
||||||
|
rm -f ./coverage/unit*.cov
|
||||||
|
# Run unit tests with coverage, for each package under 'internal'
|
||||||
|
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
|
||||||
|
# ls -1 ./cmd | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./cmd/{}/...
|
||||||
|
echo 'mode: count' > ./coverage/unit.cov
|
||||||
|
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
|
||||||
|
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
|
||||||
|
|
||||||
|
rm -f ./test/docker/coverage/*.cov
|
||||||
|
rm -f ./coverage/docker.*
|
||||||
|
mkdir -p ./test/docker/coverage/
|
||||||
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER)-cover TEST_COVER=true go test $(TEST_OPTS_DOCKER)
|
||||||
|
echo 'mode: count' > ./coverage/docker.cov
|
||||||
|
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
|
||||||
|
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
|
||||||
|
|
||||||
|
echo 'mode: count' > ./coverage/combined.cov
|
||||||
|
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
|
||||||
|
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
||||||
|
|
||||||
|
define docker-build-mq
|
||||||
|
# Create a temporary network to use for the build
|
||||||
|
$(DOCKER) network create build
|
||||||
|
# Start a web server to host the MQ downloadable (tar.gz) file
|
||||||
|
$(DOCKER) run \
|
||||||
|
--rm \
|
||||||
|
--name $(BUILD_SERVER_CONTAINER) \
|
||||||
|
--network build \
|
||||||
|
--network-alias build \
|
||||||
|
--volume $(DOWNLOADS_DIR):/usr/share/nginx/html:ro \
|
||||||
|
--detach \
|
||||||
|
nginx:alpine
|
||||||
|
# Build the new image
|
||||||
|
$(DOCKER) build \
|
||||||
|
--tag $1 \
|
||||||
|
--file $2 \
|
||||||
|
--network build \
|
||||||
|
--build-arg MQ_URL=http://build:80/$3 \
|
||||||
|
--build-arg BASE_IMAGE=$(BASE_IMAGE) \
|
||||||
|
--build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) \
|
||||||
|
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
||||||
|
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
||||||
|
--build-arg IMAGE_TAG="$1" \
|
||||||
|
--build-arg MQM_UID=$(MQM_UID) \
|
||||||
|
--label IBM_PRODUCT_ID=$4 \
|
||||||
|
--label IBM_PRODUCT_NAME=$5 \
|
||||||
|
--label IBM_PRODUCT_VERSION=$6 \
|
||||||
|
--build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \
|
||||||
|
. ; $(DOCKER) kill $(BUILD_SERVER_CONTAINER) && $(DOCKER) network rm build
|
||||||
|
endef
|
||||||
|
|
||||||
|
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
|
||||||
|
DOCKER_CLIENT_VERSION=$(shell docker version --format "{{ .Client.Version }}")
|
||||||
|
.PHONY: docker-version
|
||||||
|
docker-version:
|
||||||
|
@test "$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
|
||||||
|
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
|
||||||
|
|
||||||
|
.PHONY: build-advancedserver
|
||||||
|
build-advancedserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE)
|
||||||
|
build-advancedserver: downloads/$(MQ_ARCHIVE) docker-version build-golang-sdk-ex
|
||||||
|
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
|
||||||
|
$(call docker-build-mq,$(MQ_IMAGE_ADVANCEDSERVER),Dockerfile-server,$(MQ_ARCHIVE),"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced",$(MQ_VERSION))
|
||||||
|
|
||||||
|
.PHONY: build-devserver
|
||||||
|
# Target-specific variable to add web server into devserver image
|
||||||
|
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
||||||
|
build-devserver: MQ_PACKAGES=ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams ibmmq-web
|
||||||
|
else
|
||||||
|
build-devserver: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm MQSeriesWeb-*.rpm
|
||||||
|
endif
|
||||||
|
build-devserver: MQ_SDK_ARCHIVE=$(MQ_ARCHIVE_DEV)
|
||||||
|
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version build-golang-sdk-ex
|
||||||
|
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER_BASE)"$(END)))
|
||||||
|
$(call docker-build-mq,$(MQ_IMAGE_DEVSERVER_BASE),Dockerfile-server,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
|
||||||
|
$(DOCKER) build --tag $(MQ_IMAGE_DEVSERVER) --build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" --build-arg IMAGE_REVISION="$(IMAGE_REVISION)" --build-arg IMAGE_TAG="$(MQ_IMAGE_DEVSERVER)" --build-arg BASE_IMAGE=$(MQ_IMAGE_DEVSERVER_BASE) --build-arg BUILDER_IMAGE=$(MQ_IMAGE_GOLANG_SDK) --build-arg MQM_UID=$(MQM_UID) --file incubating/mqadvanced-server-dev/Dockerfile .
|
||||||
|
|
||||||
|
.PHONY: build-advancedserver-cover
|
||||||
|
build-advancedserver-cover: docker-version
|
||||||
|
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_IMAGE_ADVANCEDSERVER)-cover -f Dockerfile-server.cover .
|
||||||
|
|
||||||
|
.PHONY: build-explorer
|
||||||
|
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
||||||
|
build-explorer: MQ_PACKAGES=ibmmq-explorer
|
||||||
|
else
|
||||||
|
build-explorer: MQ_PACKAGES=MQSeriesRuntime*.rpm MQSeriesJRE*.rpm MQSeriesExplorer*.rpm
|
||||||
|
endif
|
||||||
|
build-explorer: downloads/$(MQ_ARCHIVE_DEV) docker-pull
|
||||||
|
$(call docker-build-mq,mq-explorer:latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
|
||||||
|
|
||||||
|
.PHONY: build-sdk
|
||||||
|
build-sdk: downloads/$(MQ_SDK_ARCHIVE) build-sdk-ex
|
||||||
|
|
||||||
|
.PHONY: build-sdk-ex
|
||||||
|
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
|
||||||
|
build-sdk-ex: MQ_PACKAGES=ibmmq-sdk ibmmq-samples build-essential
|
||||||
|
else
|
||||||
|
build-sdk-ex: MQ_PACKAGES=MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm
|
||||||
|
endif
|
||||||
|
build-sdk-ex: docker-version docker-pull
|
||||||
|
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_SDK)"$(END)))
|
||||||
|
$(call docker-build-mq,$(MQ_IMAGE_SDK),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))
|
||||||
|
|
||||||
|
.PHONY: build-golang-sdk
|
||||||
|
build-golang-sdk: downloads/$(MQ_SDK_ARCHIVE) build-golang-sdk-ex
|
||||||
|
|
||||||
|
.PHONY: build-golang-sdk-ex
|
||||||
|
build-golang-sdk-ex: docker-version build-sdk-ex
|
||||||
|
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_GOLANG_SDK)"$(END)))
|
||||||
|
@echo hello
|
||||||
|
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_SDK) -t $(MQ_IMAGE_GOLANG_SDK) -f incubating/mq-golang-sdk/Dockerfile .
|
||||||
|
@echo goodbye
|
||||||
|
|
||||||
|
.PHONY: docker-pull
|
||||||
|
docker-pull:
|
||||||
|
$(DOCKER) pull $(BASE_IMAGE)
|
||||||
|
|
||||||
|
include formatting.mk
|
||||||
33
README.md
33
README.md
@@ -1,26 +1,29 @@
|
|||||||

|
# IBM MQ container
|
||||||
|
|
||||||
# Overview
|
[](https://travis-ci.org/ibm-messaging/mq-container)
|
||||||
|
|
||||||
|
**Note**: The `master` branch may be in an *unstable or even broken state* during development.
|
||||||
|
To get a stable version, please use the correct [branch](https://github.com/ibm-messaging/mq-container/branches) for your MQ version, instead of the `master` branch.
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/IBM/charts/master/logo/ibm-mq-icon.svg?sanitize=true" width="100" alt="IBM MQ logo" />
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container.
|
Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container.
|
||||||
|
|
||||||
You can build an image containing either IBM MQ Advanced, or IBM MQ Advanced for Developers. The developer image includes a [default developer configuration](docs/developer-config.md), to make it easier to get started. There is also an [incubating](incubating) folder for additional images for other MQ components, which you might find useful.
|
You can build an image containing either IBM MQ Advanced, or IBM MQ Advanced for Developers. The developer image includes a [default developer configuration](docs/developer-config.md), to make it easier to get started. There is also an [incubating](incubating) folder for additional images for other MQ components, which you might find useful.
|
||||||
|
|
||||||
# Current status
|
## Build
|
||||||
|
|
||||||
MQ Advanced for Developers image [](https://travis-ci.org/ibm-messaging/mq-container)
|
|
||||||
|
|
||||||
# Build
|
|
||||||
|
|
||||||
After extracting the code from this repository, you can follow the [build documentation](docs/building.md) to build an image.
|
After extracting the code from this repository, you can follow the [build documentation](docs/building.md) to build an image.
|
||||||
|
|
||||||
# Usage
|
## Usage
|
||||||
|
|
||||||
See the [usage documentation](docs/usage.md) for details on how to run a container.
|
See the [usage documentation](docs/usage.md) for details on how to run a container.
|
||||||
|
|
||||||
Note that in order to use the image, it is necessary to accept the terms of the [IBM MQ license](#license).
|
Note that in order to use the image, it is necessary to accept the terms of the [IBM MQ license](#license).
|
||||||
|
|
||||||
## Environment variables supported by this image
|
### Environment variables supported by this image
|
||||||
|
|
||||||
- **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
|
- **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
|
||||||
- **LANG** - Set this to the language you would like the license to be printed in.
|
- **LANG** - Set this to the language you would like the license to be printed in.
|
||||||
@@ -30,25 +33,25 @@ Note that in order to use the image, it is necessary to accept the terms of the
|
|||||||
|
|
||||||
See the [default developer configuration docs](docs/developer-config.md) for the extra environment variables supported by the MQ Advanced for Developers image.
|
See the [default developer configuration docs](docs/developer-config.md) for the extra environment variables supported by the MQ Advanced for Developers image.
|
||||||
|
|
||||||
## Kubernetes
|
### Kubernetes
|
||||||
|
|
||||||
If you want to use IBM MQ in [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM charts](https://github.com/IBM/charts). This can be used to run the container on a cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
|
If you want to use IBM MQ in [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM charts](https://github.com/IBM/charts). This can be used to run the container on a cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
|
||||||
|
|
||||||
# Issues and contributions
|
## Issues and contributions
|
||||||
|
|
||||||
For issues relating specifically to the container image or Helm chart, please use the [GitHub issue tracker](https://github.com/ibm-messaging/mq-container/issues). If you do submit a Pull Request related to this Docker image, please indicate in the Pull Request that you accept and agree to be bound by the terms of the [IBM Contributor License Agreement](CLA.md).
|
For issues relating specifically to the container image or Helm chart, please use the [GitHub issue tracker](https://github.com/ibm-messaging/mq-container/issues). If you do submit a Pull Request related to this Docker image, please indicate in the Pull Request that you accept and agree to be bound by the terms of the [IBM Contributor License Agreement](CLA.md).
|
||||||
|
|
||||||
# License
|
## License
|
||||||
|
|
||||||
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
||||||
Licenses for the products installed within the images are as follows:
|
Licenses for the products installed within the images are as follows:
|
||||||
|
|
||||||
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-AKHJY4) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-AVCJ4S) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||||
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-AKHJJP) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-AZYF4X) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||||
- License information for Ubuntu packages may be found in `/usr/share/doc/${package}/copyright`
|
- License information for Ubuntu packages may be found in `/usr/share/doc/${package}/copyright`
|
||||||
|
|
||||||
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine.
|
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine.
|
||||||
|
|
||||||
# Copyright
|
## Copyright
|
||||||
|
|
||||||
© Copyright IBM Corporation 2015, 2018
|
© Copyright IBM Corporation 2015, 2018
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ func queueManagerHealthy() (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
// Specify the queue manager name, just in case someone's created a second queue manager
|
// Specify the queue manager name, just in case someone's created a second queue manager
|
||||||
|
// #nosec G204
|
||||||
cmd := exec.Command("dspmq", "-n", "-m", name)
|
cmd := exec.Command("dspmq", "-n", "-m", name)
|
||||||
// Run the command and wait for completion
|
// Run the command and wait for completion
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
@@ -39,7 +40,7 @@ func queueManagerHealthy() (bool, error) {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
fmt.Println(out)
|
fmt.Printf("%s", out)
|
||||||
if !strings.Contains(string(out), "(RUNNING)") {
|
if !strings.Contains(string(out), "(RUNNING)") {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,5 +37,8 @@ func main() {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
conn.Close()
|
err = conn.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,11 +65,27 @@ func (ks *KeyStore) Create() error {
|
|||||||
stashFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".sth"
|
stashFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".sth"
|
||||||
rdbFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".rdb"
|
rdbFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".rdb"
|
||||||
crlFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".crl"
|
crlFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".crl"
|
||||||
os.Remove(stashFile)
|
err = os.Remove(stashFile)
|
||||||
os.Remove(rdbFile)
|
if err != nil {
|
||||||
os.Remove(crlFile)
|
log.Errorf("Error removing %s: %v", stashFile, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Remove(rdbFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error removing %s: %v", rdbFile, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Remove(crlFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error removing %s: %v", crlFile, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = os.Remove(ks.Filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error removing %s: %v", ks.Filename, err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
os.Remove(ks.Filename)
|
|
||||||
} else if !os.IsNotExist(err) {
|
} else if !os.IsNotExist(err) {
|
||||||
// If the keystore exists but cannot be accessed then return the error
|
// If the keystore exists but cannot be accessed then return the error
|
||||||
return err
|
return err
|
||||||
|
|||||||
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.
|
||||||
@@ -30,16 +30,21 @@ import (
|
|||||||
var log *logger.Logger
|
var log *logger.Logger
|
||||||
|
|
||||||
func setPassword(user string, password string) error {
|
func setPassword(user string, password string) error {
|
||||||
cmd := exec.Command("chpasswd")
|
// #nosec G204
|
||||||
|
cmd := exec.Command("sudo", "chpasswd")
|
||||||
stdin, err := cmd.StdinPipe()
|
stdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(stdin, "%s:%s", user, password)
|
fmt.Fprintf(stdin, "%s:%s", user, password)
|
||||||
stdin.Close()
|
err = stdin.Close()
|
||||||
_, _, err = command.RunCmd(cmd)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Errorf("Error closing password stdin: %v", err)
|
||||||
|
}
|
||||||
|
out, _, err := command.RunCmd(cmd)
|
||||||
|
if err != nil {
|
||||||
|
// Include the command output in the error
|
||||||
|
return fmt.Errorf("%v: %v", err.Error(), out)
|
||||||
}
|
}
|
||||||
log.Printf("Set password for \"%v\" user", user)
|
log.Printf("Set password for \"%v\" user", user)
|
||||||
return nil
|
return nil
|
||||||
@@ -89,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)
|
||||||
}
|
}
|
||||||
@@ -111,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)
|
||||||
@@ -165,6 +173,10 @@ func main() {
|
|||||||
osExit(1)
|
osExit(1)
|
||||||
} else {
|
} else {
|
||||||
// Replace this process with runmqserver
|
// Replace this process with runmqserver
|
||||||
syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver"}, os.Environ())
|
// #nosec G204
|
||||||
|
err = syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver", "-dev"}, os.Environ())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error replacing this process with runmqserver: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,14 @@ func updateMQSC(appPasswordRequired bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
os.Remove(mqsc)
|
_, err := os.Stat(mqsc)
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
err = os.Remove(mqsc)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error removing file %s: %v", mqsc, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,12 @@ 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) {
|
||||||
os.MkdirAll(dir, 0660)
|
// #nosec G301
|
||||||
|
err = os.MkdirAll(dir, 0770)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
mqmUID, mqmGID, err := command.LookupMQM()
|
mqmUID, mqmGID, err := command.LookupMQM()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -51,6 +56,7 @@ func processTemplateFile(templateFile, destFile string, data interface{}) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// #nosec G302
|
||||||
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
|
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
err = t.Execute(f, data)
|
err = t.Execute(f, data)
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ func configureTLS(qmName string, inputFile string, passPhrase string) error {
|
|||||||
_, err = os.Stat(dir)
|
_, err = os.Stat(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
// #nosec G301
|
||||||
err = os.MkdirAll(dir, 0770)
|
err = os.MkdirAll(dir, 0770)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ func createVolume(path string) error {
|
|||||||
fi, err := os.Stat(dataPath)
|
fi, err := os.Stat(dataPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
// #nosec G301
|
||||||
err = os.MkdirAll(dataPath, 0755)
|
err = os.MkdirAll(dataPath, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ func checkLicense() (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
case ok && lic == "view":
|
case ok && lic == "view":
|
||||||
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
|
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
|
||||||
|
// #nosec G304
|
||||||
buf, err := ioutil.ReadFile(file)
|
buf, err := ioutil.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(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.
|
||||||
@@ -21,9 +21,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
"github.com/ibm-messaging/mq-container/internal/logger"
|
"github.com/ibm-messaging/mq-container/internal/logger"
|
||||||
"github.com/ibm-messaging/mq-container/internal/mqini"
|
"github.com/ibm-messaging/mq-container/internal/mqini"
|
||||||
)
|
)
|
||||||
@@ -31,20 +33,26 @@ import (
|
|||||||
// var debug = false
|
// var debug = false
|
||||||
var log *logger.Logger
|
var log *logger.Logger
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
log.Error(msg)
|
log.Error(msg)
|
||||||
|
|
||||||
|
if collectDiagOnFail {
|
||||||
|
logDiagnostics()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLogFormat() string {
|
func getLogFormat() string {
|
||||||
@@ -100,8 +108,12 @@ func configureLogger(name string) (mirrorFunc, error) {
|
|||||||
return func(msg string) {
|
return func(msg string) {
|
||||||
// Parse the JSON message, and print a simplified version
|
// Parse the JSON message, and print a simplified version
|
||||||
var obj map[string]interface{}
|
var obj map[string]interface{}
|
||||||
json.Unmarshal([]byte(msg), &obj)
|
err := json.Unmarshal([]byte(msg), &obj)
|
||||||
fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to Unmarshall JSON - %v", err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
|
||||||
|
}
|
||||||
}, nil
|
}, nil
|
||||||
default:
|
default:
|
||||||
log, err = logger.NewLogger(os.Stdout, d, false, name)
|
log, err = logger.NewLogger(os.Stdout, d, false, name)
|
||||||
@@ -111,3 +123,34 @@ func configureLogger(name string) (mirrorFunc, error) {
|
|||||||
return nil, fmt.Errorf("invalid value for LOG_FORMAT: %v", f)
|
return nil, fmt.Errorf("invalid value for LOG_FORMAT: %v", f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logDiagnostics() {
|
||||||
|
log.Debug("--- Start Diagnostics ---")
|
||||||
|
|
||||||
|
// show the directory ownership/permissions
|
||||||
|
// #nosec G104
|
||||||
|
out, _, _ := command.Run("ls", "-l", "/mnt/")
|
||||||
|
log.Debugf("/mnt/:\n%s", out)
|
||||||
|
// #nosec G104
|
||||||
|
out, _, _ = command.Run("ls", "-l", "/mnt/mqm")
|
||||||
|
log.Debugf("/mnt/mqm:\n%s", out)
|
||||||
|
// #nosec G104
|
||||||
|
out, _, _ = command.Run("ls", "-l", "/mnt/mqm/data")
|
||||||
|
log.Debugf("/mnt/mqm/data:\n%s", out)
|
||||||
|
// #nosec G104
|
||||||
|
out, _, _ = command.Run("ls", "-l", "/var/mqm")
|
||||||
|
log.Debugf("/var/mqm:\n%s", out)
|
||||||
|
// #nosec G104
|
||||||
|
out, _, _ = command.Run("ls", "-l", "/var/mqm/errors")
|
||||||
|
log.Debugf("/var/mqm/errors:\n%s", out)
|
||||||
|
|
||||||
|
// Print out summary of any FDCs
|
||||||
|
// #nosec G204
|
||||||
|
cmd := exec.Command("/opt/mqm/bin/ffstsummary")
|
||||||
|
cmd.Dir = "/var/mqm/errors"
|
||||||
|
// #nosec G104
|
||||||
|
outB, _ := cmd.CombinedOutput()
|
||||||
|
log.Debugf("ffstsummary:\n%s", string(outB))
|
||||||
|
|
||||||
|
log.Debug("--- End Diagnostics ---")
|
||||||
|
}
|
||||||
|
|||||||
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
|
||||||
@@ -58,12 +82,17 @@ func doMain() error {
|
|||||||
|
|
||||||
// Start signal handler
|
// Start signal handler
|
||||||
signalControl := signalHandler(name)
|
signalControl := signalHandler(name)
|
||||||
|
// Enable diagnostic collecting on failure
|
||||||
|
collectDiagOnFail = true
|
||||||
|
|
||||||
err = logConfig()
|
if *devFlag == false {
|
||||||
if err != nil {
|
err = logContainerDetails()
|
||||||
logTermination(err)
|
if err != nil {
|
||||||
return err
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = createVolume("/mnt/mqm")
|
err = createVolume("/mnt/mqm")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
@@ -75,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()
|
||||||
|
|
||||||
@@ -120,7 +154,11 @@ func doMain() error {
|
|||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
configureQueueManager()
|
err = configureQueueManager()
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
enableMetrics := os.Getenv("MQ_ENABLE_METRICS")
|
enableMetrics := os.Getenv("MQ_ENABLE_METRICS")
|
||||||
if enableMetrics == "true" || enableMetrics == "1" {
|
if enableMetrics == "true" || enableMetrics == "1" {
|
||||||
@@ -136,7 +174,11 @@ func doMain() error {
|
|||||||
// Reap zombies now, just in case we've already got some
|
// Reap zombies now, just in case we've already got some
|
||||||
signalControl <- reapNow
|
signalControl <- reapNow
|
||||||
// Write a file to indicate that chkmqready should now work as normal
|
// Write a file to indicate that chkmqready should now work as normal
|
||||||
ready.Set()
|
err = ready.Set()
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Wait for terminate signal
|
// Wait for terminate signal
|
||||||
<-signalControl
|
<-signalControl
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ func waitForFile(ctx context.Context, path string) (os.FileInfo, error) {
|
|||||||
return nil, fmt.Errorf("mirror: unable to get info on file %v", path)
|
return nil, fmt.Errorf("mirror: unable to get info on file %v", path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debugf("File exists: %v, %v", path, fi.Size())
|
|
||||||
return fi, nil
|
return fi, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +120,7 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
if fi == nil {
|
if fi == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Debugf("File exists: %v, %v", path, fi.Size())
|
||||||
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -139,7 +139,10 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
// Always start at the beginning if we've been told to go from the start
|
// Always start at the beginning if we've been told to go from the start
|
||||||
if offset != 0 && !fromStart {
|
if offset != 0 && !fromStart {
|
||||||
log.Debugf("Seeking offset %v in file %v", offset, path)
|
log.Debugf("Seeking offset %v in file %v", offset, path)
|
||||||
f.Seek(offset, 0)
|
_, err = f.Seek(offset, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to return to offset %v: %v", offset, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closing := false
|
closing := false
|
||||||
for {
|
for {
|
||||||
@@ -159,7 +162,10 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
// could skip all those messages. This could happen with a very small
|
// could skip all those messages. This could happen with a very small
|
||||||
// MQ error log size.
|
// MQ error log size.
|
||||||
mirrorAvailableMessages(f, mf)
|
mirrorAvailableMessages(f, mf)
|
||||||
f.Close()
|
err = f.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to close mirror file handle: %v", err)
|
||||||
|
}
|
||||||
// Re-open file
|
// Re-open file
|
||||||
log.Debugf("Re-opening error log file %v", path)
|
log.Debugf("Re-opening error log file %v", path)
|
||||||
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
||||||
|
|||||||
@@ -1,177 +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"
|
|
||||||
"os/user"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/genuinetools/amicontained/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
func logContainerRuntime() error {
|
|
||||||
r, err := container.DetectRuntime()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Container runtime: %v", r)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func logBaseImage() error {
|
|
||||||
buf, err := ioutil.ReadFile("/etc/os-release")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
lines := strings.Split(string(buf), "\n")
|
|
||||||
for _, l := range lines {
|
|
||||||
if strings.HasPrefix(l, "PRETTY_NAME=") {
|
|
||||||
words := strings.Split(l, "\"")
|
|
||||||
if len(words) >= 2 {
|
|
||||||
log.Printf("Base image: %v", words[1])
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func logUser() {
|
|
||||||
u, err := user.Current()
|
|
||||||
if err == nil {
|
|
||||||
g, err := u.GroupIds()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Running as user ID %v (%v) with primary group %v", u.Uid, u.Name, u.Gid)
|
|
||||||
} else {
|
|
||||||
// Look for the primary group in the list of group IDs
|
|
||||||
for i, v := range g {
|
|
||||||
if v == u.Gid {
|
|
||||||
// Remove the element from the slice
|
|
||||||
g = append(g[:i], g[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Printf("Running as user ID %v (%v) with primary group %v, and supplemental groups %v", u.Uid, u.Name, u.Gid, strings.Join(g, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// logCapabilities logs the Linux capabilities (e.g. setuid, setgid). See https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
|
|
||||||
func logCapabilities() error {
|
|
||||||
caps, err := container.Capabilities()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for k, v := range caps {
|
|
||||||
if len(v) > 0 {
|
|
||||||
log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ","))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// logSeccomp logs the seccomp enforcing mode, which affects which kernel calls can be made
|
|
||||||
func logSeccomp() error {
|
|
||||||
s, err := container.SeccompEnforcingMode()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("seccomp enforcing mode: %v", s)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// logSecurityAttributes logs the security attributes of the current process.
|
|
||||||
// The security attributes indicate whether AppArmor or SELinux are being used,
|
|
||||||
// and what the level of confinement is.
|
|
||||||
func logSecurityAttributes() error {
|
|
||||||
a, err := readProc("/proc/self/attr/current")
|
|
||||||
// On some systems, if AppArmor or SELinux are not installed, you get an
|
|
||||||
// error when you try and read `/proc/self/attr/current`, even though the
|
|
||||||
// file exists.
|
|
||||||
if err != nil || a == "" {
|
|
||||||
a = "none"
|
|
||||||
}
|
|
||||||
log.Printf("Process security attributes: %v", a)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readProc(filename string) (value string, err error) {
|
|
||||||
buf, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(string(buf)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readMounts() error {
|
|
||||||
all, err := readProc("/proc/mounts")
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Error: Couldn't read /proc/mounts")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
lines := strings.Split(all, "\n")
|
|
||||||
detected := false
|
|
||||||
for i := range lines {
|
|
||||||
parts := strings.Split(lines[i], " ")
|
|
||||||
//dev := parts[0]
|
|
||||||
mountPoint := parts[1]
|
|
||||||
fsType := parts[2]
|
|
||||||
if strings.Contains(mountPoint, "/mnt") {
|
|
||||||
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.
|
||||||
@@ -90,6 +90,7 @@ func configureQueueManager() error {
|
|||||||
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
|
||||||
cmd := exec.Command("runmqsc")
|
cmd := exec.Command("runmqsc")
|
||||||
stdin, err := cmd.StdinPipe()
|
stdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -97,6 +98,7 @@ func configureQueueManager() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Open the MQSC file for reading
|
// Open the MQSC file for reading
|
||||||
|
// #nosec G304
|
||||||
f, err := os.Open(abs)
|
f, err := os.Open(abs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error opening %v: %v", abs, err)
|
log.Printf("Error opening %v: %v", abs, err)
|
||||||
@@ -104,14 +106,20 @@ func configureQueueManager() error {
|
|||||||
// Copy the contents to stdin of the runmqsc process
|
// Copy the contents to stdin of the runmqsc process
|
||||||
_, err = io.Copy(stdin, f)
|
_, err = io.Copy(stdin, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error reading %v: %v", abs, err)
|
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)
|
||||||
}
|
}
|
||||||
f.Close()
|
|
||||||
stdin.Close()
|
|
||||||
// Run the command and wait for completion
|
// 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, strings.Replace(string(out), "\n", "\n\t", -1))
|
||||||
}
|
}
|
||||||
// Print the runmqsc output, adding tab characters to make it more readable as part of the log
|
// 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))
|
log.Printf("Output for \"runmqsc\" with %v:\n\t%v", abs, strings.Replace(string(out), "\n", "\n\t", -1))
|
||||||
@@ -122,7 +130,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
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ func signalHandler(qmgr string) chan int {
|
|||||||
log.Printf("Signal received: %v", sig)
|
log.Printf("Signal received: %v", sig)
|
||||||
signal.Stop(reapSignals)
|
signal.Stop(reapSignals)
|
||||||
signal.Stop(stopSignals)
|
signal.Stop(stopSignals)
|
||||||
metrics.StopMetricsGathering()
|
metrics.StopMetricsGathering(log)
|
||||||
|
// #nosec G104
|
||||||
stopQueueManager(qmgr)
|
stopQueueManager(qmgr)
|
||||||
// One final reap
|
// One final reap
|
||||||
reapZombies()
|
reapZombies()
|
||||||
|
|||||||
@@ -23,9 +23,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ImageCreated = "Not specified"
|
// ImageCreated is the date the image was built
|
||||||
|
ImageCreated = "Not specified"
|
||||||
|
// ImageRevision is the source control revision identifier
|
||||||
ImageRevision = "Not specified"
|
ImageRevision = "Not specified"
|
||||||
ImageSource = "Not specified"
|
// ImageSource is the URL to get source code for building the image
|
||||||
|
ImageSource = "Not specified"
|
||||||
|
// ImageTag is the tag of the image
|
||||||
|
ImageTag = "Not specified"
|
||||||
)
|
)
|
||||||
|
|
||||||
func logDateStamp() {
|
func logDateStamp() {
|
||||||
@@ -40,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 {
|
||||||
@@ -64,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.
|
||||||
@@ -21,7 +21,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
)
|
)
|
||||||
@@ -33,7 +37,31 @@ func startWebServer() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Println("Starting web server")
|
log.Println("Starting web server")
|
||||||
out, rc, err := command.RunAsMQM("strmqweb")
|
cmd := exec.Command("strmqweb")
|
||||||
|
// Set a default app password for the web server, if one isn't already set
|
||||||
|
_, set := os.LookupEnv("MQ_APP_PASSWORD")
|
||||||
|
if !set {
|
||||||
|
// Take all current environment variables, and add the app password
|
||||||
|
cmd.Env = append(os.Environ(), "MQ_APP_PASSWORD=passw0rd")
|
||||||
|
}
|
||||||
|
uid, gid, err := command.LookupMQM()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
currentUID, err := strconv.Atoi(u.Uid)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error converting UID to string: %v", err)
|
||||||
|
}
|
||||||
|
// Add credentials to run as 'mqm', only if we aren't already 'mqm'
|
||||||
|
if currentUID != uid {
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
|
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||||
|
}
|
||||||
|
out, rc, err := command.RunCmd(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error %v starting web server: %v", rc, string(out))
|
log.Printf("Error %v starting web server: %v", rc, string(out))
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,25 +1,46 @@
|
|||||||
# Building a Docker image
|
# Building a container image
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
You need to ensure you have the following tools installed:
|
|
||||||
|
### Prerequisites for building an Ubuntu image
|
||||||
|
If you want to build a container image with Ubuntu Linux as the base OS, then you need to have the following tools installed:
|
||||||
|
|
||||||
* [Docker](https://www.docker.com/) V17.06.1 or later
|
* [Docker](https://www.docker.com/) V17.06.1 or later
|
||||||
* [GNU make](https://www.gnu.org/software/make/)
|
* [GNU make](https://www.gnu.org/software/make/)
|
||||||
|
|
||||||
If you are working in the Windows Subsystem for Linux, follow [this guide by Microsoft to set up Docker](https://blogs.msdn.microsoft.com/commandline/2017/12/08/cross-post-wsl-interoperability-with-docker/) first.
|
If you are working in the Windows Subsystem for Linux, follow [this guide by Microsoft to set up Docker](https://blogs.msdn.microsoft.com/commandline/2017/12/08/cross-post-wsl-interoperability-with-docker/) first.
|
||||||
|
|
||||||
|
### Prerequisites for building a Red Hat Enterprise Linux image
|
||||||
|
If you want to build a container image with Red Hat Enterprise Linux as the base OS, then you need to use a host server with Red Hat Enterprise Linux. You must also have the following tools installed:
|
||||||
|
|
||||||
|
* [`buildah`](https://buildah.io) (available in `rhel-7-server-extras`)
|
||||||
|
* [`podman`](https://podman.io) (available in `rhel-7-server-extras`)
|
||||||
|
|
||||||
|
In addition, you need the following commonly installed tools:
|
||||||
|
|
||||||
|
* `bash`
|
||||||
|
* `coreutils`
|
||||||
|
* `findutils`
|
||||||
|
* `make`
|
||||||
|
* `sed`
|
||||||
|
* `shadow-utils`
|
||||||
|
* `tar`
|
||||||
|
|
||||||
## Building a production image
|
## Building a production image
|
||||||
This procedure works for building the MQ Continuous Delivery release, on `x86_64`, `ppc64le` and `s390x` architectures.
|
This procedure works for building the MQ Continuous Delivery release, on `x86_64`, `ppc64le` and `s390x` architectures.
|
||||||
|
|
||||||
1. Create a `downloads` directory in the root of this repository
|
1. Create a `downloads` directory in the root of this repository
|
||||||
2. Download MQ from IBM Passport Advantage, and place the downloaded file (for example, `IBM_MQ_9.1.0.0_UBUNTU_X86-64.tar.gz` for MQ V9.1.0 for Ubuntu on x86_64 architecture) in the `downloads` directory
|
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/) or [IBM Fix Central](https://www.ibm.com/support/fixcentral), and place the downloaded file (for example, `IBM_MQ_9.1.1_UBUNTU_X86-64.tar.gz` for MQ V9.1.1 for Ubuntu on x86_64 architecture) in the `downloads` directory
|
||||||
2. Run `make build-advancedserver`
|
3. Run `make build-advancedserver`
|
||||||
|
|
||||||
> **Warning**: Note that MQ offers two different sets of packaging on Linux: one is called "MQ for Linux" and contains RPM files for installing on Red Hat Enterprise Linux and SUSE Linux Enterprise Server. The other package is called "MQ for Ubuntu", and contains DEB files for installing on Ubuntu.
|
> **Warning**: Note that MQ offers two different sets of packaging on Linux: one is called "MQ for Linux" and contains RPM files for installing on Red Hat Enterprise Linux and SUSE Linux Enterprise Server. The other package is called "MQ for Ubuntu", and contains DEB files for installing on Ubuntu.
|
||||||
|
|
||||||
|
On a Red Hat Enterprise Linux host, the command `make build-advancedserver` will build a container image using Red Hat Enterprise Linux as the base. On all other hosts, the base image will be Ubuntu.
|
||||||
|
|
||||||
You can build a different version of MQ by setting the `MQ_VERSION` environment variable, for example:
|
You can build a different version of MQ by setting the `MQ_VERSION` environment variable, for example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
MQ_VERSION=9.0.5.0 make build-advancedserver
|
MQ_VERSION=9.1.0.0 make build-advancedserver
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
|
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
|
||||||
@@ -29,22 +50,10 @@ MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Building a developer image
|
## Building a developer image
|
||||||
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers from IBM developerWorks. This is currently only available on the `x86_64` architecture.
|
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers from IBM developerWorks. This is currently only available on the `x86_64` architecture. On a Red Hat Enterprise Linux host, this command will build a container image using Red Hat Enterprise Linux as the base. On all other hosts, the base image will be Ubuntu.
|
||||||
|
|
||||||
You can use the environment variable `MQ_ARCHIVE_DEV` to specify an alternative local file to install from (which must be in the `downloads` directory).
|
You can use the environment variable `MQ_ARCHIVE_DEV` to specify an alternative local file to install from (which must be in the `downloads` directory).
|
||||||
|
|
||||||
## Building on a different base image
|
|
||||||
By default, the MQ images use Ubuntu as the base layer. You can build using a Red Hat Enterprise Linux compatible base layer by setting the `BASE_IMAGE` environment variable. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
BASE_IMAGE=centos:7 make build-advancedserver
|
|
||||||
```
|
|
||||||
|
|
||||||
The `make` tool will try and locate the right archive file under the `downloads` directory, based on your platform architecture and your `MQ_VERSION` environment variable, for example `IBM_MQ_9.1.0.0_LINUX_X86_64.tar.gz` for MQ V9.1.0.0 on x86_64. You can also set the `MQ_ARCHIVE` environment variable to set the specific file name.
|
|
||||||
|
|
||||||
Note that if you are using Red Hat Enterprise Linux, you will need to create your own base image layer, with your subscription enabled, as described [here](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/getting_started_with_containers/get_started_with_docker_formatted_container_images). The MQ image build needs to install some additional packages, and a subscription is required to access the Red Hat repositories.
|
|
||||||
|
|
||||||
|
|
||||||
## Installed components
|
## Installed components
|
||||||
|
|
||||||
This image includes the core MQ server, Java, language packs, and GSKit. This can be configured by setting the `MQ_PACKAGES` argument to `make`, or directly as a [Docker build argument](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables-build-arg).
|
This image includes the core MQ server, Java, language packs, and GSKit. This can be configured by setting the `MQ_PACKAGES` argument to `make`. For the Ubuntu-based image, you can also directly set a [Docker build argument](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables-build-arg).
|
||||||
|
|||||||
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.0.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.0.5.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.0.5.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
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ In order to use the image, it is necessary to accept the terms of the IBM MQ lic
|
|||||||
## Running with the default configuration
|
## Running with the default configuration
|
||||||
You can run a queue manager with the default configuration and a listener on port 1414 using the following command. For example, the following command creates and starts a queue manager called `QM1`, and maps port 1414 on the host to the MQ listener on port 1414 inside the container, as well as port 9443 on the host to the web console on port 9443 inside the container:
|
You can run a queue manager with the default configuration and a listener on port 1414 using the following command. For example, the following command creates and starts a queue manager called `QM1`, and maps port 1414 on the host to the MQ listener on port 1414 inside the container, as well as port 9443 on the host to the web console on port 9443 inside the container:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
docker run \
|
docker run \
|
||||||
--env LICENSE=accept \
|
--env LICENSE=accept \
|
||||||
--env MQ_QMGR_NAME=QM1 \
|
--env MQ_QMGR_NAME=QM1 \
|
||||||
@@ -16,15 +16,15 @@ docker run \
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Running with the default configuration and a volume
|
## Running with the default configuration and a volume
|
||||||
The above example will not persist any configuration data or messages across container runs. In order to do this, you need to use a [volume](https://docs.docker.com/engine/admin/volumes/volumes/). For example, you can create a volume with the following command:
|
The above example will not persist any configuration data or messages across container runs. In order to do this, you need to use a [volume](https://docs.docker.com/storage/volumes/). For example, you can create a volume with the following command:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
docker volume create qm1data
|
docker volume create qm1data
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then run a queue manager using this volume as follows:
|
You can then run a queue manager using this volume as follows:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
docker run \
|
docker run \
|
||||||
--env LICENSE=accept \
|
--env LICENSE=accept \
|
||||||
--env MQ_QMGR_NAME=QM1 \
|
--env MQ_QMGR_NAME=QM1 \
|
||||||
@@ -40,7 +40,7 @@ The Docker image always uses `/mnt/mqm` for MQ data, which is correctly linked f
|
|||||||
## Running with the default configuration and Prometheus metrics enabled
|
## Running with the default configuration and Prometheus metrics enabled
|
||||||
You can run a queue manager with [Prometheus](https://prometheus.io) metrics enabled. The following command will generate Prometheus metrics for your queue manager on `/metrics` port `9157`:
|
You can run a queue manager with [Prometheus](https://prometheus.io) metrics enabled. The following command will generate Prometheus metrics for your queue manager on `/metrics` port `9157`:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
docker run \
|
docker run \
|
||||||
--env LICENSE=accept \
|
--env LICENSE=accept \
|
||||||
--env MQ_QMGR_NAME=QM1 \
|
--env MQ_QMGR_NAME=QM1 \
|
||||||
@@ -58,34 +58,36 @@ You can customize the configuration in several ways:
|
|||||||
|
|
||||||
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
|
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
|
||||||
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
|
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
|
||||||
3. By using [remote MQ administration](http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
|
3. By using [remote MQ administration](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.1.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
|
||||||
|
|
||||||
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
|
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
|
||||||
|
|
||||||
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom `config.mqsc` and an administrative user `alice`. Note that it is not normally recommended to include passwords in this way:
|
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file, and an administrative user `alice`. Note that it is not normally recommended to include passwords in this way:
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM ibmcom/mq
|
FROM ibmcom/mq
|
||||||
|
USER 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://www.ibm.com/developerworks/community/blogs/messaging/entry/getting_going_without_turning_off_mq_security?lang=en), which allows users with passwords to connect on the `PASSWORD.SVRCONN` channel:
|
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
|
||||||
|
DEFINE QLOCAL(MY.QUEUE.1) REPLACE
|
||||||
|
DEFINE QLOCAL(MY.QUEUE.2) REPLACE
|
||||||
```
|
```
|
||||||
DEFINE CHANNEL(PASSWORD.SVRCONN) CHLTYPE(SVRCONN) REPLACE
|
|
||||||
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allow privileged users on this channel')
|
The file `20-config.mqsc` should be saved into the same directory as the `Dockerfile`.
|
||||||
SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('BackStop rule')
|
|
||||||
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT(REQUIRED)
|
|
||||||
ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) ADOPTCTX(YES)
|
|
||||||
REFRESH SECURITY TYPE(CONNAUTH)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running MQ commands
|
## Running MQ commands
|
||||||
It is recommended that you configure MQ in your own custom image. However, you may need to run MQ commands directly inside the process space of the container. To run a command against a running queue manager, you can use `docker exec`, for example:
|
It is recommended that you configure MQ in your own custom image. However, you may need to run MQ commands directly inside the process space of the container. To run a command against a running queue manager, you can use `docker exec`, for example:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
docker exec \
|
docker exec \
|
||||||
--tty \
|
--tty \
|
||||||
--interactive \
|
--interactive \
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -15,14 +15,16 @@
|
|||||||
FROM ubuntu:16.04
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
# The URL to download the MQ installer from in tar.gz format
|
# The URL to download the MQ installer from in tar.gz format
|
||||||
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_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-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,7 +0,0 @@
|
|||||||
This is a work-in-progress for a Docker image based on Red Hat Enterprise Linux (RHEL).
|
|
||||||
|
|
||||||
The current MQ container build requires Docker V17.05 or greater (required features include multi-stage Docker build, and "ARG"s in the "FROM" statement). Red Hat Enterprise Linux V7.5 includes Docker up to version V1.13.
|
|
||||||
|
|
||||||
In order to build images with Red Hat Enterprise Linux, license registration is required. The license of the host server can be used, as long as you either use Red Hat's patched version of Docker (which is an old version), or if you use alternative container management tools such as [`buildah`](https://github.com/projectatomic/buildah/) and `podman` (from [`libpod`](https://github.com/projectatomic/libpod)).
|
|
||||||
|
|
||||||
This directory contains scripts for building with `buildah`. The build itself isn't containerized, so more software than usual is needed on the RHEL host, so an Ansible playbook is also provided to help set up the host.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
hosts
|
|
||||||
@@ -1,62 +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.
|
|
||||||
---
|
|
||||||
# Sets up a server for building the Red Hat image.
|
|
||||||
- hosts: rhbuild
|
|
||||||
become: true
|
|
||||||
any_errors_fatal: true
|
|
||||||
tasks:
|
|
||||||
- name: install buildah
|
|
||||||
package:
|
|
||||||
name: buildah
|
|
||||||
state: present
|
|
||||||
when: ansible_distribution == "RedHat"
|
|
||||||
- name: install podman
|
|
||||||
package:
|
|
||||||
name: buildah
|
|
||||||
state: present
|
|
||||||
when: ansible_distribution == "RedHat"
|
|
||||||
- name: install golang
|
|
||||||
package:
|
|
||||||
name: golang
|
|
||||||
state: absent
|
|
||||||
- name: install make
|
|
||||||
package:
|
|
||||||
name: make
|
|
||||||
state: present
|
|
||||||
- name: install git
|
|
||||||
package:
|
|
||||||
name: git
|
|
||||||
state: present
|
|
||||||
- name: install golang 1.10 from TAR
|
|
||||||
unarchive:
|
|
||||||
src: "https://dl.google.com/go/go1.10.3.linux-amd64.tar.gz"
|
|
||||||
dest: "/usr/local"
|
|
||||||
remote_src: yes
|
|
||||||
# TODO: Re-factor to use get_url first, so we can use the checksum
|
|
||||||
#checksum: sha256:fa1b0e45d3b647c252f51f5e1204aba049cde4af177ef9f2181f43004f901035
|
|
||||||
creates: /usr/local/go/doc/go1.10.html
|
|
||||||
- name: add golang to PATH
|
|
||||||
copy:
|
|
||||||
dest: "/etc/profile.d/golang.sh"
|
|
||||||
content: |
|
|
||||||
PATH=$PATH:/usr/local/go/bin
|
|
||||||
- name: install dep from GitHub
|
|
||||||
get_url:
|
|
||||||
url: https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64
|
|
||||||
dest: /usr/local/bin/dep
|
|
||||||
mode: 0755
|
|
||||||
checksum: sha256:31144e465e52ffbc0035248a10ddea61a09bf28b00784fd3fdd9882c8cbb2315
|
|
||||||
when: ansible_architecture == "x86_64"
|
|
||||||
# TODO: Install MQ SDK
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# -*- mode: sh -*-
|
|
||||||
# © Copyright IBM Corporation 2018
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# Build a RHEL image, using the buildah tool
|
|
||||||
|
|
||||||
set -x
|
|
||||||
set -e
|
|
||||||
|
|
||||||
MQ_ARCHIVE=downloads/mqadv_dev905_linux_x86-64.tar.gz
|
|
||||||
MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesAMS-*.rpm"
|
|
||||||
|
|
||||||
# Use a "scratch" container, so the resulting image has minimal files
|
|
||||||
# Resulting image won't have yum, for example
|
|
||||||
ctr=$(buildah from scratch)
|
|
||||||
scratchmnt=$(buildah mount $ctr)
|
|
||||||
|
|
||||||
# Initialize yum for use with the scratch container
|
|
||||||
rpm --root $scratchmnt --initdb
|
|
||||||
yum install yum-utils
|
|
||||||
yumdownloader --destdir=/tmp redhat-release-server
|
|
||||||
rpm --root $scratchmnt -ihv /tmp/redhat-release-server*.rpm
|
|
||||||
|
|
||||||
# Install the packages required by MQ
|
|
||||||
yum install -y --installroot=$scratchmnt \
|
|
||||||
bash \
|
|
||||||
bc \
|
|
||||||
coreutils \
|
|
||||||
file \
|
|
||||||
findutils \
|
|
||||||
gawk \
|
|
||||||
glibc-common \
|
|
||||||
grep \
|
|
||||||
passwd \
|
|
||||||
procps-ng \
|
|
||||||
sed \
|
|
||||||
tar \
|
|
||||||
util-linux
|
|
||||||
|
|
||||||
# Clean up cached files
|
|
||||||
yum clean all --installroot=$scratchmnt
|
|
||||||
rm -rf $scratchmnt/var/cache/yum/*
|
|
||||||
|
|
||||||
groupadd --root $scratchmnt --system --gid 888 mqm
|
|
||||||
useradd --root $scratchmnt --system --uid 888 --gid mqm mqm
|
|
||||||
usermod --root $scratchmnt -G root mqm
|
|
||||||
|
|
||||||
DIR_EXTRACT=$scratchmnt/tmp/extract
|
|
||||||
mkdir -p $scratchmnt/tmp/extract
|
|
||||||
tar -zxvf ${MQ_ARCHIVE} -C ${DIR_EXTRACT}
|
|
||||||
DIR_RPM=$(find ${DIR_EXTRACT} -name "*.rpm" -printf "%h\n" | sort -u | head -1)
|
|
||||||
DIR_RPM=${DIR_RPM#$scratchmnt}
|
|
||||||
#DIR_RPM=$(buildah run $ctr -- find ${DIR_EXTRACT} -name "*.rpm" -printf "%h\n" | sort -u | head -1)
|
|
||||||
# Find location of mqlicense.sh
|
|
||||||
#MQLICENSE=$(buildah run $ctr -- find ${DIR_EXTRACT} -name "mqlicense.sh")
|
|
||||||
MQLICENSE=$(find ${DIR_EXTRACT} -name "mqlicense.sh")
|
|
||||||
MQLICENSE=${MQLICENSE#$scratchmnt}
|
|
||||||
|
|
||||||
# Accept the MQ license
|
|
||||||
buildah run $ctr -- ${MQLICENSE} -text_only -accept
|
|
||||||
|
|
||||||
buildah run $ctr -- bash -c "cd $DIR_RPM && rpm -ivh $MQ_PACKAGES"
|
|
||||||
rm -rf ${DIR_EXTRACT}
|
|
||||||
|
|
||||||
# Remove 32-bit libraries from 64-bit container
|
|
||||||
find $scratchmnt/opt/mqm $scratchmnt/var/mqm -type f -exec file {} \; | awk -F: '/ELF 32-bit/{print $1}' | xargs --no-run-if-empty rm -f
|
|
||||||
|
|
||||||
# Remove tar.gz files unpacked by RPM postinst scripts
|
|
||||||
find $scratchmnt/opt/mqm -name '*.tar.gz' -delete
|
|
||||||
|
|
||||||
# Recommended: Set the default MQ installation (makes the MQ commands available on the PATH)
|
|
||||||
buildah run $ctr -- /opt/mqm/bin/setmqinst -p /opt/mqm -i
|
|
||||||
|
|
||||||
# Remove the directory structure under /var/mqm which was created by the installer
|
|
||||||
rm -rf $scratchmnt/var/mqm
|
|
||||||
|
|
||||||
# Create the mount point for volumes
|
|
||||||
mkdir -p $scratchmnt/mnt/mqm
|
|
||||||
|
|
||||||
# Create the directory for MQ configuration files
|
|
||||||
mkdir -p $scratchmnt/etc/mqm
|
|
||||||
|
|
||||||
# Create a symlink for /var/mqm -> /mnt/mqm/data
|
|
||||||
buildah run $ctr ln -s /mnt/mqm/data /var/mqm
|
|
||||||
|
|
||||||
# Optional: Set these values for the Bluemix Vulnerability Report
|
|
||||||
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' $scratchmnt/etc/login.defs
|
|
||||||
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' $scratchmnt/etc/login.defs
|
|
||||||
sed -i 's/password\t\[success=1 default=ignore\]\tpam_unix\.so obscure sha512/password\t[success=1 default=ignore]\tpam_unix.so obscure sha512 minlen=8/' $scratchmnt/etc/pam.d/password-auth
|
|
||||||
|
|
||||||
# Build and test the Go code
|
|
||||||
go build ./cmd/runmqserver/
|
|
||||||
go build ./cmd/chkmqready/
|
|
||||||
go build ./cmd/chkmqhealthy/
|
|
||||||
go test -v ./cmd/runmqserver/
|
|
||||||
go test -v ./cmd/chkmqready/
|
|
||||||
go test -v ./cmd/chkmqhealthy/
|
|
||||||
go test -v ./internal/...
|
|
||||||
go vet ./cmd/... ./internal/...
|
|
||||||
# Install the Go binaries into the image
|
|
||||||
cp runmqserver $scratchmnt/usr/local/bin/
|
|
||||||
cp chkmq* $scratchmnt/usr/local/bin/
|
|
||||||
cp NOTICES.txt $scratchmnt/opt/mqm/licenses/notices-container.txt
|
|
||||||
chmod ug+x $scratchmnt/usr/local/bin/runmqserver
|
|
||||||
chown mqm:mqm $scratchmnt/usr/local/bin/*mq*
|
|
||||||
chmod ug+xs $scratchmnt/usr/local/bin/chkmq*
|
|
||||||
|
|
||||||
buildah config \
|
|
||||||
--port 1414/tcp \
|
|
||||||
--port 9157/tcp \
|
|
||||||
--os linux \
|
|
||||||
--label architecture=x86_64 \
|
|
||||||
--label io.openshift.tags="mq messaging" \
|
|
||||||
--label io.k8s.display-name="IBM MQ Advanced Server" \
|
|
||||||
--label io.k8s.description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
|
|
||||||
--label name="mqadvanced-server" \
|
|
||||||
--label vendor="IBM" \
|
|
||||||
--label version="9.0.5.0" \
|
|
||||||
--env AMQ_ADDITIONAL_JSON_LOG=1 \
|
|
||||||
--env LANG=en_US.UTF-8 \
|
|
||||||
--env LOG_FORMAT=basic \
|
|
||||||
--entrypoint runmqserver \
|
|
||||||
--user 888 \
|
|
||||||
$ctr
|
|
||||||
buildah unmount $ctr
|
|
||||||
buildah commit $ctr mymq
|
|
||||||
|
|
||||||
# TODO: Leaves the working container lying around. Good for dev.
|
|
||||||
@@ -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.
|
||||||
@@ -15,10 +15,12 @@
|
|||||||
FROM ubuntu:16.04
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
# The URL to download the MQ installer from in tar.gz format
|
# The URL to download the MQ installer from in tar.gz format
|
||||||
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_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,8 +11,8 @@
|
|||||||
# 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.0.5.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,22 +12,22 @@
|
|||||||
# 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.0.5.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.0.5.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
|
||||||
###############################################################################
|
###############################################################################
|
||||||
FROM $BUILDER_IMAGE as builder
|
FROM $BUILDER_IMAGE as builder
|
||||||
ARG IMAGE_REVISION="Not specified"
|
ARG IMAGE_REVISION="Not specified"
|
||||||
ARG IMAGE_CREATED="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=$IMAGE_CREATED\" -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/...
|
||||||
@@ -43,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 \
|
||||||
@@ -55,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
|
||||||
@@ -16,14 +16,25 @@
|
|||||||
<security-role name="MQWebAdmin">
|
<security-role name="MQWebAdmin">
|
||||||
<group name="MQWebUI" realm="defaultRealm"/>
|
<group name="MQWebUI" realm="defaultRealm"/>
|
||||||
</security-role>
|
</security-role>
|
||||||
|
<security-role name="MQWebUser">
|
||||||
|
<group name="MQWebMessaging" realm="defaultRealm"/>
|
||||||
|
</security-role>
|
||||||
</application-bnd>
|
</application-bnd>
|
||||||
</enterpriseApplication>
|
</enterpriseApplication>
|
||||||
<basicRegistry id="basic" realm="defaultRealm">
|
<basicRegistry id="basic" realm="defaultRealm">
|
||||||
<user name="admin" password="${env.MQ_ADMIN_PASSWORD}"/>
|
<user name="admin" password="${env.MQ_ADMIN_PASSWORD}"/>
|
||||||
|
<!-- The app user will always get a default password of "passw0rd",
|
||||||
|
even if you don't set the environment variable.
|
||||||
|
See `webserver.go` -->
|
||||||
|
<user name="app" password="${env.MQ_APP_PASSWORD}"/>
|
||||||
<group name="MQWebUI">
|
<group name="MQWebUI">
|
||||||
<member name="admin"/>
|
<member name="admin"/>
|
||||||
</group>
|
</group>
|
||||||
|
<group name="MQWebMessaging">
|
||||||
|
<member name="app"/>
|
||||||
|
</group>
|
||||||
</basicRegistry>
|
</basicRegistry>
|
||||||
<variable name="httpHost" value="*"/>
|
<variable name="httpHost" value="*"/>
|
||||||
|
<variable name="managementMode" value="externallyprovisioned"/>
|
||||||
<include location="tls.xml"/>
|
<include location="tls.xml"/>
|
||||||
</server>
|
</server>
|
||||||
|
|||||||
26
install-build-deps-ubuntu.sh
Executable file
26
install-build-deps-ubuntu.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- mode: sh -*-
|
||||||
|
# © Copyright IBM Corporation 2015, 2019
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Install Docker and dep, required by build (assumes Ubuntu host, as used by Travis build)
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
curl https://glide.sh/get | sh
|
||||||
|
sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64
|
||||||
|
sudo chmod +x /usr/local/bin/dep
|
||||||
|
|
||||||
|
go get -u golang.org/x/lint/golint
|
||||||
@@ -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 -G 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 gcc-5-base gnupg gpgv libgcrypt20 libstdc++6 perl-base --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
|
||||||
|
|
||||||
|
|||||||
@@ -53,11 +53,13 @@ func RunCmd(cmd *exec.Cmd) (string, int, error) {
|
|||||||
// Do not use this function to run shell built-ins (like "cd"), because
|
// Do not use this function to run shell built-ins (like "cd"), because
|
||||||
// the error handling works differently
|
// the error handling works differently
|
||||||
func Run(name string, arg ...string) (string, int, error) {
|
func Run(name string, arg ...string) (string, int, error) {
|
||||||
|
// #nosec G204
|
||||||
return RunCmd(exec.Command(name, arg...))
|
return RunCmd(exec.Command(name, arg...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunAsMQM runs the specified command as the mqm user
|
// RunAsMQM runs the specified command as the mqm user
|
||||||
func RunAsMQM(name string, arg ...string) (string, int, error) {
|
func RunAsMQM(name string, arg ...string) (string, int, error) {
|
||||||
|
// #nosec G204
|
||||||
cmd := exec.Command(name, arg...)
|
cmd := exec.Command(name, arg...)
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
uid, gid, err := LookupMQM()
|
uid, gid, err := LookupMQM()
|
||||||
|
|||||||
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)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func GatherMetrics(qmName string, log *logger.Logger) {
|
|||||||
err := startMetricsGathering(qmName, log)
|
err := startMetricsGathering(qmName, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Metrics Error: %s", err.Error())
|
log.Errorf("Metrics Error: %s", err.Error())
|
||||||
StopMetricsGathering()
|
StopMetricsGathering(log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +76,7 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
|
|||||||
http.Handle("/metrics", prometheus.Handler())
|
http.Handle("/metrics", prometheus.Handler())
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
|
// #nosec G104
|
||||||
w.Write([]byte("Status: METRICS ACTIVE"))
|
w.Write([]byte("Status: METRICS ACTIVE"))
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
|
|||||||
err = metricsServer.ListenAndServe()
|
err = metricsServer.ListenAndServe()
|
||||||
if err != nil && err != http.ErrServerClosed {
|
if err != nil && err != http.ErrServerClosed {
|
||||||
log.Errorf("Metrics Error: Failed to handle metrics request: %v", err)
|
log.Errorf("Metrics Error: Failed to handle metrics request: %v", err)
|
||||||
StopMetricsGathering()
|
StopMetricsGathering(log)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -91,7 +92,7 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StopMetricsGathering stops gathering metrics for the queue manager
|
// StopMetricsGathering stops gathering metrics for the queue manager
|
||||||
func StopMetricsGathering() {
|
func StopMetricsGathering(log *logger.Logger) {
|
||||||
|
|
||||||
if metricsEnabled {
|
if metricsEnabled {
|
||||||
|
|
||||||
@@ -101,6 +102,9 @@ func StopMetricsGathering() {
|
|||||||
// Shutdown HTTP server
|
// Shutdown HTTP server
|
||||||
timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
metricsServer.Shutdown(timeout)
|
err := metricsServer.Shutdown(timeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to shutdown metrics server: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ func processMetrics(log *logger.Logger, qmName string) {
|
|||||||
firstConnect = false
|
firstConnect = false
|
||||||
startChannel <- true
|
startChannel <- true
|
||||||
}
|
}
|
||||||
|
// #nosec G104
|
||||||
metrics, _ = initialiseMetrics(log)
|
metrics, _ = initialiseMetrics(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
|
}
|
||||||
@@ -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.1.0
|
||||||
manifests:
|
manifests:
|
||||||
- image: ibmcom/mq:9.1.0.0-x86_64
|
- image: ibmcom/mq:9.1.1.0-x86_64
|
||||||
platform:
|
platform:
|
||||||
architecture: amd64
|
architecture: amd64
|
||||||
os: linux
|
os: linux
|
||||||
- image: ibmcom/mq:9.1.0.0-ppc64le
|
- image: ibmcom/mq:9.1.1.0-ppc64le
|
||||||
platform:
|
platform:
|
||||||
architecture: ppc64le
|
architecture: ppc64le
|
||||||
os: linux
|
os: linux
|
||||||
- image: ibmcom/mq:9.1.0.0-s390x
|
- image: ibmcom/mq:9.1.1.0-s390x
|
||||||
platform:
|
platform:
|
||||||
architecture: s390x
|
architecture: s390x
|
||||||
os: linux
|
os: linux
|
||||||
29
manifests/dockerhub/manifest-9.1.2.yaml
Normal file
29
manifests/dockerhub/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: ibmcom/mq:9.1.2.0
|
||||||
|
manifests:
|
||||||
|
- image: ibmcom/mq:9.1.2.0-x86_64
|
||||||
|
platform:
|
||||||
|
architecture: amd64
|
||||||
|
os: linux
|
||||||
|
- image: ibmcom/mq:9.1.2.0-ppc64le
|
||||||
|
platform:
|
||||||
|
architecture: ppc64le
|
||||||
|
os: linux
|
||||||
|
- image: ibmcom/mq:9.1.2.0-s390x
|
||||||
|
platform:
|
||||||
|
architecture: s390x
|
||||||
|
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.0.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.0.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.0.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.1.yaml
Normal file
29
manifests/dockerstore/manifest-9.1.1.yaml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# © Copyright IBM Corporation 2018
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
image: ibmcorp/mqadvanced-server-dev:9.1.1.0
|
||||||
|
manifests:
|
||||||
|
- image: ibmcorp/mqadvanced-server-dev:9.1.1.0-x86_64
|
||||||
|
platform:
|
||||||
|
architecture: amd64
|
||||||
|
os: linux
|
||||||
|
- image: ibmcorp/mqadvanced-server-dev:9.1.1.0-ppc64le
|
||||||
|
platform:
|
||||||
|
architecture: ppc64le
|
||||||
|
os: linux
|
||||||
|
- image: ibmcorp/mqadvanced-server-dev:9.1.1.0-s390x
|
||||||
|
platform:
|
||||||
|
architecture: s390x
|
||||||
|
os: linux
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
3
mq-advanced-server-rhel/README.md
Normal file
3
mq-advanced-server-rhel/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# RHEL-based container build
|
||||||
|
|
||||||
|
Build scripts for building a container image based on Red Hat Enterprise Linux (RHEL), using the [`buildah`](https://github.com/containers/buildah) tool. buildah is supported on RHEL V7.5 and greater.
|
||||||
49
mq-advanced-server-rhel/go-build.sh
Executable file
49
mq-advanced-server-rhel/go-build.sh
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- mode: sh -*-
|
||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Builds and tests the golang programs used by the MQ image.
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
# Handle a GOPATH with multiple entries (just choose the first one)
|
||||||
|
IFS=':' read -ra DIR <<< "$GOPATH"
|
||||||
|
cd ${DIR[0]}/src/github.com/ibm-messaging/mq-container/
|
||||||
|
|
||||||
|
# Build and test the Go code
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
rm -f chkmqready chkmqhealthy runmqserver runmqdevserver
|
||||||
|
|
||||||
|
if [ "$MQDEV" = "TRUE" ]; then
|
||||||
|
# Build and test the Go code
|
||||||
|
go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\"" --tags 'mqdev' ../cmd/runmqserver/
|
||||||
|
go build ../cmd/runmqdevserver/
|
||||||
|
else
|
||||||
|
go build -ldflags "-X \"main.ImageCreated=$(date --iso-8601=seconds)\" -X \"main.ImageRevision=$IMAGE_REVISION\" -X \"main.ImageSource=$IMAGE_SOURCE\"" ../cmd/runmqserver/
|
||||||
|
fi
|
||||||
|
|
||||||
|
go build ../cmd/chkmqready/
|
||||||
|
go build ../cmd/chkmqhealthy/
|
||||||
|
go test -v ../cmd/runmqserver/
|
||||||
|
go test -v ../cmd/chkmqready/
|
||||||
|
go test -v ../cmd/chkmqhealthy/
|
||||||
|
if [ "$MQDEV" = "TRUE" ]; then
|
||||||
|
go test -v ../cmd/runmqdevserver
|
||||||
|
fi
|
||||||
|
go test -v ../internal/...
|
||||||
|
go vet ../cmd/... ../internal/...
|
||||||
49
mq-advanced-server-rhel/go-buildah.sh
Executable file
49
mq-advanced-server-rhel/go-buildah.sh
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- mode: sh -*-
|
||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Run the Go build script inside the Go container, mounting the source
|
||||||
|
# directory in
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
echo "Usage: $0 TAG DevModeFlag"
|
||||||
|
exit 20
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
echo "ERROR: Invalid number of parameters"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly tag=$1
|
||||||
|
readonly dev=$2
|
||||||
|
|
||||||
|
IMAGE_REVISION=${IMAGE_REVISION:="Not Applicable"}
|
||||||
|
IMAGE_SOURCE=${IMAGE_SOURCE:="Not Applicable"}
|
||||||
|
|
||||||
|
# Run the build in a container
|
||||||
|
# Note the ":Z" on the volume is to allow the container to access the files when SELinux is enabled
|
||||||
|
# Note the "podman" network is used explicitly, to avoid problems other CNI networks (e.g. on an OpenShift node)
|
||||||
|
podman run \
|
||||||
|
--volume ${PWD}:/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/:Z \
|
||||||
|
--env IMAGE_REVISION="$IMAGE_REVISION" \
|
||||||
|
--env IMAGE_SOURCE="$IMAGE_SOURCE" \
|
||||||
|
--env MQDEV=${dev} \
|
||||||
|
--user $(id -u) \
|
||||||
|
--rm \
|
||||||
|
--network podman \
|
||||||
|
${tag} \
|
||||||
|
bash -c "cd /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/ && ./mq-advanced-server-rhel/go-build.sh"
|
||||||
88
mq-advanced-server-rhel/install-mq-rhel.sh
Executable file
88
mq-advanced-server-rhel/install-mq-rhel.sh
Executable file
@@ -0,0 +1,88 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- mode: sh -*-
|
||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Install one or more MQ components into a buildah container
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
echo "Usage: $0 MQContainer MountLocation ARCHIVENAME PACKAGES"
|
||||||
|
exit 20
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 4 ]; then
|
||||||
|
echo "ERROR: Invalid number of parameters"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly ctr_mq=$1
|
||||||
|
readonly mnt_mq=$2
|
||||||
|
readonly archive=$3
|
||||||
|
readonly mq_packages=$4
|
||||||
|
readonly dir_extract=/tmp/extract
|
||||||
|
readonly mqm_uid=888
|
||||||
|
readonly mqm_gid=888
|
||||||
|
|
||||||
|
if [ ! -d ${dir_extract}/MQServer ]; then
|
||||||
|
mkdir -p ${dir_extract}
|
||||||
|
echo Extracting $archive
|
||||||
|
tar -zxf $archive -C ${dir_extract}
|
||||||
|
echo Extracting finished
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Accept the MQ license
|
||||||
|
buildah run --user root --volume ${dir_extract}:/mnt/mq-download:Z $ctr_mq -- /mnt/mq-download/MQServer/mqlicense.sh -text_only -accept
|
||||||
|
|
||||||
|
# Install MQ
|
||||||
|
buildah run --user root --volume ${dir_extract}:/mnt/mq-download:Z $ctr_mq -- bash -c "cd /mnt/mq-download/MQServer && rpm -ivh $mq_packages"
|
||||||
|
|
||||||
|
rm -rf ${dir_extract}/MQServer
|
||||||
|
|
||||||
|
# Remove 32-bit libraries from 64-bit container
|
||||||
|
find $mnt_mq/opt/mqm $mnt_mq/var/mqm -type f -exec file {} \; | awk -F: '/ELF 32-bit/{print $1}' | xargs --no-run-if-empty rm -f
|
||||||
|
|
||||||
|
# Remove tar.gz files unpacked by RPM postinst scripts
|
||||||
|
find $mnt_mq/opt/mqm -name '*.tar.gz' -delete
|
||||||
|
|
||||||
|
# Recommended: Set the default MQ installation (makes the MQ commands available on the PATH)
|
||||||
|
buildah run $ctr_mq -- /opt/mqm/bin/setmqinst -p /opt/mqm -i
|
||||||
|
|
||||||
|
mkdir -p $mnt_mq/run/runmqserver
|
||||||
|
chown ${mqm_uid}:${mqm_gid} $mnt_mq/run/runmqserver
|
||||||
|
|
||||||
|
# Remove the directory structure under /var/mqm which was created by the installer
|
||||||
|
rm -rf $mnt_mq/var/mqm
|
||||||
|
|
||||||
|
# Create the mount point for volumes, ensuring MQ has permissions to all directories
|
||||||
|
mkdir -p $mnt_mq/mnt/mqm
|
||||||
|
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/mnt
|
||||||
|
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/mnt/mqm
|
||||||
|
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/mnt/mqm/data
|
||||||
|
|
||||||
|
# Create the directory for MQ configuration files
|
||||||
|
mkdir -p /etc/mqm
|
||||||
|
install --directory --mode 0775 --owner ${mqm_uid} --group root $mnt_mq/etc/mqm
|
||||||
|
|
||||||
|
# Create a symlink for /var/mqm -> /mnt/mqm/data
|
||||||
|
buildah run --user root $ctr_mq -- ln -s /mnt/mqm/data /var/mqm
|
||||||
|
|
||||||
|
# Optional: Set these values for the IBM Cloud Vulnerability Report
|
||||||
|
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' $mnt_mq/etc/login.defs
|
||||||
|
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' $mnt_mq/etc/login.defs
|
||||||
|
sed -i 's/password\t\[success=1 default=ignore\]\tpam_unix\.so obscure sha512/password\t[success=1 default=ignore]\tpam_unix.so obscure sha512 minlen=8/' $mnt_mq/etc/pam.d/password-auth
|
||||||
|
|
||||||
|
buildah run $ctr_mq -- cp -rs /opt/mqm/licenses/ /
|
||||||
165
mq-advanced-server-rhel/mq-buildah.sh
Executable file
165
mq-advanced-server-rhel/mq-buildah.sh
Executable file
@@ -0,0 +1,165 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- mode: sh -*-
|
||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Build a RHEL image, using the buildah tool
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
echo "Usage: $0 ARCHIVE-NAME PACKAGES TAG VERSION MQDevFlag"
|
||||||
|
exit 20
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 5 ]; then
|
||||||
|
echo "ERROR: Invalid number of parameters"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Setup MQ server working container
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# Use RHEL 7 minimal container (which doesn't include things like Python or Yum)
|
||||||
|
readonly ctr_mq=$(buildah from rhel7-minimal)
|
||||||
|
if [ -z "$ctr_mq" ]
|
||||||
|
then
|
||||||
|
echo "ERROR: ctr_mq is empty. Check above output for errors"
|
||||||
|
exit 50
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly mnt_mq=$(buildah mount $ctr_mq)
|
||||||
|
if [ -z "$mnt_mq" ]
|
||||||
|
then
|
||||||
|
echo "ERROR: mnt_mq is empty. Check above output for errors"
|
||||||
|
exit 50
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly archive=downloads/$1
|
||||||
|
readonly packages=$2
|
||||||
|
readonly tag=$3
|
||||||
|
readonly version=$4
|
||||||
|
readonly mqdev=$5
|
||||||
|
readonly mqm_uid=888
|
||||||
|
readonly mqm_gid=888
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Install MQ server
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
microdnf_opts="--nodocs"
|
||||||
|
# Check whether the host is registered with Red Hat
|
||||||
|
if subscription-manager status ; then
|
||||||
|
# Host is subscribed, but the minimal image has no enabled repos
|
||||||
|
# Note that the "bc" package is the only one in "extras"
|
||||||
|
microdnf_opts="${microdnf_opts} --enablerepo=rhel-7-server-rpms --enablerepo=rhel-7-server-extras-rpms"
|
||||||
|
else
|
||||||
|
# Use the Yum repositories configured on the host
|
||||||
|
cp -R /etc/yum.repos.d/* ${mnt_mq}/etc/yum.repos.d/
|
||||||
|
fi
|
||||||
|
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} install \
|
||||||
|
bash \
|
||||||
|
bc \
|
||||||
|
coreutils \
|
||||||
|
file \
|
||||||
|
findutils \
|
||||||
|
gawk \
|
||||||
|
glibc-common \
|
||||||
|
grep \
|
||||||
|
passwd \
|
||||||
|
procps-ng \
|
||||||
|
sed \
|
||||||
|
shadow-utils \
|
||||||
|
tar \
|
||||||
|
util-linux \
|
||||||
|
which
|
||||||
|
|
||||||
|
# Install "sudo" if using MQ Advanced for Developers
|
||||||
|
if [ "$mqdev" = "TRUE" ]; then
|
||||||
|
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} install sudo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up cached files
|
||||||
|
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} clean all
|
||||||
|
rm -rf ${mnt_mq}/etc/yum.repos.d/*
|
||||||
|
|
||||||
|
buildah run --user root $ctr_mq -- groupadd --system --gid ${mqm_gid} mqm
|
||||||
|
buildah run --user root $ctr_mq -- useradd --system --uid ${mqm_uid} --gid mqm --groups 0 mqm
|
||||||
|
|
||||||
|
# Install MQ server packages into the MQ builder image
|
||||||
|
./mq-advanced-server-rhel/install-mq-rhel.sh ${ctr_mq} "${mnt_mq}" "${archive}" "${packages}"
|
||||||
|
|
||||||
|
# Create the directory for MQ configuration files
|
||||||
|
mkdir -p ${mnt_mq}/etc/mqm
|
||||||
|
chown ${mqm_uid}:${mqm_gid} ${mnt_mq}/etc/mqm
|
||||||
|
|
||||||
|
# Install the Go binaries into the image
|
||||||
|
install --mode 0750 --owner ${mqm_uid} --group 0 ./build/runmqserver ${mnt_mq}/usr/local/bin/
|
||||||
|
install --mode 6750 --owner ${mqm_uid} --group 0 ./build/chk* ${mnt_mq}/usr/local/bin/
|
||||||
|
install --mode 0750 --owner ${mqm_uid} --group 0 ./NOTICES.txt ${mnt_mq}/opt/mqm/licenses/notices-container.txt
|
||||||
|
|
||||||
|
install --directory --mode 0775 --owner ${mqm_uid} --group 0 ${mnt_mq}/run/runmqserver
|
||||||
|
buildah run --user root $ctr_mq -- touch /run/termination-log
|
||||||
|
buildah run --user root $ctr_mq -- chown mqm:root /run/termination-log
|
||||||
|
buildah run --user root $ctr_mq -- chmod 0660 /run/termination-log
|
||||||
|
|
||||||
|
# Copy in licenses from installed packages
|
||||||
|
install --mode 0550 --owner root --group root ./mq-advanced-server-rhel/writePackages.sh ${mnt_mq}/usr/local/bin/writePackages
|
||||||
|
buildah run --user root $ctr_mq -- /usr/local/bin/writePackages
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Final Buildah commands
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
if [ "$mqdev" = "TRUE" ]; then
|
||||||
|
OSTAG="mq messaging developer"
|
||||||
|
DISNAME="IBM MQ Advanced Server Developer Edition"
|
||||||
|
PID="98102d16795c4263ad9ca075190a2d4d"
|
||||||
|
else
|
||||||
|
OSTAG="mq messaging"
|
||||||
|
DISNAME="IBM MQ Advanced Server"
|
||||||
|
PID="4486e8c4cc9146fd9b3ce1f14a2dfc5b"
|
||||||
|
fi
|
||||||
|
|
||||||
|
buildah config \
|
||||||
|
--port 1414/tcp \
|
||||||
|
--port 9157/tcp \
|
||||||
|
--os linux \
|
||||||
|
--label architecture=x86_64 \
|
||||||
|
--label io.openshift.tags="$OSTAG" \
|
||||||
|
--label io.k8s.display-name="$DISNAME" \
|
||||||
|
--label io.k8s.description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
|
||||||
|
--label name="${tag%:*}" \
|
||||||
|
--label vendor="IBM" \
|
||||||
|
--label version="$version" \
|
||||||
|
--label release="1" \
|
||||||
|
--label run="docker run -d -e LICENSE=accept --name ibm-mq ${tag%:*}" \
|
||||||
|
--label summary="$DISNAME" \
|
||||||
|
--label description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
|
||||||
|
--label IBM_PRODUCT_ID="$PID" \
|
||||||
|
--label IBM_PRODUCT_NAME="$DISNAME" \
|
||||||
|
--label IBM_PRODUCT_VERSION="$version" \
|
||||||
|
--env AMQ_ADDITIONAL_JSON_LOG=1 \
|
||||||
|
--env LANG=en_US.UTF-8 \
|
||||||
|
--env LOG_FORMAT=basic \
|
||||||
|
--entrypoint runmqserver \
|
||||||
|
--user ${mqm_uid} \
|
||||||
|
$ctr_mq
|
||||||
|
buildah unmount $ctr_mq
|
||||||
|
buildah commit $ctr_mq $tag
|
||||||
|
|
||||||
|
buildah rm $ctr_mq
|
||||||
65
mq-advanced-server-rhel/mq-golang-sdk-buildah.sh
Executable file
65
mq-advanced-server-rhel/mq-golang-sdk-buildah.sh
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- mode: sh -*-
|
||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Build a RHEL image for building Go programs which use MQ
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
echo "Usage: $0 REDIST-ARCHIVE-NAME TAG"
|
||||||
|
exit 20
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
echo "ERROR: Invalid number of parameters"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly mq_redist_archive=downloads/$1
|
||||||
|
readonly tag=$2
|
||||||
|
# Use Red Hat's Go toolset image as the base
|
||||||
|
readonly ctr_mq=$(buildah from devtools/go-toolset-7-rhel7)
|
||||||
|
if [ -z "$ctr_mq" ]
|
||||||
|
then
|
||||||
|
echo "ERROR: ctr_mq is empty. Check above output for errors"
|
||||||
|
exit 50
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly mnt_mq_go=$(buildah mount $ctr_mq)
|
||||||
|
if [ -z "$mnt_mq_go" ]
|
||||||
|
then
|
||||||
|
echo "ERROR: mnt_mq_go is empty. Check above output for errors"
|
||||||
|
exit 50
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install the MQ redistributable client (including header files) into the Go builder image
|
||||||
|
mkdir -p ${mnt_mq_go}/opt/mqm
|
||||||
|
tar -xzf ${mq_redist_archive} -C ${mnt_mq_go}/opt/mqm
|
||||||
|
|
||||||
|
# Clean up Yum files
|
||||||
|
rm -rf ${mnt_mq_go}/etc/yum.repos.d/*
|
||||||
|
|
||||||
|
buildah unmount ${ctr_mq}
|
||||||
|
# Set environment variables for MQ/Go compilation
|
||||||
|
buildah config \
|
||||||
|
--os linux \
|
||||||
|
--env CGO_CFLAGS="-I/opt/mqm/inc/" \
|
||||||
|
--env CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
|
||||||
|
${ctr_mq}
|
||||||
|
buildah commit ${ctr_mq} ${tag}
|
||||||
|
|
||||||
|
buildah rm ${ctr_mq}
|
||||||
122
mq-advanced-server-rhel/mqdev-buildah.sh
Executable file
122
mq-advanced-server-rhel/mqdev-buildah.sh
Executable file
@@ -0,0 +1,122 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# -*- mode: sh -*-
|
||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Build a RHEL image of MQ Advanced for Developers, using the buildah tool
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
echo "Usage: $0 BASETAG TAG VERSION"
|
||||||
|
exit 20
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 3 ]; then
|
||||||
|
echo "ERROR: Invalid number of parameters"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Setup MQ server working container
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# Use a "scratch" container, so the resulting image has minimal files
|
||||||
|
# Resulting image won't have yum, for example
|
||||||
|
readonly basetag=$1
|
||||||
|
readonly ctr_mq=$(buildah from $basetag)
|
||||||
|
if [ -z "$ctr_mq" ]
|
||||||
|
then
|
||||||
|
echo "ERROR: ctr_mq is empty. Check above output for errors"
|
||||||
|
exit 50
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly mnt_mq=$(buildah mount $ctr_mq)
|
||||||
|
if [ -z "$mnt_mq" ]
|
||||||
|
then
|
||||||
|
echo "ERROR: mnt_mq is empty. Check above output for errors"
|
||||||
|
exit 50
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly tag=$2
|
||||||
|
readonly version=$3
|
||||||
|
readonly mqm_uid=888
|
||||||
|
readonly mqm_gid=888
|
||||||
|
|
||||||
|
# WARNING: This is what allows the mqm user to change the password of any other user
|
||||||
|
# It's used by runmqdevserver to change the admin/app passwords.
|
||||||
|
echo "mqm ALL = NOPASSWD: /usr/sbin/chpasswd" > $mnt_mq/etc/sudoers.d/mq-dev-config
|
||||||
|
|
||||||
|
# Run these commands inside the container so that the SELinux context is handled correctly
|
||||||
|
buildah run --user root $ctr_mq -- useradd --gid mqm admin
|
||||||
|
buildah run --user root $ctr_mq -- groupadd --system mqclient
|
||||||
|
buildah run --user root $ctr_mq -- useradd --gid mqclient app
|
||||||
|
buildah run --user root $ctr_mq -- bash -c "echo admin:passw0rd | chpasswd"
|
||||||
|
|
||||||
|
mkdir --parents $mnt_mq/run/runmqdevserver
|
||||||
|
chown ${mqm_uid}:${mqm_gid} $mnt_mq/run/runmqdevserver
|
||||||
|
|
||||||
|
# Copy runmqdevserver program
|
||||||
|
install --mode 0750 --owner ${mqm_uid} --group ${mqm_gid} ./build/runmqdevserver ${mnt_mq}/usr/local/bin/
|
||||||
|
|
||||||
|
install --directory --mode 0775 --owner ${mqm_uid} --group 0 ${mnt_mq}/run/runmqdevserver
|
||||||
|
|
||||||
|
# Copy template files
|
||||||
|
cp ./incubating/mqadvanced-server-dev/*.tpl ${mnt_mq}/etc/mqm/
|
||||||
|
|
||||||
|
# Copy web XML files for default developer configuration
|
||||||
|
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
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
buildah config \
|
||||||
|
--port 1414/tcp \
|
||||||
|
--port 9157/tcp \
|
||||||
|
--port 9443/tcp \
|
||||||
|
--os linux \
|
||||||
|
--label architecture=x86_64 \
|
||||||
|
--label io.openshift.tags="mq messaging developer" \
|
||||||
|
--label io.k8s.display-name="IBM MQ Advanced Server Developer Edition" \
|
||||||
|
--label io.k8s.description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
|
||||||
|
--label name="${tag%:*}" \
|
||||||
|
--label vendor="IBM" \
|
||||||
|
--label version="$version" \
|
||||||
|
--label release="1" \
|
||||||
|
--label run="docker run -d -e LICENSE=accept --name ibm-mq-dev ${tag%:*}" \
|
||||||
|
--label summary="IBM MQ Advanced Server Developer Edition" \
|
||||||
|
--label description="IBM MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments." \
|
||||||
|
--label IBM_PRODUCT_ID="98102d16795c4263ad9ca075190a2d4d" \
|
||||||
|
--label IBM_PRODUCT_NAME="IBM MQ Advanced Server Developer Edition" \
|
||||||
|
--label IBM_PRODUCT_VERSION="$version" \
|
||||||
|
--env AMQ_ADDITIONAL_JSON_LOG=1 \
|
||||||
|
--env LANG=en_US.UTF-8 \
|
||||||
|
--env LOG_FORMAT=basic \
|
||||||
|
--env MQ_ADMIN_PASSWORD=passw0rd \
|
||||||
|
--env MQ_DEV=true \
|
||||||
|
--entrypoint runmqdevserver \
|
||||||
|
--user ${mqm_uid} \
|
||||||
|
$ctr_mq
|
||||||
|
buildah unmount $ctr_mq
|
||||||
|
buildah commit $ctr_mq $tag
|
||||||
|
|
||||||
|
buildah rm $ctr_mq
|
||||||
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,14 +33,16 @@ 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)
|
||||||
}
|
}
|
||||||
|
qm := "qm1"
|
||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=qm1",
|
"MQ_QMGR_NAME=" + qm,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
||||||
@@ -49,7 +51,13 @@ func TestDevGoldenPath(t *testing.T) {
|
|||||||
waitForWebReady(t, cli, id, insecureTLSConfig)
|
waitForWebReady(t, cli, id, insecureTLSConfig)
|
||||||
t.Run("JMS", func(t *testing.T) {
|
t.Run("JMS", func(t *testing.T) {
|
||||||
// Run the JMS tests, with no password specified
|
// Run the JMS tests, with no password specified
|
||||||
runJMSTests(t, cli, id, false, "app", "")
|
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS)
|
||||||
|
})
|
||||||
|
t.Run("REST admin", func(t *testing.T) {
|
||||||
|
testRESTAdmin(t, cli, id, insecureTLSConfig)
|
||||||
|
})
|
||||||
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
|
testRESTMessaging(t, cli, id, insecureTLSConfig, qm, "app", defaultAppPasswordWeb)
|
||||||
})
|
})
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
@@ -59,16 +67,20 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tlsPassPhrase string = "passw0rd"
|
const tlsPassPhrase string = "passw0rd"
|
||||||
|
qm := "qm1"
|
||||||
|
appPassword := "differentPassw0rd"
|
||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=qm1",
|
"MQ_QMGR_NAME=" + qm,
|
||||||
"MQ_APP_PASSWORD=" + devAppPassword,
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
"MQ_TLS_KEYSTORE=/var/tls/server.p12",
|
"MQ_TLS_KEYSTORE=/var/tls/server.p12",
|
||||||
"MQ_TLS_PASSPHRASE=" + tlsPassPhrase,
|
"MQ_TLS_PASSPHRASE=" + tlsPassPhrase,
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
@@ -100,13 +112,24 @@ func TestDevSecure(t *testing.T) {
|
|||||||
waitForReady(t, cli, ctr.ID)
|
waitForReady(t, cli, ctr.ID)
|
||||||
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
||||||
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
||||||
runJMSTests(t, cli, ctr.ID, true, "app", devAppPassword)
|
|
||||||
|
t.Run("JMS", func(t *testing.T) {
|
||||||
|
runJMSTests(t, cli, ctr.ID, true, "app", appPassword)
|
||||||
|
})
|
||||||
|
t.Run("REST admin", func(t *testing.T) {
|
||||||
|
testRESTAdmin(t, cli, ctr.ID, insecureTLSConfig)
|
||||||
|
})
|
||||||
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
|
testRESTMessaging(t, cli, ctr.ID, insecureTLSConfig, qm, "app", appPassword)
|
||||||
|
})
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ctr.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -129,7 +152,7 @@ func TestDevWebDisabled(t *testing.T) {
|
|||||||
})
|
})
|
||||||
t.Run("JMS", func(t *testing.T) {
|
t.Run("JMS", func(t *testing.T) {
|
||||||
// Run the JMS tests, with no password specified
|
// Run the JMS tests, with no password specified
|
||||||
runJMSTests(t, cli, id, false, "app", "")
|
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS)
|
||||||
})
|
})
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
@@ -137,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.
|
||||||
@@ -18,12 +18,15 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -34,8 +37,9 @@ import (
|
|||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
const devAdminPassword string = "passw0rd"
|
const defaultAdminPassword string = "passw0rd"
|
||||||
const devAppPassword string = "passw0rd"
|
const defaultAppPasswordOS string = ""
|
||||||
|
const defaultAppPasswordWeb string = "passw0rd"
|
||||||
|
|
||||||
// Disable TLS verification (server uses a self-signed certificate by default,
|
// Disable TLS verification (server uses a self-signed certificate by default,
|
||||||
// so verification isn't useful anyway)
|
// so verification isn't useful anyway)
|
||||||
@@ -58,7 +62,7 @@ func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls
|
|||||||
select {
|
select {
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(1 * time.Second):
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
req.SetBasicAuth("admin", devAdminPassword)
|
req.SetBasicAuth("admin", defaultAdminPassword)
|
||||||
resp, err := httpClient.Do(req.WithContext(ctx))
|
resp, err := httpClient.Do(req.WithContext(ctx))
|
||||||
if err == nil && resp.StatusCode == http.StatusOK {
|
if err == nil && resp.StatusCode == http.StatusOK {
|
||||||
t.Log("MQ web server is ready")
|
t.Log("MQ web server is ready")
|
||||||
@@ -83,6 +87,7 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa
|
|||||||
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
|
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
|
||||||
"MQ_USERNAME=" + user,
|
"MQ_USERNAME=" + user,
|
||||||
"MQ_CHANNEL=DEV.APP.SVRCONN",
|
"MQ_CHANNEL=DEV.APP.SVRCONN",
|
||||||
|
"IBMJRE=" + os.Getenv("IBMJRE"),
|
||||||
},
|
},
|
||||||
Image: imageNameDevJMS(),
|
Image: imageNameDevJMS(),
|
||||||
}
|
}
|
||||||
@@ -109,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)
|
||||||
}
|
}
|
||||||
@@ -140,17 +145,16 @@ func createTLSConfig(t *testing.T, certFile, password string) *tls.Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testREST(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
|
func testRESTAdmin(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(30 * time.Second),
|
Timeout: time.Duration(30 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getPort(t, cli, ID, 9443))
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
req.SetBasicAuth("admin", devAdminPassword)
|
req.SetBasicAuth("admin", defaultAdminPassword)
|
||||||
resp, err := httpClient.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -159,3 +163,70 @@ func testREST(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config
|
|||||||
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode)
|
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// curl -i -k https://localhost:1234/ibmmq/rest/v1/messaging/qmgr/qm1/queue/DEV.QUEUE.1/message -X POST -u app -H “ibm-mq-rest-csrf-token: N/A” -H “Content-Type: text/plain;charset=utf-8" -d “Hello World”
|
||||||
|
|
||||||
|
func logHTTPRequest(t *testing.T, req *http.Request) {
|
||||||
|
d, err := httputil.DumpRequestOut(req, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
t.Logf("HTTP request: %v", string(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func logHTTPResponse(t *testing.T, resp *http.Response) {
|
||||||
|
d, err := httputil.DumpResponse(resp, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
t.Logf("HTTP response: %v", string(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config, qmName string, user string, password string) {
|
||||||
|
httpClient := http.Client{
|
||||||
|
Timeout: time.Duration(30 * time.Second),
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: tlsConfig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
q := "DEV.QUEUE.1"
|
||||||
|
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/messaging/qmgr/%s/queue/%s/message", getPort(t, cli, ID, 9443), qmName, q)
|
||||||
|
putMessage := []byte("Hello")
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(putMessage))
|
||||||
|
req.SetBasicAuth(user, password)
|
||||||
|
req.Header.Add("ibm-mq-rest-csrf-token", "n/a")
|
||||||
|
req.Header.Add("Content-Type", "text/plain;charset=utf-8")
|
||||||
|
logHTTPRequest(t, req)
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
logHTTPResponse(t, resp)
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
t.Errorf("Expected HTTP status code %v from 'POST to queue'; got %v", http.StatusOK, resp.StatusCode)
|
||||||
|
t.Logf("HTTP response: %+v", resp)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err = http.NewRequest("DELETE", url, nil)
|
||||||
|
req.Header.Add("ibm-mq-rest-csrf-token", "n/a")
|
||||||
|
req.SetBasicAuth(user, password)
|
||||||
|
logHTTPRequest(t, req)
|
||||||
|
resp, err = httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
logHTTPResponse(t, resp)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
t.Errorf("Expected HTTP status code %v from 'DELETE from queue'; got %v", http.StatusOK, resp.StatusCode)
|
||||||
|
t.Logf("HTTP response: %+v", resp)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
gotMessage, err := ioutil.ReadAll(resp.Body)
|
||||||
|
//gotMessage := string(b)
|
||||||
|
if string(gotMessage) != string(putMessage) {
|
||||||
|
t.Errorf("Expected payload to be \"%s\"; got \"%s\"", putMessage, gotMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,48 @@ func TestMQSC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestInvalidMQSC creates a new image with an MQSC file containing invalid MQSC,
|
||||||
|
// tries to start a container based on that image, and checks that container terminates
|
||||||
|
// func TestInvalidMQSC(t *testing.T) {
|
||||||
|
// t.Parallel()
|
||||||
|
// cli, err := client.NewEnvClient()
|
||||||
|
// if err != nil {
|
||||||
|
// t.Fatal(err)
|
||||||
|
// }
|
||||||
|
// var files = []struct {
|
||||||
|
// Name, Body string
|
||||||
|
// }{
|
||||||
|
// {"Dockerfile", fmt.Sprintf(`
|
||||||
|
// FROM %v
|
||||||
|
// USER root
|
||||||
|
// RUN rm -f /etc/mqm/*.mqsc
|
||||||
|
// ADD mqscTest.mqsc /etc/mqm/
|
||||||
|
// RUN chmod 0660 /etc/mqm/mqscTest.mqsc
|
||||||
|
// USER mqm`, imageName())},
|
||||||
|
// {"mqscTest.mqsc", "DEFINE INVALIDLISTENER('TEST.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE"},
|
||||||
|
// }
|
||||||
|
// tag := createImage(t, cli, files)
|
||||||
|
// defer deleteImage(t, cli, tag)
|
||||||
|
|
||||||
|
// containerConfig := container.Config{
|
||||||
|
// Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||||
|
// Image: tag,
|
||||||
|
// }
|
||||||
|
// id := runContainer(t, cli, &containerConfig)
|
||||||
|
// defer cleanContainer(t, cli, id)
|
||||||
|
// rc := waitForContainer(t, cli, id, 60*time.Second)
|
||||||
|
// if rc != 1 {
|
||||||
|
// t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||||
|
// }
|
||||||
|
// expectTerminationMessage(t, cli, id)
|
||||||
|
// }
|
||||||
|
|
||||||
// TestReadiness creates a new image with large amounts of MQSC in, to
|
// 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 +608,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 +650,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 +685,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 +728,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 +776,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 +789,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
|
||||||
@@ -684,10 +886,11 @@ func TestVersioning(t *testing.T) {
|
|||||||
dataAr := strings.Split(line, " ")
|
dataAr := strings.Split(line, " ")
|
||||||
data := dataAr[len(dataAr)-1]
|
data := dataAr[len(dataAr)-1]
|
||||||
|
|
||||||
// Verify created
|
// Verify created is in a known timestamp format
|
||||||
_, err := time.Parse(time.RFC3339, data)
|
_, err := time.Parse(time.RFC3339, data)
|
||||||
if err != nil {
|
_, err2 := time.Parse("2006-01-02T15:04:05-0700", data)
|
||||||
t.Errorf("Failed to validate Image created (%v) - %v", data, err)
|
if err != nil && err2 != nil {
|
||||||
|
t.Errorf("Failed to validate Image created stamp (%v) - %v or %v", data, time.RFC3339, "2006-01-02T15:04:05-0700")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ RUN find /usr/src/mymaven
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Application runtime (JRE only, no build environment)
|
# Application runtime (JRE only, no build environment)
|
||||||
###############################################################################
|
###############################################################################
|
||||||
FROM ibmjava:sfj
|
FROM ibmjava:8-jre
|
||||||
COPY --from=builder /usr/src/mymaven/target/*.jar /opt/app/
|
COPY --from=builder /usr/src/mymaven/target/*.jar /opt/app/
|
||||||
COPY --from=builder /usr/src/mymaven/target/lib/*.jar /opt/app/
|
COPY --from=builder /usr/src/mymaven/target/lib/*.jar /opt/app/
|
||||||
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"]
|
||||||
|
|||||||
84
test/messaging/buildah.sh
Executable file
84
test/messaging/buildah.sh
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# © Copyright IBM Corporation 2018, 2019
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Setup MQ JMS Test container
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# Use a "scratch" container, so the resulting image has minimal files
|
||||||
|
# Resulting image won't have yum, for example
|
||||||
|
readonly ctr_mq=$(buildah from rhel7-minimal)
|
||||||
|
readonly mnt_mq=$(buildah mount $ctr_mq)
|
||||||
|
readonly imagename=$1
|
||||||
|
|
||||||
|
microdnf_opts="--nodocs"
|
||||||
|
# Check whether the host is registered with Red Hat
|
||||||
|
if subscription-manager status ; then
|
||||||
|
# Host is subscribed, but the minimal image has no enabled repos
|
||||||
|
# Note that the "bc" package is the only one in "extras"
|
||||||
|
microdnf_opts="${microdnf_opts} --enablerepo=rhel-7-server-rpms --enablerepo=rhel-7-server-extras-rpms"
|
||||||
|
else
|
||||||
|
# Use the Yum repositories configured on the host
|
||||||
|
cp -R /etc/yum.repos.d/* ${mnt_mq}/etc/yum.repos.d/
|
||||||
|
fi
|
||||||
|
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} install \
|
||||||
|
java-1.8.0-openjdk-devel \
|
||||||
|
java \
|
||||||
|
which \
|
||||||
|
wget
|
||||||
|
|
||||||
|
buildah run $ctr_mq -- sh -c "cd /tmp && wget https://www-eu.apache.org/dist/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz"
|
||||||
|
tar xvf $mnt_mq/tmp/apache-maven-3.6.0-bin.tar.gz -C $mnt_mq/tmp/
|
||||||
|
|
||||||
|
mkdir -p $mnt_mq/usr/src/mymaven
|
||||||
|
cp pom.xml $mnt_mq/usr/src/mymaven/
|
||||||
|
cp -R src $mnt_mq/usr/src/mymaven/src
|
||||||
|
|
||||||
|
buildah run $ctr_mq -- sh -c "cd /usr/src/mymaven && export M2_HOME=/tmp/apache-maven-3.6.0 && export M2=\$M2_HOME/bin && export PATH=\$M2:\$PATH && mvn --version && mvn dependency:go-offline install && mvn --offline install"
|
||||||
|
|
||||||
|
mkdir -p $mnt_mq/opt/app
|
||||||
|
|
||||||
|
cp $mnt_mq/usr/src/mymaven/target/*.jar $mnt_mq/opt/app/
|
||||||
|
cp $mnt_mq/usr/src/mymaven/target/lib/*.jar $mnt_mq/opt/app/
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Post install tidy up
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
rm -rf $mnt_mq/tmp/*
|
||||||
|
rm -rf $mnt_mq/usr/src/mymaven
|
||||||
|
|
||||||
|
# Clean up cached files
|
||||||
|
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} clean all
|
||||||
|
rm -rf ${mnt_mq}/etc/yum.repos.d/*
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Contain image finalization
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
buildah config \
|
||||||
|
--os linux \
|
||||||
|
--label architecture=x86_64 \
|
||||||
|
--label name="${imagename%:*}" \
|
||||||
|
--cmd "" \
|
||||||
|
--entrypoint '["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]' \
|
||||||
|
$ctr_mq
|
||||||
|
buildah unmount $ctr_mq
|
||||||
|
buildah commit $ctr_mq $imagename
|
||||||
|
|
||||||
|
buildah rm $ctr_mq
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ class JMSTests {
|
|||||||
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
|
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
|
||||||
factory.setChannel(channel);
|
factory.setChannel(channel);
|
||||||
factory.setConnectionNameList(String.format("%s(1414)", addr));
|
factory.setConnectionNameList(String.format("%s(1414)", addr));
|
||||||
|
// If a password is set, make sure it gets sent to the queue manager for authentication
|
||||||
|
if (password != null) {
|
||||||
|
factory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
|
||||||
|
}
|
||||||
// factory.setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT);
|
// factory.setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT);
|
||||||
if (TRUSTSTORE == null) {
|
if (TRUSTSTORE == null) {
|
||||||
LOGGER.info("Not using TLS");
|
LOGGER.info("Not using TLS");
|
||||||
@@ -80,9 +84,15 @@ class JMSTests {
|
|||||||
else {
|
else {
|
||||||
LOGGER.info(String.format("Using TLS. Trust store=%s", TRUSTSTORE));
|
LOGGER.info(String.format("Using TLS. Trust store=%s", TRUSTSTORE));
|
||||||
SSLSocketFactory ssl = createSSLSocketFactory();
|
SSLSocketFactory ssl = createSSLSocketFactory();
|
||||||
factory.setSSLSocketFactory(ssl);
|
factory.setSSLSocketFactory(ssl);
|
||||||
factory.setSSLCipherSuite("SSL_RSA_WITH_AES_128_CBC_SHA256");
|
boolean ibmjre = System.getenv("IBMJRE").equals("true");
|
||||||
// LOGGER.info(Arrays.toString(ssl.getSupportedCipherSuites()));
|
if (ibmjre){
|
||||||
|
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
|
||||||
|
factory.setSSLCipherSuite("SSL_RSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
} else {
|
||||||
|
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
|
||||||
|
factory.setSSLCipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA256");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Give up if unable to reconnect for 10 minutes
|
// Give up if unable to reconnect for 10 minutes
|
||||||
// factory.setClientReconnectTimeout(600);
|
// factory.setClientReconnectTimeout(600);
|
||||||
|
|||||||
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