diff --git a/.travis.yml b/.travis.yml index 3f7300d..f2e30ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# © Copyright IBM Corporation 2018, 2019 +# © Copyright IBM Corporation 2018, 2020 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -41,15 +41,15 @@ jobs: if: branch != private-master AND tag IS blank os: linux env: - - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_AMD64 + - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_915_ARCHIVE_REPOSITORY_DEV_AMD64 script: bash -e travis-build-scripts/run.sh - if: branch = private-master OR tag =~ ^pre-release* name: "Multi-Arch AMD64 build" os: linux env: - BUILD_ALL=true - - MQ_ARCHIVE_REPOSITORY=$MQ_914_ARCHIVE_REPOSITORY_AMD64 - - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_AMD64 + - MQ_ARCHIVE_REPOSITORY=$MQ_915_ARCHIVE_REPOSITORY_AMD64 + - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_915_ARCHIVE_REPOSITORY_DEV_AMD64 script: bash -e travis-build-scripts/run.sh - if: branch = private-master OR tag =~ ^pre-release* name: "Multi-Arch PPC64LE build" @@ -57,8 +57,8 @@ jobs: env: - BUILD_ALL=true - TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics" - - MQ_ARCHIVE_REPOSITORY=$MQ_914_ARCHIVE_REPOSITORY_PPC64LE - - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_PPC64LE + - MQ_ARCHIVE_REPOSITORY=$MQ_915_ARCHIVE_REPOSITORY_PPC64LE + - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_915_ARCHIVE_REPOSITORY_DEV_PPC64LE script: bash -e travis-build-scripts/run.sh - if: branch = private-master OR tag =~ ^pre-release* name: "Multi-Arch S390X build" @@ -66,8 +66,8 @@ jobs: env: - BUILD_ALL=true - TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics" - - MQ_ARCHIVE_REPOSITORY=$MQ_914_ARCHIVE_REPOSITORY_S390X - - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_S390X + - MQ_ARCHIVE_REPOSITORY=$MQ_915_ARCHIVE_REPOSITORY_S390X + - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_915_ARCHIVE_REPOSITORY_DEV_S390X script: bash -e travis-build-scripts/run.sh - stage: deploy name: "Pre-release deploy" diff --git a/CHANGELOG.md b/CHANGELOG.md index 79d07d6..2992413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log +## 9.1.5.0 (2020-04-02) + +* Updated to MQ version 9.1.5.0 +* Can now run as a random user, instead of the "mqm" user, which has now been removed. This adds compatability for the [Red Hat OpenShift restricted SCC](https://docs.openshift.com/container-platform/4.3/authentication/managing-security-context-constraints.html#security-context-constraints-about_configuring-internal-oauth). The default image UID is `1001`. + ## 9.1.4.0 (2019-12-06) * Updated to MQ version 9.1.4.0 diff --git a/Dockerfile-server b/Dockerfile-server index 256f2bd..79cf707 100644 --- a/Dockerfile-server +++ b/Dockerfile-server @@ -25,12 +25,13 @@ ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messa ARG IMAGE_REVISION="Not specified" ARG IMAGE_SOURCE="Not specified" ARG IMAGE_TAG="Not specified" -ARG MQM_UID=888 USER 0 COPY install-mq.sh /usr/local/bin/ -RUN chmod a+x /usr/local/bin/install-mq.sh \ +RUN mkdir /opt/mqm \ + && chmod a+x /usr/local/bin/install-mq.sh \ && sleep 1 \ - && MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm" install-mq.sh $MQM_UID + && install-mq.sh \ + && chown -R 1001:root /opt/mqm/* WORKDIR /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/ COPY cmd/ ./cmd COPY internal/ ./internal @@ -59,7 +60,6 @@ FROM $BASE_IMAGE:$BASE_TAG AS mq-server ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev914_linux_x86-64.tar.gz" ARG MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesWeb*.rpm MQSeriesAMS-*.rpm" #ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-web ibmmq-ams" -ARG MQM_UID=888 ARG BASE_IMAGE ARG BASE_TAG LABEL summary="IBM MQ Advanced Server" @@ -76,13 +76,17 @@ LABEL base-image-release=$BASE_TAG COPY install-mq.sh /usr/local/bin/ COPY install-mq-server-prereqs.sh /usr/local/bin/ # Install MQ. To avoid a "text file busy" error here, we sleep before installing. -RUN env && chmod u+x /usr/local/bin/install-*.sh \ +RUN env \ + && mkdir /opt/mqm \ + && chmod u+x /usr/local/bin/install-*.sh \ && sleep 1 \ - && install-mq-server-prereqs.sh $MQM_UID \ - && install-mq.sh $MQM_UID + && install-mq-server-prereqs.sh \ + && install-mq.sh \ + && /opt/mqm/bin/security/amqpamcf \ + && chown -R 1001:root /opt/mqm/* # Create a directory for runtime data from runmqserver RUN mkdir -p /run/runmqserver \ - && chown mqm:mqm /run/runmqserver + && chown 1001:root /run/runmqserver COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/runmqserver /usr/local/bin/ COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/chkmq* /usr/local/bin/ COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt @@ -90,31 +94,30 @@ COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt COPY web /etc/mqm/web COPY etc/mqm/*.tpl /etc/mqm/ RUN chmod ug+x /usr/local/bin/runmqserver \ - && chown mqm:mqm /usr/local/bin/*mq* \ + && chown 1001:root /usr/local/bin/*mq* \ && chmod ug+xs /usr/local/bin/chkmq* \ - && chown -R mqm:mqm /etc/mqm/* \ - && install --directory --mode 0775 --owner mqm --group root /run/runmqserver \ + && chown -R 1001:root /etc/mqm/* \ + && install --directory --mode 0775 --owner 1001 --group root /run/runmqserver \ && touch /run/termination-log \ - && chown mqm:root /run/termination-log \ + && chown 1001:root /run/termination-log \ && chmod 0660 /run/termination-log # Always use port 1414 for MQ & 9157 for the metrics EXPOSE 1414 9157 9443 +ENV MQ_OVERRIDE_DATA_PATH=/mnt/mqm/data MQ_INSTALLATION_NAME=Installation1 MQ_USER_NAME="mqm" PATH="${PATH}:/opt/mqm/bin" ENV MQ_GRACE_PERIOD=30 ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic -USER $MQM_UID +# We can run as any UID +USER 1001 ENTRYPOINT ["runmqserver"] ############################################################################### # Add default developer config ############################################################################### FROM mq-server AS mq-dev-server -ARG MQM_UID=888 ARG BASE_IMAGE ARG BASE_TAG # Enable MQ developer default configuration ENV MQ_DEV=true -# Default administrator password -ENV MQ_ADMIN_PASSWORD=passw0rd LABEL summary="IBM MQ Advanced for Developers Server" LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises" LABEL vendor="IBM" @@ -131,25 +134,17 @@ COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/ RUN chmod u+x /usr/local/bin/install-extra-packages.sh \ && sleep 1 \ && install-extra-packages.sh -# WARNING: This is what allows the mqm user to change the password of any other user -# It's used by runmqdevserver to change the admin/app passwords. -RUN echo "mqm ALL = NOPASSWD: /usr/sbin/chpasswd" > /etc/sudoers.d/mq-dev-config -## Add admin and app users, and set a default password for admin -RUN useradd admin -G mqm \ - && groupadd mqclient \ - && useradd app -G mqclient \ - && echo admin:$MQ_ADMIN_PASSWORD | chpasswd # Create a directory for runtime data from runmqserver RUN mkdir -p /run/runmqdevserver \ - && chown mqm:mqm /run/runmqdevserver + && chown 1001:root /run/runmqdevserver COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/ # Copy template files COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/ # Copy web XML files for default developer configuration COPY incubating/mqadvanced-server-dev/web /etc/mqm/web -RUN chown -R mqm:mqm /etc/mqm/* \ +RUN chown -R 1001:root /etc/mqm/* \ && chmod +x /usr/local/bin/runmq* \ - && install --directory --mode 0775 --owner mqm --group root /run/runmqdevserver + && install --directory --mode 0775 --owner 1001 --group root /run/runmqdevserver ENV MQ_ENABLE_EMBEDDED_WEB_SERVER=1 MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost -USER $MQM_UID +USER 1001 ENTRYPOINT ["runmqdevserver"] diff --git a/Makefile b/Makefile index 8f78767..6b6ee1b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# © Copyright IBM Corporation 2017, 2019 +# © Copyright IBM Corporation 2017, 2020 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ # RELEASE shows what release of the container code has been built RELEASE ?= # MQ_VERSION is the fully qualified MQ version number to build -MQ_VERSION ?= 9.1.4.0 +MQ_VERSION ?= 9.1.5.0 # MQ_ARCHIVE_REPOSITORY is a remote repository from which to pull the MQ_ARCHIVE (if required) MQ_ARCHIVE_REPOSITORY ?= # MQ_ARCHIVE_REPOSITORY_DEV is a remote repository from which to pull the MQ_ARCHIVE_DEV (if required) @@ -45,10 +45,6 @@ MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server MQ_IMAGE_DEVSERVER ?=ibm-mqadvanced-server-dev # MQ_TAG is the tag of the built MQ Advanced image & MQ Advanced for Developers image MQ_TAG ?=$(MQ_VERSION)-$(ARCH) -# MQ_PACKAGES specifies the MQ packages (.deb or .rpm) to install. Defaults vary on base image. -MQ_PACKAGES ?=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesWeb*.rpm MQSeriesAMS-*.rpm -# MQM_UID is the UID to use for the "mqm" user -MQM_UID ?= 888 # COMMAND is the container command to run. "podman" or "docker" COMMAND ?=$(shell type -p podman 2>&1 >/dev/null && echo podman || echo docker) # MQ_DELIVERY_REGISTRY_HOSTNAME is a remote registry to push the MQ Image to (if required) @@ -88,7 +84,7 @@ 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.4 instead of 9.1.4.0 +# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.5 instead of 9.1.5.0 MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION)))) ifneq (,$(findstring Microsoft,$(shell uname -r))) @@ -116,6 +112,7 @@ MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).ta MQ_ARCHIVE_DEV_9.1.2.0=mqadv_dev912_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz MQ_ARCHIVE_DEV_9.1.3.0=mqadv_dev913_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz MQ_ARCHIVE_DEV_9.1.4.0=mqadv_dev914_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz +MQ_ARCHIVE_DEV_9.1.5.0=mqadv_dev915_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz ifneq "$(MQ_DELIVERY_REGISTRY_NAMESPACE)" "$(EMPTY)" MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_DELIVERY_REGISTRY_NAMESPACE) @@ -236,11 +233,9 @@ define build-mq --tag $1:$2 \ --file $3 \ $(EXTRA_ARGS) \ - --build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \ --build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \ --build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \ --build-arg IMAGE_TAG="$1:$2" \ - --build-arg MQM_UID=$(MQM_UID) \ --label version=$(MQ_VERSION) \ --label name=$1 \ --label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \ @@ -315,7 +310,6 @@ log-build-vars: @echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER) @echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER) @echo COMMAND=$(COMMAND) - @echo MQM_UID=$(MQM_UID) @echo REGISTRY_USER=$(REGISTRY_USER) .PHONY: log-build-env diff --git a/cmd/runmqserver/crtmqvol.go b/cmd/runmqserver/crtmqvol.go index e064e72..2a79904 100644 --- a/cmd/runmqserver/crtmqvol.go +++ b/cmd/runmqserver/crtmqvol.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2017, 2019 +© Copyright IBM Corporation 2017, 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,14 +17,10 @@ package main import ( "os" - "runtime" - "syscall" - - "github.com/ibm-messaging/mq-container/internal/command" ) func createVolume(dataPath string) error { - fi, err := os.Stat(dataPath) + _, err := os.Stat(dataPath) if err != nil { if os.IsNotExist(err) { // #nosec G301 @@ -36,25 +32,5 @@ func createVolume(dataPath string) error { return err } } - fi, err = os.Stat(dataPath) - if err != nil { - return err - } - sys := fi.Sys() - if sys != nil && runtime.GOOS == "linux" { - stat := sys.(*syscall.Stat_t) - mqmUID, mqmGID, err := command.LookupMQM() - if err != nil { - return err - } - log.Debugf("mqm user is %v (%v)", mqmUID, mqmGID) - if int(stat.Uid) != mqmUID || int(stat.Gid) != mqmGID { - err = os.Chown(dataPath, mqmUID, mqmGID) - if err != nil { - log.Printf("Error: Unable to change ownership of %v", dataPath) - return err - } - } - } return nil } diff --git a/cmd/runmqserver/main.go b/cmd/runmqserver/main.go index 7133ba1..13e60a7 100644 --- a/cmd/runmqserver/main.go +++ b/cmd/runmqserver/main.go @@ -112,12 +112,29 @@ func doMain() error { return err } + enableTraceCrtmqdir := os.Getenv("MQ_ENABLE_TRACE_CRTMQDIR") + if enableTraceCrtmqdir == "true" || enableTraceCrtmqdir == "1" { + err = startMQTrace() + if err != nil { + logTermination(err) + return err + } + } + err = createDirStructure() if err != nil { logTermination(err) return err } + if enableTraceCrtmqdir == "true" || enableTraceCrtmqdir == "1" { + err = endMQTrace() + if err != nil { + logTermination(err) + return err + } + } + // If init flag is set, exit now if *initFlag { return nil @@ -149,6 +166,7 @@ func doMain() error { logTermination(err) return err } + var wg sync.WaitGroup defer func() { log.Debug("Waiting for log mirroring to complete") diff --git a/cmd/runmqserver/qmgr.go b/cmd/runmqserver/qmgr.go index 549e259..709caf4 100644 --- a/cmd/runmqserver/qmgr.go +++ b/cmd/runmqserver/qmgr.go @@ -32,10 +32,14 @@ import ( // createDirStructure creates the default MQ directory structure under /var/mqm func createDirStructure() error { - out, _, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-a") + out, rc, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-a") if err != nil { - log.Printf("Error creating directory structure: %v\n", string(out)) - return err + if rc == 10 { + log.Printf("Warning creating directory structure: %v\n", string(out)) + } else { + log.Printf("Error creating directory structure: %v\n", string(out)) + return err + } } log.Println("Created directory structure under /var/mqm") return nil diff --git a/cmd/runmqserver/webserver.go b/cmd/runmqserver/webserver.go index f3b98d6..ed26aa7 100644 --- a/cmd/runmqserver/webserver.go +++ b/cmd/runmqserver/webserver.go @@ -19,13 +19,9 @@ import ( "fmt" "os" "os/exec" - "os/user" "path/filepath" - "strconv" "strings" - "syscall" - "github.com/ibm-messaging/mq-container/internal/command" "github.com/ibm-messaging/mq-container/internal/copy" "github.com/ibm-messaging/mq-container/internal/mqtemplate" "github.com/ibm-messaging/mq-container/internal/tls" @@ -55,24 +51,6 @@ func startWebServer(webKeystore, webkeystorePW, webTruststoreRef string) error { cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTOREPW="+webkeystorePW) cmd.Env = append(cmd.Env, "AMQ_WEBTRUSTSTOREREF="+webTruststoreRef) } - - 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, err := cmd.CombinedOutput() rc := cmd.ProcessState.ExitCode() if err != nil { @@ -162,10 +140,6 @@ func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string } return "", err } - uid, gid, err := command.LookupMQM() - if err != nil { - return "", err - } const prefix string = "/etc/mqm/web" err = filepath.Walk(prefix, func(from string, info os.FileInfo, err error) error { if err != nil { @@ -202,10 +176,6 @@ func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string return err } } - err = os.Chown(to, uid, gid) - if err != nil { - return err - } return nil }) diff --git a/docs/security.md b/docs/security.md index fc8cc81..d327d96 100644 --- a/docs/security.md +++ b/docs/security.md @@ -4,7 +4,7 @@ ### User -The MQ server image is run using the "mqm" user, with a fixed UID and GID of 888. +The MQ server image is run using with UID 1001, though this can be any UID, with a fixed GID of 0 (root). ### Capabilities @@ -16,7 +16,7 @@ docker run \ --env LICENSE=accept \ --env MQ_QMGR_NAME=QM1 \ --detach \ - ibm-mqadvanced-server:9.1.4.0-amd64 + ibm-mqadvanced-server:9.1.5.0-amd64 ``` The MQ Advanced for Developers image does require the "chown", "setuid", "setgid" and "audit_write" capabilities (plus "dac_override" if you're using an image based on Red Hat Enterprise Linux). This is because it uses the "sudo" command to change passwords inside the container. For example, in Docker, you could do the following: @@ -31,5 +31,5 @@ docker run \ --env LICENSE=accept \ --env MQ_QMGR_NAME=QM1 \ --detach \ - ibm-mqadvanced-server-dev:9.1.4.0-amd64 + ibm-mqadvanced-server-dev:9.1.5.0-amd64 ``` diff --git a/docs/testing.md b/docs/testing.md index 38e387b..43d01f3 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -24,19 +24,18 @@ make test-advancedserver You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example: ``` -MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.1.4.0-amd64 make test-advancedserver -``` +MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.1.5.0-amd64 make test-advancedserver -You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command:: +You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command: ``` TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver ``` -You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `ibm-mqadvanced-server:9.1.4.0-amd64`: +You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `ibm-mqadvanced-server:9.1.5.0-amd64`: ``` -MQ_VERSION=9.1.4.0 make test-advancedserver +MQ_VERSION=9.1.5.0 make test-advancedserver ``` ### Running the Docker tests with code coverage @@ -48,12 +47,3 @@ make test-advancedserver-cover ``` In order to generate code coverage metrics from the Docker tests, the build step creates a new Docker image with an instrumented version of the code. Each test is then run individually, producing a coverage report each under `test/docker/coverage/`. These individual reports are then combined. The combined report is written to the `coverage` directory. - - -### Running the Kubernetes tests - -For the Kubernetes tests, you need to have built the Docker image, and pushed it to the registry used by your Kubernetes cluster. Most of the configuration used by the tests is picked up from your `kubectl` configuration, but you will typically need to specify the image details. For example: - -```bash -MQ_IMAGE=mycluster.icp:8500/default/mq-devserver make test-kubernetes-devserver -``` diff --git a/docs/usage.md b/docs/usage.md index 4206e65..9e1e716 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -71,7 +71,7 @@ FROM ibmcom/mq USER root RUN useradd alice -G mqm && \ echo alice:passw0rd | chpasswd -USER mqm +USER 1001 COPY 20-config.mqsc /etc/mqm/ ``` diff --git a/install-mq.sh b/install-mq.sh index fcfa81b..9528403 100644 --- a/install-mq.sh +++ b/install-mq.sh @@ -1,6 +1,6 @@ #!/bin/bash # -*- mode: sh -*- -# © Copyright IBM Corporation 2015, 2019 +# © Copyright IBM Corporation 2015, 2020 # # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,74 +18,44 @@ # Fail on any non-zero return code set -ex -mqm_uid=${1:-888} - -test -f /usr/bin/yum && YUM=true || YUM=false -test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false test -f /usr/bin/rpm && RPM=true || RPM=false test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false -# Download and extract the MQ installation files -DIR_EXTRACT=/tmp/mq -mkdir -p ${DIR_EXTRACT} -cd ${DIR_EXTRACT} +# Download and extract the MQ unzippable server +DIR_TMP=/tmp/mq +mkdir -p ${DIR_TMP} +cd ${DIR_TMP} curl -LO $MQ_URL -tar -zxf ./*.tar.gz -# Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images -groupadd --system --gid ${mqm_uid} mqm -useradd --system --uid ${mqm_uid} --gid mqm --groups 0 mqm - -# Find directory containing .deb files -$UBUNTU && DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1) -$RPM && DIR_RPM=$(find ${DIR_EXTRACT} -name "*.rpm" -printf "%h\n" | sort -u | head -1) -# Find location of mqlicense.sh -MQLICENSE=$(find ${DIR_EXTRACT} -name "mqlicense.sh") +INSTALLATION_DIR=/opt/mqm +tar -C ${INSTALLATION_DIR} -xzf ./*.tar.gz +ls -la ${INSTALLATION_DIR} +rm -rf ${DIR_TMP} # Accept the MQ license -${MQLICENSE} -text_only -accept -$UBUNTU && echo "deb [trusted=yes] file:${DIR_DEB} ./" > /etc/apt/sources.list.d/IBM_MQ.list - -# Install MQ using the DEB packages -$UBUNTU && apt-get update -$UBUNTU && apt-get install -y $MQ_PACKAGES - -$RPM && cd $DIR_RPM && rpm -ivh $MQ_PACKAGES +${INSTALLATION_DIR}/bin/mqlicense -accept # Remove 32-bit libraries from 64-bit container # The "file" utility isn't installed by default in UBI, so only try this if it's installed -which file && find /opt/mqm /var/mqm -type f -exec file {} \; | awk -F: '/ELF 32-bit/{print $1}' | xargs --no-run-if-empty rm -f - -# Remove tar.gz files unpacked by RPM postinst scripts -find /opt/mqm -name '*.tar.gz' -delete - -# Recommended: Set the default MQ installation (makes the MQ commands available on the PATH) -/opt/mqm/bin/setmqinst -p /opt/mqm -i - -# Clean up all the downloaded files -$UBUNTU && rm -f /etc/apt/sources.list.d/IBM_MQ.list -rm -rf ${DIR_EXTRACT} +which file && find ${INSTALLATION_DIR} /var/mqm -type f -exec file {} \; | awk -F: '/ELF 32-bit/{print $1}' | xargs --no-run-if-empty rm -f # Optional: Update the command prompt with the MQ version $UBUNTU && echo "mq:$(dspmqver -b -f 2)" > /etc/debian_chroot -# Remove the directory structure under /var/mqm which was created by the installer -rm -rf /var/mqm - # Create the mount point for volumes, ensuring MQ has permissions to all directories -install --directory --mode 0775 --owner mqm --group root /mnt -install --directory --mode 0775 --owner mqm --group root /mnt/mqm -install --directory --mode 0775 --owner mqm --group root /mnt/mqm/data -install --directory --mode 0775 --owner mqm --group root /mnt/mqm-log -install --directory --mode 0775 --owner mqm --group root /mnt/mqm-log/log -install --directory --mode 0775 --owner mqm --group root /mnt/mqm-data -install --directory --mode 0775 --owner mqm --group root /mnt/mqm-data/qmgrs +install --directory --mode 0775 --owner 1001 --group root /mnt +install --directory --mode 0775 --owner 1001 --group root /mnt/mqm +install --directory --mode 0775 --owner 1001 --group root /mnt/mqm/data +install --directory --mode 0775 --owner 1001 --group root /mnt/mqm-log +install --directory --mode 0775 --owner 1001 --group root /mnt/mqm-log/log +install --directory --mode 0775 --owner 1001 --group root /mnt/mqm-data +install --directory --mode 0775 --owner 1001 --group root /mnt/mqm-data/qmgrs # Create the directory for MQ configuration files -install --directory --mode 0775 --owner mqm --group root /etc/mqm +install --directory --mode 0775 --owner 1001 --group root /etc/mqm # Create the directory for MQ runtime files -install --directory --mode 0775 --owner mqm --group root /run/mqm +install --directory --mode 2775 --owner 1001 --group root /run/mqm # Create a symlink for /var/mqm -> /mnt/mqm/data ln -s /mnt/mqm/data /var/mqm @@ -110,4 +80,3 @@ sed -i 's/v7.0/v8.0/g' /opt/mqm/licenses/non_ibm_license.txt # Copy MQ Licenses into the correct location mkdir -p /licenses cp /opt/mqm/licenses/*.txt /licenses/ - diff --git a/internal/command/command.go b/internal/command/command.go index 2dc23e2..b3b80ac 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2017, 2018 +© Copyright IBM Corporation 2017, 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,9 +20,6 @@ package command import ( "fmt" "os/exec" - "os/user" - "strconv" - "syscall" ) // Run runs an OS command. On Linux it waits for the command to @@ -40,33 +37,3 @@ func Run(name string, arg ...string) (string, int, error) { } return string(out), rc, nil } - -// RunAsMQM runs the specified command as the mqm user -func RunAsMQM(name string, arg ...string) (string, int, error) { - // #nosec G204 - cmd := exec.Command(name, arg...) - cmd.SysProcAttr = &syscall.SysProcAttr{} - uid, gid, err := LookupMQM() - if err != nil { - return "", 0, err - } - cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)} - return Run(name, arg...) -} - -// LookupMQM looks up the UID & GID of the mqm user -func LookupMQM() (int, int, error) { - mqm, err := user.Lookup("mqm") - if err != nil { - return -1, -1, err - } - mqmUID, err := strconv.Atoi(mqm.Uid) - if err != nil { - return -1, -1, err - } - mqmGID, err := strconv.Atoi(mqm.Gid) - if err != nil { - return -1, -1, err - } - return mqmUID, mqmGID, nil -} diff --git a/internal/keystore/keystore.go b/internal/keystore/keystore.go index 792f691..e24856c 100644 --- a/internal/keystore/keystore.go +++ b/internal/keystore/keystore.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2018, 2019 +© Copyright IBM Corporation 2018, 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -105,14 +105,6 @@ func (ks *KeyStore) Create() error { return fmt.Errorf("error running \"%v -keydb -create\": %v %s", ks.command, err, out) } - mqmUID, mqmGID, err := command.LookupMQM() - if err != nil { - return err - } - err = os.Chown(ks.Filename, mqmUID, mqmGID) - if err != nil { - return err - } return nil } @@ -130,14 +122,6 @@ func (ks *KeyStore) CreateStash() error { } return err } - mqmUID, mqmGID, err := command.LookupMQM() - if err != nil { - return err - } - err = os.Chown(stashFile, mqmUID, mqmGID) - if err != nil { - return err - } return nil } diff --git a/internal/mqtemplate/mqtemplate.go b/internal/mqtemplate/mqtemplate.go index 75e2062..c128ce2 100644 --- a/internal/mqtemplate/mqtemplate.go +++ b/internal/mqtemplate/mqtemplate.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2018, 2019 +© Copyright IBM Corporation 2018, 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,6 @@ import ( "path" "text/template" - "github.com/ibm-messaging/mq-container/internal/command" "github.com/ibm-messaging/mq-container/pkg/logger" ) @@ -45,16 +44,6 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l log.Error(err) return err } - mqmUID, mqmGID, err := command.LookupMQM() - if err != nil { - log.Error(err) - return err - } - err = os.Chown(dir, mqmUID, mqmGID) - if err != nil { - log.Error(err) - return err - } } else { return err } @@ -67,15 +56,5 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l log.Error(err) return err } - mqmUID, mqmGID, err := command.LookupMQM() - if err != nil { - log.Error(err) - return err - } - err = os.Chown(destFile, mqmUID, mqmGID) - if err != nil { - log.Error(err) - return err - } return nil } diff --git a/internal/tls/tls_web.go b/internal/tls/tls_web.go index 441cb85..d22a93e 100644 --- a/internal/tls/tls_web.go +++ b/internal/tls/tls_web.go @@ -20,7 +20,6 @@ import ( "os" "path/filepath" - "github.com/ibm-messaging/mq-container/internal/command" "github.com/ibm-messaging/mq-container/internal/keystore" ) @@ -51,14 +50,6 @@ func ConfigureWebTLS(keyLabel string) error { if err != nil { return fmt.Errorf("Failed to create symlink %s->%s: %v", newTLSConfig, tlsConfig, err) } - mqmUID, mqmGID, err := command.LookupMQM() - if err != nil { - return fmt.Errorf("Failed to find mqm user or group: %v", err) - } - err = os.Chown(tlsConfig, mqmUID, mqmGID) - if err != nil { - return fmt.Errorf("Failed to change ownership of %s to mqm: %v", tlsConfig, err) - } return nil } diff --git a/test/docker/devconfig_test.go b/test/docker/devconfig_test.go index 94c8fdd..e8aa2a0 100644 --- a/test/docker/devconfig_test.go +++ b/test/docker/devconfig_test.go @@ -143,7 +143,7 @@ func TestDevWebDisabled(t *testing.T) { defer cleanContainer(t, cli, id) waitForReady(t, cli, id) t.Run("Web", func(t *testing.T) { - _, dspmqweb := execContainer(t, cli, id, "mqm", []string{"dspmqweb"}) + _, dspmqweb := execContainer(t, cli, id, "", []string{"dspmqweb"}) if !strings.Contains(dspmqweb, "Server mqweb is not running.") && !strings.Contains(dspmqweb, "MQWB1125I") { t.Errorf("Expected dspmqweb to say 'Server is not running' or 'MQWB1125I'; got \"%v\"", dspmqweb) } @@ -174,7 +174,7 @@ func TestDevConfigDisabled(t *testing.T) { defer cleanContainer(t, cli, id) waitForReady(t, cli, id) waitForWebReady(t, cli, id, insecureTLSConfig) - rc, _ := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"}) + rc, _ := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"}) if rc == 0 { t.Errorf("Expected DEV queues to be missing") } diff --git a/test/docker/docker_api_test.go b/test/docker/docker_api_test.go index 4863c52..807a9dc 100644 --- a/test/docker/docker_api_test.go +++ b/test/docker/docker_api_test.go @@ -91,7 +91,7 @@ func TestEndMQMOpts(t *testing.T) { defer cleanContainer(t, cli, id) waitForReady(t, cli, id) killContainer(t, cli, id, "SIGTERM") - _, out := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "ps -ef | grep 'endmqm -w -r -tp 27'"}) + _, out := execContainer(t, cli, id, "", []string{"bash", "-c", "ps -ef | grep 'endmqm -w -r -tp 27'"}) t.Log(out) if !strings.Contains(out, "endmqm -w -r -tp 27") { t.Errorf("Expected endmqm options endmqm -w -r -tp 27; got \"%v\"", out) @@ -182,7 +182,7 @@ func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName stri id := runContainer(t, cli, &containerConfig) defer cleanContainer(t, cli, id) waitForReady(t, cli, id) - _, out := execContainer(t, cli, id, "mqm", []string{"dspmq"}) + _, out := execContainer(t, cli, id, "", []string{"dspmq"}) if !strings.Contains(out, search) { t.Errorf("Expected result of running dspmq to contain name=%v, got name=%v", search, out) } @@ -414,9 +414,7 @@ func TestCreateQueueManagerFail(t *testing.T) { 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())}, + USER 1001`, imageName())}, } tag := createImage(t, cli, files) defer deleteImage(t, cli, tag) @@ -449,9 +447,7 @@ func TestStartQueueManagerFail(t *testing.T) { 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())}, + USER 1001`, imageName())}, } tag := createImage(t, cli, files) defer deleteImage(t, cli, tag) @@ -510,12 +506,12 @@ func TestVolumeUnmount(t *testing.T) { t.Fatalf("Expected umount to work with rc=0, got %v. Output was: %s", rc, out) } time.Sleep(3 * time.Second) - rc, _ = execContainer(t, cli, ctr.ID, "mqm", []string{"chkmqhealthy"}) + rc, _ = execContainer(t, cli, ctr.ID, "", []string{"chkmqhealthy"}) if rc == 0 { t.Errorf("Expected chkmqhealthy to fail") - _, df := execContainer(t, cli, ctr.ID, "mqm", []string{"df"}) + _, df := execContainer(t, cli, ctr.ID, "", []string{"df"}) t.Logf(df) - _, ps := execContainer(t, cli, ctr.ID, "mqm", []string{"ps", "-ef"}) + _, ps := execContainer(t, cli, ctr.ID, "", []string{"ps", "-ef"}) t.Logf(ps) } } @@ -541,14 +537,14 @@ func TestZombies(t *testing.T) { waitForReady(t, cli, id) // Kill an MQ process with children. After it is killed, its children // will be adopted by PID 1, and should then be reaped when they die. - _, out := execContainer(t, cli, id, "mqm", []string{"pkill", "--signal", "kill", "-c", "amqzxma0"}) + _, out := execContainer(t, cli, id, "", []string{"pkill", "--signal", "kill", "-c", "amqzxma0"}) if out == "0" { t.Log("Failed to kill process 'amqzxma0'") - _, out := execContainer(t, cli, id, "root", []string{"ps", "-lA"}) + _, out := execContainer(t, cli, id, "", []string{"ps", "-lA"}) t.Fatalf("Here is a list of currently running processes:\n%s", out) } time.Sleep(3 * time.Second) - _, out = execContainer(t, cli, id, "mqm", []string{"bash", "-c", "ps -lA | grep '^. Z'"}) + _, out = execContainer(t, cli, id, "", []string{"bash", "-c", "ps -lA | grep '^. Z'"}) if out != "" { count := strings.Count(out, "\n") + 1 t.Errorf("Expected zombies=0, got %v", count) @@ -575,7 +571,7 @@ func TestMQSC(t *testing.T) { RUN rm -f /etc/mqm/*.mqsc ADD test.mqsc /etc/mqm/ RUN chmod 0660 /etc/mqm/test.mqsc - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test.mqsc", "DEFINE QLOCAL(test)"}, } tag := createImage(t, cli, files) @@ -588,7 +584,7 @@ func TestMQSC(t *testing.T) { id := runContainer(t, cli, &containerConfig) defer cleanContainer(t, cli, id) waitForReady(t, cli, id) - rc, mqscOutput := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test)' | runmqsc"}) + rc, mqscOutput := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test)' | runmqsc"}) if rc != 0 { r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E") t.Fatalf("Expected runmqsc to exit with rc=0, got %v with error %v", rc, r.FindString(mqscOutput)) @@ -618,7 +614,7 @@ func TestLargeMQSC(t *testing.T) { RUN rm -f /etc/mqm/*.mqsc ADD test.mqsc /etc/mqm/ RUN chmod 0660 /etc/mqm/test.mqsc - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test.mqsc", buf.String()}, } tag := createImage(t, cli, files) @@ -632,7 +628,7 @@ func TestLargeMQSC(t *testing.T) { defer cleanContainer(t, cli, id) waitForReady(t, cli, id) - rc, mqscOutput := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test" + strconv.Itoa(numQueues) + ")' | runmqsc"}) + rc, mqscOutput := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test" + strconv.Itoa(numQueues) + ")' | runmqsc"}) if rc != 0 { r := regexp.MustCompile("AMQ[0-9][0-9][0-9][0-9]E") t.Fatalf("Expected runmqsc to exit with rc=0, got %v with error %v", rc, r.FindString(mqscOutput)) @@ -690,7 +686,7 @@ func TestRedactValidMQSC(t *testing.T) { RUN rm -f /etc/mqm/*.mqsc ADD test.mqsc /etc/mqm/ RUN chmod 0660 /etc/mqm/test.mqsc - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test.mqsc", buf.String()}, } tag := createImage(t, cli, files) @@ -762,7 +758,7 @@ func TestRedactInvalidMQSC(t *testing.T) { RUN rm -f /etc/mqm/*.mqsc ADD test.mqsc /etc/mqm/ RUN chmod 0660 /etc/mqm/test.mqsc - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test.mqsc", buf.String()}, } tag := createImage(t, cli, files) @@ -808,7 +804,7 @@ func TestInvalidMQSC(t *testing.T) { RUN rm -f /etc/mqm/*.mqsc ADD mqscTest.mqsc /etc/mqm/ RUN chmod 0660 /etc/mqm/mqscTest.mqsc - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"mqscTest.mqsc", "DEFINE INVALIDLISTENER('TEST.LISTENER.TCP') TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE"}, } tag := createImage(t, cli, files) @@ -841,7 +837,7 @@ func TestSimpleMQIniMerge(t *testing.T) { USER root ADD test1.ini /etc/mqm/ RUN chmod 0660 /etc/mqm/test1.ini - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test1.ini", "Log:\n LogSecondaryFiles=28"}, } @@ -857,7 +853,7 @@ func TestSimpleMQIniMerge(t *testing.T) { waitForReady(t, cli, id) catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/qm1/qm.ini") - _, test := execContainer(t, cli, id, "mqm", []string{"bash", "-c", catIniFileCommand}) + _, test := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand}) merged := strings.Contains(test, "LogSecondaryFiles=28") if !merged { @@ -883,7 +879,7 @@ func TestMultipleIniMerge(t *testing.T) { RUN chmod 0660 /etc/mqm/test1.ini RUN chmod 0660 /etc/mqm/test2.ini RUN chmod 0660 /etc/mqm/test3.ini - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test1.ini", "Log:\n LogSecondaryFiles=28"}, {"test2.ini", @@ -903,7 +899,7 @@ func TestMultipleIniMerge(t *testing.T) { waitForReady(t, cli, id) catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/qm1/qm.ini") - _, test := execContainer(t, cli, id, "mqm", []string{"bash", "-c", catIniFileCommand}) + _, test := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand}) //checks that no duplicates are created by adding 2 ini files with the same line numberOfDuplicates := strings.Count(test, "LogSecondaryFiles=28") @@ -929,7 +925,7 @@ func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) { USER root ADD test1.ini /etc/mqm/ RUN chmod 0660 /etc/mqm/test1.ini - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test1.ini", "ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF"}, } @@ -959,7 +955,7 @@ func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) { waitForReady(t, cli, ctr1.ID) catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/qm1/qm.ini") - _, test := execContainer(t, cli, ctr1.ID, "mqm", []string{"bash", "-c", catIniFileCommand}) + _, test := execContainer(t, cli, ctr1.ID, "", []string{"bash", "-c", catIniFileCommand}) addedStanza := strings.Contains(test, "ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF") if addedStanza != true { @@ -976,7 +972,7 @@ func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) { USER root ADD test1.ini /etc/mqm/ RUN chmod 0660 /etc/mqm/test1.ini - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test1.ini", "Log:\n LogFilePages=5000"}, } @@ -997,7 +993,7 @@ func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) { startContainer(t, cli, ctr2.ID) waitForReady(t, cli, ctr2.ID) - _, test2 := execContainer(t, cli, ctr2.ID, "mqm", []string{"bash", "-c", catIniFileCommand}) + _, test2 := execContainer(t, cli, ctr2.ID, "", []string{"bash", "-c", catIniFileCommand}) changedStanza := strings.Contains(test2, "LogFilePages=5000") //check if stanza that was merged in the first container doesnt exist in this one. firstMergedStanza := strings.Contains(test2, "ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF") @@ -1032,7 +1028,7 @@ func TestReadiness(t *testing.T) { RUN rm -f /etc/mqm/*.mqsc ADD test.mqsc /etc/mqm/ RUN chmod 0660 /etc/mqm/test.mqsc - USER mqm`, imageName())}, + USER 1001`, imageName())}, {"test.mqsc", buf.String()}, } tag := createImage(t, cli, files) @@ -1045,11 +1041,11 @@ func TestReadiness(t *testing.T) { id := runContainer(t, cli, &containerConfig) defer cleanContainer(t, cli, id) queueCheckCommand := fmt.Sprintf("echo 'DISPLAY QLOCAL(test%v)' | runmqsc", numQueues) - _, mqsc := execContainer(t, cli, id, "root", []string{"cat", "/etc/mqm/test.mqsc"}) + _, mqsc := execContainer(t, cli, id, "", []string{"cat", "/etc/mqm/test.mqsc"}) t.Log(mqsc) for { - readyRC, _ := execContainer(t, cli, id, "mqm", []string{"chkmqready"}) - queueCheckRC, queueCheckOut := execContainer(t, cli, id, "mqm", []string{"bash", "-c", queueCheckCommand}) + readyRC, _ := execContainer(t, cli, id, "", []string{"chkmqready"}) + queueCheckRC, queueCheckOut := execContainer(t, cli, id, "", []string{"bash", "-c", queueCheckCommand}) t.Logf("readyRC=%v,queueCheckRC=%v\n", readyRC, queueCheckRC) if readyRC == 0 { @@ -1058,7 +1054,7 @@ func TestReadiness(t *testing.T) { t.Fatalf("Runmqsc returned %v with error %v. chkmqready returned %v when MQSC had not finished", queueCheckRC, r.FindString(queueCheckOut), readyRC) } else { // chkmqready says OK, and the last queue exists, so return - _, runmqsc := execContainer(t, cli, id, "root", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test1)' | runmqsc"}) + _, runmqsc := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QLOCAL(test1)' | runmqsc"}) t.Log(runmqsc) return } @@ -1107,7 +1103,7 @@ func TestErrorLogRotation(t *testing.T) { for { execContainer(t, cli, id, "fred", []string{"bash", "-c", "/opt/mqm/samp/bin/amqsput FAKE"}) - _, atoiStr := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "wc -c < " + filepath.Join(dir, "AMQERR02.json")}) + _, atoiStr := execContainer(t, cli, id, "", []string{"bash", "-c", "wc -c < " + filepath.Join(dir, "AMQERR02.json")}) amqerr02size, _ := strconv.Atoi(atoiStr) if amqerr02size > 0 { @@ -1115,7 +1111,7 @@ func TestErrorLogRotation(t *testing.T) { break } } - _, out := execContainer(t, cli, id, "root", []string{"ls", "-l", dir}) + _, out := execContainer(t, cli, id, "", []string{"ls", "-l", dir}) t.Log(out) stopContainer(t, cli, id) b := copyFromContainer(t, cli, id, filepath.Join(dir, "AMQERR01.json")) @@ -1259,7 +1255,7 @@ func TestCorrectLicense(t *testing.T) { defer cleanContainer(t, cli, id) waitForReady(t, cli, id) - rc, license := execContainer(t, cli, id, "mqm", []string{"dspmqver", "-f", "8192", "-b"}) + rc, license := execContainer(t, cli, id, "", []string{"dspmqver", "-f", "8192", "-b"}) if rc != 0 { t.Fatalf("Failed to get license string. RC=%d. Output=%s", rc, license) } @@ -1408,7 +1404,7 @@ func TestTraceStrmqm(t *testing.T) { defer cleanContainer(t, cli, id) waitForReady(t, cli, id) - rc, _ := execContainer(t, cli, id, "mqm", []string{"bash", "-c", "ls -A /var/mqm/trace | grep .TRC"}) + rc, _ := execContainer(t, cli, id, "", []string{"bash", "-c", "ls -A /var/mqm/trace | grep .TRC"}) if rc != 0 { t.Fatalf("No trace files found in trace directory /var/mqm/trace. RC=%d.", rc) } diff --git a/test/docker/docker_api_test_util.go b/test/docker/docker_api_test_util.go index 72e2176..c2c589c 100644 --- a/test/docker/docker_api_test_util.go +++ b/test/docker/docker_api_test_util.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2017, 2019 +© Copyright IBM Corporation 2017, 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import ( "fmt" "io" "io/ioutil" + "math/rand" "os" "os/exec" "path/filepath" @@ -259,6 +260,13 @@ func cleanContainer(t *testing.T, cli *client.Client, ID string) { } } +func generateRandomUID() string { + rand.Seed(time.Now().UnixNano()) + min := 1000 + max := 9999 + return fmt.Sprint(rand.Intn(max-min) + min) +} + // runContainerWithPorts creates and starts a container, exposing the specified ports on the host. // If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE // environment variable. @@ -266,9 +274,9 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co if containerConfig.Image == "" { containerConfig.Image = imageName() } - // Always run as the "mqm" user, unless the test has specified otherwise + // Always run as a random user, unless the test has specified otherwise if containerConfig.User == "" { - containerConfig.User = "mqm" + containerConfig.User = generateRandomUID() } // if coverage containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov") @@ -281,15 +289,9 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co CapDrop: []string{ "ALL", }, + Privileged: false, } 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") @@ -592,13 +594,15 @@ func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd } func waitForReady(t *testing.T, cli *client.Client, ID string) { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() for { select { case <-time.After(1 * time.Second): - rc, _ := execContainer(t, cli, ID, "mqm", []string{"chkmqready"}) + rc, _ := execContainer(t, cli, ID, "", []string{"chkmqready"}) + if rc == 0 { t.Log("MQ is ready") return diff --git a/test/docker/mq_multi_instance_test.go b/test/docker/mq_multi_instance_test.go index c54e28f..42f3c95 100644 --- a/test/docker/mq_multi_instance_test.go +++ b/test/docker/mq_multi_instance_test.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2019 +© Copyright IBM Corporation 2019, 2020 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/test/docker/mq_multi_instance_test_util.go b/test/docker/mq_multi_instance_test_util.go index 969527f..6dfde7d 100644 --- a/test/docker/mq_multi_instance_test_util.go +++ b/test/docker/mq_multi_instance_test_util.go @@ -76,7 +76,7 @@ func getActiveStandbyQueueManager(t *testing.T, cli *client.Client, qm1aId strin } func getQueueManagerStatus(t *testing.T, cli *client.Client, containerID string, queueManagerName string) string { - _, dspmqOut := execContainer(t, cli, containerID, "mqm", []string{"bash", "-c", "dspmq", "-m", queueManagerName}) + _, dspmqOut := execContainer(t, cli, containerID, "", []string{"bash", "-c", "dspmq", "-m", queueManagerName}) regex := regexp.MustCompile(`STATUS\(.*\)`) status := regex.FindString(dspmqOut) status = strings.TrimSuffix(strings.TrimPrefix(status, "STATUS("), ")") diff --git a/test/docker/mqmetric_test.go b/test/docker/mqmetric_test.go index ee24ec3..752ecd1 100644 --- a/test/docker/mqmetric_test.go +++ b/test/docker/mqmetric_test.go @@ -286,12 +286,12 @@ func TestQMRestart(t *testing.T) { // Restart just the QM (to simulate a lost connection) t.Log("Stopping queue manager\n") - rc, out := execContainer(t, cli, id, "mqm", []string{"endmqm", "-w", "-r", defaultMetricQMName}) + rc, out := execContainer(t, cli, id, "", []string{"endmqm", "-w", "-r", defaultMetricQMName}) if rc != 0 { t.Fatalf("Failed to stop the queue manager. rc=%d, err=%s", rc, out) } t.Log("starting queue manager\n") - rc, out = execContainer(t, cli, id, "mqm", []string{"strmqm", defaultMetricQMName}) + rc, out = execContainer(t, cli, id, "", []string{"strmqm", defaultMetricQMName}) if rc != 0 { t.Fatalf("Failed to start the queue manager. rc=%d, err=%s", rc, out) }