Compare commits
236 Commits
setuid-chk
...
9.3.0.5-r3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d14e60c24 | ||
|
|
4e1393e166 | ||
|
|
c6b9a9c948 | ||
|
|
09427ff5e8 | ||
|
|
3c7a2bc962 | ||
|
|
e00858fd73 | ||
|
|
594ba29e56 | ||
|
|
c614db01b7 | ||
|
|
8257b9634d | ||
|
|
6d624ae33b | ||
|
|
2cb6cf3a4d | ||
|
|
c90c95fc12 | ||
|
|
a88063aa5c | ||
|
|
d655ad283b | ||
|
|
0e66afa78b | ||
|
|
fd527fb30a | ||
|
|
d6d837928f | ||
|
|
a28c8a3acb | ||
|
|
4311c04634 | ||
|
|
5ff3c358ed | ||
|
|
880fa699ef | ||
|
|
bd7c7cd91d | ||
|
|
fb2e7c71e1 | ||
|
|
923407e77f | ||
|
|
2181258e38 | ||
|
|
015481bd3e | ||
|
|
27dada90d6 | ||
|
|
de2d068bb6 | ||
|
|
fd34ea0a78 | ||
|
|
ad02f98858 | ||
|
|
27679a6c58 | ||
|
|
592ebdf555 | ||
|
|
35101841cc | ||
|
|
9033fd67d7 | ||
|
|
066db7bf04 | ||
|
|
c64c188ae5 | ||
|
|
8889ced3c8 | ||
|
|
c4bf74bdf5 | ||
|
|
090a761aef | ||
|
|
11d6685c45 | ||
|
|
45934d8a59 | ||
|
|
c9de739331 | ||
|
|
c78bc602b0 | ||
|
|
f78ac15820 | ||
|
|
0e05030047 | ||
|
|
46869e4df4 | ||
|
|
8ba8ae4f6c | ||
|
|
03e939a49b | ||
|
|
f60281688e | ||
|
|
c3a23b7a1b | ||
|
|
1941fc1675 | ||
|
|
167319022f | ||
|
|
fb1d17764a | ||
|
|
5a20b85759 | ||
|
|
d4668af82f | ||
|
|
ce8a34b1bb | ||
|
|
f9852fb553 | ||
|
|
3957d487c3 | ||
|
|
6427e0d84b | ||
|
|
9f12fc5a04 | ||
|
|
813e1ac2dc | ||
|
|
3111d48330 | ||
|
|
b8dcbde7b7 | ||
|
|
c74cc13a3b | ||
|
|
35cc716fcb | ||
|
|
163873d7a8 | ||
|
|
0e18f17dc9 | ||
|
|
d6ea28ee6b | ||
|
|
093c6be85a | ||
|
|
28faa252a2 | ||
|
|
334df22cfd | ||
|
|
b32963854b | ||
|
|
ad153a3fc2 | ||
|
|
caa0fd6904 | ||
|
|
bd7e1193bf | ||
|
|
7c4d95aa2d | ||
|
|
7f8ffbf914 | ||
|
|
d3c543a42e | ||
|
|
4931e43b67 | ||
|
|
4e26150542 | ||
|
|
bf3d8dd26d | ||
|
|
7c58e2bea2 | ||
|
|
ae5b736f40 | ||
|
|
c1b092e0b1 | ||
|
|
adf7582e8b | ||
|
|
544c2d1e41 | ||
|
|
c3f60c5e24 | ||
|
|
b16246455e | ||
|
|
fdc447761c | ||
|
|
7f5563fa97 | ||
|
|
767381b2a0 | ||
|
|
3ad3e7ea16 | ||
|
|
f6fbc71092 | ||
|
|
0943d420bc | ||
|
|
48cac4fb6c | ||
|
|
c56ec8cd79 | ||
|
|
748d2fd11f | ||
|
|
24eb903b56 | ||
|
|
ebbe30ccf9 | ||
|
|
65e5d60984 | ||
|
|
2279f0b33c | ||
|
|
8fa8d8cb2a | ||
|
|
40d3a9e9ce | ||
|
|
6a8dcfae79 | ||
|
|
85976e1c08 | ||
|
|
4bf3c81e4e | ||
|
|
61e94ed50c | ||
|
|
5c964ef5f7 | ||
|
|
8db0023815 | ||
|
|
060a2e9655 | ||
|
|
d7595f46ff | ||
|
|
d2c11089c8 | ||
|
|
d7fd217770 | ||
|
|
00ada50f06 | ||
|
|
5d88af462f | ||
|
|
eff6ded259 | ||
|
|
2f103128f3 | ||
|
|
a48ac18522 | ||
|
|
1f6d37afed | ||
|
|
5f706e0282 | ||
|
|
1a8855547b | ||
|
|
d0062e71e8 | ||
|
|
353a671c27 | ||
|
|
a46177893c | ||
|
|
65c0ddb289 | ||
|
|
78203aaead | ||
|
|
7cba9ee95f | ||
|
|
7e6b01825b | ||
|
|
79d79ca3d6 | ||
|
|
1e415a30aa | ||
|
|
8461c8822a | ||
|
|
eac4363913 | ||
|
|
a3bf84bcea | ||
|
|
8284ac3169 | ||
|
|
68ef36fafb | ||
|
|
1af99634b4 | ||
|
|
53353c6bac | ||
|
|
a73303d6e6 | ||
|
|
18b0458fa5 | ||
|
|
44eeda157a | ||
|
|
062b29960f | ||
|
|
d4e38c6d85 | ||
|
|
25ba610c6a | ||
|
|
6d2ff0933a | ||
|
|
7a6afb4654 | ||
|
|
f5fdd1008f | ||
|
|
0857c654d2 | ||
|
|
480c3ee027 | ||
|
|
54076af43d | ||
|
|
608f255ab0 | ||
|
|
a927b6e01e | ||
|
|
987a7657ce | ||
|
|
94a78b3122 | ||
|
|
fcc458bf31 | ||
|
|
14987c1170 | ||
|
|
46b0ceede3 | ||
|
|
4bbb447e74 | ||
|
|
ebbbbb04ab | ||
|
|
54bad805c1 | ||
|
|
cecade9845 | ||
|
|
f61a08fe50 | ||
|
|
573fbb8fb1 | ||
|
|
e99c07192d | ||
|
|
9252465cab | ||
|
|
a778eb1cc9 | ||
|
|
2bf2052248 | ||
|
|
d903336fe0 | ||
|
|
b7dcff0bbc | ||
|
|
3e6ceb4bb9 | ||
|
|
b2767947a0 | ||
|
|
a24258834e | ||
|
|
76070234d4 | ||
|
|
d2ea17ec30 | ||
|
|
c0e05be791 | ||
|
|
12a2dee175 | ||
|
|
ac3dcdd0d0 | ||
|
|
4257f6a199 | ||
|
|
5fd9fc5e26 | ||
|
|
adbc95c5d5 | ||
|
|
99a1e4aa74 | ||
|
|
2ae82d71d6 | ||
|
|
8a2faf2955 | ||
|
|
1d41f4b138 | ||
|
|
e1c96655b1 | ||
|
|
68fe4a1dc1 | ||
|
|
adf15b7bd3 | ||
|
|
e77ac9617d | ||
|
|
54824879c5 | ||
|
|
bf8580248b | ||
|
|
e1978541db | ||
|
|
aa7580aa5a | ||
|
|
4366cd8c81 | ||
|
|
2a5242a4d9 | ||
|
|
a4dc545a4f | ||
|
|
f16ce5e4a4 | ||
|
|
03cdf67439 | ||
|
|
e8e86dcc92 | ||
|
|
abf969a64d | ||
|
|
34a55135fb | ||
|
|
dd1d534045 | ||
|
|
c39a532da9 | ||
|
|
efb35ff1b0 | ||
|
|
c2b8753c76 | ||
|
|
f8ae8b0be1 | ||
|
|
e8d26aa79e | ||
|
|
a3e3b0d8c6 | ||
|
|
23f31b1639 | ||
|
|
8d164340c6 | ||
|
|
94ad66661e | ||
|
|
f39f90728f | ||
|
|
a7125b7700 | ||
|
|
9f50b0efaa | ||
|
|
0d5ed76979 | ||
|
|
c37f8f1c4c | ||
|
|
f74777e498 | ||
|
|
55c094a58a | ||
|
|
3d6199e0d8 | ||
|
|
8111761c4f | ||
|
|
4fcdb50928 | ||
|
|
23eba2524e | ||
|
|
678a62f152 | ||
|
|
a2940a4ba8 | ||
|
|
70def702b8 | ||
|
|
f72dc51475 | ||
|
|
afe8aba912 | ||
|
|
444cadf864 | ||
|
|
c2d46d1dff | ||
|
|
6808af107b | ||
|
|
720ecae5bb | ||
|
|
490055e74c | ||
|
|
461529dd98 | ||
|
|
8d7085c18f | ||
|
|
b84581c7ee | ||
|
|
b9dd2f5e79 | ||
|
|
12bcf8b2da | ||
|
|
64a66f6590 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -13,3 +13,10 @@ vendor/github.com/prometheus/client_model/.project
|
|||||||
vendor/github.com/prometheus/client_model/.settings*
|
vendor/github.com/prometheus/client_model/.settings*
|
||||||
gosec_results.json
|
gosec_results.json
|
||||||
internal/qmgrauth/qmgroam/patch
|
internal/qmgrauth/qmgroam/patch
|
||||||
|
.tagcache
|
||||||
|
|
||||||
|
# Nix
|
||||||
|
*.nix
|
||||||
|
.envrc
|
||||||
|
.direnv
|
||||||
|
result
|
||||||
|
|||||||
67
.travis.yml
67
.travis.yml
@@ -12,69 +12,82 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
# Temporarily removing dist tag as not supported by power build
|
dist: bionic
|
||||||
# dist: xenial
|
group: beta
|
||||||
|
|
||||||
sudo: required
|
sudo: required
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- "1.13.15"
|
- "1.19.9"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- MAIN_BRANCH=v9.3.0.x
|
||||||
|
- TAGCACHE_FILE=tagcache
|
||||||
|
- RELEASE=r3
|
||||||
|
|
||||||
go_import_path: "github.com/ibm-messaging/mq-container"
|
go_import_path: "github.com/ibm-messaging/mq-container"
|
||||||
|
|
||||||
# cache:
|
# cache:
|
||||||
# directories:
|
# directories:
|
||||||
# - downloads
|
# - downloads
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- RELEASE="r2"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- stage: basic-build
|
- stage: basic-build
|
||||||
if: branch != private-master AND tag IS blank
|
if: branch != v9.3.0.x AND tag IS blank
|
||||||
name: "Basic AMD64 build"
|
name: "Basic AMD64 build"
|
||||||
os: linux
|
os: linux
|
||||||
env:
|
env:
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_920_ARCHIVE_REPOSITORY_DEV_AMD64
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_930_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
|
|
||||||
|
# CD Build
|
||||||
|
|
||||||
|
- stage: global-tag
|
||||||
|
if: branch = v9.3.0.x AND type != pull_request OR tag =~ ^release-candidate*
|
||||||
|
name: "Generate Global Tag"
|
||||||
|
os: linux
|
||||||
|
script: bash -e travis-build-scripts/global-tag.sh
|
||||||
- stage: build
|
- stage: build
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = v9.3.0.x OR tag =~ ^release-candidate*
|
||||||
name: "Multi-Arch AMD64 build"
|
name: "Multi-Arch AMD64 build"
|
||||||
os: linux
|
os: linux
|
||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_920_ARCHIVE_REPOSITORY_AMD64
|
- MQ_ARCHIVE_REPOSITORY=$MQ_930_ARCHIVE_REPOSITORY_AMD64
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_920_ARCHIVE_REPOSITORY_DEV_AMD64
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_930_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
# - if: branch = private-master OR tag =~ ^release-candidate*
|
|
||||||
# name: "Multi-Arch PPC64LE build"
|
|
||||||
# os: linux-ppc64le
|
|
||||||
# env:
|
|
||||||
# - BUILD_ALL=true
|
|
||||||
# - TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
|
||||||
# # - MQ_ARCHIVE_REPOSITORY=$MQ_920_ARCHIVE_REPOSITORY_PPC64LE
|
|
||||||
# - MQ_ARCHIVE_REPOSITORY_DEV=$MQ_920_ARCHIVE_REPOSITORY_DEV_PPC64LE
|
|
||||||
# script: bash -e travis-build-scripts/run.sh
|
|
||||||
- stage: build
|
- stage: build
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = v9.3.0.x OR tag =~ ^release-candidate*
|
||||||
name: "Multi-Arch S390X build"
|
name: "Multi-Arch S390X build"
|
||||||
os: linux-s390
|
os: linux-s390
|
||||||
env:
|
env:
|
||||||
- BUILD_ALL=true
|
- BUILD_ALL=true
|
||||||
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||||
- MQ_ARCHIVE_REPOSITORY=$MQ_920_ARCHIVE_REPOSITORY_S390X
|
- MQ_ARCHIVE_REPOSITORY=$MQ_930_ARCHIVE_REPOSITORY_S390X
|
||||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_920_ARCHIVE_REPOSITORY_DEV_S390X
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_930_ARCHIVE_REPOSITORY_DEV_S390X
|
||||||
|
script: bash -e travis-build-scripts/run.sh
|
||||||
|
- stage: build
|
||||||
|
if: branch = v9.3.0.x OR tag =~ ^release-candidate*
|
||||||
|
name: "Multi-Arch PPC64LE build"
|
||||||
|
os: linux-ppc64le
|
||||||
|
env:
|
||||||
|
- BUILD_ALL=true
|
||||||
|
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||||
|
- MQ_ARCHIVE_REPOSITORY=$MQ_930_ARCHIVE_REPOSITORY_PPC64LE
|
||||||
|
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_930_ARCHIVE_REPOSITORY_DEV_PPC64LE
|
||||||
script: bash -e travis-build-scripts/run.sh
|
script: bash -e travis-build-scripts/run.sh
|
||||||
- stage: push-manifest
|
- stage: push-manifest
|
||||||
if: branch = private-master OR tag =~ ^release-candidate*
|
if: branch = v9.3.0.x AND type != pull_request OR tag =~ ^release-candidate*
|
||||||
name: "Push Manifest-list to registry"
|
name: "Push Manifest-list to registry"
|
||||||
script: make push-manifest
|
env:
|
||||||
|
- PUSH_MANIFEST_ONLY=true
|
||||||
|
script: bash -e travis-build-scripts/run.sh
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- make install-build-deps
|
- make install-build-deps
|
||||||
- make install-credential-helper
|
- make install-credential-helper
|
||||||
|
|||||||
6
.whitesource
Normal file
6
.whitesource
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"settingsInheritedFrom": "whitesource-config/whitesource-config@master",
|
||||||
|
"scanSettings": {
|
||||||
|
"baseBranches": ["private-master", "v9.2.0.x-eus", "v9.2.5"]
|
||||||
|
}
|
||||||
|
}
|
||||||
55
CHANGELOG.md
55
CHANGELOG.md
@@ -1,5 +1,56 @@
|
|||||||
# Change log
|
# Change log
|
||||||
|
|
||||||
|
## 9.3.0.5-LTS (2023-04)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.3.0.5
|
||||||
|
|
||||||
|
## 9.3.0.4-LTS (2023-02)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.3.0.4
|
||||||
|
|
||||||
|
## 9.3.0.3-LTS (2023-01)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.3.0.3
|
||||||
|
|
||||||
|
## 9.3.0.1-LTS (2022-09)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.3.0.1
|
||||||
|
|
||||||
|
## 9.3.0.0 (2022-06)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.3.0.0
|
||||||
|
* Use `registry.access.redhat.com` instead of `registry.redhat.io`, so that you don't need to login with a Red Hat account.
|
||||||
|
* Updated default developer config to use TLS cipher `ANY_TLS12_OR_HIGHER` instead of `ANY_TLS12`
|
||||||
|
* Added default `jvm.options` file fix issue with missing preferences file causing an error in the web server log.
|
||||||
|
* Updated to allow building image from Podman on macOS (requires Podman 4.1)
|
||||||
|
* Container builds are now faster
|
||||||
|
* Updated signal handling to use a buffer, as recommended by the Go 1.17 vetting tool
|
||||||
|
|
||||||
|
## 9.2.5.0 (2022-03)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.2.5.0
|
||||||
|
|
||||||
|
## 9.2.4.0 (2021-11)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.2.4.0
|
||||||
|
|
||||||
|
## 9.2.3.0 (2021-07-22)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.2.3.0
|
||||||
|
|
||||||
|
## 9.2.2.0 (2021-03-26)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.2.2.0
|
||||||
|
|
||||||
|
## 9.2.1.0 (2020-02-18)
|
||||||
|
|
||||||
|
* Updated to MQ version 9.2.1.0
|
||||||
|
|
||||||
|
|
||||||
|
## 9.2.0.1-LTS (2020-12-04)
|
||||||
|
|
||||||
|
* Added support for MQ Long Term Support (production licensed only) in the mq-container
|
||||||
|
|
||||||
## 9.2.0.0 (2020-07-23)
|
## 9.2.0.0 (2020-07-23)
|
||||||
|
|
||||||
* Updated to [MQ version 9.2.0.0](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.2.0/com.ibm.mq.pro.doc/q113110_.htm)
|
* Updated to [MQ version 9.2.0.0](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.2.0/com.ibm.mq.pro.doc/q113110_.htm)
|
||||||
@@ -15,7 +66,7 @@
|
|||||||
* Updated to MQ version 9.1.4.0
|
* Updated to MQ version 9.1.4.0
|
||||||
* Updated to use UBI8 as base image
|
* Updated to use UBI8 as base image
|
||||||
* Added required security settings to self signed certificates to align with macOS Catalina requirements
|
* Added required security settings to self signed certificates to align with macOS Catalina requirements
|
||||||
|
|
||||||
## 9.1.3.0 (2019-07-19)
|
## 9.1.3.0 (2019-07-19)
|
||||||
|
|
||||||
* Updated to MQ version 9.1.3.0
|
* Updated to MQ version 9.1.3.0
|
||||||
@@ -36,7 +87,7 @@
|
|||||||
* Security fixes
|
* Security fixes
|
||||||
* Web console added to production image
|
* Web console added to production image
|
||||||
* Container built on RedHat host
|
* Container built on RedHat host
|
||||||
|
|
||||||
## 9.1.2.0 (2019-03-21)
|
## 9.1.2.0 (2019-03-21)
|
||||||
|
|
||||||
* Updated to MQ version 9.1.2.0
|
* Updated to MQ version 9.1.2.0
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2015, 2020
|
# © Copyright IBM Corporation 2015, 2022
|
||||||
#
|
#
|
||||||
# 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,14 +12,16 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
ARG BASE_IMAGE=registry.redhat.io/ubi8/ubi-minimal
|
ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal
|
||||||
ARG BASE_TAG=8.2-349
|
ARG BASE_TAG=8.8-860
|
||||||
ARG GO_WORKDIR=/go/src/github.com/ibm-messaging/mq-container
|
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
|
||||||
ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/9.2.0.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
|
ARG BUILDER_TAG=1.19.9-2
|
||||||
|
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
|
||||||
|
ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/9.3.0.5-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build stage to build Go code
|
# Build stage to build Go code
|
||||||
###############################################################################
|
###############################################################################
|
||||||
FROM golang:1.13.15 as builder
|
FROM $BUILDER_IMAGE:$BUILDER_TAG as builder
|
||||||
# The URL to download the MQ installer from in tar.gz format
|
# The URL to download the MQ installer from in tar.gz format
|
||||||
# This assumes an archive containing the MQ Non-Install packages
|
# This assumes an archive containing the MQ Non-Install packages
|
||||||
ARG MQ_URL
|
ARG MQ_URL
|
||||||
@@ -28,31 +30,33 @@ ARG IMAGE_SOURCE="Not specified"
|
|||||||
ARG IMAGE_TAG="Not specified"
|
ARG IMAGE_TAG="Not specified"
|
||||||
ARG GO_WORKDIR
|
ARG GO_WORKDIR
|
||||||
USER 0
|
USER 0
|
||||||
COPY install-mq.sh /usr/local/bin/
|
WORKDIR /opt/mqm
|
||||||
RUN mkdir /opt/mqm \
|
# Download and extract MQ files, to get the MQ client needed to compile.
|
||||||
&& chmod a+x /usr/local/bin/install-mq.sh \
|
# Only extract certain MQ files to make the build quicker
|
||||||
&& sleep 1 \
|
RUN curl --fail --location $MQ_URL | tar --extract --gunzip \
|
||||||
&& INSTALL_SDK=1 install-mq.sh \
|
|
||||||
&& chown -R 1001:root /opt/mqm/*
|
&& chown -R 1001:root /opt/mqm/*
|
||||||
WORKDIR $GO_WORKDIR/
|
WORKDIR $GO_WORKDIR/
|
||||||
|
COPY go.mod go.sum ./
|
||||||
COPY cmd/ ./cmd
|
COPY cmd/ ./cmd
|
||||||
COPY internal/ ./internal
|
COPY internal/ ./internal
|
||||||
COPY pkg/ ./pkg
|
COPY pkg/ ./pkg
|
||||||
COPY vendor/ ./vendor
|
COPY vendor/ ./vendor
|
||||||
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \
|
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \
|
||||||
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*"
|
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
|
||||||
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/
|
PATH="${PATH}:/opt/mqm/bin"
|
||||||
RUN go build ./cmd/chkmqready/
|
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/chkmqhealthy/
|
&& go build ./cmd/chkmqready/ \
|
||||||
RUN go build ./cmd/runmqdevserver/
|
&& go build ./cmd/chkmqhealthy/ \
|
||||||
RUN go build -buildmode=c-shared -o amqpasdev.so ./internal/qmgrauth/pas.go
|
&& go build ./cmd/chkmqstarted/ \
|
||||||
RUN go test -v ./cmd/runmqdevserver/...
|
&& go build ./cmd/runmqdevserver/ \
|
||||||
RUN go test -v ./cmd/runmqserver/
|
&& go test -v ./cmd/runmqdevserver/... \
|
||||||
RUN go test -v ./cmd/chkmqready/
|
&& go test -v ./cmd/runmqserver/ \
|
||||||
RUN go test -v ./cmd/chkmqhealthy/
|
&& go test -v ./cmd/chkmqready/ \
|
||||||
RUN go test -v ./pkg/...
|
&& go test -v ./cmd/chkmqhealthy/ \
|
||||||
RUN go test -v ./internal/...
|
&& go test -v ./cmd/chkmqstarted/ \
|
||||||
RUN go vet ./cmd/... ./internal/...
|
&& go test -v ./pkg/... \
|
||||||
|
&& go test -v ./internal/... \
|
||||||
|
&& go vet ./cmd/... ./internal/...
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Main build stage, to build MQ image
|
# Main build stage, to build MQ image
|
||||||
@@ -63,18 +67,18 @@ ARG MQ_URL
|
|||||||
ARG BASE_IMAGE
|
ARG BASE_IMAGE
|
||||||
ARG BASE_TAG
|
ARG BASE_TAG
|
||||||
ARG GO_WORKDIR
|
ARG GO_WORKDIR
|
||||||
LABEL summary="IBM MQ Advanced Server"
|
LABEL summary="IBM MQ Advanced Server" \
|
||||||
LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises"
|
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"
|
vendor="IBM" \
|
||||||
LABEL maintainer="IBM"
|
maintainer="IBM" \
|
||||||
LABEL distribution-scope="private"
|
distribution-scope="private" \
|
||||||
LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/"
|
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
|
||||||
LABEL url="https://www.ibm.com/products/mq/advanced"
|
url="https://www.ibm.com/products/mq/advanced" \
|
||||||
LABEL io.openshift.tags="mq messaging"
|
io.openshift.tags="mq messaging" \
|
||||||
LABEL io.k8s.display-name="IBM MQ Advanced Server"
|
io.k8s.display-name="IBM MQ Advanced Server" \
|
||||||
LABEL io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises"
|
io.k8s.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 base-image=$BASE_IMAGE
|
base-image=$BASE_IMAGE \
|
||||||
LABEL base-image-release=$BASE_TAG
|
base-image-release=$BASE_TAG
|
||||||
COPY install-mq.sh /usr/local/bin/
|
COPY install-mq.sh /usr/local/bin/
|
||||||
COPY install-mq-server-prereqs.sh /usr/local/bin/
|
COPY install-mq-server-prereqs.sh /usr/local/bin/
|
||||||
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
|
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
|
||||||
@@ -86,12 +90,10 @@ RUN env \
|
|||||||
&& install-mq.sh \
|
&& install-mq.sh \
|
||||||
&& /opt/mqm/bin/security/amqpamcf \
|
&& /opt/mqm/bin/security/amqpamcf \
|
||||||
&& chown -R 1001:root /opt/mqm/*
|
&& chown -R 1001:root /opt/mqm/*
|
||||||
# Create a directory for runtime data from runmqserver
|
|
||||||
RUN mkdir -p /run/runmqserver \
|
|
||||||
&& chown 1001:root /run/runmqserver
|
|
||||||
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/
|
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/
|
||||||
COPY --from=builder $GO_WORKDIR/chkmq* /usr/local/bin/
|
COPY --from=builder $GO_WORKDIR/chkmq* /usr/local/bin/
|
||||||
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
||||||
|
COPY ha/native-ha.ini.tpl /etc/mqm/native-ha.ini.tpl
|
||||||
# Copy web XML files
|
# Copy web XML files
|
||||||
COPY web /etc/mqm/web
|
COPY web /etc/mqm/web
|
||||||
COPY etc/mqm/*.tpl /etc/mqm/
|
COPY etc/mqm/*.tpl /etc/mqm/
|
||||||
@@ -114,6 +116,21 @@ USER 1001
|
|||||||
ENV MQ_CONNAUTH_USE_HTP=false
|
ENV MQ_CONNAUTH_USE_HTP=false
|
||||||
ENTRYPOINT ["runmqserver"]
|
ENTRYPOINT ["runmqserver"]
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Build stage to build C code for custom authorization service (developer-only)
|
||||||
|
###############################################################################
|
||||||
|
# Use the Go toolset image, which already includes gcc and the MQ SDK
|
||||||
|
FROM builder as cbuilder
|
||||||
|
# The URL to download the MQ installer from in tar.gz format
|
||||||
|
# This assumes an archive containing the MQ Non-Install packages
|
||||||
|
ARG MQ_URL
|
||||||
|
USER 0
|
||||||
|
# Install the Apache Portable Runtime code (used for htpasswd hash checking)
|
||||||
|
RUN yum --assumeyes --disableplugin=subscription-manager install apr-devel apr-util-openssl apr-util-devel
|
||||||
|
COPY authservice/ /opt/app-root/src/authservice/
|
||||||
|
WORKDIR /opt/app-root/src/authservice/mqhtpass
|
||||||
|
RUN make all
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Add default developer config
|
# Add default developer config
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -121,31 +138,25 @@ FROM mq-server AS mq-dev-server
|
|||||||
ARG BASE_IMAGE
|
ARG BASE_IMAGE
|
||||||
ARG BASE_TAG
|
ARG BASE_TAG
|
||||||
ARG GO_WORKDIR
|
ARG GO_WORKDIR
|
||||||
# Enable MQ developer default configuration
|
LABEL summary="IBM MQ Advanced for Developers Server" \
|
||||||
ENV MQ_DEV=true
|
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 summary="IBM MQ Advanced for Developers Server"
|
vendor="IBM" \
|
||||||
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"
|
distribution-scope="private" \
|
||||||
LABEL vendor="IBM"
|
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
|
||||||
LABEL distribution-scope="private"
|
url="https://www.ibm.com/products/mq/advanced" \
|
||||||
LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/"
|
io.openshift.tags="mq messaging" \
|
||||||
LABEL url="https://www.ibm.com/products/mq/advanced"
|
io.k8s.display-name="IBM MQ Advanced for Developers Server" \
|
||||||
LABEL io.openshift.tags="mq messaging"
|
io.k8s.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 io.k8s.display-name="IBM MQ Advanced for Developers Server"
|
base-image=$BASE_IMAGE \
|
||||||
LABEL io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises"
|
base-image-release=$BASE_TAG
|
||||||
LABEL base-image=$BASE_IMAGE
|
|
||||||
LABEL base-image-release=$BASE_TAG
|
|
||||||
USER 0
|
USER 0
|
||||||
COPY --from=builder $GO_WORKDIR/amqpas* /opt/mqm/lib64/
|
COPY --from=cbuilder /opt/app-root/src/authservice/mqhtpass/build/mqhtpass.so /opt/mqm/lib64/
|
||||||
COPY etc/mqm/*.ini /etc/mqm/
|
COPY etc/mqm/*.ini /etc/mqm/
|
||||||
COPY etc/mqm/mq.htpasswd /etc/mqm/
|
COPY etc/mqm/mq.htpasswd /etc/mqm/
|
||||||
RUN chmod 0660 /etc/mqm/mq.htpasswd
|
|
||||||
COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/
|
COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/
|
||||||
RUN chmod u+x /usr/local/bin/install-extra-packages.sh \
|
RUN chmod u+x /usr/local/bin/install-extra-packages.sh \
|
||||||
&& sleep 1 \
|
&& sleep 1 \
|
||||||
&& install-extra-packages.sh
|
&& install-extra-packages.sh
|
||||||
# Create a directory for runtime data from runmqserver
|
|
||||||
RUN mkdir -p /run/runmqdevserver \
|
|
||||||
&& chown 1001:root /run/runmqdevserver
|
|
||||||
COPY --from=builder $GO_WORKDIR/runmqdevserver /usr/local/bin/
|
COPY --from=builder $GO_WORKDIR/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/
|
||||||
@@ -154,10 +165,13 @@ COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
|
|||||||
RUN chown -R 1001:root /etc/mqm/* \
|
RUN chown -R 1001:root /etc/mqm/* \
|
||||||
&& chmod -R g+w /etc/mqm/web \
|
&& chmod -R g+w /etc/mqm/web \
|
||||||
&& chmod +x /usr/local/bin/runmq* \
|
&& chmod +x /usr/local/bin/runmq* \
|
||||||
|
&& chmod 0660 /etc/mqm/mq.htpasswd \
|
||||||
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqdevserver
|
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqdevserver
|
||||||
ENV MQ_ENABLE_EMBEDDED_WEB_SERVER=1 MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost
|
ENV MQ_DEV=true \
|
||||||
ENV LD_LIBRARY_PATH=/opt/mqm/lib64
|
MQ_ENABLE_EMBEDDED_WEB_SERVER=1 \
|
||||||
ENV MQS_PERMIT_UNKNOWN_ID=true
|
MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost \
|
||||||
ENV MQ_CONNAUTH_USE_HTP=true
|
LD_LIBRARY_PATH=/opt/mqm/lib64 \
|
||||||
|
MQ_CONNAUTH_USE_HTP=true \
|
||||||
|
MQS_PERMIT_UNKNOWN_ID=true
|
||||||
USER 1001
|
USER 1001
|
||||||
ENTRYPOINT ["runmqdevserver"]
|
ENTRYPOINT ["runmqdevserver"]
|
||||||
|
|||||||
361
Makefile
361
Makefile
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2017, 2020
|
# © Copyright IBM Corporation 2017, 2023
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -16,10 +16,12 @@
|
|||||||
# Conditional variables - you can override the values of these variables from
|
# Conditional variables - you can override the values of these variables from
|
||||||
# the command line
|
# the command line
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
include config.env
|
||||||
|
include source-branch.env
|
||||||
|
|
||||||
# RELEASE shows what release of the container code has been built
|
# RELEASE shows what release of the container code has been built
|
||||||
RELEASE ?=
|
RELEASE ?=
|
||||||
# MQ_VERSION is the fully qualified MQ version number to build
|
|
||||||
MQ_VERSION ?= 9.2.0.0
|
|
||||||
# MQ_ARCHIVE_REPOSITORY is a remote repository from which to pull the MQ_ARCHIVE (if required)
|
# MQ_ARCHIVE_REPOSITORY is a remote repository from which to pull the MQ_ARCHIVE (if required)
|
||||||
MQ_ARCHIVE_REPOSITORY ?=
|
MQ_ARCHIVE_REPOSITORY ?=
|
||||||
# MQ_ARCHIVE_REPOSITORY_DEV is a remote repository from which to pull the MQ_ARCHIVE_DEV (if required)
|
# MQ_ARCHIVE_REPOSITORY_DEV is a remote repository from which to pull the MQ_ARCHIVE_DEV (if required)
|
||||||
@@ -37,15 +39,17 @@ MQ_ARCHIVE_DEV ?= $(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-$(MQ_
|
|||||||
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
|
||||||
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||||
# Options to `go test` for the Docker tests
|
# Options to `go test` for the Docker tests
|
||||||
TEST_OPTS_DOCKER ?=
|
TEST_OPTS_DOCKER ?=
|
||||||
# Timeout for the Docker tests
|
# Timeout for the Docker tests
|
||||||
TEST_TIMEOUT_DOCKER ?= 30m
|
TEST_TIMEOUT_DOCKER ?= 30m
|
||||||
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
||||||
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
||||||
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
||||||
MQ_IMAGE_DEVSERVER ?=ibm-mqadvanced-server-dev
|
MQ_IMAGE_DEVSERVER ?=ibm-mqadvanced-server-dev
|
||||||
|
# MQ_MANIFEST_TAG is the tag to use for fat-manifest
|
||||||
|
MQ_MANIFEST_TAG ?= $(MQ_VERSION)$(RELEASE_TAG)$(LTS_TAG)$(MQ_MANIFEST_TAG_SUFFIX)
|
||||||
# MQ_TAG is the tag of the built MQ Advanced image & MQ Advanced for Developers image
|
# MQ_TAG is the tag of the built MQ Advanced image & MQ Advanced for Developers image
|
||||||
MQ_TAG ?=$(MQ_VERSION)-$(ARCH)
|
MQ_TAG ?= $(MQ_MANIFEST_TAG)-$(ARCH)
|
||||||
# COMMAND is the container command to run. "podman" or "docker"
|
# COMMAND is the container command to run. "podman" or "docker"
|
||||||
COMMAND ?=$(shell type -p podman 2>&1 >/dev/null && echo podman || echo docker)
|
COMMAND ?=$(shell type -p podman 2>&1 >/dev/null && echo podman || echo docker)
|
||||||
# MQ_DELIVERY_REGISTRY_HOSTNAME is a remote registry to push the MQ Image to (if required)
|
# MQ_DELIVERY_REGISTRY_HOSTNAME is a remote registry to push the MQ Image to (if required)
|
||||||
@@ -56,26 +60,28 @@ MQ_DELIVERY_REGISTRY_NAMESPACE ?=
|
|||||||
MQ_DELIVERY_REGISTRY_USER ?=
|
MQ_DELIVERY_REGISTRY_USER ?=
|
||||||
# MQ_DELIVERY_REGISTRY_CREDENTIAL is the password/API key for the remote registry (if required)
|
# MQ_DELIVERY_REGISTRY_CREDENTIAL is the password/API key for the remote registry (if required)
|
||||||
MQ_DELIVERY_REGISTRY_CREDENTIAL ?=
|
MQ_DELIVERY_REGISTRY_CREDENTIAL ?=
|
||||||
# REGISTRY_USER is the username used to login to the Red Hat registry
|
|
||||||
REGISTRY_USER ?=
|
|
||||||
# REGISTRY_PASS is the password used to login to the Red Hat registry
|
|
||||||
REGISTRY_PASS ?=
|
|
||||||
# ARCH is the platform architecture (e.g. amd64, ppc64le or s390x)
|
# ARCH is the platform architecture (e.g. amd64, ppc64le or s390x)
|
||||||
ARCH ?= $(if $(findstring x86_64,$(shell uname -m)),amd64,$(shell uname -m))
|
ARCH ?= $(if $(findstring x86_64,$(shell uname -m)),amd64,$(shell uname -m))
|
||||||
# Tag to use for fat-manifest
|
# LTS is a boolean value to enable/disable LTS container build
|
||||||
MQ_MANIFEST_TAG=$(MQ_VERSION)
|
LTS ?= false
|
||||||
|
# VOLUME_MOUNT_OPTIONS is used when bind-mounting files from the "downloads" directory into the container. By default, SELinux labels are automatically re-written, but this doesn't work on some filesystems with extended attributes (xattrs). You can turn off the label re-writing by setting this variable to be blank.
|
||||||
|
VOLUME_MOUNT_OPTIONS ?= :Z
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Other variables
|
# Other variables
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
# Lock Docker API version for compatibility with Podman and with the Docker version in Travis' Ubuntu Bionic
|
||||||
|
DOCKER_API_VERSION=1.40
|
||||||
GO_PKG_DIRS = ./cmd ./internal ./test
|
GO_PKG_DIRS = ./cmd ./internal ./test
|
||||||
MQ_ARCHIVE_TYPE=LINUX
|
MQ_ARCHIVE_TYPE=LINUX
|
||||||
MQ_ARCHIVE_DEV_TYPE=Linux
|
MQ_ARCHIVE_DEV_TYPE=Linux
|
||||||
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
|
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
|
||||||
BUILD_SERVER_CONTAINER=build-server
|
BUILD_SERVER_CONTAINER=build-server
|
||||||
|
# BUILD_SERVER_NETWORK is the name of the network to use for the web server container used at build time
|
||||||
|
BUILD_SERVER_NETWORK=build
|
||||||
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
|
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
|
||||||
# test run in parallel
|
# test run in parallel
|
||||||
NUM_CPU ?= $(or $(shell docker info --format "{{ .NCPU }}"),2)
|
NUM_CPU ?= $(or $(shell $(COMMAND) info --format "{{ .NCPU }}"),2)
|
||||||
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
|
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
|
||||||
BASE_IMAGE_TAG=$(lastword $(subst /, ,$(subst :,-,$(BASE_IMAGE))))
|
BASE_IMAGE_TAG=$(lastword $(subst /, ,$(subst :,-,$(BASE_IMAGE))))
|
||||||
#BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
|
#BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
|
||||||
@@ -108,27 +114,83 @@ else ifeq "$(ARCH)" "s390x"
|
|||||||
MQ_ARCHIVE_ARCH=S390X
|
MQ_ARCHIVE_ARCH=S390X
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# If this is a fake master build, push images to alternative location (pipeline wont consider these images GA candidates)
|
||||||
|
ifeq ($(shell [ "$(TRAVIS)" = "true" ] && [ -n "$(MAIN_BRANCH)" ] && [ -n "$(SOURCE_BRANCH)" ] && [ "$(MAIN_BRANCH)" != "$(SOURCE_BRANCH)" ] && echo "true"), true)
|
||||||
|
MQ_DELIVERY_REGISTRY_NAMESPACE="master-fake"
|
||||||
|
endif
|
||||||
|
|
||||||
|
# LTS_TAG is the tag modifier for an LTS container build
|
||||||
|
LTS_TAG=
|
||||||
|
ifeq "$(LTS)" "true"
|
||||||
|
ifneq "$(LTS_TAG_OVERRIDE)" "$(EMPTY)"
|
||||||
|
LTS_TAG=$(LTS_TAG_OVERRIDE)
|
||||||
|
else
|
||||||
|
LTS_TAG=-lts
|
||||||
|
endif
|
||||||
|
MQ_ARCHIVE:=$(MQ_VERSION)-IBM-MQ-Advanced-Non-Install-Linux$(MQ_ARCHIVE_ARCH).tar.gz
|
||||||
|
MQ_DELIVERY_REGISTRY_NAMESPACE:=$(MQ_DELIVERY_REGISTRY_NAMESPACE)$(LTS_TAG)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring release-candidate,$(TRAVIS_TAG)))
|
||||||
|
MQ_DELIVERY_REGISTRY_NAMESPACE=release-candidates
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq "$(MQ_DELIVERY_REGISTRY_NAMESPACE)" "$(EMPTY)"
|
ifneq "$(MQ_DELIVERY_REGISTRY_NAMESPACE)" "$(EMPTY)"
|
||||||
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_DELIVERY_REGISTRY_NAMESPACE)
|
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_DELIVERY_REGISTRY_NAMESPACE)
|
||||||
else
|
else
|
||||||
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)
|
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# image tagging
|
||||||
|
|
||||||
ifneq "$(RELEASE)" "$(EMPTY)"
|
ifneq "$(RELEASE)" "$(EMPTY)"
|
||||||
MQ_TAG=$(MQ_VERSION)-$(RELEASE)-$(ARCH)
|
EXTRA_LABELS_RELEASE=--label "release=$(RELEASE)"
|
||||||
EXTRA_LABELS=--label release=$(RELEASE)
|
RELEASE_TAG="-$(RELEASE)"
|
||||||
MQ_MANIFEST_TAG=$(MQ_VERSION)-$(RELEASE)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq "$(MQ_ARCHIVE_LEVEL)" "$(EMPTY)"
|
||||||
|
EXTRA_LABELS_LEVEL=--label "mq-build=$(MQ_ARCHIVE_LEVEL)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
EXTRA_LABELS=$(EXTRA_LABELS_RELEASE) $(EXTRA_LABELS_LEVEL)
|
||||||
|
|
||||||
|
ifeq "$(TIMESTAMPFLAT)" "$(EMPTY)"
|
||||||
|
TIMESTAMPFLAT=$(shell date "+%Y%m%d%H%M%S")
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(GIT_COMMIT)" "$(EMPTY)"
|
||||||
|
GIT_COMMIT=$(shell git rev-parse --short HEAD)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(shell [ ! -z $(TRAVIS) ] && [ "$(TRAVIS_PULL_REQUEST)" = "false" ] && [ "$(TRAVIS_BRANCH)" = "$(MAIN_BRANCH)" ] && echo true), true)
|
||||||
|
MQ_MANIFEST_TAG_SUFFIX=.$(TIMESTAMPFLAT).$(GIT_COMMIT)
|
||||||
|
endif
|
||||||
|
|
||||||
|
PATH_TO_MQ_TAG_CACHE=$(TRAVIS_BUILD_DIR)/.tagcache
|
||||||
|
ifneq "$(TRAVIS)" "$(EMPTY)"
|
||||||
|
ifneq ("$(wildcard $(PATH_TO_MQ_TAG_CACHE))","")
|
||||||
|
include $(PATH_TO_MQ_TAG_CACHE)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
MQ_AMD64_TAG=$(MQ_MANIFEST_TAG)-amd64
|
||||||
|
MQ_S390X_TAG?=$(MQ_MANIFEST_TAG)-s390x
|
||||||
|
MQ_PPC64LE_TAG?=$(MQ_MANIFEST_TAG)-ppc64le
|
||||||
|
|
||||||
|
# end image tagging
|
||||||
|
|
||||||
MQ_IMAGE_FULL_RELEASE_NAME=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
MQ_IMAGE_FULL_RELEASE_NAME=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
||||||
MQ_IMAGE_DEV_FULL_RELEASE_NAME=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
MQ_IMAGE_DEV_FULL_RELEASE_NAME=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
||||||
|
|
||||||
#setup variables for fat-manifests
|
#setup variables for fat-manifests
|
||||||
MQ_IMAGE_DEVSERVER_MANIFEST=$(MQ_IMAGE_DEVSERVER):$(MQ_MANIFEST_TAG)
|
MQ_IMAGE_DEVSERVER_MANIFEST=$(MQ_IMAGE_DEVSERVER):$(MQ_MANIFEST_TAG)
|
||||||
MQ_IMAGE_ADVANCEDSERVER_MANIFEST=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_MANIFEST_TAG)
|
MQ_IMAGE_ADVANCEDSERVER_MANIFEST=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_MANIFEST_TAG)
|
||||||
MQ_IMAGE_DEVSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_MANIFEST_TAG)-amd64
|
MQ_IMAGE_DEVSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_AMD64_TAG)
|
||||||
MQ_IMAGE_DEVSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_MANIFEST_TAG)-s390x
|
MQ_IMAGE_DEVSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_S390X_TAG)
|
||||||
MQ_IMAGE_ADVANCEDSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_MANIFEST_TAG)-amd64
|
MQ_IMAGE_DEVSERVER_PPC64LE=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_PPC64LE_TAG)
|
||||||
MQ_IMAGE_ADVANCEDSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_MANIFEST_TAG)-s390x
|
MQ_IMAGE_ADVANCEDSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_AMD64_TAG)
|
||||||
|
MQ_IMAGE_ADVANCEDSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_S390X_TAG)
|
||||||
|
MQ_IMAGE_ADVANCEDSERVER_PPC64LE=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_PPC64LE_TAG)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Build targets
|
# Build targets
|
||||||
@@ -156,36 +218,63 @@ incubating: build-explorer
|
|||||||
downloads/$(MQ_ARCHIVE_DEV):
|
downloads/$(MQ_ARCHIVE_DEV):
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
||||||
mkdir -p downloads
|
mkdir -p downloads
|
||||||
ifneq "$(MQ_ARCHIVE_REPOSITORY_DEV)" "$(EMPTY)"
|
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)"
|
||||||
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" -o downloads/$(MQ_ARCHIVE_DEV)
|
# Use key which is not stored in the repository to fetch the files from the fileserver
|
||||||
|
curl --fail --location $(BUILD_RSYNC_ENCRYPTED_KEY_URL) --output ./host.key.gpg
|
||||||
|
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --batch --passphrase-fd 0 ./host.key.gpg
|
||||||
|
chmod 600 ./host.key
|
||||||
|
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE_DEV)
|
||||||
|
-@rm host.key.gpg host.key
|
||||||
else
|
else
|
||||||
curl -L https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV) -o downloads/$(MQ_ARCHIVE_DEV)
|
ifneq "$(MQ_ARCHIVE_REPOSITORY_DEV)" "$(EMPTY)"
|
||||||
|
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" --output downloads/$(MQ_ARCHIVE_DEV)
|
||||||
|
else
|
||||||
|
curl --fail --location https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV) --output downloads/$(MQ_ARCHIVE_DEV)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
downloads/$(MQ_ARCHIVE):
|
downloads/$(MQ_ARCHIVE):
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced "$(MQ_VERSION)$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced "$(MQ_VERSION)$(END)))
|
||||||
mkdir -p downloads
|
mkdir -p downloads
|
||||||
|
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)"
|
||||||
|
# Use key which is not stored in the repository to fetch the files from the fileserver
|
||||||
|
-@rm host.key.gpg host.key
|
||||||
|
curl --fail --location $(BUILD_RSYNC_ENCRYPTED_KEY_URL) --output ./host.key.gpg
|
||||||
|
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --batch --passphrase-fd 0 ./host.key.gpg
|
||||||
|
chmod 600 ./host.key
|
||||||
|
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE)
|
||||||
|
-@rm host.key.gpg host.key
|
||||||
|
else
|
||||||
ifneq "$(MQ_ARCHIVE_REPOSITORY)" "$(EMPTY)"
|
ifneq "$(MQ_ARCHIVE_REPOSITORY)" "$(EMPTY)"
|
||||||
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY)" -o downloads/$(MQ_ARCHIVE)
|
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY)" --output downloads/$(MQ_ARCHIVE)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: downloads
|
.PHONY: downloads
|
||||||
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
||||||
|
|
||||||
|
.PHONY: cache-mq-tag
|
||||||
|
cache-mq-tag:
|
||||||
|
@printf "MQ_MANIFEST_TAG=$(MQ_MANIFEST_TAG)\n" | tee $(PATH_TO_MQ_TAG_CACHE)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Test targets
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
# Vendor Go dependencies for the Docker tests
|
# Vendor Go dependencies for the Docker tests
|
||||||
test/docker/vendor:
|
test/docker/vendor:
|
||||||
cd test/docker && dep ensure -vendor-only
|
cd test/docker && go mod vendor
|
||||||
|
|
||||||
# Shortcut to just run the unit tests
|
# Shortcut to just run the unit tests
|
||||||
.PHONY: test-unit
|
.PHONY: test-unit
|
||||||
test-unit:
|
test-unit:
|
||||||
docker build --target builder --file Dockerfile-server .
|
$(COMMAND) build --target builder --file Dockerfile-server .
|
||||||
|
|
||||||
.PHONY: test-advancedserver
|
.PHONY: test-advancedserver
|
||||||
test-advancedserver: test/docker/vendor
|
test-advancedserver: test/docker/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||||
docker inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
$(COMMAND) inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) $(TEST_OPTS_DOCKER)
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
.PHONY: build-devjmstest
|
.PHONY: build-devjmstest
|
||||||
build-devjmstest:
|
build-devjmstest:
|
||||||
@@ -194,10 +283,9 @@ build-devjmstest:
|
|||||||
|
|
||||||
.PHONY: test-devserver
|
.PHONY: test-devserver
|
||||||
test-devserver: test/docker/vendor
|
test-devserver: test/docker/vendor
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||||
|
$(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
||||||
docker inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=true DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER)
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=true go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER)
|
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
coverage:
|
coverage:
|
||||||
@@ -205,7 +293,7 @@ coverage:
|
|||||||
|
|
||||||
.PHONY: test-advancedserver-cover
|
.PHONY: test-advancedserver-cover
|
||||||
test-advancedserver-cover: test/docker/vendor coverage
|
test-advancedserver-cover: test/docker/vendor coverage
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell docker --version)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell $(COMMAND) --version)"$(END)))
|
||||||
rm -f ./coverage/unit*.cov
|
rm -f ./coverage/unit*.cov
|
||||||
# Run unit tests with coverage, for each package under 'internal'
|
# 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/{}
|
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
|
||||||
@@ -217,7 +305,7 @@ test-advancedserver-cover: test/docker/vendor coverage
|
|||||||
rm -f ./test/docker/coverage/*.cov
|
rm -f ./test/docker/coverage/*.cov
|
||||||
rm -f ./coverage/docker.*
|
rm -f ./coverage/docker.*
|
||||||
mkdir -p ./test/docker/coverage/
|
mkdir -p ./test/docker/coverage/
|
||||||
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true go test $(TEST_OPTS_DOCKER)
|
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test $(TEST_OPTS_DOCKER)
|
||||||
echo 'mode: count' > ./coverage/docker.cov
|
echo 'mode: count' > ./coverage/docker.cov
|
||||||
tail -q -n +2 ./test/docker/coverage/*.cov >> ./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
|
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
|
||||||
@@ -226,16 +314,17 @@ test-advancedserver-cover: test/docker/vendor coverage
|
|||||||
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./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
|
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
||||||
|
|
||||||
# Build an MQ image. The commands used are slightly different between Docker and Podman
|
###############################################################################
|
||||||
define build-mq
|
# Build functions
|
||||||
$(if $(findstring docker,$(COMMAND)), @docker network create build,)
|
###############################################################################
|
||||||
$(if $(findstring docker,$(COMMAND)), @docker run --rm --name $(BUILD_SERVER_CONTAINER) --network build --network-alias build --volume $(DOWNLOADS_DIR):/usr/share/nginx/html:ro --detach docker.io/nginx:alpine,)
|
|
||||||
$(eval EXTRA_ARGS=$(if $(findstring docker,$(COMMAND)), --network build --build-arg MQ_URL=http://build:80/$4, --volume $(DOWNLOADS_DIR):/var/downloads --build-arg MQ_URL=file:///var/downloads/$4))
|
# Command to build the image
|
||||||
# Build the new image
|
# Args: imageName, imageTag, dockerfile, extraArgs, dockerfileTarget
|
||||||
|
define build-mq-command
|
||||||
$(COMMAND) build \
|
$(COMMAND) build \
|
||||||
--tag $1:$2 \
|
--tag $1:$2 \
|
||||||
--file $3 \
|
--file $3 \
|
||||||
$(EXTRA_ARGS) \
|
$4 \
|
||||||
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
||||||
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
||||||
--build-arg IMAGE_TAG="$1:$2" \
|
--build-arg IMAGE_TAG="$1:$2" \
|
||||||
@@ -243,36 +332,81 @@ define build-mq
|
|||||||
--label name=$1 \
|
--label name=$1 \
|
||||||
--label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \
|
--label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \
|
||||||
--label architecture="$(ARCH)" \
|
--label architecture="$(ARCH)" \
|
||||||
--label run="docker run -d -e LICENSE=accept $1:$2" \
|
--label run="podman run -d -e LICENSE=accept $1:$2" \
|
||||||
--label vcs-ref=$(IMAGE_REVISION) \
|
--label vcs-ref=$(IMAGE_REVISION) \
|
||||||
--label vcs-type=git \
|
--label vcs-type=git \
|
||||||
--label vcs-url=$(IMAGE_SOURCE) \
|
--label vcs-url=$(IMAGE_SOURCE) \
|
||||||
$(EXTRA_LABELS) \
|
$(EXTRA_LABELS) \
|
||||||
--target $5 \
|
--target $5 \
|
||||||
.
|
.
|
||||||
$(if $(findstring docker,$(COMMAND)), @docker kill $(BUILD_SERVER_CONTAINER))
|
|
||||||
$(if $(findstring docker,$(COMMAND)), @docker network rm build)
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
|
# Build using a separate container to host the MQ download files.
|
||||||
DOCKER_CLIENT_VERSION=$(shell docker version --format "{{ .Client.Version }}")
|
# To minimize the layers in the resulting image, the download files can't be part of the build context.
|
||||||
PODMAN_VERSION=$(shell podman version --format "{{ .Version }}")
|
# The "docker build" command (and "podman build" on macOS) don't allow you to mount a directory into the build, so a
|
||||||
.PHONY: command-version
|
# separate container is used to host a web server.
|
||||||
command-version:
|
# Note that for Podman, this means that you need to be using the "rootful" mode, because the rootless mode doesn't allow
|
||||||
# If we're using Docker, then check it's recent enough to support multi-stage builds
|
# much control of networking, so the containers can't talk to each other.
|
||||||
ifneq (,$(findstring docker,$(COMMAND)))
|
define build-mq-using-web-server
|
||||||
@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)
|
$(COMMAND) network create $(BUILD_SERVER_NETWORK)
|
||||||
@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)
|
$(COMMAND) run \
|
||||||
endif
|
--rm \
|
||||||
ifneq (,$(findstring podman,$(COMMAND)))
|
--name $(BUILD_SERVER_CONTAINER) \
|
||||||
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
|
--network $(BUILD_SERVER_NETWORK) \
|
||||||
|
--volume $(DOWNLOADS_DIR):/opt/app-root/src$(VOLUME_MOUNT_OPTIONS) \
|
||||||
|
--detach \
|
||||||
|
registry.access.redhat.com/ubi8/nginx-120 nginx -g "daemon off;" || ($(COMMAND) network rm $(BUILD_SERVER_NETWORK) && exit 1)
|
||||||
|
BUILD_SERVER_IP=$$($(COMMAND) inspect -f '{{ .NetworkSettings.Networks.$(BUILD_SERVER_NETWORK).IPAddress }}' $(BUILD_SERVER_CONTAINER)); \
|
||||||
|
DOCKER_BUILDKIT=0 $(call build-mq-command,$1,$2,$3,--network build --build-arg MQ_URL=http://$$BUILD_SERVER_IP:8080/$4,$5) || ($(COMMAND) rm -f $(BUILD_SERVER_CONTAINER) && $(COMMAND) network rm $(BUILD_SERVER_NETWORK) && exit 1)
|
||||||
|
$(COMMAND) rm -f $(BUILD_SERVER_CONTAINER)
|
||||||
|
$(COMMAND) network rm $(BUILD_SERVER_NETWORK)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# When building with Docker, always use the web server build because you can't use bind-mounted volumes.
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-docker
|
||||||
|
$(call build-mq-using-web-server,$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Make sure we don't use VOLUME_MOUNT_OPTIONS for Podman on macOS
|
||||||
|
ifeq "$(COMMAND)" "podman"
|
||||||
|
ifeq "$(shell uname -s)" "Darwin"
|
||||||
|
VOLUME_MOUNT_OPTIONS:=
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# When building with Podman on macOS (Darwin), use the web server build because you can't use bind-mounted volumes with `podman build` on macOS
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-podman-Darwin
|
||||||
|
$(call build-mq-using-web-server,$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# When building with Podman on Linux, just pass the downloads directory as a volume
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-podman-Linux
|
||||||
|
$(call build-mq-command,$1,$2,$3,--volume $(DOWNLOADS_DIR):/var/downloads$(VOLUME_MOUNT_OPTIONS) --build-arg MQ_URL=file:///var/downloads/$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# When building with Podman, just pass the downloads directory as a volume
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq-podman
|
||||||
|
$(call build-mq-podman-$(shell uname -s),$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Build an MQ image. The commands used are slightly different between Docker and Podman
|
||||||
|
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||||
|
define build-mq
|
||||||
|
$(call build-mq-$(COMMAND),$1,$2,$3,$4,$5)
|
||||||
|
endef
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Build targets
|
||||||
|
###############################################################################
|
||||||
.PHONY: build-advancedserver-host
|
.PHONY: build-advancedserver-host
|
||||||
build-advancedserver-host: build-advancedserver
|
build-advancedserver-host: build-advancedserver
|
||||||
|
|
||||||
.PHONY: build-advancedserver
|
.PHONY: build-advancedserver
|
||||||
build-advancedserver: registry-login log-build-env downloads/$(MQ_ARCHIVE) command-version
|
build-advancedserver: log-build-env downloads/$(MQ_ARCHIVE) command-version
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)"$(END)))
|
||||||
$(call build-mq,$(MQ_IMAGE_ADVANCEDSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE),mq-server)
|
$(call build-mq,$(MQ_IMAGE_ADVANCEDSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE),mq-server)
|
||||||
|
|
||||||
@@ -280,29 +414,26 @@ build-advancedserver: registry-login log-build-env downloads/$(MQ_ARCHIVE) comma
|
|||||||
build-devserver-host: build-devserver
|
build-devserver-host: build-devserver
|
||||||
|
|
||||||
.PHONY: build-devserver
|
.PHONY: build-devserver
|
||||||
build-devserver: registry-login log-build-env downloads/$(MQ_ARCHIVE_DEV) command-version
|
build-devserver: log-build-env downloads/$(MQ_ARCHIVE_DEV) command-version
|
||||||
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)"$(END)))
|
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)"$(END)))
|
||||||
$(call build-mq,$(MQ_IMAGE_DEVSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE_DEV),mq-dev-server)
|
$(call build-mq,$(MQ_IMAGE_DEVSERVER),$(MQ_TAG),Dockerfile-server,$(MQ_ARCHIVE_DEV),mq-dev-server)
|
||||||
|
|
||||||
.PHONY: build-advancedserver-cover
|
.PHONY: build-advancedserver-cover
|
||||||
build-advancedserver-cover: registry-login command-version
|
build-advancedserver-cover: command-version
|
||||||
$(COMMAND) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) -t $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover -f Dockerfile-server.cover .
|
$(COMMAND) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) -t $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover -f Dockerfile-server.cover .
|
||||||
|
|
||||||
.PHONY: build-explorer
|
.PHONY: build-explorer
|
||||||
build-explorer: registry-login downloads/$(MQ_ARCHIVE_DEV)
|
build-explorer: downloads/$(MQ_ARCHIVE_DEV)
|
||||||
$(call build-mq,mq-explorer,latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),mq-explorer)
|
$(call build-mq,mq-explorer,latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),mq-explorer)
|
||||||
|
|
||||||
.PHONY: build-sdk
|
.PHONY: build-sdk
|
||||||
build-sdk: registry-login downloads/$(MQ_ARCHIVE_DEV)
|
build-sdk: downloads/$(MQ_ARCHIVE_DEV)
|
||||||
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_SDK)"$(END)))
|
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_SDK)"$(END)))
|
||||||
$(call build-mq,mq-sdk,$(MQ_TAG),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),mq-sdk)
|
$(call build-mq,mq-sdk,$(MQ_TAG),incubating/mq-sdk/Dockerfile,$(MQ_SDK_ARCHIVE),mq-sdk)
|
||||||
|
|
||||||
.PHONY: registry-login
|
###############################################################################
|
||||||
registry-login:
|
# Logging targets
|
||||||
ifneq ($(REGISTRY_USER),)
|
###############################################################################
|
||||||
$(COMMAND) login -u $(REGISTRY_USER) -p $(REGISTRY_PASS) registry.redhat.io
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: log-build-env
|
.PHONY: log-build-env
|
||||||
log-build-vars:
|
log-build-vars:
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build environment"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Build environment"$(END)))
|
||||||
@@ -313,7 +444,6 @@ log-build-vars:
|
|||||||
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
|
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
|
||||||
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
|
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
|
||||||
@echo COMMAND=$(COMMAND)
|
@echo COMMAND=$(COMMAND)
|
||||||
@echo REGISTRY_USER=$(REGISTRY_USER)
|
|
||||||
|
|
||||||
.PHONY: log-build-env
|
.PHONY: log-build-env
|
||||||
log-build-env: log-build-vars
|
log-build-env: log-build-vars
|
||||||
@@ -323,16 +453,22 @@ log-build-env: log-build-vars
|
|||||||
|
|
||||||
include formatting.mk
|
include formatting.mk
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Push/pull targets
|
||||||
|
###############################################################################
|
||||||
.PHONY: pull-mq-archive
|
.PHONY: pull-mq-archive
|
||||||
pull-mq-archive:
|
pull-mq-archive:
|
||||||
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY)" -o downloads/$(MQ_ARCHIVE)
|
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY)" --output downloads/$(MQ_ARCHIVE)
|
||||||
|
|
||||||
.PHONY: pull-mq-archive-dev
|
.PHONY: pull-mq-archive-dev
|
||||||
pull-mq-archive-dev:
|
pull-mq-archive-dev:
|
||||||
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" -o downloads/$(MQ_ARCHIVE_DEV)
|
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" --output downloads/$(MQ_ARCHIVE_DEV)
|
||||||
|
|
||||||
.PHONY: push-advancedserver
|
.PHONY: push-advancedserver
|
||||||
push-advancedserver:
|
push-advancedserver:
|
||||||
|
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
|
||||||
|
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
|
||||||
|
fi
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Push production image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Push production image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
|
||||||
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
|
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
|
||||||
$(COMMAND) tag $(MQ_IMAGE_ADVANCEDSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
|
$(COMMAND) tag $(MQ_IMAGE_ADVANCEDSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
|
||||||
@@ -340,6 +476,9 @@ push-advancedserver:
|
|||||||
|
|
||||||
.PHONY: push-devserver
|
.PHONY: push-devserver
|
||||||
push-devserver:
|
push-devserver:
|
||||||
|
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
|
||||||
|
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
|
||||||
|
fi
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Push developer image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Push developer image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
|
||||||
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
|
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
|
||||||
$(COMMAND) tag $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
|
$(COMMAND) tag $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
|
||||||
@@ -362,22 +501,34 @@ pull-devserver:
|
|||||||
.PHONY: push-manifest
|
.PHONY: push-manifest
|
||||||
push-manifest: build-skopeo-container
|
push-manifest: build-skopeo-container
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"** Determining the image digests **"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"** Determining the image digests **"$(END)))
|
||||||
$(eval MQ_IMAGE_DEVSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux --override-arch s390x inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_AMD64) | jq -r .Digest))
|
ifneq "$(LTS)" "true"
|
||||||
|
$(eval MQ_IMAGE_DEVSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_AMD64) | jq -r .Digest))
|
||||||
$(eval MQ_IMAGE_DEVSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_S390X) | jq -r .Digest))
|
$(eval MQ_IMAGE_DEVSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_S390X) | jq -r .Digest))
|
||||||
$(eval MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_AMD64) | jq -r .Digest))
|
$(eval MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_PPC64LE) | jq -r .Digest))
|
||||||
$(eval MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_S390X) | jq -r .Digest))
|
|
||||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_AMD64) has a digest of $(MQ_IMAGE_DEVSERVER_AMD64_DIGEST)**"$(END)))
|
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_AMD64) has a digest of $(MQ_IMAGE_DEVSERVER_AMD64_DIGEST)**"$(END)))
|
||||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_S390X) has a digest of $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)**"$(END)))
|
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_S390X) has a digest of $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)**"$(END)))
|
||||||
|
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_PPC64LE) has a digest of $(MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST)**"$(END)))
|
||||||
|
endif
|
||||||
|
$(eval MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_AMD64) | jq -r .Digest))
|
||||||
|
$(eval MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_S390X) | jq -r .Digest))
|
||||||
|
$(eval MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_PPC64LE) | jq -r .Digest))
|
||||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_AMD64) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST)**"$(END)))
|
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_AMD64) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST)**"$(END)))
|
||||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_S390X) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)**"$(END)))
|
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_S390X) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)**"$(END)))
|
||||||
|
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST)**"$(END)))
|
||||||
|
ifneq "$(LTS)" "true"
|
||||||
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_DEVSERVER_MANIFEST)**"$(END)))
|
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_DEVSERVER_MANIFEST)**"$(END)))
|
||||||
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_DEVSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_DEVSERVER_AMD64_DIGEST) $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)" $(END))
|
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_DEVSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_DEVSERVER_AMD64_DIGEST) $(MQ_IMAGE_DEVSERVER_S390X_DIGEST) $(MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST)" $(END))
|
||||||
|
endif
|
||||||
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_ADVANCEDSERVER_MANIFEST)**"$(END)))
|
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_ADVANCEDSERVER_MANIFEST)**"$(END)))
|
||||||
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)" $(END))
|
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST)" $(END))
|
||||||
|
|
||||||
.PHONY: build-skopeo-container
|
.PHONY: build-skopeo-container
|
||||||
build-skopeo-container:
|
build-skopeo-container:
|
||||||
$(COMMAND) images | grep -q "skopeo"; if [ $$? != 0 ]; then docker build -t skopeo:latest ./docker-builds/skopeo/; fi
|
$(COMMAND) images | grep -q "skopeo"; if [ $$? != 0 ]; then $(COMMAND) build -t skopeo:latest ./docker-builds/skopeo/; fi
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Other targets
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@@ -416,28 +567,40 @@ lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
|||||||
.PHONY: gosec
|
.PHONY: gosec
|
||||||
gosec:
|
gosec:
|
||||||
$(info $(SPACER)$(shell printf "Running gosec test"$(END)))
|
$(info $(SPACER)$(shell printf "Running gosec test"$(END)))
|
||||||
@gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\
|
@gosecrc=0; gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null || gosecrc=$$?; \
|
||||||
cat "gosec_results.json" ;\
|
cat gosec_results.json | jq '{"GolangErrors": (.["Golang errors"]|length>0),"Issues":(.Issues|length>0)}' | grep 'true' >/dev/null ;\
|
||||||
cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\
|
if [ $$? -eq 0 ] || [ $$gosecrc -ne 0 ]; then \
|
||||||
if [ $$? -eq 0 ]; then \
|
printf "FAILURE: Issues found running gosec - see gosec_results.json\n" ;\
|
||||||
printf "\nFAILURE: gosec found files containing HIGH severity issues - see results.json\n" ;\
|
cat "gosec_results.json" ;\
|
||||||
exit 1 ;\
|
exit 1 ;\
|
||||||
else \
|
else \
|
||||||
printf "\ngosec found no HIGH severity issues\n" ;\
|
printf "gosec found no issues\n" ;\
|
||||||
fi ;\
|
cat "gosec_results.json" ;\
|
||||||
cat gosec_results.json | grep MEDIUM | grep severity > /dev/null ;\
|
fi
|
||||||
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 ;\
|
|
||||||
|
|
||||||
include formatting.mk
|
.PHONY: update-release-information
|
||||||
|
update-release-information:
|
||||||
|
sed -i.bak 's/ARG MQ_URL=.*-LinuxX64.tar.gz"/ARG MQ_URL="https:\/\/public.dhe.ibm.com\/ibmdl\/export\/pub\/software\/websphere\/messaging\/mqadv\/$(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"/g' Dockerfile-server && rm Dockerfile-server.bak
|
||||||
|
$(eval MQ_VERSION_1=$(shell echo '${MQ_VERSION}' | rev | cut -c 3- | rev))
|
||||||
|
sed -i.bak 's/IBM_MQ_.*_LINUX_X86-64_NOINST.tar.gz/IBM_MQ_${MQ_VERSION_1}_LINUX_X86-64_NOINST.tar.gz/g' docs/building.md && rm docs/building.md.bak
|
||||||
|
sed -i.bak 's/ibm-mqadvanced-server:.*-amd64/ibm-mqadvanced-server:$(MQ_VERSION)-amd64/g' docs/security.md
|
||||||
|
sed -i.bak 's/ibm-mqadvanced-server-dev.*-amd64/ibm-mqadvanced-server-dev:$(MQ_VERSION)-amd64/g' docs/security.md && rm docs/security.md.bak
|
||||||
|
sed -i.bak 's/MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:.*-amd64/MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:$(MQ_VERSION)-amd64/g' docs/testing.md && rm docs/testing.md.bak
|
||||||
|
$(eval MQ_VERSION_2=$(shell echo '${MQ_VERSION_1}' | rev | cut -c 3- | rev))
|
||||||
|
sed -i.bak 's/knowledgecenter\/SSFKSJ_.*\/com/knowledgecenter\/SSFKSJ_${MQ_VERSION_2}.0\/com/g' docs/usage.md && rm docs/usage.md.bak
|
||||||
|
$(eval MQ_VERSION_3=$(shell echo '${MQ_VERSION_1}' | sed "s/\.//g"))
|
||||||
|
sed -i.bak 's/MQ_..._ARCHIVE_REPOSITORY/MQ_${MQ_VERSION_3}_ARCHIVE_REPOSITORY/g' .travis.yml && rm .travis.yml.bak
|
||||||
|
|
||||||
|
COMMAND_SERVER_VERSION=$(shell $(COMMAND) version --format "{{ .Server.Version }}")
|
||||||
|
COMMAND_CLIENT_VERSION=$(shell $(COMMAND) version --format "{{ .Client.Version }}")
|
||||||
|
PODMAN_VERSION=$(shell podman version --format "{{ .Version }}")
|
||||||
|
.PHONY: command-version
|
||||||
|
command-version:
|
||||||
|
# If we're using Docker, then check it's recent enough to support multi-stage builds
|
||||||
|
ifneq (,$(findstring docker,$(COMMAND)))
|
||||||
|
@test "$(word 1,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
|
||||||
|
@test "$(word 1,$(subst ., ,$(COMMAND_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(COMMAND_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring podman,$(COMMAND)))
|
||||||
|
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
|
||||||
|
endif
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -1,5 +1,6 @@
|
|||||||
# IBM MQ container
|
# IBM MQ container
|
||||||
|
|
||||||
|
|
||||||
[](https://travis-ci.org/ibm-messaging/mq-container)
|
[](https://travis-ci.org/ibm-messaging/mq-container)
|
||||||
|
|
||||||
**Note**: The `master` branch may be in an *unstable or even broken state* during development.
|
**Note**: The `master` branch may be in an *unstable or even broken state* during development.
|
||||||
@@ -33,7 +34,7 @@ See the [default developer configuration docs](docs/developer-config.md) for the
|
|||||||
|
|
||||||
### 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 on [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM MQ Sample Helm Chart](https://github.com/ibm-messaging/mq-helm). This can be used to run the container on a Kubernetes cluster, such as the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
|
||||||
|
|
||||||
## Issues and contributions
|
## Issues and contributions
|
||||||
|
|
||||||
@@ -44,11 +45,12 @@ For issues relating specifically to the container image or Helm chart, please us
|
|||||||
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
||||||
Licenses for the products installed within the images are as follows:
|
Licenses for the products installed within the images are as follows:
|
||||||
|
|
||||||
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-BMKG5H) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-CAUEQC) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||||
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-BMJJBM) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-CAUEBE) (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.
|
||||||
|
|
||||||
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, 2020
|
© Copyright IBM Corporation 2015, 2022
|
||||||
|
|||||||
50
authservice/mqhtpass/Makefile
Normal file
50
authservice/mqhtpass/Makefile
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# © 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.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# This Makefile expects the following to be installed:
|
||||||
|
# - gcc
|
||||||
|
# - ldd
|
||||||
|
# - MQ SDK (mqm_r library, plus header files)
|
||||||
|
# - Apache Portable Runtime (apr-1 and aprutil-1 libraries, plus header files)
|
||||||
|
|
||||||
|
SRC_DIR = src
|
||||||
|
BUILD_DIR = ./build
|
||||||
|
|
||||||
|
# Flags passed to the C compiler. Need to use gnu11 to get POSIX functions needed for file locking.
|
||||||
|
CFLAGS += -std=gnu11 -fPIC -Wall -m64
|
||||||
|
|
||||||
|
LIB_APR = -L/usr/lib64 -lapr-1 -laprutil-1
|
||||||
|
LIB_MQ = -L/opt/mqm/lib64 -lmqm_r
|
||||||
|
|
||||||
|
all: $(BUILD_DIR)/mqhtpass.so $(BUILD_DIR)/htpass_test
|
||||||
|
|
||||||
|
$(BUILD_DIR)/log.o : $(SRC_DIR)/log.c $(SRC_DIR)/log.h
|
||||||
|
mkdir -p ${dir $@}
|
||||||
|
gcc $(CFLAGS) -c $(SRC_DIR)/log.c -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/htpass.o : $(SRC_DIR)/htpass.c $(SRC_DIR)/htpass.h
|
||||||
|
mkdir -p ${dir $@}
|
||||||
|
gcc $(CFLAGS) -c $(SRC_DIR)/htpass.c -I /usr/include/apr-1 -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/htpass_test : $(BUILD_DIR)/htpass.o $(BUILD_DIR)/log.o
|
||||||
|
mkdir -p ${dir $@}
|
||||||
|
gcc $(CFLAGS) $(LIB_APR) -lpthread $(SRC_DIR)/htpass_test.c $^ -o $@
|
||||||
|
# Run HTPasswd tests, and print log if they fail
|
||||||
|
$@ || (cat htpass_test*.log && exit 1)
|
||||||
|
|
||||||
|
$(BUILD_DIR)/mqhtpass.so : $(BUILD_DIR)/log.o $(BUILD_DIR)/htpass.o
|
||||||
|
mkdir -p ${dir $@}
|
||||||
|
# NOTE: rpath for libapr will be different on Ubuntu
|
||||||
|
gcc $(CFLAGS) -I/opt/mqm/inc -D_REENTRANT $(LIB_APR) $(LIB_MQ) -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64 -shared $(SRC_DIR)/mqhtpass.c $^ -o $@
|
||||||
|
ldd $@
|
||||||
145
authservice/mqhtpass/src/htpass.c
Normal file
145
authservice/mqhtpass/src/htpass.c
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "htpass.h"
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <apr_general.h>
|
||||||
|
#include <apr_errno.h>
|
||||||
|
#include <apr_md5.h>
|
||||||
|
|
||||||
|
bool htpass_valid_file(char *filename)
|
||||||
|
{
|
||||||
|
bool valid = true;
|
||||||
|
FILE *fp;
|
||||||
|
char *huser;
|
||||||
|
|
||||||
|
fp = fopen(filename, "r");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
log_errorf("Error %d opening htpasswd file '%s'", errno, filename);
|
||||||
|
}
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
const size_t line_size = 1024;
|
||||||
|
char *line = malloc(line_size);
|
||||||
|
while (fgets(line, line_size, fp) != NULL)
|
||||||
|
{
|
||||||
|
char *saveptr;
|
||||||
|
// Need to use strtok_r to be safe for multiple threads
|
||||||
|
huser = strtok_r(line, ":", &saveptr);
|
||||||
|
if (strlen(huser) >= 12)
|
||||||
|
{
|
||||||
|
log_errorf("Invalid htpasswd file for use with IBM MQ. User '%s' is longer than twelve characters", huser);
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
if (line)
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *find_hash(char *filename, char *user)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
FILE *fp;
|
||||||
|
char *huser;
|
||||||
|
char *hash;
|
||||||
|
|
||||||
|
fp = fopen(filename, "r");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
log_errorf("Error %d opening htpasswd file '%s'", errno, filename);
|
||||||
|
}
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
const size_t line_size = 1024;
|
||||||
|
char *line = malloc(line_size);
|
||||||
|
while (fgets(line, line_size, fp) != NULL)
|
||||||
|
{
|
||||||
|
char *saveptr;
|
||||||
|
// Need to use strtok_r to be safe for multiple threads
|
||||||
|
huser = strtok_r(line, ":", &saveptr);
|
||||||
|
if (huser && (strcmp(user, huser) == 0))
|
||||||
|
{
|
||||||
|
// Make a duplicate of the string, because we'll be keeping it
|
||||||
|
hash = strdup(strtok_r(NULL, " \r\n\t", &saveptr));
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
if (line)
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
hash = NULL;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
int htpass_authenticate_user(char *filename, char *user, char *password)
|
||||||
|
{
|
||||||
|
char *hash = find_hash(filename, user);
|
||||||
|
int result = -1;
|
||||||
|
if (hash == NULL)
|
||||||
|
{
|
||||||
|
result = HTPASS_INVALID_USER;
|
||||||
|
log_debugf("User does not exist. user=%s", user);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use the Apache Portable Runtime utilities to validate the password against the hash.
|
||||||
|
// Supports multiple hashing algorithms, but we should only be using bcrypt
|
||||||
|
apr_status_t status = apr_password_validate(password, hash);
|
||||||
|
// status is usually either APR_SUCCESS or APR_EMISMATCH
|
||||||
|
if (status == APR_SUCCESS)
|
||||||
|
{
|
||||||
|
result = HTPASS_VALID;
|
||||||
|
log_debugf("Correct password supplied. user=%s", user);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = HTPASS_INVALID_PASSWORD;
|
||||||
|
log_debugf("Incorrect password supplied. user=%s", user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool htpass_valid_user(char *filename, char *user)
|
||||||
|
{
|
||||||
|
char *hash = find_hash(filename, user);
|
||||||
|
bool valid = false;
|
||||||
|
if (hash != NULL)
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
49
authservice/mqhtpass/src/htpass.h
Normal file
49
authservice/mqhtpass/src/htpass.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HTPASS_H
|
||||||
|
#define _HTPASS_H
|
||||||
|
|
||||||
|
#define HTPASS_VALID 0
|
||||||
|
#define HTPASS_INVALID_USER 1
|
||||||
|
#define HTPASS_INVALID_PASSWORD 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate an HTPasswd file for use with IBM MQ.
|
||||||
|
*
|
||||||
|
* @param filename the HTPasswd file
|
||||||
|
*/
|
||||||
|
_Bool htpass_valid_file(char *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate a user, based on the supplied file name.
|
||||||
|
*
|
||||||
|
* @param filename the HTPasswd file
|
||||||
|
* @param user the user name to authenticate
|
||||||
|
* @param password the password of the user
|
||||||
|
* @return HTPASS_VALID, HTPASS_INVALID_USER or HTPASS_INVALID_PASSWORD
|
||||||
|
*/
|
||||||
|
int htpass_authenticate_user(char *filename, char *user, char *password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that a user exists in the password file.
|
||||||
|
*
|
||||||
|
* @param filename the HTPasswd file
|
||||||
|
* @param user the user name to validate
|
||||||
|
*/
|
||||||
|
_Bool htpass_valid_user(char *filename, char *user);
|
||||||
|
|
||||||
|
#endif
|
||||||
223
authservice/mqhtpass/src/htpass_test.c
Normal file
223
authservice/mqhtpass/src/htpass_test.c
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "htpass.h"
|
||||||
|
|
||||||
|
// Headers for multi-threaded tests
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
// Start a test and log the function name
|
||||||
|
#define test_start() printf("=== RUN: %s\n", __func__)
|
||||||
|
|
||||||
|
// Indicate test has passed
|
||||||
|
#define test_pass() printf("--- PASS: %s\n", __func__)
|
||||||
|
|
||||||
|
// Indicate test has failed
|
||||||
|
void test_fail(const char *test_name)
|
||||||
|
{
|
||||||
|
printf("--- FAIL: %s\n", test_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Simple tests for file validation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void test_htpass_valid_file_ok()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int ok = htpass_valid_file("./src/htpass_test.htpasswd");
|
||||||
|
if (!ok)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_htpass_valid_file_too_long()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int ok = htpass_valid_file("./src/htpass_test_invalid.htpasswd");
|
||||||
|
if (ok)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Simple tests for authentication
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void test_htpass_authenticate_user_fred_valid()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
|
||||||
|
printf("%s: fred - %d\n", __func__, rc);
|
||||||
|
if (rc != HTPASS_VALID)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_htpass_authenticate_user_fred_invalid1()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd ");
|
||||||
|
printf("%s: fred - %d\n", __func__, rc);
|
||||||
|
if (rc != HTPASS_INVALID_PASSWORD)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_htpass_authenticate_user_fred_invalid2()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "");
|
||||||
|
printf("%s: fred - %d\n", __func__, rc);
|
||||||
|
if (rc != HTPASS_INVALID_PASSWORD)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_htpass_authenticate_user_fred_invalid3()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "clearlywrong");
|
||||||
|
printf("%s: fred - %d\n", __func__, rc);
|
||||||
|
if (rc != HTPASS_INVALID_PASSWORD)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_htpass_authenticate_user_barney_valid()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
|
||||||
|
printf("%s: barney - %d\n", __func__, rc);
|
||||||
|
if (rc != HTPASS_VALID)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_htpass_authenticate_user_unknown()
|
||||||
|
{
|
||||||
|
test_start();
|
||||||
|
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "george", "s3cret");
|
||||||
|
printf("%s: barney - %d\n", __func__, rc);
|
||||||
|
if (rc != HTPASS_INVALID_USER)
|
||||||
|
test_fail(__func__);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Multi-threaded test
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define NUM_THREADS 5
|
||||||
|
// Number of tests to perform per thread. Higher numbers are more likely to trigger timing issue.
|
||||||
|
#define NUM_TESTS_PER_THREAD 1000
|
||||||
|
// Maximum number of JSON errors to report (log can get flooded)
|
||||||
|
#define MAX_JSON_ERRORS 10
|
||||||
|
|
||||||
|
// Authenticate multiple users, multiple times
|
||||||
|
void *authenticate_many_times(void *p)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NUM_TESTS_PER_THREAD; i++)
|
||||||
|
{
|
||||||
|
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
|
||||||
|
if (rc != HTPASS_VALID)
|
||||||
|
test_fail(__func__);
|
||||||
|
rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
|
||||||
|
if (rc != HTPASS_VALID)
|
||||||
|
test_fail(__func__);
|
||||||
|
}
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_log_file_valid(char *filename)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
printf("--- Checking log file is valid\n");
|
||||||
|
// Check that the JSON log file isn't corrupted
|
||||||
|
FILE *log = fopen(filename, "r");
|
||||||
|
if (log == NULL)
|
||||||
|
{
|
||||||
|
test_fail(__func__);
|
||||||
|
}
|
||||||
|
const size_t line_size = 1024;
|
||||||
|
char *line = malloc(line_size);
|
||||||
|
while (fgets(line, line_size, log) != NULL)
|
||||||
|
{
|
||||||
|
if ((line[0] != '{') && (errors < MAX_JSON_ERRORS))
|
||||||
|
{
|
||||||
|
printf("*** Invalid JSON detected: %s\n", line);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line)
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
fclose(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test authenticate_user with multiple threads, each doing many authentications
|
||||||
|
void test_htpass_authenticate_user_multithreaded(char *logfile)
|
||||||
|
{
|
||||||
|
pthread_t threads[NUM_THREADS];
|
||||||
|
int rc;
|
||||||
|
test_start();
|
||||||
|
// Re-initialize the log to use a file for the multi-threaded test
|
||||||
|
log_init(logfile);
|
||||||
|
for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
{
|
||||||
|
printf("Creating thread %d\n", i);
|
||||||
|
rc = pthread_create(&threads[i], NULL, authenticate_many_times, NULL);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
printf("Error: Unable to create thread, %d\n", rc);
|
||||||
|
test_fail(__func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait for all the threads to complete
|
||||||
|
for (int i = 0; i < NUM_THREADS; i++)
|
||||||
|
{
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
check_log_file_valid(logfile);
|
||||||
|
test_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Turn on debugging for the tests
|
||||||
|
setenv("DEBUG", "true", true);
|
||||||
|
log_init("htpass_test.log");
|
||||||
|
test_htpass_valid_file_ok();
|
||||||
|
test_htpass_valid_file_too_long();
|
||||||
|
test_htpass_authenticate_user_fred_valid();
|
||||||
|
test_htpass_authenticate_user_fred_invalid1();
|
||||||
|
test_htpass_authenticate_user_fred_invalid2();
|
||||||
|
test_htpass_authenticate_user_fred_invalid3();
|
||||||
|
test_htpass_authenticate_user_barney_valid();
|
||||||
|
test_htpass_authenticate_user_unknown();
|
||||||
|
log_close();
|
||||||
|
|
||||||
|
// Call multi-threaded test last, because it re-initializes the log to use a file
|
||||||
|
test_htpass_authenticate_user_multithreaded("htpass_test_multithreaded.log");
|
||||||
|
}
|
||||||
2
authservice/mqhtpass/src/htpass_test.htpasswd
Normal file
2
authservice/mqhtpass/src/htpass_test.htpasswd
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fred:$2y$05$3Fp9epsqEwWOHdyj9Ngf9.qfX34kzc9zNrdQ7kac0GmcCvQjIkAwy
|
||||||
|
barney:$2y$05$l8EoyCQ9y2PyfUzIDDfTyu7SSaJEYB1TuHy07xZvN7xt/pR3SIw0a
|
||||||
3
authservice/mqhtpass/src/htpass_test_invalid.htpasswd
Normal file
3
authservice/mqhtpass/src/htpass_test_invalid.htpasswd
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fred:$2y$05$3Fp9epsqEwWOHdyj9Ngf9.qfX34kzc9zNrdQ7kac0GmcCvQjIkAwy
|
||||||
|
barney:$2y$05$l8EoyCQ9y2PyfUzIDDfTyu7SSaJEYB1TuHy07xZvN7xt/pR3SIw0a
|
||||||
|
namewhichisfartoolongformq:$2y$05$l8EoyCQ9y2PyfUzIDDfTyu7SSaJEYB1TuHy07xZvN7xt/pR3SIw0a
|
||||||
152
authservice/mqhtpass/src/log.c
Normal file
152
authservice/mqhtpass/src/log.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
FILE *fp = NULL;
|
||||||
|
int pid;
|
||||||
|
char hostname[255];
|
||||||
|
bool debug = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether debugging is enabled or not, using an environment variable.
|
||||||
|
*/
|
||||||
|
void init_debug(){
|
||||||
|
char *debug_env = getenv("DEBUG");
|
||||||
|
if (debug_env != NULL)
|
||||||
|
{
|
||||||
|
// Enable debug logging if the DEBUG environment variable is set
|
||||||
|
if (strncmp(debug_env, "true", 4) || strncmp(debug_env, "1", 1))
|
||||||
|
{
|
||||||
|
debug = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function to initialize the log with the given file mode.
|
||||||
|
*/
|
||||||
|
int log_init_internal(char *filename, const char *mode)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
pid = getpid();
|
||||||
|
hostname[254] = '\0';
|
||||||
|
gethostname(hostname, 254);
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fp = fopen(filename, "a");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
// Disable buffering for this file
|
||||||
|
setbuf(fp, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
init_debug();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_init_reset(char *filename)
|
||||||
|
{
|
||||||
|
// Open the log file for writing (overwrite if it already exists)
|
||||||
|
return log_init_internal(filename, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_init(char *filename)
|
||||||
|
{
|
||||||
|
// Open the log file file for appending
|
||||||
|
return log_init_internal(filename, "a");
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_init_file(FILE *f)
|
||||||
|
{
|
||||||
|
fp = f;
|
||||||
|
init_debug();
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_close()
|
||||||
|
{
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
fp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_printf(const char *source_file, int source_line, const char *level, const char *format, ...)
|
||||||
|
{
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
// If this is a DEBUG message, and debugging is off
|
||||||
|
if ((strncmp(level, "DEBUG", 5) == 0) && !debug)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char buf[1024] = "";
|
||||||
|
char *cur = buf;
|
||||||
|
char* const end = buf + sizeof buf;
|
||||||
|
char date_buf[70];
|
||||||
|
struct tm *utc;
|
||||||
|
time_t t;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
t = now.tv_sec;
|
||||||
|
t = time(NULL);
|
||||||
|
utc = gmtime(&t);
|
||||||
|
|
||||||
|
cur += snprintf(cur, end-cur, "{");
|
||||||
|
cur += snprintf(cur, end-cur, "\"loglevel\":\"%s\"", level);
|
||||||
|
// Print ISO-8601 time and date
|
||||||
|
if (strftime(date_buf, sizeof date_buf, "%FT%T", utc))
|
||||||
|
{
|
||||||
|
// Round microseconds down to milliseconds, for consistency
|
||||||
|
cur += snprintf(cur, end-cur, ", \"ibm_datetime\":\"%s.%03ldZ\"", date_buf, now.tv_usec / 1000);
|
||||||
|
}
|
||||||
|
cur += snprintf(cur, end-cur, ", \"ibm_processId\":\"%d\"", pid);
|
||||||
|
cur += snprintf(cur, end-cur, ", \"host\":\"%s\"", hostname);
|
||||||
|
cur += snprintf(cur, end-cur, ", \"module\":\"%s:%d\"", source_file, source_line);
|
||||||
|
cur += snprintf(cur, end-cur, ", \"message\":\"");
|
||||||
|
|
||||||
|
if (strncmp(level, "DEBUG", 5) == 0)
|
||||||
|
{
|
||||||
|
// Add a prefix on any debug messages
|
||||||
|
cur += snprintf(cur, end-cur, "mqhtpass: ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print log message, using varargs
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
cur += vsnprintf(cur, end-cur, format, args);
|
||||||
|
va_end(args);
|
||||||
|
cur += snprintf(cur, end-cur, "\"}\n");
|
||||||
|
|
||||||
|
// Important: Just do one file write, to prevent problems with multi-threading.
|
||||||
|
// This only works if the log message is not too long for the buffer.
|
||||||
|
fprintf(fp, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
63
authservice/mqhtpass/src/log.h
Normal file
63
authservice/mqhtpass/src/log.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LOG_H
|
||||||
|
#define _LOG_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the log to use the given file name, wiping any existing contents.
|
||||||
|
*/
|
||||||
|
int log_init_reset(char *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the log to use the given file name.
|
||||||
|
*/
|
||||||
|
int log_init(char *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the log with an existing file handle.
|
||||||
|
*/
|
||||||
|
void log_init_file(FILE *f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a message to the log file, based on a printf format string.
|
||||||
|
*
|
||||||
|
* @param source_file the name of the source code file submitting this log message
|
||||||
|
* @param source_line the line of code in the source file
|
||||||
|
* @param level the log level, one of "DEBUG", "INFO" or "ERROR"
|
||||||
|
* @param format the printf format string for the message
|
||||||
|
*/
|
||||||
|
void log_printf(const char *source_file, int source_line, const char *level, const char *format, ...);
|
||||||
|
|
||||||
|
void log_close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variadic macro to write an informational message to the log file, based on a printf format string.
|
||||||
|
*/
|
||||||
|
#define log_infof(format,...) log_printf(__FILE__, __LINE__, "INFO", format, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variadic macro to write an error message to the log file, based on a printf format string.
|
||||||
|
*/
|
||||||
|
#define log_errorf(format,...) log_printf(__FILE__, __LINE__, "ERROR", format, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variadic macro to write a debug message to the log file, based on a printf format string.
|
||||||
|
*/
|
||||||
|
#define log_debugf(format,...) log_printf(__FILE__, __LINE__, "DEBUG", format, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
350
authservice/mqhtpass/src/mqhtpass.c
Normal file
350
authservice/mqhtpass/src/mqhtpass.c
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021, 2022
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is a developer only configuration and not recommended for production usage.
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <cmqec.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "htpass.h"
|
||||||
|
|
||||||
|
// Declare the internal functions that implement the interface
|
||||||
|
MQZ_INIT_AUTHORITY MQStart;
|
||||||
|
static MQZ_AUTHENTICATE_USER mqhtpass_authenticate_user;
|
||||||
|
static MQZ_FREE_USER mqhtpass_free_user;
|
||||||
|
static MQZ_TERM_AUTHORITY mqhtpass_terminate;
|
||||||
|
|
||||||
|
#define LOG_FILE "/var/mqm/errors/mqhtpass.json"
|
||||||
|
#define HTPASSWD_FILE "/etc/mqm/mq.htpasswd"
|
||||||
|
#define NAME "MQ Advanced for Developers custom authentication service"
|
||||||
|
|
||||||
|
static char *trim(char *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization and entrypoint for the dynamically loaded
|
||||||
|
* authorization installable service. It registers the addresses of the
|
||||||
|
* other functions which are to be called by the queue manager.
|
||||||
|
*
|
||||||
|
* This function is called whenever the module is loaded. The Options
|
||||||
|
* field will show whether it's a PRIMARY (i.e. during qmgr startup) or
|
||||||
|
* SECONDARY.
|
||||||
|
*/
|
||||||
|
void MQENTRY MQStart(
|
||||||
|
MQHCONFIG hc,
|
||||||
|
MQLONG Options,
|
||||||
|
MQCHAR48 QMgrName,
|
||||||
|
MQLONG ComponentDataLength,
|
||||||
|
PMQBYTE ComponentData,
|
||||||
|
PMQLONG Version,
|
||||||
|
PMQLONG pCompCode,
|
||||||
|
PMQLONG pReason)
|
||||||
|
{
|
||||||
|
MQLONG CC = MQCC_OK;
|
||||||
|
MQLONG Reason = MQRC_NONE;
|
||||||
|
int log_rc = 0;
|
||||||
|
|
||||||
|
if (Options == MQZIO_PRIMARY)
|
||||||
|
{
|
||||||
|
// Reset the log file. The file could still get large if debug is turned on,
|
||||||
|
// but this is a simpler solution for now.
|
||||||
|
log_rc = log_init_reset(LOG_FILE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_rc = log_init(LOG_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log_rc != 0)
|
||||||
|
{
|
||||||
|
CC = MQCC_FAILED;
|
||||||
|
Reason = MQRC_INITIALIZATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Options == MQZIO_PRIMARY)
|
||||||
|
{
|
||||||
|
log_infof("Initializing %s", NAME);
|
||||||
|
}
|
||||||
|
log_debugf("MQStart options=%s qmgr=%s", ((Options == MQZIO_SECONDARY) ? "Secondary" : "Primary"), trim(QMgrName));
|
||||||
|
|
||||||
|
if (!htpass_valid_file(HTPASSWD_FILE))
|
||||||
|
{
|
||||||
|
CC = MQCC_FAILED;
|
||||||
|
Reason = MQRC_INITIALIZATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the functions to use for each entry point
|
||||||
|
if (CC == MQCC_OK)
|
||||||
|
{
|
||||||
|
hc->MQZEP_Call(hc, MQZID_INIT_AUTHORITY, (PMQFUNC)MQStart, &CC, &Reason);
|
||||||
|
}
|
||||||
|
if (CC == MQCC_OK)
|
||||||
|
{
|
||||||
|
hc->MQZEP_Call(hc, MQZID_TERM_AUTHORITY, (PMQFUNC)mqhtpass_terminate, &CC, &Reason);
|
||||||
|
}
|
||||||
|
if (CC == MQCC_OK)
|
||||||
|
{
|
||||||
|
hc->MQZEP_Call(hc, MQZID_AUTHENTICATE_USER, (PMQFUNC)mqhtpass_authenticate_user, &CC, &Reason);
|
||||||
|
}
|
||||||
|
if (CC == MQCC_OK)
|
||||||
|
{
|
||||||
|
hc->MQZEP_Call(hc, MQZID_FREE_USER, (PMQFUNC)mqhtpass_free_user, &CC, &Reason);
|
||||||
|
}
|
||||||
|
*Version = MQZAS_VERSION_5;
|
||||||
|
*pCompCode = CC;
|
||||||
|
*pReason = Reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called during the connection of any application which supplies an MQCSP (Connection Security Parameters).
|
||||||
|
* This is the usual case.
|
||||||
|
* See https://www.ibm.com/support/knowledgecenter/SSFKSJ_latest/com.ibm.mq.ref.dev.doc/q095610_.html
|
||||||
|
*/
|
||||||
|
static void MQENTRY mqhtpass_authenticate_user_csp(
|
||||||
|
PMQCHAR pQMgrName,
|
||||||
|
PMQCSP pSecurityParms,
|
||||||
|
PMQZAC pApplicationContext,
|
||||||
|
PMQZIC pIdentityContext,
|
||||||
|
PMQPTR pCorrelationPtr,
|
||||||
|
PMQBYTE pComponentData,
|
||||||
|
PMQLONG pContinuation,
|
||||||
|
PMQLONG pCompCode,
|
||||||
|
PMQLONG pReason)
|
||||||
|
{
|
||||||
|
char *csp_user = NULL;
|
||||||
|
char *csp_pass = NULL;
|
||||||
|
|
||||||
|
// Firstly, create null-terminated strings from the user credentials in the MQ CSP object
|
||||||
|
csp_user = malloc(pSecurityParms->CSPUserIdLength + 1);
|
||||||
|
if (!csp_user)
|
||||||
|
{
|
||||||
|
log_errorf("%s is unable to allocate memory for a user", NAME);
|
||||||
|
*pCompCode = MQCC_FAILED;
|
||||||
|
*pReason = MQRC_SERVICE_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strncpy(csp_user, pSecurityParms->CSPUserIdPtr, pSecurityParms->CSPUserIdLength);
|
||||||
|
csp_user[pSecurityParms->CSPUserIdLength] = 0;
|
||||||
|
csp_pass = malloc((pSecurityParms->CSPPasswordLength + 1));
|
||||||
|
if (!csp_pass)
|
||||||
|
{
|
||||||
|
log_errorf("%s is unable to allocate memory for a password", NAME);
|
||||||
|
*pCompCode = MQCC_FAILED;
|
||||||
|
*pReason = MQRC_SERVICE_ERROR;
|
||||||
|
if (csp_user)
|
||||||
|
{
|
||||||
|
free(csp_user);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strncpy(csp_pass, pSecurityParms->CSPPasswordPtr, pSecurityParms->CSPPasswordLength);
|
||||||
|
csp_pass[pSecurityParms->CSPPasswordLength] = 0;
|
||||||
|
log_debugf("%s with CSP user set. user=%s", __func__, csp_user);
|
||||||
|
int auth_result = htpass_authenticate_user(HTPASSWD_FILE, csp_user, csp_pass);
|
||||||
|
|
||||||
|
if (auth_result == HTPASS_VALID)
|
||||||
|
{
|
||||||
|
// An OK completion code means MQ will accept this user is authenticated
|
||||||
|
*pCompCode = MQCC_OK;
|
||||||
|
*pReason = MQRC_NONE;
|
||||||
|
// Tell the queue manager to stop trying other authorization services.
|
||||||
|
*pContinuation = MQZCI_STOP;
|
||||||
|
memcpy(pIdentityContext->UserIdentifier, csp_user, sizeof(pIdentityContext->UserIdentifier));
|
||||||
|
log_debugf("Authenticated user=%s", pIdentityContext->UserIdentifier);
|
||||||
|
}
|
||||||
|
// If the htpasswd file does not have an entry for this user
|
||||||
|
else if (auth_result == HTPASS_INVALID_USER)
|
||||||
|
{
|
||||||
|
*pCompCode = MQCC_WARNING;
|
||||||
|
*pReason = MQRC_NONE;
|
||||||
|
// Tell the queue manager to continue trying other authorization services, as they might have the user.
|
||||||
|
*pContinuation = MQZCI_CONTINUE;
|
||||||
|
log_debugf(
|
||||||
|
"User authentication failed due to invalid user. user=%s effuser=%s applname=%s csp_user=%s cc=%d reason=%d",
|
||||||
|
trim(pIdentityContext->UserIdentifier),
|
||||||
|
trim(pApplicationContext->EffectiveUserID),
|
||||||
|
trim(pApplicationContext->ApplName),
|
||||||
|
trim(csp_user),
|
||||||
|
*pCompCode,
|
||||||
|
*pReason);
|
||||||
|
}
|
||||||
|
// If the htpasswd file has an entry for this user, but the password supplied is incorrect
|
||||||
|
else if (auth_result == HTPASS_INVALID_PASSWORD)
|
||||||
|
{
|
||||||
|
*pCompCode = MQCC_WARNING;
|
||||||
|
*pReason = MQRC_NOT_AUTHORIZED;
|
||||||
|
// Tell the queue manager to stop trying other authorization services.
|
||||||
|
*pContinuation = MQZCI_STOP;
|
||||||
|
log_debugf(
|
||||||
|
"User authentication failed due to invalid password. user=%s effuser=%s applname=%s csp_user=%s cc=%d reason=%d",
|
||||||
|
trim(pIdentityContext->UserIdentifier),
|
||||||
|
trim(pApplicationContext->EffectiveUserID),
|
||||||
|
trim(pApplicationContext->ApplName),
|
||||||
|
trim(csp_user),
|
||||||
|
*pCompCode,
|
||||||
|
*pReason);
|
||||||
|
}
|
||||||
|
if (csp_user)
|
||||||
|
{
|
||||||
|
free(csp_user);
|
||||||
|
}
|
||||||
|
if (csp_pass)
|
||||||
|
{
|
||||||
|
free(csp_pass);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called during the connection of any application.
|
||||||
|
* For more information on the parameters, see https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_latest/com.ibm.mq.ref.dev.doc/q110090_.html
|
||||||
|
*/
|
||||||
|
static void MQENTRY mqhtpass_authenticate_user(
|
||||||
|
PMQCHAR pQMgrName,
|
||||||
|
PMQCSP pSecurityParms,
|
||||||
|
PMQZAC pApplicationContext,
|
||||||
|
PMQZIC pIdentityContext,
|
||||||
|
PMQPTR pCorrelationPtr,
|
||||||
|
PMQBYTE pComponentData,
|
||||||
|
PMQLONG pContinuation,
|
||||||
|
PMQLONG pCompCode,
|
||||||
|
PMQLONG pReason)
|
||||||
|
{
|
||||||
|
char *spuser = NULL;
|
||||||
|
// By default, return a warning, which indicates to MQ that this
|
||||||
|
// authorization service hasn't authenticated the user.
|
||||||
|
*pCompCode = MQCC_WARNING;
|
||||||
|
*pReason = MQRC_NONE;
|
||||||
|
// By default, tell the queue manager to continue trying other
|
||||||
|
// authorization services.
|
||||||
|
*pContinuation = MQZCI_CONTINUE;
|
||||||
|
|
||||||
|
if ((pSecurityParms->AuthenticationType) == MQCSP_AUTH_USER_ID_AND_PWD)
|
||||||
|
{
|
||||||
|
mqhtpass_authenticate_user_csp(pQMgrName, pSecurityParms, pApplicationContext, pIdentityContext, pCorrelationPtr, pComponentData, pContinuation, pCompCode, pReason);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Password not supplied, so just check that the user ID is valid
|
||||||
|
spuser = malloc(sizeof(PMQCHAR12) + 1);
|
||||||
|
if (!spuser)
|
||||||
|
{
|
||||||
|
log_errorf("%s is unable to allocate memory to check a user", NAME);
|
||||||
|
*pCompCode = MQCC_FAILED;
|
||||||
|
*pReason = MQRC_SERVICE_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strncpy(spuser, pApplicationContext->EffectiveUserID, strlen(pApplicationContext->EffectiveUserID));
|
||||||
|
spuser[sizeof(PMQCHAR12)] = 0;
|
||||||
|
log_debugf("%s without CSP user set. effectiveuid=%s env=%d, callertype=%d, type=%d, accttoken=%d applidentitydata=%d", __func__, spuser, pApplicationContext->Environment, pApplicationContext->CallerType, pApplicationContext->AuthenticationType, pIdentityContext->AccountingToken, pIdentityContext->ApplIdentityData);
|
||||||
|
if (strncmp(spuser, "mqm", 3) == 0)
|
||||||
|
{
|
||||||
|
// Special case: pass the "mqm" user on for validation up the chain
|
||||||
|
// A warning in the completion code means MQ will pass this to other authorization services
|
||||||
|
*pCompCode = MQCC_WARNING;
|
||||||
|
*pReason = MQRC_NONE;
|
||||||
|
*pContinuation = MQZCI_CONTINUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool valid_user = htpass_valid_user(HTPASSWD_FILE, spuser);
|
||||||
|
if (valid_user)
|
||||||
|
{
|
||||||
|
// An OK completion code means MQ will accept this user is authenticated
|
||||||
|
*pCompCode = MQCC_OK;
|
||||||
|
*pReason = MQRC_NONE;
|
||||||
|
*pContinuation = MQZCI_STOP;
|
||||||
|
memcpy(pIdentityContext->UserIdentifier, spuser, sizeof(pIdentityContext->UserIdentifier));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_debugf(
|
||||||
|
"User authentication failed user=%s effuser=%s applname=%s cspuser=%s cc=%d reason=%d",
|
||||||
|
trim(pIdentityContext->UserIdentifier),
|
||||||
|
trim(pApplicationContext->EffectiveUserID),
|
||||||
|
trim(pApplicationContext->ApplName),
|
||||||
|
trim(spuser),
|
||||||
|
*pCompCode,
|
||||||
|
*pReason);
|
||||||
|
}
|
||||||
|
if (spuser)
|
||||||
|
{
|
||||||
|
free(spuser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called during MQDISC, as the inverse of the call to authenticate.
|
||||||
|
*/
|
||||||
|
static void MQENTRY mqhtpass_free_user(
|
||||||
|
PMQCHAR pQMgrName,
|
||||||
|
PMQZFP pFreeParms,
|
||||||
|
PMQBYTE pComponentData,
|
||||||
|
PMQLONG pContinuation,
|
||||||
|
|
||||||
|
PMQLONG pCompCode,
|
||||||
|
PMQLONG pReason)
|
||||||
|
{
|
||||||
|
log_debugf("mqhtpass_freeuser()");
|
||||||
|
*pCompCode = MQCC_WARNING;
|
||||||
|
*pReason = MQRC_NONE;
|
||||||
|
*pContinuation = MQZCI_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the authorization service is terminated.
|
||||||
|
*/
|
||||||
|
static void MQENTRY mqhtpass_terminate(
|
||||||
|
MQHCONFIG hc,
|
||||||
|
MQLONG Options,
|
||||||
|
PMQCHAR pQMgrName,
|
||||||
|
PMQBYTE pComponentData,
|
||||||
|
PMQLONG pCompCode,
|
||||||
|
PMQLONG pReason)
|
||||||
|
{
|
||||||
|
if (Options == MQZTO_PRIMARY)
|
||||||
|
{
|
||||||
|
log_infof("Terminating %s", NAME);
|
||||||
|
log_close();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_debugf("Terminating secondary");
|
||||||
|
}
|
||||||
|
*pCompCode = MQCC_OK;
|
||||||
|
*pReason = MQRC_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove trailing spaces from a string.
|
||||||
|
*/
|
||||||
|
static char *trim(char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = strlen(s) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (s[i] == ' ')
|
||||||
|
s[i] = 0;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ func queueManagerHealthy() (bool, error) {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") {
|
if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") && !strings.Contains(string(out), "(REPLICA)") {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the queue manager has a running listener
|
// Check if the queue manager has a running listener
|
||||||
if standby, _ := ready.IsRunningAsStandbyQM(name); !standby {
|
if active, _ := ready.IsRunningAsActiveQM(name); active {
|
||||||
conn, err := net.Dial("tcp", "127.0.0.1:1414")
|
conn, err := net.Dial("tcp", "127.0.0.1:1414")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -49,8 +49,13 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else if standby, _ := ready.IsRunningAsStandbyQM(name); standby {
|
||||||
fmt.Printf("Detected queue manager running in standby mode")
|
fmt.Printf("Detected queue manager running in standby mode")
|
||||||
os.Exit(10)
|
os.Exit(10)
|
||||||
|
} else if replica, _ := ready.IsRunningAsReplicaQM(name); replica {
|
||||||
|
fmt.Printf("Detected queue manager running in replica mode")
|
||||||
|
os.Exit(20)
|
||||||
|
} else {
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
cmd/chkmqstarted/main.go
Normal file
58
cmd/chkmqstarted/main.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// chkmqstarted checks that MQ has successfully started, by checking the output of the "dspmq" command
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/pkg/name"
|
||||||
|
)
|
||||||
|
|
||||||
|
func queueManagerStarted() (bool, error) {
|
||||||
|
name, err := name.GetQueueManagerName()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// Specify the queue manager name, just in case someone's created a second queue manager
|
||||||
|
// #nosec G204
|
||||||
|
cmd := exec.Command("dspmq", "-n", "-m", name)
|
||||||
|
// Run the command and wait for completion
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") && !strings.Contains(string(out), "(REPLICA)") {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
started, err := queueManagerStarted()
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
if !started {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2020
|
© Copyright IBM Corporation 2018, 2021
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/htpasswd"
|
"github.com/ibm-messaging/mq-container/internal/htpasswd"
|
||||||
@@ -30,27 +29,6 @@ import (
|
|||||||
|
|
||||||
var log *logger.Logger
|
var log *logger.Logger
|
||||||
|
|
||||||
func setPassword(user string, password string) error {
|
|
||||||
// #nosec G204
|
|
||||||
cmd := exec.Command("sudo", "chpasswd")
|
|
||||||
stdin, err := cmd.StdinPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(stdin, "%s:%s", user, password)
|
|
||||||
err = stdin.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error closing password stdin: %v", err)
|
|
||||||
}
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
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)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLogFormat() string {
|
func getLogFormat() string {
|
||||||
return os.Getenv("LOG_FORMAT")
|
return os.Getenv("LOG_FORMAT")
|
||||||
}
|
}
|
||||||
@@ -99,6 +77,7 @@ func logTermination(args ...interface{}) {
|
|||||||
// Write the message to the termination log. This is not 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)
|
||||||
|
// #nosec G306 - its a read by owner/s group, and pose no harm.
|
||||||
err := ioutil.WriteFile("/run/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)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2020
|
© Copyright IBM Corporation 2017, 2021
|
||||||
|
|
||||||
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.
|
||||||
@@ -46,6 +46,7 @@ func logTermination(args ...interface{}) {
|
|||||||
// Write the message to the termination log. This is not 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)
|
||||||
|
// #nosec G306 - its a read by owner/s group, and pose no harm.
|
||||||
err := ioutil.WriteFile("/run/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)
|
||||||
@@ -79,6 +80,8 @@ func formatBasic(obj map[string]interface{}) string {
|
|||||||
if len(inserts) > 0 {
|
if len(inserts) > 0 {
|
||||||
return fmt.Sprintf("%s %s [%v]\n", obj["ibm_datetime"], obj["message"], strings.Join(inserts, ", "))
|
return fmt.Sprintf("%s %s [%v]\n", obj["ibm_datetime"], obj["message"], strings.Join(inserts, ", "))
|
||||||
}
|
}
|
||||||
|
// Convert time zone information from some logs (e.g. Liberty) for consistency
|
||||||
|
obj["ibm_datetime"] = strings.Replace(obj["ibm_datetime"].(string), "+0000", "Z", 1)
|
||||||
return fmt.Sprintf("%s %s\n", obj["ibm_datetime"], obj["message"])
|
return fmt.Sprintf("%s %s\n", obj["ibm_datetime"], obj["message"])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +103,16 @@ func mirrorQueueManagerErrorLogs(ctx context.Context, wg *sync.WaitGroup, name s
|
|||||||
return mirrorLog(ctx, wg, f, fromStart, mf, true)
|
return mirrorLog(ctx, wg, f, fromStart, mf, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mirrorHTPasswdLogs starts a goroutine to mirror the contents of the MQ HTPasswd authorization service's log
|
||||||
|
func mirrorHTPasswdLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
||||||
|
return mirrorLog(ctx, wg, "/var/mqm/errors/mqhtpass.json", false, mf, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mirrorWebServerLogs starts a goroutine to mirror the contents of the Liberty web server messages.log
|
||||||
|
func mirrorWebServerLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
||||||
|
return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", false, mf, true)
|
||||||
|
}
|
||||||
|
|
||||||
func getDebug() bool {
|
func getDebug() bool {
|
||||||
debug := os.Getenv("DEBUG")
|
debug := os.Getenv("DEBUG")
|
||||||
if debug == "true" || debug == "1" {
|
if debug == "true" || debug == "1" {
|
||||||
@@ -119,14 +132,21 @@ func configureLogger(name string) (mirrorFunc, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func(msg string, isQMLog bool) bool {
|
return func(msg string, isQMLog bool) bool {
|
||||||
obj, err := processLogMessage(msg)
|
// Check if the message is JSON
|
||||||
if err == nil && isQMLog && filterQMLogMessage(obj) {
|
if len(msg) > 0 && msg[0] == '{' {
|
||||||
return false
|
obj, err := processLogMessage(msg)
|
||||||
}
|
if err == nil && isQMLog && filterQMLogMessage(obj) {
|
||||||
if err != nil {
|
return false
|
||||||
log.Printf("Failed to unmarshall JSON - %v", msg)
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to unmarshall JSON in log message - %v", msg)
|
||||||
|
} else {
|
||||||
|
fmt.Println(msg)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(msg)
|
// The log being mirrored isn't JSON, so wrap it in a simple JSON message
|
||||||
|
// MQ error logs are usually JSON, but this is useful for Liberty logs - usually expect WLP_LOGGING_MESSAGE_FORMAT=JSON to be set when mirroring Liberty logs.
|
||||||
|
fmt.Printf("{\"message\":\"%s\"}\n", msg)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}, nil
|
}, nil
|
||||||
@@ -136,16 +156,22 @@ func configureLogger(name string) (mirrorFunc, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func(msg string, isQMLog bool) bool {
|
return func(msg string, isQMLog bool) bool {
|
||||||
// Parse the JSON message, and print a simplified version
|
// Check if the message is JSON
|
||||||
obj, err := processLogMessage(msg)
|
if len(msg) > 0 && msg[0] == '{' {
|
||||||
if err == nil && isQMLog && filterQMLogMessage(obj) {
|
// Parse the JSON message, and print a simplified version
|
||||||
return false
|
obj, err := processLogMessage(msg)
|
||||||
}
|
if err == nil && isQMLog && filterQMLogMessage(obj) {
|
||||||
if err != nil {
|
return false
|
||||||
log.Printf("Failed to unmarshall JSON - %v", err)
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to unmarshall JSON in log message - %v", err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(formatBasic(obj))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(formatBasic(obj))
|
// The log being mirrored isn't JSON, so just print it.
|
||||||
// fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
|
// MQ error logs are usually JSON, but this is useful for Liberty logs - usually expect WLP_LOGGING_MESSAGE_FORMAT=JSON to be set when mirroring Liberty logs.
|
||||||
|
fmt.Println(msg)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2020
|
© Copyright IBM Corporation 2017, 2021
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/ha"
|
||||||
"github.com/ibm-messaging/mq-container/internal/metrics"
|
"github.com/ibm-messaging/mq-container/internal/metrics"
|
||||||
"github.com/ibm-messaging/mq-container/internal/ready"
|
"github.com/ibm-messaging/mq-container/internal/ready"
|
||||||
"github.com/ibm-messaging/mq-container/internal/tls"
|
"github.com/ibm-messaging/mq-container/internal/tls"
|
||||||
@@ -143,30 +144,55 @@ func doMain() error {
|
|||||||
// Print out versioning information
|
// Print out versioning information
|
||||||
logVersionInfo()
|
logVersionInfo()
|
||||||
|
|
||||||
keyLabel, cmsKeystore, p12Truststore, err := tls.ConfigureTLSKeystores()
|
keyLabel, defaultCmsKeystore, defaultP12Truststore, err := tls.ConfigureDefaultTLSKeystores()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tls.ConfigureTLS(keyLabel, cmsKeystore, *devFlag, log)
|
err = tls.ConfigureTLS(keyLabel, defaultCmsKeystore, *devFlag, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = postInit(name, keyLabel, p12Truststore)
|
err = postInit(name, keyLabel, defaultP12Truststore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if os.Getenv("MQ_NATIVE_HA") == "true" {
|
||||||
|
err = ha.ConfigureNativeHA(log)
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enableTraceCrtmqm := os.Getenv("MQ_ENABLE_TRACE_CRTMQM")
|
||||||
|
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
||||||
|
err = startMQTrace()
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newQM, err := createQueueManager(name, *devFlag)
|
newQM, err := createQueueManager(name, *devFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
||||||
|
err = endMQTrace()
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
defer func() {
|
defer func() {
|
||||||
log.Debug("Waiting for log mirroring to complete")
|
log.Debug("Waiting for log mirroring to complete")
|
||||||
@@ -188,6 +214,23 @@ func doMain() error {
|
|||||||
logTermination(err)
|
logTermination(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if *devFlag {
|
||||||
|
_, err = mirrorHTPasswdLogs(ctx, &wg, name, newQM, mf)
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Recommended to use this option in conjunction with setting WLP_LOGGING_MESSAGE_FORMAT=JSON
|
||||||
|
mirrorWebLog := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG")
|
||||||
|
if mirrorWebLog == "true" || mirrorWebLog == "1" {
|
||||||
|
_, err = mirrorWebServerLogs(ctx, &wg, name, newQM, mf)
|
||||||
|
if err != nil {
|
||||||
|
logTermination(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = updateCommandLevel()
|
err = updateCommandLevel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
// the file is open before the queue manager is created or started.
|
// the file is open before the queue manager is created or started.
|
||||||
// Otherwise, there would be the potential for a nearly-full file to
|
// Otherwise, there would be the potential for a nearly-full file to
|
||||||
// rotate before the goroutine had a chance to open it.
|
// rotate before the goroutine had a chance to open it.
|
||||||
|
// #nosec G304 - no harm, we open readonly and check error.
|
||||||
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
f, err = os.OpenFile(path, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -122,6 +123,7 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("File exists: %v, %v", path, fi.Size())
|
log.Debugf("File exists: %v, %v", path, fi.Size())
|
||||||
|
// #nosec G304 - no harm, we open readonly and check error.
|
||||||
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)
|
||||||
@@ -169,6 +171,7 @@ func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart b
|
|||||||
}
|
}
|
||||||
// Re-open file
|
// Re-open file
|
||||||
log.Debugf("Re-opening error log file %v", path)
|
log.Debugf("Re-opening error log file %v", path)
|
||||||
|
// #nosec G304 - no harm, we open readonly and check error.
|
||||||
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)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
containerruntime "github.com/ibm-messaging/mq-container/internal/containerruntime"
|
containerruntime "github.com/ibm-messaging/mq-container/internal/containerruntime"
|
||||||
"github.com/ibm-messaging/mq-container/internal/mqscredact"
|
"github.com/ibm-messaging/mq-container/internal/mqscredact"
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/mqversion"
|
||||||
"github.com/ibm-messaging/mq-container/internal/ready"
|
"github.com/ibm-messaging/mq-container/internal/ready"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -112,9 +113,13 @@ func startQueueManager(name string) error {
|
|||||||
out, rc, err := command.Run("strmqm", "-x", name)
|
out, rc, err := command.Run("strmqm", "-x", name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 30=standby queue manager started, which is fine
|
// 30=standby queue manager started, which is fine
|
||||||
|
// 94=native HA replica started, which is fine
|
||||||
if rc == 30 {
|
if rc == 30 {
|
||||||
log.Printf("Started standby queue manager")
|
log.Printf("Started standby queue manager")
|
||||||
return nil
|
return nil
|
||||||
|
} else if rc == 94 {
|
||||||
|
log.Printf("Started replica queue manager")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
log.Printf("Error %v starting queue manager: %v", rc, string(out))
|
log.Printf("Error %v starting queue manager: %v", rc, string(out))
|
||||||
return err
|
return err
|
||||||
@@ -203,9 +208,28 @@ func getQueueManagerDataDir(mounts map[string]string, name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getCreateQueueManagerArgs(mounts map[string]string, name string, devMode bool) []string {
|
func getCreateQueueManagerArgs(mounts map[string]string, name string, devMode bool) []string {
|
||||||
|
|
||||||
|
mqversionBase := "9.2.1.0"
|
||||||
|
|
||||||
|
// use "UserExternal" only if we are 9.2.1.0 or above.
|
||||||
|
oaVal := "user"
|
||||||
|
mqVersionCheck, err := mqversion.Compare(mqversionBase)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error comparing MQ versions for oa,rc: %v", mqVersionCheck)
|
||||||
|
}
|
||||||
|
if mqVersionCheck >= 0 {
|
||||||
|
oaVal = "UserExternal"
|
||||||
|
}
|
||||||
|
|
||||||
|
//build args
|
||||||
args := []string{"-ii", "/etc/mqm/", "-ic", "/etc/mqm/", "-q", "-p", "1414"}
|
args := []string{"-ii", "/etc/mqm/", "-ic", "/etc/mqm/", "-q", "-p", "1414"}
|
||||||
|
|
||||||
|
if os.Getenv("MQ_NATIVE_HA") == "true" {
|
||||||
|
args = append(args, "-lr", os.Getenv("HOSTNAME"))
|
||||||
|
}
|
||||||
if devMode {
|
if devMode {
|
||||||
args = append(args, "-oa", "user")
|
args = append(args, "-oa", oaVal)
|
||||||
}
|
}
|
||||||
if _, ok := mounts["/mnt/mqm-log"]; ok {
|
if _, ok := mounts["/mnt/mqm-log"]; ok {
|
||||||
args = append(args, "-ld", "/mnt/mqm-log/log")
|
args = append(args, "-ld", "/mnt/mqm-log/log")
|
||||||
@@ -262,7 +286,8 @@ func updateQMini(qmname string) error {
|
|||||||
if strings.Contains(qminiConfigStr, "ServiceComponent:") {
|
if strings.Contains(qminiConfigStr, "ServiceComponent:") {
|
||||||
var re = regexp.MustCompile(`(?m)^.*ServiceComponent.*$\s^.*Service.*$\s^.*Name.*$\s^.*Module.*$\s^.*ComponentDataSize.*$`)
|
var re = regexp.MustCompile(`(?m)^.*ServiceComponent.*$\s^.*Service.*$\s^.*Name.*$\s^.*Module.*$\s^.*ComponentDataSize.*$`)
|
||||||
curFile := re.ReplaceAllString(qminiConfigStr, "")
|
curFile := re.ReplaceAllString(qminiConfigStr, "")
|
||||||
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
|
// #nosec G304 G306 - qmgrDir filepath is derived from dspmqinf and
|
||||||
|
// its a read by owner/s group, and pose no harm.
|
||||||
err := ioutil.WriteFile(qmgrDir, []byte(curFile), 0660)
|
err := ioutil.WriteFile(qmgrDir, []byte(curFile), 0660)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2018
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
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.
|
||||||
@@ -33,8 +33,8 @@ func signalHandler(qmgr string) chan int {
|
|||||||
control := make(chan int)
|
control := make(chan int)
|
||||||
// Use separate channels for the signals, to avoid SIGCHLD signals swamping
|
// Use separate channels for the signals, to avoid SIGCHLD signals swamping
|
||||||
// the buffer, and preventing other signals.
|
// the buffer, and preventing other signals.
|
||||||
stopSignals := make(chan os.Signal)
|
stopSignals := make(chan os.Signal, 1)
|
||||||
reapSignals := make(chan os.Signal)
|
reapSignals := make(chan os.Signal, 1)
|
||||||
signal.Notify(stopSignals, syscall.SIGTERM, syscall.SIGINT)
|
signal.Notify(stopSignals, syscall.SIGTERM, syscall.SIGINT)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/mqversion"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -50,7 +51,7 @@ func logImageTag() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func logMQVersion() {
|
func logMQVersion() {
|
||||||
mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
|
mqVersion, err := mqversion.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error Getting MQ version: %v", strings.TrimSuffix(string(mqVersion), "\n"))
|
log.Printf("Error Getting MQ version: %v", strings.TrimSuffix(string(mqVersion), "\n"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,15 +62,31 @@ func startWebServer(webKeystore, webkeystorePW, webTruststoreRef string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func configureSSO(p12TrustStore tls.KeyStoreData, webKeystore string) (string, error) {
|
func configureSSO(p12TrustStore tls.KeyStoreData, webKeystore string) (string, error) {
|
||||||
// Ensure all required environment variables are set for SSO
|
requiredEnvVars := []string{}
|
||||||
requiredEnvVars := []string{
|
_, set := os.LookupEnv("MQ_ZEN_INTERNAL_ENDPOINT")
|
||||||
"MQ_OIDC_CLIENT_ID",
|
if !set {
|
||||||
"MQ_OIDC_CLIENT_SECRET",
|
// Ensure all required environment variables are set for SSO
|
||||||
"MQ_OIDC_UNIQUE_USER_IDENTIFIER",
|
requiredEnvVars = []string{
|
||||||
"MQ_OIDC_AUTHORIZATION_ENDPOINT",
|
"MQ_OIDC_CLIENT_ID",
|
||||||
"MQ_OIDC_TOKEN_ENDPOINT",
|
"MQ_OIDC_CLIENT_SECRET",
|
||||||
"MQ_OIDC_JWK_ENDPOINT",
|
"MQ_OIDC_UNIQUE_USER_IDENTIFIER",
|
||||||
"MQ_OIDC_ISSUER_IDENTIFIER",
|
"MQ_OIDC_AUTHORIZATION_ENDPOINT",
|
||||||
|
"MQ_OIDC_TOKEN_ENDPOINT",
|
||||||
|
"MQ_OIDC_JWK_ENDPOINT",
|
||||||
|
"MQ_OIDC_ISSUER_IDENTIFIER",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Ensure all required environment variables are set for Zen SSO
|
||||||
|
requiredEnvVars = []string{
|
||||||
|
"MQ_ZEN_UNIQUE_USER_IDENTIFIER",
|
||||||
|
"MQ_ZEN_INTERNAL_ENDPOINT",
|
||||||
|
"MQ_ZEN_ISSUER_IDENTIFIER",
|
||||||
|
"MQ_ZEN_AUDIENCES",
|
||||||
|
"MQ_ZEN_CONTEXT_NAME",
|
||||||
|
"MQ_ZEN_BASE_URI",
|
||||||
|
"MQ_ZEN_CONTEXT_NAMESPACE",
|
||||||
|
"IAM_URL",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, envVar := range requiredEnvVars {
|
for _, envVar := range requiredEnvVars {
|
||||||
if len(os.Getenv(envVar)) == 0 {
|
if len(os.Getenv(envVar)) == 0 {
|
||||||
|
|||||||
6
config.env
Normal file
6
config.env
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
###########################################################################################################################################################
|
||||||
|
|
||||||
|
# MQ_VERSION is the fully qualified MQ version number to build
|
||||||
|
MQ_VERSION ?= 9.3.0.5
|
||||||
|
|
||||||
|
###########################################################################################################################################################
|
||||||
@@ -4,33 +4,41 @@
|
|||||||
|
|
||||||
You need to have the following tools installed:
|
You need to have the following tools installed:
|
||||||
|
|
||||||
* [Docker](https://www.docker.com/) V17.06.1 or later, or [Podman](https://podman.io) V1.0 or later
|
* [Docker](https://www.docker.com/) 17.06.1 or later, or [Podman](https://podman.io) 1.0 or later (Podman 4.1 on macOS). If using Podman on macOS, the you need to be in "rootful" mode to allow the use of a network during builds. Run `podman machine init --rootful`.
|
||||||
* [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.
|
||||||
|
|
||||||
You will also need a [Red Hat Account](https://access.redhat.com) to be able to access the Red Hat Registry.
|
|
||||||
|
|
||||||
## Building a production image
|
## Building a production image
|
||||||
|
|
||||||
This procedure works for building the MQ Continuous Delivery release, on `amd64`, `ppc64le` and `s390x` architectures.
|
From MQ 9.2.X, the MQ container adds support for MQ Long Term Support (LTS) **production licensed** releases.
|
||||||
|
|
||||||
|
### Building MQ 9.3 Long Term Support (LTS) and Continuous Delivery (CD)
|
||||||
|
|
||||||
|
**Note**: MQ 9.3 is the latest MQ version with MQ Long Term Support (LTS), as well as being the latest Continuous Delivery (CD) version.
|
||||||
|
|
||||||
|
The procedure below is for building the 9.3 release, on `amd64`, `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](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.2.0_LINUX_X86-64_NOINST.tar.gz`) in the `downloads` directory
|
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/). Identify the correct 'Long Term Support Release for Containers' eImage part number for your architecture from the 9.3.0 LTS tab at https://www.ibm.com/support/pages/downloading-ibm-mq-930
|
||||||
3. Login to the Red Hat Registry: `docker login registry.redhat.io` using your Customer Portal credentials.
|
3. Ensure the `tar.gz` file is in the `downloads` directory
|
||||||
4. Run `make build-advancedserver`
|
4. Run `make build-advancedserver`
|
||||||
|
|
||||||
> **Warning**: Note that from MQ 9.2.X, the MQ container build uses a 'No-Install' MQ Package, available under `IBM MQ V9.2.x Continuous Delivery Release components eAssembly, part no. CJ7CNML`
|
|
||||||
|
|
||||||
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
|
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
|
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Building previous MQ Long Term Support (LTS)
|
||||||
|
|
||||||
|
**Note**: MQ 9.3 is the latest MQ version with MQ Long Term Support (LTS), as well as being the latest Continuous Delivery (CD) version. Therefore, to build build 9.3.0.X, follow the [instructions above for MQ 9.3](#building-mq-93-long-term-support-lts-and-continuous-delivery-cd).
|
||||||
|
|
||||||
|
However, if you wish to build the previous MQ LTS, use the [instructions](/../9.2.0.x/docs/building.md#mq-long-term-support-lts) in the `v9.2.0.x-eus` branch.
|
||||||
|
|
||||||
|
|
||||||
## Building a developer image
|
## Building a developer image
|
||||||
|
|
||||||
Login to the Red Hat Registry: `docker login registry.redhat.io` using your Customer Portal credentials.
|
|
||||||
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers from IBM developerWorks. This is currently only available on the `amd64` architecture.
|
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers from IBM developerWorks. This is currently only available on the `amd64` architecture.
|
||||||
|
|
||||||
You can use the environment variable `MQ_ARCHIVE_DEV` to specify an alternative local file to install from (which must be in the `downloads` directory).
|
You can use the environment variable `MQ_ARCHIVE_DEV` to specify an alternative local file to install from (which must be in the `downloads` directory).
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ The resulting Docker image contains the following:
|
|||||||
- `runmqdevserver` - The main process for MQ Advanced for Developers
|
- `runmqdevserver` - The main process for MQ Advanced for Developers
|
||||||
- `chkmqhealthy` - Checks the health of the queue manager. This can be used by (say) a Kubernetes liveness probe.
|
- `chkmqhealthy` - Checks the health of the queue manager. This can be used by (say) a Kubernetes liveness probe.
|
||||||
- `chkmqready` - Checks if the queue manager is ready for work. This can be used by (say) a Kubernetes readiness probe.
|
- `chkmqready` - Checks if the queue manager is ready for work. This can be used by (say) a Kubernetes readiness probe.
|
||||||
|
- `chkmqstarted` - Checks if the queue manager has successfully started. This can be used by (say) a Kubernetes startup probe.
|
||||||
|
|
||||||
## runmqserver
|
## runmqserver
|
||||||
The `runmqserver` command has the following responsibilities:
|
The `runmqserver` command has the following responsibilities:
|
||||||
|
|||||||
@@ -24,6 +24,6 @@ Use an administrative tool or your application to connect to queue manager using
|
|||||||
|
|
||||||
#### Troubleshooting
|
#### Troubleshooting
|
||||||
|
|
||||||
A log file named `amqpasdev.log` is generated under `/var/mqm/errors` directory path of the container. This file will contain all the failed connection authentication requests.
|
A log file named `mqhtpass.log` is generated under `/var/mqm/errors` directory path of the container. This file will contain all the failed connection authentication requests. Additional information is logged to this file if the environment variable `DEBUG` is set to `true`.
|
||||||
|
|
||||||
**Please note**: This log file is based on circular logging and the maximum size is restricted to 1MB.
|
**Please note**: This log file will be wiped when the queue manager is next started.
|
||||||
|
|||||||
@@ -16,20 +16,5 @@ docker run \
|
|||||||
--env LICENSE=accept \
|
--env LICENSE=accept \
|
||||||
--env MQ_QMGR_NAME=QM1 \
|
--env MQ_QMGR_NAME=QM1 \
|
||||||
--detach \
|
--detach \
|
||||||
ibm-mqadvanced-server:9.2.0.0-amd64
|
ibm-mqadvanced-server:9.3.0.5-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:
|
|
||||||
|
|
||||||
```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 \
|
|
||||||
ibm-mqadvanced-server-dev:9.2.0.0-amd64
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
You need to ensure you have the following tools installed:
|
You need to ensure you have the following tools installed:
|
||||||
* [Docker](https://www.docker.com/)
|
* [Docker](https://www.docker.com/) 19.03 or higher (API version 1.40)
|
||||||
* [GNU make](https://www.gnu.org/software/make/)
|
* [GNU make](https://www.gnu.org/software/make/)
|
||||||
* [Go](https://golang.org/) - only needed for running the tests
|
* [Go](https://golang.org/) - only needed for running the tests
|
||||||
* [dep](https://github.com/golang/dep) (official Go dependency management tool) - needed to prepare for running the tests
|
|
||||||
|
|
||||||
## Running the tests
|
## Running the tests
|
||||||
There are two main sets of tests:
|
There are two main sets of tests:
|
||||||
@@ -14,7 +13,7 @@ There are two main sets of tests:
|
|||||||
2. Docker tests, which test a complete Docker image, using the Docker API
|
2. Docker tests, which test a complete Docker image, using the Docker API
|
||||||
|
|
||||||
### Running the Docker tests
|
### Running the Docker tests
|
||||||
|
|
||||||
The Docker tests can be run locally on a machine with Docker. For example:
|
The Docker tests can be run locally on a machine with Docker. For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -25,7 +24,7 @@ make advancedserver
|
|||||||
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
|
||||||
|
|
||||||
```
|
```
|
||||||
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.2.0.0-amd64 make test-advancedserver
|
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:9.3.0.5-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:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ docker run \
|
|||||||
--publish 1414:1414 \
|
--publish 1414:1414 \
|
||||||
--publish 9443:9443 \
|
--publish 9443:9443 \
|
||||||
--detach \
|
--detach \
|
||||||
ibmcom/mq
|
icr.io/ibm-messaging/mq
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running with the default configuration and a volume
|
## Running with the default configuration and a volume
|
||||||
@@ -34,7 +34,7 @@ docker run \
|
|||||||
--publish 9443:9443 \
|
--publish 9443:9443 \
|
||||||
--detach \
|
--detach \
|
||||||
--volume qm1data:/mnt/mqm \
|
--volume qm1data:/mnt/mqm \
|
||||||
ibmcom/mq
|
icr.io/ibm-messaging/mq
|
||||||
```
|
```
|
||||||
|
|
||||||
The Docker image always uses `/mnt/mqm` for MQ data, which is correctly linked for you under `/var/mqm` at runtime. This is to handle problems with file permissions on some platforms.
|
The Docker image always uses `/mnt/mqm` for MQ data, which is correctly linked for you under `/var/mqm` at runtime. This is to handle problems with file permissions on some platforms.
|
||||||
@@ -51,7 +51,7 @@ docker run \
|
|||||||
--publish 9443:9443 \
|
--publish 9443:9443 \
|
||||||
--publish 9157:9157 \
|
--publish 9157:9157 \
|
||||||
--detach \
|
--detach \
|
||||||
ibmcom/mq
|
icr.io/ibm-messaging/mq
|
||||||
```
|
```
|
||||||
|
|
||||||
## Customizing the queue manager configuration
|
## Customizing the queue manager configuration
|
||||||
@@ -60,14 +60,14 @@ You can customize the configuration in several ways:
|
|||||||
|
|
||||||
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
|
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
|
||||||
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
|
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
|
||||||
3. By using [remote MQ administration](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.2.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.3.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
|
||||||
|
|
||||||
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
|
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
|
||||||
|
|
||||||
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file:
|
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file:
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM ibmcom/mq
|
FROM icr.io/ibm-messaging/mq
|
||||||
USER 1001
|
USER 1001
|
||||||
COPY 20-config.mqsc /etc/mqm/
|
COPY 20-config.mqsc /etc/mqm/
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
ServiceComponent:
|
ServiceComponent:
|
||||||
Service=AuthorizationService
|
Service=AuthorizationService
|
||||||
Name=Dev.HtpAuth.Service
|
Name=Dev.HtpAuth.Service
|
||||||
Module=/opt/mqm/lib64/amqpasdev.so
|
Module=/opt/mqm/lib64/mqhtpass.so
|
||||||
ComponentDataSize=0
|
ComponentDataSize=0
|
||||||
ServiceComponent:
|
ServiceComponent:
|
||||||
Service=AuthorizationService
|
Service=AuthorizationService
|
||||||
|
|||||||
24
go.mod
Normal file
24
go.mod
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
module github.com/ibm-messaging/mq-container
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/genuinetools/amicontained v0.4.3
|
||||||
|
github.com/ibm-messaging/mq-golang v2.0.0+incompatible
|
||||||
|
github.com/prometheus/client_golang v1.11.1
|
||||||
|
github.com/prometheus/client_model v0.2.0
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1
|
||||||
|
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/golang/protobuf v1.4.3 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/prometheus/common v0.26.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1 // indirect
|
||||||
|
)
|
||||||
149
go.sum
Normal file
149
go.sum
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/genuinetools/amicontained v0.4.3 h1:cqq9XiAHfWWY3dk8VU8bSJFu9yh8Il5coEdeTAPq72o=
|
||||||
|
github.com/genuinetools/amicontained v0.4.3/go.mod h1:PAMZkg9CcUTa6gNyULQ6tOMTMEb2HTKJufvKeFqDw+o=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/ibm-messaging/mq-golang v2.0.0+incompatible h1:xAufRPYSzoRGaME2+x7LcW5+uvy/G3xL/3Sn3u+G/lY=
|
||||||
|
github.com/ibm-messaging/mq-golang v2.0.0+incompatible/go.mod h1:qjsZDb7m1oKnbPeDma2JVJTKgyCA91I4bcJ1qHY+gcA=
|
||||||
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
|
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||||
|
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||||
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
|
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||||
|
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
|
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||||
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||||
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001 h1:AVd6O+azYjVQYW1l55IqkbL8/JxjrLtO6q4FCmV8N5c=
|
||||||
|
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
|
||||||
18
ha/native-ha.ini.tpl
Normal file
18
ha/native-ha.ini.tpl
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
NativeHALocalInstance:
|
||||||
|
Name={{ .Name }}
|
||||||
|
{{ if .CertificateLabel }}
|
||||||
|
CertificateLabel={{ .CertificateLabel }}
|
||||||
|
KeyRepository={{ .KeyRepository }}
|
||||||
|
{{ if .CipherSpec }}
|
||||||
|
CipherSpec={{ .CipherSpec }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
NativeHAInstance:
|
||||||
|
Name={{ .NativeHAInstance0_Name }}
|
||||||
|
ReplicationAddress={{ .NativeHAInstance0_ReplicationAddress }}
|
||||||
|
NativeHAInstance:
|
||||||
|
Name={{ .NativeHAInstance1_Name }}
|
||||||
|
ReplicationAddress={{ .NativeHAInstance1_ReplicationAddress }}
|
||||||
|
NativeHAInstance:
|
||||||
|
Name={{ .NativeHAInstance2_Name }}
|
||||||
|
ReplicationAddress={{ .NativeHAInstance2_ReplicationAddress }}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
* © Copyright IBM Corporation 2018, 2019
|
* © Copyright IBM Corporation 2018, 2022
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -14,5 +14,5 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
|
||||||
* Set the cipherspec for dev channels
|
* Set the cipherspec for dev channels
|
||||||
ALTER CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12) SSLCAUTH(OPTIONAL)
|
ALTER CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12_OR_HIGHER) SSLCAUTH(OPTIONAL)
|
||||||
ALTER CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12) SSLCAUTH(OPTIONAL)
|
ALTER CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12_OR_HIGHER) SSLCAUTH(OPTIONAL)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2019
|
# © Copyright IBM Corporation 2019, 2021
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -25,17 +25,17 @@ test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
|
|||||||
if ($UBUNTU); then
|
if ($UBUNTU); then
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y --no-install-recommends sudo
|
apt-get install -y --no-install-recommends libaprutil1
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ($YUM); then
|
if ($YUM); then
|
||||||
yum -y install sudo
|
yum -y install apr-util-openssl
|
||||||
yum -y clean all
|
yum -y clean all
|
||||||
rm -rf /var/cache/yum/*
|
rm -rf /var/cache/yum/*
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ($MICRODNF); then
|
if ($MICRODNF); then
|
||||||
microdnf install sudo
|
microdnf --disableplugin=subscription-manager install apr-util-openssl
|
||||||
microdnf clean all
|
microdnf --disableplugin=subscription-manager clean all
|
||||||
fi
|
fi
|
||||||
@@ -36,5 +36,9 @@
|
|||||||
</basicRegistry>
|
</basicRegistry>
|
||||||
<variable name="httpHost" value="*"/>
|
<variable name="httpHost" value="*"/>
|
||||||
<variable name="managementMode" value="externallyprovisioned"/>
|
<variable name="managementMode" value="externallyprovisioned"/>
|
||||||
|
<variable name="mqConsoleRemoteSupportEnabled" value="false"/>
|
||||||
|
<variable name="mqConsoleEnableUnsafeInline" value="true"/>
|
||||||
|
<jndiEntry jndiName="mqConsoleDefaultCCDTHostname" value="${env.MQ_CONSOLE_DEFAULT_CCDT_HOSTNAME}"/>
|
||||||
|
<jndiEntry jndiName="mqConsoleDefaultCCDTPort" value="${env.MQ_CONSOLE_DEFAULT_CCDT_PORT}"/>
|
||||||
<include location="tls.xml"/>
|
<include location="tls.xml"/>
|
||||||
</server>
|
</server>
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ set -ex
|
|||||||
|
|
||||||
sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.1/dep-linux-$ARCH
|
sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.1/dep-linux-$ARCH
|
||||||
sudo chmod +x /usr/local/bin/dep
|
sudo chmod +x /usr/local/bin/dep
|
||||||
|
sudo apt-get update || :
|
||||||
|
sudo apt-get install -y jq
|
||||||
|
|
||||||
go get -u golang.org/x/lint/golint
|
go install golang.org/x/lint/golint@latest
|
||||||
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin 2.0.0 || echo "Gosec not installed. Platform may not be supported."
|
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin v2.14.0 || echo "Gosec not installed. Platform may not be supported."
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2015, 2020
|
# © Copyright IBM Corporation 2015, 2021
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -66,7 +66,7 @@ if ($RPM); then
|
|||||||
EXTRA_RPMS="bash bc ca-certificates file findutils gawk glibc-common grep ncurses-compat-libs passwd procps-ng sed shadow-utils tar util-linux which"
|
EXTRA_RPMS="bash bc ca-certificates file findutils gawk glibc-common grep ncurses-compat-libs passwd procps-ng sed shadow-utils tar util-linux which"
|
||||||
# Install additional packages required by MQ, this install process and the runtime scripts
|
# Install additional packages required by MQ, this install process and the runtime scripts
|
||||||
$YUM && yum -y install --setopt install_weak_deps=false ${EXTRA_RPMS}
|
$YUM && yum -y install --setopt install_weak_deps=false ${EXTRA_RPMS}
|
||||||
$MICRODNF && microdnf install ${EXTRA_RPMS}
|
$MICRODNF && microdnf --disableplugin=subscription-manager install ${EXTRA_RPMS}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Apply any bug fixes not included in base Ubuntu or MQ image.
|
# Apply any bug fixes not included in base Ubuntu or MQ image.
|
||||||
@@ -78,4 +78,4 @@ $UBUNTU && apt-get install -y libapparmor1 libsystemd0 systemd systemd-sysv libu
|
|||||||
$UBUNTU && rm -rf /var/lib/apt/lists/*
|
$UBUNTU && rm -rf /var/lib/apt/lists/*
|
||||||
$YUM && yum -y clean all
|
$YUM && yum -y clean all
|
||||||
$YUM && rm -rf /var/cache/yum/*
|
$YUM && rm -rf /var/cache/yum/*
|
||||||
$MICRODNF && microdnf clean all
|
$MICRODNF && microdnf --disableplugin=subscription-manager clean all
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2015, 2020
|
# © Copyright IBM Corporation 2015, 2022
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -21,17 +21,11 @@ set -ex
|
|||||||
test -f /usr/bin/rpm && RPM=true || RPM=false
|
test -f /usr/bin/rpm && RPM=true || RPM=false
|
||||||
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
|
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
|
||||||
|
|
||||||
# Only install the SDK package as part of the build stage
|
|
||||||
INSTALL_SDK=${INSTALL_SDK:-0}
|
|
||||||
|
|
||||||
# Download and extract the MQ unzippable server
|
# Download and extract the MQ unzippable server
|
||||||
DIR_TMP=/tmp/mq
|
DIR_TMP=/tmp/mq
|
||||||
mkdir -p ${DIR_TMP}
|
mkdir -p ${DIR_TMP}
|
||||||
cd ${DIR_TMP}
|
cd ${DIR_TMP}
|
||||||
curl -LO $MQ_URL
|
curl --fail --location $MQ_URL | tar --extract --gunzip
|
||||||
|
|
||||||
tar -xzf ./*.tar.gz
|
|
||||||
rm -f ./*.tar.gz
|
|
||||||
ls -la ${DIR_TMP}
|
ls -la ${DIR_TMP}
|
||||||
|
|
||||||
# Generate MQ package in INSTALLATION_DIR
|
# Generate MQ package in INSTALLATION_DIR
|
||||||
@@ -53,7 +47,7 @@ export genmqpkg_incmqxr=0
|
|||||||
export genmqpkg_incnls=1
|
export genmqpkg_incnls=1
|
||||||
export genmqpkg_incras=1
|
export genmqpkg_incras=1
|
||||||
export genmqpkg_incsamp=1
|
export genmqpkg_incsamp=1
|
||||||
export genmqpkg_incsdk=$INSTALL_SDK
|
export genmqpkg_incsdk=0
|
||||||
export genmqpkg_inctls=1
|
export genmqpkg_inctls=1
|
||||||
export genmqpkg_incunthrd=0
|
export genmqpkg_incunthrd=0
|
||||||
export genmqpkg_incweb=1
|
export genmqpkg_incweb=1
|
||||||
@@ -97,8 +91,8 @@ $RPM && PAM_FILE=/etc/pam.d/password-auth
|
|||||||
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/' $PAM_FILE
|
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/' $PAM_FILE
|
||||||
|
|
||||||
# List all the installed packages, for the build log
|
# List all the installed packages, for the build log
|
||||||
$RPM && rpm -q --all || true
|
$RPM && (rpm -q --all | sort) || true
|
||||||
$UBUNTU && dpkg --list || true
|
$UBUNTU && (dpkg --list | sort) || true
|
||||||
|
|
||||||
#Update the license file to include UBI 8 instead of UBI 7
|
#Update the license file to include UBI 8 instead of UBI 7
|
||||||
sed -i 's/v7.0/v8.0/g' /opt/mqm/licenses/non_ibm_license.txt
|
sed -i 's/v7.0/v8.0/g' /opt/mqm/licenses/non_ibm_license.txt
|
||||||
|
|||||||
@@ -36,12 +36,15 @@ func CopyFileMode(src, dest string, perm os.FileMode) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open %s for copy: %v", src, err)
|
return fmt.Errorf("failed to open %s for copy: %v", src, err)
|
||||||
}
|
}
|
||||||
|
// #nosec G307 - local to this function, pose no harm.
|
||||||
defer in.Close()
|
defer in.Close()
|
||||||
|
|
||||||
|
// #nosec G304 - this func creates based on the input filemode.
|
||||||
out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, perm)
|
out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open %s for copy: %v", dest, err)
|
return fmt.Errorf("failed to open %s for copy: %v", dest, err)
|
||||||
}
|
}
|
||||||
|
// #nosec G307 - local to this function, pose no harm.
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
|
|
||||||
_, err = io.Copy(out, in)
|
_, err = io.Copy(out, in)
|
||||||
|
|||||||
68
internal/ha/ha.go
Normal file
68
internal/ha/ha.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2020, 2021
|
||||||
|
|
||||||
|
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 ha contains code for high availability
|
||||||
|
package ha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/tls"
|
||||||
|
"github.com/ibm-messaging/mq-container/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigureNativeHA configures native high availability
|
||||||
|
func ConfigureNativeHA(log *logger.Logger) error {
|
||||||
|
|
||||||
|
file := "/etc/mqm/native-ha.ini"
|
||||||
|
templateFile := file + ".tpl"
|
||||||
|
|
||||||
|
templateMap := map[string]string{}
|
||||||
|
templateMap["Name"] = os.Getenv("HOSTNAME")
|
||||||
|
templateMap["NativeHAInstance0_Name"] = os.Getenv("MQ_NATIVE_HA_INSTANCE_0_NAME")
|
||||||
|
templateMap["NativeHAInstance1_Name"] = os.Getenv("MQ_NATIVE_HA_INSTANCE_1_NAME")
|
||||||
|
templateMap["NativeHAInstance2_Name"] = os.Getenv("MQ_NATIVE_HA_INSTANCE_2_NAME")
|
||||||
|
templateMap["NativeHAInstance0_ReplicationAddress"] = os.Getenv("MQ_NATIVE_HA_INSTANCE_0_REPLICATION_ADDRESS")
|
||||||
|
templateMap["NativeHAInstance1_ReplicationAddress"] = os.Getenv("MQ_NATIVE_HA_INSTANCE_1_REPLICATION_ADDRESS")
|
||||||
|
templateMap["NativeHAInstance2_ReplicationAddress"] = os.Getenv("MQ_NATIVE_HA_INSTANCE_2_REPLICATION_ADDRESS")
|
||||||
|
|
||||||
|
if os.Getenv("MQ_NATIVE_HA_TLS") == "true" {
|
||||||
|
keyLabel, _, _, err := tls.ConfigureHATLSKeystore()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
templateMap["CertificateLabel"] = keyLabel
|
||||||
|
|
||||||
|
keyRepository, ok := os.LookupEnv("MQ_NATIVE_HA_KEY_REPOSITORY")
|
||||||
|
if !ok {
|
||||||
|
keyRepository = "/run/runmqserver/ha/tls/key"
|
||||||
|
}
|
||||||
|
templateMap["KeyRepository"] = keyRepository
|
||||||
|
|
||||||
|
cipherSpec, ok := os.LookupEnv("MQ_NATIVE_HA_CIPHERSPEC")
|
||||||
|
if ok {
|
||||||
|
templateMap["CipherSpec"] = cipherSpec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mqtemplate.ProcessTemplateFile(templateFile, file, templateMap, log)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2020
|
© Copyright IBM Corporation 2020, 2021
|
||||||
|
|
||||||
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.
|
||||||
@@ -108,46 +108,6 @@ func (htpfile mapHtPasswd) updateHtPasswordFile(isTest bool) error {
|
|||||||
if isTest {
|
if isTest {
|
||||||
file = "my.htpasswd"
|
file = "my.htpasswd"
|
||||||
}
|
}
|
||||||
|
// #nosec G306 - its a read by owner/s group, and pose no harm.
|
||||||
return ioutil.WriteFile(file, htpfile.GetBytes(), 0660)
|
return ioutil.WriteFile(file, htpfile.GetBytes(), 0660)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthenticateUser verifies if the given user password match with htpasswrd
|
|
||||||
func AuthenticateUser(user string, password string, isTest bool) (bool, bool, error) {
|
|
||||||
passwords := mapHtPasswd(map[string]string{})
|
|
||||||
|
|
||||||
if len(strings.TrimSpace(user)) == 0 || len(strings.TrimSpace(password)) == 0 {
|
|
||||||
return false, false, fmt.Errorf("UserId or Password are empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := passwords.ReadHtPasswordFile(isTest)
|
|
||||||
if err != nil {
|
|
||||||
return false, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := false
|
|
||||||
value, found := passwords[user]
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return found, ok, fmt.Errorf("User not found in the mq.htpasswd file")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(value), []byte(password))
|
|
||||||
return found, err == nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateUser validates the given user
|
|
||||||
func ValidateUser(user string, isTest bool) (bool, error) {
|
|
||||||
passwords := mapHtPasswd(map[string]string{})
|
|
||||||
|
|
||||||
if len(strings.TrimSpace(user)) == 0 {
|
|
||||||
return false, fmt.Errorf("Userid is empty for AuthenticateUser")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := passwords.ReadHtPasswordFile(isTest)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, found := passwords[strings.TrimSpace(user)]
|
|
||||||
return found, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
© Copyright IBM Corporation 2020
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
package htpasswd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestCheckUser verifies Htpassword's use
|
|
||||||
func TestCheckUser(t *testing.T) {
|
|
||||||
err := SetPassword("guest", "guestpw", true)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("htpassword test failed due to error:%s\n", err.Error())
|
|
||||||
}
|
|
||||||
found, ok, err := AuthenticateUser("guest", "guestpw", true)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("htpassword test1 failed as user could not be found:%s\n", err.Error())
|
|
||||||
}
|
|
||||||
if found == false || ok == false {
|
|
||||||
t.Fatalf("htpassword test1 failed as user could not be found:%v, ok:%v\n", found, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
found, ok, err = AuthenticateUser("myguest", "guestpw", true)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("htpassword test2 failed as no error received for non-existing user\n")
|
|
||||||
}
|
|
||||||
if found == true || ok == true {
|
|
||||||
t.Fatalf("htpassword test2 failed for non-existing user found :%v, ok:%v\n", found, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
found, ok, err = AuthenticateUser("guest", "guest", true)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("htpassword test3 failed as incorrect password of user did not return error\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if found == false || ok == true {
|
|
||||||
t.Fatalf("htpassword test3 failed for existing user with incorrect passwored found :%v, ok:%v\n", found, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
found, err = ValidateUser("guest", true)
|
|
||||||
if err != nil || found == false {
|
|
||||||
t.Fatalf("htpassword test4 failed as user could not be found:%v, ok:%v\n", found, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
found, err = ValidateUser("myguest", true)
|
|
||||||
if err != nil || found == true {
|
|
||||||
t.Fatalf("htpassword test5 failed as non-existing user returned to be found:%v, ok:%v\n", found, ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
guest:$2y$05$ifFP0nCmFed6.m4iB9CHRuHFps2YeeuwopmOvszWt0GRnN59p8qxW
|
|
||||||
@@ -23,9 +23,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/pkg/logger"
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/ready"
|
"github.com/ibm-messaging/mq-container/internal/ready"
|
||||||
|
"github.com/ibm-messaging/mq-container/pkg/logger"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -34,6 +35,8 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
metricsEnabled = false
|
metricsEnabled = false
|
||||||
|
// #nosec G112 - this needs investigation to find reasonable timeout.
|
||||||
|
// git-issue 233 to cover this..
|
||||||
metricsServer = &http.Server{Addr: ":" + defaultPort}
|
metricsServer = &http.Server{Addr: ":" + defaultPort}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -83,7 +86,7 @@ func startMetricsGathering(qmName string, log *logger.Logger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup HTTP server to handle requests from Prometheus
|
// Setup HTTP server to handle requests from Prometheus
|
||||||
http.Handle("/metrics", prometheus.Handler())
|
http.Handle("/metrics", promhttp.Handler())
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
// #nosec G104
|
// #nosec G104
|
||||||
|
|||||||
@@ -48,8 +48,10 @@ func ProcessTemplateFile(templateFile, destFile string, data interface{}, log *l
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #nosec G302
|
|
||||||
|
// #nosec G302 G304 G306 - its a read by owner/s group, and pose no harm.
|
||||||
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
|
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
|
||||||
|
// #nosec G307 - local to this function, pose no harm.
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
err = t.Execute(f, data)
|
err = t.Execute(f, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
97
internal/mqversion/mqversion.go
Normal file
97
internal/mqversion/mqversion.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2020
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mqversion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get will return the current MQ version
|
||||||
|
func Get() (string, error) {
|
||||||
|
mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Error Getting MQ version: %v", err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(mqVersion), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare returns an integer comparing two MQ version strings lexicographically. The result will be 0 if currentVersion==checkVersion, -1 if currentVersion < checkVersion, and +1 if currentVersion > checkVersion
|
||||||
|
func Compare(checkVersion string) (int, error) {
|
||||||
|
currentVersion, err := Get()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
currentVRMF, err := parseVRMF(currentVersion)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
compareVRMF, err := parseVRMF(checkVersion)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse compare version: %w", err)
|
||||||
|
}
|
||||||
|
return currentVRMF.compare(*compareVRMF), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type vrmf [4]int
|
||||||
|
|
||||||
|
func (v vrmf) String() string {
|
||||||
|
return fmt.Sprintf("%d.%d.%d.%d", v[0], v[1], v[2], v[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v vrmf) compare(to vrmf) int {
|
||||||
|
for idx := 0; idx < 4; idx++ {
|
||||||
|
if v[idx] < to[idx] {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if v[idx] > to[idx] {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseVRMF(vrmfString string) (*vrmf, error) {
|
||||||
|
versionParts := strings.Split(vrmfString, ".")
|
||||||
|
if len(versionParts) != 4 {
|
||||||
|
return nil, fmt.Errorf("incorrect number of parts to version string: expected 4, got %d", len(versionParts))
|
||||||
|
}
|
||||||
|
vmrfPartNames := []string{"version", "release", "minor", "fix"}
|
||||||
|
parsed := vrmf{}
|
||||||
|
for idx, value := range versionParts {
|
||||||
|
partName := vmrfPartNames[idx]
|
||||||
|
if value == "" {
|
||||||
|
return nil, fmt.Errorf("empty %s found in VRMF", partName)
|
||||||
|
}
|
||||||
|
val, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("non-numeric %s found in VRMF", partName)
|
||||||
|
}
|
||||||
|
if val < 0 {
|
||||||
|
return nil, fmt.Errorf("negative %s found in VRMF", partName)
|
||||||
|
}
|
||||||
|
if idx == 0 && val == 0 {
|
||||||
|
return nil, fmt.Errorf("zero value for version not allowed")
|
||||||
|
}
|
||||||
|
parsed[idx] = val
|
||||||
|
}
|
||||||
|
return &parsed, nil
|
||||||
|
}
|
||||||
147
internal/mqversion/mqversion_test.go
Normal file
147
internal/mqversion/mqversion_test.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2020
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mqversion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompareLower(t *testing.T) {
|
||||||
|
checkVersion := "99.99.99.99"
|
||||||
|
mqVersionCheck, err := Compare(checkVersion)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to compare MQ versions: %v", err)
|
||||||
|
}
|
||||||
|
if mqVersionCheck != -1 {
|
||||||
|
t.Errorf("MQ version compare result failed. Expected -1, Got %v", mqVersionCheck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareHigher(t *testing.T) {
|
||||||
|
checkVersion := "1.1.1.1"
|
||||||
|
mqVersionCheck, err := Compare(checkVersion)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to compare MQ versions: %v", err)
|
||||||
|
}
|
||||||
|
if mqVersionCheck != 1 {
|
||||||
|
t.Errorf("MQ version compare result failed. Expected 1, Got %v", mqVersionCheck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareEqual(t *testing.T) {
|
||||||
|
checkVersion, err := Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get current MQ version: %v", err)
|
||||||
|
}
|
||||||
|
mqVersionCheck, err := Compare(checkVersion)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to compare MQ versions: %v", err)
|
||||||
|
}
|
||||||
|
if mqVersionCheck != 0 {
|
||||||
|
t.Errorf("MQ version compare result failed. Expected 0, Got %v", mqVersionCheck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionValid(t *testing.T) {
|
||||||
|
checkVersion, err := Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get current MQ version: %v", err)
|
||||||
|
}
|
||||||
|
_, err = parseVRMF(checkVersion)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Validation of MQ version failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidVRMF(t *testing.T) {
|
||||||
|
validVRMFs := map[string]vrmf{
|
||||||
|
"1.0.0.0": {1, 0, 0, 0},
|
||||||
|
"10.0.0.0": {10, 0, 0, 0},
|
||||||
|
"1.10.0.0": {1, 10, 0, 0},
|
||||||
|
"1.0.10.0": {1, 0, 10, 0},
|
||||||
|
"1.0.0.10": {1, 0, 0, 10},
|
||||||
|
"999.998.997.996": {999, 998, 997, 996},
|
||||||
|
}
|
||||||
|
for test, expect := range validVRMFs {
|
||||||
|
t.Run(test, func(t *testing.T) {
|
||||||
|
parsed, err := parseVRMF(test)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpectedly failed to parse VRMF '%s': %s", test, err.Error())
|
||||||
|
}
|
||||||
|
if *parsed != expect {
|
||||||
|
t.Fatalf("VRMF not parsed as expected. Expected '%v', got '%v'", parsed, expect)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidVRMF(t *testing.T) {
|
||||||
|
invalidVRMFs := []string{
|
||||||
|
"not-a-number",
|
||||||
|
"9.8.7.string",
|
||||||
|
"0.1.2.3",
|
||||||
|
"1.0.0.-10",
|
||||||
|
}
|
||||||
|
for _, test := range invalidVRMFs {
|
||||||
|
t.Run(test, func(t *testing.T) {
|
||||||
|
parsed, err := parseVRMF(test)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expected error when parsing VRMF '%s', but got none. VRMF returned: %v", test, parsed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompare(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
current string
|
||||||
|
compare string
|
||||||
|
expect int
|
||||||
|
}{
|
||||||
|
{"1.0.0.1", "1.0.0.1", 0},
|
||||||
|
{"1.0.0.1", "1.0.0.0", 1},
|
||||||
|
{"1.0.0.1", "1.0.0.2", -1},
|
||||||
|
{"9.9.9.9", "10.0.0.0", -1},
|
||||||
|
{"9.9.9.9", "9.10.0.0", -1},
|
||||||
|
{"9.9.9.9", "9.9.10.0", -1},
|
||||||
|
{"9.9.9.9", "9.9.9.10", -1},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(fmt.Sprintf("%s-%s", test.current, test.compare), func(t *testing.T) {
|
||||||
|
baseVRMF, err := parseVRMF(test.current)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not parse base version '%s': %s", test.current, err.Error())
|
||||||
|
}
|
||||||
|
compareVRMF, err := parseVRMF(test.compare)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not parse current version '%s': %s", test.current, err.Error())
|
||||||
|
}
|
||||||
|
result := baseVRMF.compare(*compareVRMF)
|
||||||
|
if result != test.expect {
|
||||||
|
t.Fatalf("Expected %d but got %d when comparing '%s' with '%s'", test.expect, result, test.current, test.compare)
|
||||||
|
}
|
||||||
|
if test.expect == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resultReversed := compareVRMF.compare(*baseVRMF)
|
||||||
|
if resultReversed != test.expect*-1 {
|
||||||
|
t.Fatalf("Expected %d but got %d when comparing '%s' with '%s'", test.expect*-1, resultReversed, test.compare, test.current)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,299 +0,0 @@
|
|||||||
/*
|
|
||||||
© Copyright IBM Corporation 2020
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//This is a developer only configuration and not recommended for production usage.
|
|
||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo !windows CFLAGS: -I/opt/mqm/lib64 -D_REENTRANT
|
|
||||||
#cgo !windows,!darwin LDFLAGS: -L/opt/mqm/lib64 -lmqm_r -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64
|
|
||||||
#cgo darwin LDFLAGS: -L/opt/mqm/lib64 -lmqm_r -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64
|
|
||||||
#cgo windows CFLAGS: -I"C:/Program Files/IBM/MQ/Tools/c/include"
|
|
||||||
#cgo windows LDFLAGS: -L "C:/Program Files/IBM/MQ/bin64" -lmqm
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <cmqc.h>
|
|
||||||
#include <cmqxc.h>
|
|
||||||
#include <cmqzc.h>
|
|
||||||
#include <cmqec.h>
|
|
||||||
#include <time.h>
|
|
||||||
static MQZ_INIT_AUTHORITY PASStart;
|
|
||||||
static MQZ_AUTHENTICATE_USER OAAuthUser;
|
|
||||||
static MQZ_FREE_USER OAFreeUser;
|
|
||||||
static MQZ_TERM_AUTHORITY OATermAuth;
|
|
||||||
extern int Authenticate(char *, char *);
|
|
||||||
extern int CheckAuthority(char *);
|
|
||||||
static char *OAEnvStr(MQLONG);
|
|
||||||
static void FindSize();
|
|
||||||
static void PrintDateTime();
|
|
||||||
static FILE *fp = NULL;
|
|
||||||
static int primary_process = 0;
|
|
||||||
|
|
||||||
static void MQENTRY PASStart(
|
|
||||||
MQHCONFIG hc,
|
|
||||||
MQLONG Options,
|
|
||||||
MQCHAR48 QMgrName,
|
|
||||||
MQLONG ComponentDataLength,
|
|
||||||
PMQBYTE ComponentData,
|
|
||||||
PMQLONG Version,
|
|
||||||
PMQLONG pCompCode,
|
|
||||||
PMQLONG pReason) {
|
|
||||||
MQLONG CC = MQCC_OK;
|
|
||||||
MQLONG Reason = MQRC_NONE;
|
|
||||||
|
|
||||||
if ((Options & MQZIO_PRIMARY) == MQZIO_PRIMARY)
|
|
||||||
primary_process = 1;
|
|
||||||
|
|
||||||
fp=fopen("/var/mqm/errors/amqpasdev.log","a");
|
|
||||||
|
|
||||||
if (CC == MQCC_OK)
|
|
||||||
hc->MQZEP_Call(hc, MQZID_INIT_AUTHORITY,(PMQFUNC)PASStart,&CC,&Reason);
|
|
||||||
|
|
||||||
if (CC == MQCC_OK)
|
|
||||||
hc->MQZEP_Call(hc,MQZID_TERM_AUTHORITY,(PMQFUNC)OATermAuth,&CC,&Reason);
|
|
||||||
|
|
||||||
if (CC == MQCC_OK)
|
|
||||||
hc->MQZEP_Call(hc,MQZID_AUTHENTICATE_USER,(PMQFUNC)OAAuthUser,&CC,&Reason);
|
|
||||||
|
|
||||||
if (CC == MQCC_OK)
|
|
||||||
hc->MQZEP_Call(hc,MQZID_FREE_USER,(PMQFUNC)OAFreeUser,&CC,&Reason);
|
|
||||||
|
|
||||||
*Version = MQZAS_VERSION_5;
|
|
||||||
*pCompCode = CC;
|
|
||||||
*pReason = Reason;
|
|
||||||
|
|
||||||
PrintDateTime();
|
|
||||||
fprintf(fp, "Pluggable OAM Initialized.\n");
|
|
||||||
fprintf(fp, "THIS IS A DEVELOPER ONLY CONFIGURATION AND NOT RECOMMENDED FOR PRODUCTION USAGE");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *authuserfmt =
|
|
||||||
"\tUser : \"%12.12s\"\n"\
|
|
||||||
"\tEffUser : \"%12.12s\"\n"\
|
|
||||||
"\tAppName : \"%28.28s\"\n"\
|
|
||||||
"\tApIdDt : \"%32.32s\"\n"\
|
|
||||||
"\tEnv : \"%s\"\n"\
|
|
||||||
"\tApp Pid : %d\n"\
|
|
||||||
"\tApp Tid : %d\n"\
|
|
||||||
;
|
|
||||||
static void MQENTRY OAAuthUser (
|
|
||||||
PMQCHAR pQMgrName,
|
|
||||||
PMQCSP pSecurityParms,
|
|
||||||
PMQZAC pApplicationContext,
|
|
||||||
PMQZIC pIdentityContext,
|
|
||||||
PMQPTR pCorrelationPtr,
|
|
||||||
PMQBYTE pComponentData,
|
|
||||||
PMQLONG pContinuation,
|
|
||||||
PMQLONG pCompCode,
|
|
||||||
PMQLONG pReason)
|
|
||||||
{
|
|
||||||
char *spuser = NULL;
|
|
||||||
char *sppass = NULL;
|
|
||||||
int gorc = MQRC_NOT_AUTHORIZED;
|
|
||||||
|
|
||||||
if ((pSecurityParms->CSPUserIdLength) > 0) {
|
|
||||||
//Grab the user creds from csp.
|
|
||||||
spuser = malloc(pSecurityParms->CSPUserIdLength+1);
|
|
||||||
strncpy(spuser,pSecurityParms->CSPUserIdPtr,pSecurityParms->CSPUserIdLength);
|
|
||||||
spuser[pSecurityParms->CSPUserIdLength]=0;
|
|
||||||
sppass = malloc(pSecurityParms->CSPPasswordLength+1);
|
|
||||||
strncpy(sppass,pSecurityParms->CSPPasswordPtr,pSecurityParms->CSPPasswordLength);
|
|
||||||
sppass[pSecurityParms->CSPPasswordLength]=0;
|
|
||||||
gorc = Authenticate(spuser,sppass);
|
|
||||||
|
|
||||||
if (gorc == MQRC_NONE) {
|
|
||||||
*pCompCode = MQCC_OK;
|
|
||||||
*pReason = MQRC_NONE;
|
|
||||||
*pContinuation = MQZCI_CONTINUE;
|
|
||||||
memcpy( pIdentityContext->UserIdentifier
|
|
||||||
, spuser
|
|
||||||
, sizeof(pIdentityContext->UserIdentifier) );
|
|
||||||
} else {
|
|
||||||
*pCompCode = MQCC_WARNING;
|
|
||||||
*pReason = MQRC_NONE;
|
|
||||||
*pContinuation = MQZCI_CONTINUE;
|
|
||||||
//we print to error file only if error'd
|
|
||||||
PrintDateTime();
|
|
||||||
if (fp) {
|
|
||||||
fprintf(fp, authuserfmt,
|
|
||||||
pIdentityContext->UserIdentifier,
|
|
||||||
pApplicationContext->EffectiveUserID,
|
|
||||||
pApplicationContext->ApplName,
|
|
||||||
pIdentityContext->ApplIdentityData,
|
|
||||||
OAEnvStr(pApplicationContext->Environment),
|
|
||||||
pApplicationContext->ProcessId,
|
|
||||||
pApplicationContext->ThreadId);
|
|
||||||
|
|
||||||
fprintf(fp,"\tCSP UserId : %s\n", spuser);
|
|
||||||
fprintf(fp,"\tCSP Password : %s\n", "****..");
|
|
||||||
fprintf(fp,"\tPAS-Compcode:%d\n",*pCompCode);
|
|
||||||
fprintf(fp,"\tPAS-Reasoncode:%d\n",*pReason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(spuser);
|
|
||||||
free(sppass);
|
|
||||||
} else {
|
|
||||||
//this is only a normal UID authentication.
|
|
||||||
spuser = malloc(sizeof(PMQCHAR12));
|
|
||||||
strncpy(spuser,pApplicationContext->EffectiveUserID,strlen(pApplicationContext->EffectiveUserID));
|
|
||||||
spuser[sizeof(PMQCHAR12)]=0;
|
|
||||||
gorc = CheckAuthority(spuser);
|
|
||||||
if (gorc == MQRC_NONE){
|
|
||||||
*pCompCode = MQCC_OK;
|
|
||||||
*pReason = MQRC_NONE;
|
|
||||||
*pContinuation = MQZCI_CONTINUE;
|
|
||||||
memcpy( pIdentityContext->UserIdentifier
|
|
||||||
, spuser
|
|
||||||
, sizeof(pIdentityContext->UserIdentifier) );
|
|
||||||
} else {
|
|
||||||
*pCompCode = MQCC_WARNING;
|
|
||||||
*pReason = MQRC_NONE;
|
|
||||||
*pContinuation = MQZCI_CONTINUE;
|
|
||||||
//we print only if error'd
|
|
||||||
PrintDateTime();
|
|
||||||
if (fp)
|
|
||||||
{
|
|
||||||
fprintf(fp, authuserfmt,
|
|
||||||
pIdentityContext->UserIdentifier,
|
|
||||||
pApplicationContext->EffectiveUserID,
|
|
||||||
pApplicationContext->ApplName,
|
|
||||||
pIdentityContext->ApplIdentityData,
|
|
||||||
OAEnvStr(pApplicationContext->Environment),
|
|
||||||
pApplicationContext->ProcessId,
|
|
||||||
pApplicationContext->ThreadId
|
|
||||||
);
|
|
||||||
fprintf(fp,"\tUID : %s\n", spuser);
|
|
||||||
fprintf(fp,"\tPAS-Compcode:%d\n",*pCompCode);
|
|
||||||
fprintf(fp,"\tPAS-Reasoncode:%d\n",*pReason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MQENTRY OAFreeUser (
|
|
||||||
PMQCHAR pQMgrName,
|
|
||||||
PMQZFP pFreeParms,
|
|
||||||
PMQBYTE pComponentData,
|
|
||||||
PMQLONG pContinuation,
|
|
||||||
|
|
||||||
PMQLONG pCompCode,
|
|
||||||
PMQLONG pReason)
|
|
||||||
{
|
|
||||||
*pCompCode = MQCC_WARNING;
|
|
||||||
*pReason = MQRC_NONE;
|
|
||||||
*pContinuation = MQZCI_CONTINUE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MQENTRY OATermAuth(
|
|
||||||
MQHCONFIG hc,
|
|
||||||
MQLONG Options,
|
|
||||||
PMQCHAR pQMgrName,
|
|
||||||
PMQBYTE pComponentData,
|
|
||||||
PMQLONG pCompCode,
|
|
||||||
PMQLONG pReason)
|
|
||||||
{
|
|
||||||
if ((primary_process) && ((Options & MQZTO_PRIMARY) == MQZTO_PRIMARY) ||
|
|
||||||
((Options & MQZTO_SECONDARY) == MQZTO_SECONDARY))
|
|
||||||
{
|
|
||||||
if (fp)
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
fp = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*pCompCode = MQCC_OK;
|
|
||||||
*pReason = MQRC_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PrintDateTime() {
|
|
||||||
FindSize();
|
|
||||||
struct tm *local;
|
|
||||||
time_t t;
|
|
||||||
t = time(NULL);
|
|
||||||
local = localtime(&t);
|
|
||||||
if (fp) {
|
|
||||||
fprintf(fp, "-------------------------------------------------\n");
|
|
||||||
fprintf(fp, "Local time: %s", asctime(local));
|
|
||||||
local = gmtime(&t);
|
|
||||||
fprintf(fp, "UTC time: %s", asctime(local));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *OAEnvStr(MQLONG x)
|
|
||||||
{
|
|
||||||
switch (x)
|
|
||||||
{
|
|
||||||
case MQXE_OTHER: return "Application";
|
|
||||||
case MQXE_MCA: return "Channel";
|
|
||||||
case MQXE_MCA_SVRCONN: return "Channel SvrConn";
|
|
||||||
case MQXE_COMMAND_SERVER: return "Command Server";
|
|
||||||
case MQXE_MQSC: return "MQSC";
|
|
||||||
default: return "Invalid Environment";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FindSize()
|
|
||||||
{
|
|
||||||
int sz = 0;
|
|
||||||
int prev=ftell(fp);
|
|
||||||
fseek(fp, 0L, SEEK_END);
|
|
||||||
sz=ftell(fp);
|
|
||||||
//if log file size goes over 1mb, rewind it.
|
|
||||||
if (sz > 1000000) {
|
|
||||||
rewind(fp);
|
|
||||||
} else {
|
|
||||||
fseek(fp, prev, SEEK_SET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import "github.com/ibm-messaging/mq-container/internal/htpasswd"
|
|
||||||
|
|
||||||
//export MQStart
|
|
||||||
func MQStart(hc C.MQHCONFIG, Options C.MQLONG, QMgrName C.PMQCHAR, ComponentDataLength C.MQLONG, ComponentData C.PMQBYTE, Version C.PMQLONG, pCompCode C.PMQLONG, pReason C.PMQLONG) {
|
|
||||||
C.PASStart(hc, Options, QMgrName, ComponentDataLength, ComponentData, Version, pCompCode, pReason)
|
|
||||||
}
|
|
||||||
|
|
||||||
//export Authenticate
|
|
||||||
func Authenticate(x *C.char, y *C.char) C.int {
|
|
||||||
user := C.GoString(x)
|
|
||||||
pwd := C.GoString(y)
|
|
||||||
found, ok, err := htpasswd.AuthenticateUser(user, pwd, false)
|
|
||||||
|
|
||||||
if !found || !ok || err != nil {
|
|
||||||
return C.MQRC_UNKNOWN_OBJECT_NAME
|
|
||||||
}
|
|
||||||
return C.MQRC_NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
//export CheckAuthority
|
|
||||||
func CheckAuthority(x *C.char) C.int {
|
|
||||||
user := C.GoString(x)
|
|
||||||
found, err := htpasswd.ValidateUser(user, false)
|
|
||||||
if !found || err != nil {
|
|
||||||
return C.MQRC_UNKNOWN_OBJECT_NAME
|
|
||||||
}
|
|
||||||
return C.MQRC_NONE
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {}
|
|
||||||
@@ -53,6 +53,7 @@ func Clear() error {
|
|||||||
// Set lets any subsequent calls to `CheckReady` know that the queue
|
// Set lets any subsequent calls to `CheckReady` know that the queue
|
||||||
// manager has finished its configuration step
|
// manager has finished its configuration step
|
||||||
func Set() error {
|
func Set() error {
|
||||||
|
// #nosec G306 - this gives permissions to owner/s group only.
|
||||||
return ioutil.WriteFile(fileName, []byte("1"), 0770)
|
return ioutil.WriteFile(fileName, []byte("1"), 0770)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +77,11 @@ func IsRunningAsStandbyQM(name string) (bool, error) {
|
|||||||
return isRunningQM(name, "(RUNNING AS STANDBY)")
|
return isRunningQM(name, "(RUNNING AS STANDBY)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsRunningAsReplicaQM returns true if the queue manager is running in replica mode
|
||||||
|
func IsRunningAsReplicaQM(name string) (bool, error) {
|
||||||
|
return isRunningQM(name, "(REPLICA)")
|
||||||
|
}
|
||||||
|
|
||||||
func isRunningQM(name string, status string) (bool, error) {
|
func isRunningQM(name string, status string) (bool, error) {
|
||||||
out, _, err := command.Run("dspmq", "-n", "-m", name)
|
out, _, err := command.Run("dspmq", "-n", "-m", name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019
|
© Copyright IBM Corporation 2019, 2023
|
||||||
|
|
||||||
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,14 +43,20 @@ const cmsKeystoreName = "key.kdb"
|
|||||||
// p12TruststoreName is the name of the PKCS#12 Truststore
|
// p12TruststoreName is the name of the PKCS#12 Truststore
|
||||||
const p12TruststoreName = "trust.p12"
|
const p12TruststoreName = "trust.p12"
|
||||||
|
|
||||||
// keystoreDir is the location for the CMS Keystore & PKCS#12 Truststore
|
// keystoreDirDefault is the location for the default CMS Keystore & PKCS#12 Truststore
|
||||||
const keystoreDir = "/run/runmqserver/tls/"
|
const keystoreDirDefault = "/run/runmqserver/tls/"
|
||||||
|
|
||||||
// keyDir is the location of the keys to import
|
// keystoreDirHA is the location for the HA CMS Keystore
|
||||||
const keyDir = "/etc/mqm/pki/keys"
|
const keystoreDirHA = "/run/runmqserver/ha/tls/"
|
||||||
|
|
||||||
// trustDir is the location of the trust certificates to import
|
// keyDirDefault is the location of the default keys to import
|
||||||
const trustDir = "/etc/mqm/pki/trust"
|
const keyDirDefault = "/etc/mqm/pki/keys"
|
||||||
|
|
||||||
|
// keyDirHA is the location of the HA keys to import
|
||||||
|
const keyDirHA = "/etc/mqm/ha/pki/keys"
|
||||||
|
|
||||||
|
// trustDirDefault is the location of the trust certificates to import
|
||||||
|
const trustDirDefault = "/etc/mqm/pki/trust"
|
||||||
|
|
||||||
type KeyStoreData struct {
|
type KeyStoreData struct {
|
||||||
Keystore *keystore.KeyStore
|
Keystore *keystore.KeyStore
|
||||||
@@ -65,28 +71,43 @@ type P12KeyFiles struct {
|
|||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigureTLSKeystores configures the CMS Keystore & PKCS#12 Truststore
|
type TLSStore struct {
|
||||||
func ConfigureTLSKeystores() (string, KeyStoreData, KeyStoreData, error) {
|
Keystore KeyStoreData
|
||||||
|
Truststore KeyStoreData
|
||||||
|
}
|
||||||
|
|
||||||
// Create the CMS Keystore & PKCS#12 Truststore
|
func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool) (string, KeyStoreData, KeyStoreData, error) {
|
||||||
cmsKeystore, p12Truststore, err := generateAllKeystores()
|
|
||||||
|
// Create the CMS Keystore & PKCS#12 Truststore (if required)
|
||||||
|
tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", cmsKeystore, p12Truststore, err
|
return "", tlsStore.Keystore, tlsStore.Truststore, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process all keys - add them to the CMS KeyStore
|
// Process all keys - add them to the CMS KeyStore
|
||||||
keyLabel, err := processKeys(&cmsKeystore, &p12Truststore)
|
keyLabel, err := processKeys(&tlsStore, keystoreDir, keyDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", cmsKeystore, p12Truststore, err
|
return "", tlsStore.Keystore, tlsStore.Truststore, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process all trust certificates - add them to the CMS KeyStore & PKCS#12 Truststore
|
// Process all trust certificates - add them to the CMS KeyStore & PKCS#12 Truststore (if required)
|
||||||
err = processTrustCertificates(&cmsKeystore, &p12Truststore)
|
err = processTrustCertificates(&tlsStore, trustDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", cmsKeystore, p12Truststore, err
|
return "", tlsStore.Keystore, tlsStore.Truststore, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyLabel, cmsKeystore, p12Truststore, err
|
return keyLabel, tlsStore.Keystore, tlsStore.Truststore, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigureDefaultTLSKeystores configures the CMS Keystore & PKCS#12 Truststore
|
||||||
|
func ConfigureDefaultTLSKeystores() (string, KeyStoreData, KeyStoreData, error) {
|
||||||
|
return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigureHATLSKeystore configures the CMS Keystore & PKCS#12 Truststore
|
||||||
|
func ConfigureHATLSKeystore() (string, KeyStoreData, KeyStoreData, error) {
|
||||||
|
// *.crt files mounted to the HA TLS dir keyDirHA will be processed as trusted in the CMS keystore
|
||||||
|
return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigureTLS configures TLS for the queue manager
|
// ConfigureTLS configures TLS for the queue manager
|
||||||
@@ -137,8 +158,9 @@ func configureTLSDev(log *logger.Logger) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateAllKeystores creates the CMS Keystore & PKCS#12 Truststore
|
// generateAllKeystores creates the CMS Keystore & PKCS#12 Truststore (if required)
|
||||||
func generateAllKeystores() (KeyStoreData, KeyStoreData, error) {
|
func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool) (TLSStore, error) {
|
||||||
|
|
||||||
var cmsKeystore, p12Truststore KeyStoreData
|
var cmsKeystore, p12Truststore KeyStoreData
|
||||||
|
|
||||||
// Generate a pasword for use with both the CMS Keystore & PKCS#12 Truststore
|
// Generate a pasword for use with both the CMS Keystore & PKCS#12 Truststore
|
||||||
@@ -150,28 +172,30 @@ func generateAllKeystores() (KeyStoreData, KeyStoreData, error) {
|
|||||||
// #nosec G301 - write group permissions are required
|
// #nosec G301 - write group permissions are required
|
||||||
err := os.MkdirAll(keystoreDir, 0770)
|
err := os.MkdirAll(keystoreDir, 0770)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmsKeystore, p12Truststore, fmt.Errorf("Failed to create Keystore directory: %v", err)
|
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create Keystore directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the CMS Keystore
|
// Create the CMS Keystore
|
||||||
cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password)
|
cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password)
|
||||||
err = cmsKeystore.Keystore.Create()
|
err = cmsKeystore.Keystore.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmsKeystore, p12Truststore, fmt.Errorf("Failed to create CMS Keystore: %v", err)
|
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the PKCS#12 Truststore
|
// Create the PKCS#12 Truststore (if required)
|
||||||
p12Truststore.Keystore = keystore.NewPKCS12KeyStore(filepath.Join(keystoreDir, p12TruststoreName), p12Truststore.Password)
|
if p12TruststoreRequired {
|
||||||
err = p12Truststore.Keystore.Create()
|
p12Truststore.Keystore = keystore.NewPKCS12KeyStore(filepath.Join(keystoreDir, p12TruststoreName), p12Truststore.Password)
|
||||||
if err != nil {
|
err = p12Truststore.Keystore.Create()
|
||||||
return cmsKeystore, p12Truststore, fmt.Errorf("Failed to create PKCS#12 Truststore: %v", err)
|
if err != nil {
|
||||||
|
return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create PKCS#12 Truststore: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmsKeystore, p12Truststore, nil
|
return TLSStore{cmsKeystore, p12Truststore}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// processKeys processes all keys - adding them to the CMS KeyStore
|
// processKeys processes all keys - adding them to the CMS KeyStore
|
||||||
func processKeys(cmsKeystore, p12Truststore *KeyStoreData) (string, error) {
|
func processKeys(tlsStore *TLSStore, keystoreDir string, keyDir string) (string, error) {
|
||||||
|
|
||||||
// Key label - will be set to the label of the first set of keys
|
// Key label - will be set to the label of the first set of keys
|
||||||
keyLabel := ""
|
keyLabel := ""
|
||||||
@@ -190,7 +214,7 @@ func processKeys(cmsKeystore, p12Truststore *KeyStoreData) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process private key (*.key)
|
// Process private key (*.key)
|
||||||
privateKey, keyPrefix, err := processPrivateKey(keySet.Name(), keys)
|
privateKey, keyPrefix, err := processPrivateKey(keyDir, keySet.Name(), keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -201,29 +225,30 @@ func processKeys(cmsKeystore, p12Truststore *KeyStoreData) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process certificates (*.crt) - public certificate & optional CA certificate
|
// Process certificates (*.crt) - public certificate & optional CA certificate
|
||||||
publicCertificate, caCertificate, err := processCertificates(keySet.Name(), keyPrefix, keys, cmsKeystore, p12Truststore)
|
publicCertificate, caCertificate, err := processCertificates(keyDir, keySet.Name(), keyPrefix, keys, &tlsStore.Keystore, &tlsStore.Truststore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new PKCS#12 Keystore - containing private key, public certificate & optional CA certificate
|
// Create a new PKCS#12 Keystore - containing private key, public certificate & optional CA certificate
|
||||||
file, err := pkcs.Encode(rand.Reader, privateKey, publicCertificate, caCertificate, cmsKeystore.Password)
|
file, err := pkcs.Encode(rand.Reader, privateKey, publicCertificate, caCertificate, tlsStore.Keystore.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to encode PKCS#12 Keystore %s: %v", keySet.Name()+".p12", err)
|
return "", fmt.Errorf("Failed to encode PKCS#12 Keystore %s: %v", keySet.Name()+".p12", err)
|
||||||
}
|
}
|
||||||
|
// #nosec G306 - this gives permissions to owner/s group only.
|
||||||
err = ioutil.WriteFile(filepath.Join(keystoreDir, keySet.Name()+".p12"), file, 0644)
|
err = ioutil.WriteFile(filepath.Join(keystoreDir, keySet.Name()+".p12"), file, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to write PKCS#12 Keystore %s: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
|
return "", fmt.Errorf("Failed to write PKCS#12 Keystore %s: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import the new PKCS#12 Keystore into the CMS Keystore
|
// Import the new PKCS#12 Keystore into the CMS Keystore
|
||||||
err = cmsKeystore.Keystore.Import(filepath.Join(keystoreDir, keySet.Name()+".p12"), cmsKeystore.Password)
|
err = tlsStore.Keystore.Keystore.Import(filepath.Join(keystoreDir, keySet.Name()+".p12"), tlsStore.Keystore.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed tp import keys from %s into CMS Keystore: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
|
return "", fmt.Errorf("Failed to import keys from %s into CMS Keystore: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relabel the certificate in the CMS Keystore
|
// Relabel the certificate in the CMS Keystore
|
||||||
err = relabelCertificate(keySet.Name(), cmsKeystore)
|
err = relabelCertificate(keySet.Name(), &tlsStore.Keystore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -238,8 +263,8 @@ func processKeys(cmsKeystore, p12Truststore *KeyStoreData) (string, error) {
|
|||||||
return keyLabel, nil
|
return keyLabel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// processTrustCertificates processes all trust certificates - adding them to the CMS KeyStore & PKCS#12 Truststore
|
// processTrustCertificates processes all trust certificates - adding them to the CMS KeyStore & PKCS#12 Truststore (if required)
|
||||||
func processTrustCertificates(cmsKeystore, p12Truststore *KeyStoreData) error {
|
func processTrustCertificates(tlsStore *TLSStore, trustDir string) error {
|
||||||
|
|
||||||
// Process all trust certiifcates
|
// Process all trust certiifcates
|
||||||
trustList, err := ioutil.ReadDir(trustDir)
|
trustList, err := ioutil.ReadDir(trustDir)
|
||||||
@@ -265,15 +290,17 @@ func processTrustCertificates(cmsKeystore, p12Truststore *KeyStoreData) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add to known certificates for the CMS Keystore
|
// Add to known certificates for the CMS Keystore
|
||||||
err = addToKnownCertificates(block, cmsKeystore, true)
|
err = addToKnownCertificates(block, &tlsStore.Keystore, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to add to know certificates for CMS Keystore")
|
return fmt.Errorf("Failed to add to know certificates for CMS Keystore")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to known certificates for the PKCS#12 Truststore
|
if tlsStore.Truststore.Keystore != nil {
|
||||||
err = addToKnownCertificates(block, p12Truststore, true)
|
// Add to known certificates for the PKCS#12 Truststore
|
||||||
if err != nil {
|
err = addToKnownCertificates(block, &tlsStore.Truststore, true)
|
||||||
return fmt.Errorf("Failed to add to know certificates for PKCS#12 Truststore")
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to add to know certificates for PKCS#12 Truststore")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,17 +308,17 @@ func processTrustCertificates(cmsKeystore, p12Truststore *KeyStoreData) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all trust certificates to PKCS#12 Truststore
|
// Add all trust certificates to PKCS#12 Truststore (if required)
|
||||||
if len(p12Truststore.TrustedCerts) > 0 {
|
if tlsStore.Truststore.Keystore != nil && len(tlsStore.Truststore.TrustedCerts) > 0 {
|
||||||
err = addCertificatesToTruststore(p12Truststore)
|
err = addCertificatesToTruststore(&tlsStore.Truststore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all trust certificates to CMS Keystore
|
// Add all trust certificates to CMS Keystore
|
||||||
if len(cmsKeystore.TrustedCerts) > 0 {
|
if len(tlsStore.Keystore.TrustedCerts) > 0 {
|
||||||
err = addCertificatesToCMSKeystore(cmsKeystore)
|
err = addCertificatesToCMSKeystore(&tlsStore.Keystore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -301,7 +328,7 @@ func processTrustCertificates(cmsKeystore, p12Truststore *KeyStoreData) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// processPrivateKey processes the private key (*.key) from a set of keys
|
// processPrivateKey processes the private key (*.key) from a set of keys
|
||||||
func processPrivateKey(keySetName string, keys []os.FileInfo) (interface{}, string, error) {
|
func processPrivateKey(keyDir string, keySetName string, keys []os.FileInfo) (interface{}, string, error) {
|
||||||
|
|
||||||
var privateKey interface{}
|
var privateKey interface{}
|
||||||
keyPrefix := ""
|
keyPrefix := ""
|
||||||
@@ -336,7 +363,7 @@ func processPrivateKey(keySetName string, keys []os.FileInfo) (interface{}, stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// processCertificates processes the certificates (*.crt) from a set of keys
|
// processCertificates processes the certificates (*.crt) from a set of keys
|
||||||
func processCertificates(keySetName, keyPrefix string, keys []os.FileInfo, cmsKeystore, p12Truststore *KeyStoreData) (*x509.Certificate, []*x509.Certificate, error) {
|
func processCertificates(keyDir string, keySetName, keyPrefix string, keys []os.FileInfo, cmsKeystore, p12Truststore *KeyStoreData) (*x509.Certificate, []*x509.Certificate, error) {
|
||||||
|
|
||||||
var publicCertificate *x509.Certificate
|
var publicCertificate *x509.Certificate
|
||||||
var caCertificate []*x509.Certificate
|
var caCertificate []*x509.Certificate
|
||||||
@@ -384,10 +411,12 @@ func processCertificates(keySetName, keyPrefix string, keys []os.FileInfo, cmsKe
|
|||||||
return nil, nil, fmt.Errorf("Failed to add to know certificates for CMS Keystore")
|
return nil, nil, fmt.Errorf("Failed to add to know certificates for CMS Keystore")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to known certificates for the PKCS#12 Truststore
|
if p12Truststore.Keystore != nil {
|
||||||
err = addToKnownCertificates(block, p12Truststore, true)
|
// Add to known certificates for the PKCS#12 Truststore
|
||||||
if err != nil {
|
err = addToKnownCertificates(block, p12Truststore, true)
|
||||||
return nil, nil, fmt.Errorf("Failed to add to know certificates for PKCS#12 Truststore")
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Failed to add to know certificates for PKCS#12 Truststore")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
certificate, err := x509.ParseCertificate(block.Bytes)
|
certificate, err := x509.ParseCertificate(block.Bytes)
|
||||||
@@ -510,6 +539,7 @@ func generateRandomPassword() string {
|
|||||||
validcharArray := []byte(validChars)
|
validcharArray := []byte(validChars)
|
||||||
password := ""
|
password := ""
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
|
// #nosec G404 - this is only for internal keystore and using math/rand pose no harm.
|
||||||
password = password + string(validcharArray[pwr.Intn(len(validcharArray))])
|
password = password + string(validcharArray[pwr.Intn(len(validcharArray))])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,10 +584,13 @@ func getCertificateFingerprint(block *pem.Block) (string, error) {
|
|||||||
|
|
||||||
// writeCertificatesToFile writes a list of certificates to a file
|
// writeCertificatesToFile writes a list of certificates to a file
|
||||||
func writeCertificatesToFile(file string, certificates []*pem.Block) error {
|
func writeCertificatesToFile(file string, certificates []*pem.Block) error {
|
||||||
|
|
||||||
|
// #nosec G304 - this is a temporary pem file to write certs.
|
||||||
f, err := os.Create(file)
|
f, err := os.Create(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to create file %s: %v", file, err)
|
return fmt.Errorf("Failed to create file %s: %v", file, err)
|
||||||
}
|
}
|
||||||
|
// #nosec G307 - local to this function, pose no harm.
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
w := bufio.NewWriter(f)
|
w := bufio.NewWriter(f)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2019, 2020
|
© Copyright IBM Corporation 2019, 2021
|
||||||
|
|
||||||
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.
|
||||||
@@ -60,7 +60,7 @@ func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (strin
|
|||||||
if webKeystore == "" {
|
if webKeystore == "" {
|
||||||
webKeystore = webKeystoreDefault
|
webKeystore = webKeystoreDefault
|
||||||
}
|
}
|
||||||
webKeystoreFile := filepath.Join(keystoreDir, webKeystore)
|
webKeystoreFile := filepath.Join(keystoreDirDefault, webKeystore)
|
||||||
|
|
||||||
// Check if a new self-signed certificate should be generated
|
// Check if a new self-signed certificate should be generated
|
||||||
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
|
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2019
|
© Copyright IBM Corporation 2018, 2021
|
||||||
|
|
||||||
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.
|
||||||
@@ -117,14 +117,22 @@ func (l *Logger) log(level string, msg string) {
|
|||||||
// Debug logs a line as debug
|
// Debug logs a line as debug
|
||||||
func (l *Logger) Debug(args ...interface{}) {
|
func (l *Logger) Debug(args ...interface{}) {
|
||||||
if l.debug {
|
if l.debug {
|
||||||
l.log(debugLevel, fmt.Sprint(args...))
|
if l.json {
|
||||||
|
l.log(debugLevel, fmt.Sprint(args...))
|
||||||
|
} else {
|
||||||
|
l.log(debugLevel, "DEBUG: "+fmt.Sprint(args...))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf logs a line as debug using format specifiers
|
// Debugf logs a line as debug using format specifiers
|
||||||
func (l *Logger) Debugf(format string, args ...interface{}) {
|
func (l *Logger) Debugf(format string, args ...interface{}) {
|
||||||
if l.debug {
|
if l.debug {
|
||||||
l.log(debugLevel, fmt.Sprintf(format, args...))
|
if l.json {
|
||||||
|
l.log(debugLevel, fmt.Sprintf(format, args...))
|
||||||
|
} else {
|
||||||
|
l.log(debugLevel, fmt.Sprintf("DEBUG: "+format, args...))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
7
source-branch.env
Normal file
7
source-branch.env
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
###########################################################################################################################################################
|
||||||
|
|
||||||
|
# SOURCE_BRANCH is the repository branch name for this release stream.
|
||||||
|
# It should be updated when a new release fork is created but not for testing of personal builds or pre-fork updates.
|
||||||
|
SOURCE_BRANCH ?= v9.3.0.x
|
||||||
|
|
||||||
|
###########################################################################################################################################################
|
||||||
114
test/docker/Gopkg.lock
generated
114
test/docker/Gopkg.lock
generated
@@ -1,114 +0,0 @@
|
|||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
|
||||||
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/Azure/go-ansiterm"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"winterm"
|
|
||||||
]
|
|
||||||
revision = "d6e3b3328b783f23731bc4d058875b0371ff8109"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/Microsoft/go-winio"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
|
|
||||||
version = "v0.4.7"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/Sirupsen/logrus"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
|
||||||
version = "v1.0.5"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/docker/distribution"
|
|
||||||
packages = [
|
|
||||||
"digest",
|
|
||||||
"reference"
|
|
||||||
]
|
|
||||||
revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89"
|
|
||||||
version = "v2.6.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/docker/docker"
|
|
||||||
packages = [
|
|
||||||
"api/types",
|
|
||||||
"api/types/blkiodev",
|
|
||||||
"api/types/container",
|
|
||||||
"api/types/events",
|
|
||||||
"api/types/filters",
|
|
||||||
"api/types/mount",
|
|
||||||
"api/types/network",
|
|
||||||
"api/types/reference",
|
|
||||||
"api/types/registry",
|
|
||||||
"api/types/strslice",
|
|
||||||
"api/types/swarm",
|
|
||||||
"api/types/time",
|
|
||||||
"api/types/versions",
|
|
||||||
"api/types/volume",
|
|
||||||
"client",
|
|
||||||
"pkg/jsonlog",
|
|
||||||
"pkg/jsonmessage",
|
|
||||||
"pkg/stdcopy",
|
|
||||||
"pkg/term",
|
|
||||||
"pkg/term/windows",
|
|
||||||
"pkg/tlsconfig"
|
|
||||||
]
|
|
||||||
revision = "f5ec1e2936dcbe7b5001c2b817188b095c700c27"
|
|
||||||
version = "v17.03.2-ce"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/docker/go-connections"
|
|
||||||
packages = [
|
|
||||||
"nat",
|
|
||||||
"sockets",
|
|
||||||
"tlsconfig"
|
|
||||||
]
|
|
||||||
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
|
|
||||||
version = "v0.3.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/docker/go-units"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "0dadbb0345b35ec7ef35e228dabb8de89a65bf52"
|
|
||||||
version = "v0.3.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/pkg/errors"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
|
||||||
version = "v0.8.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/crypto"
|
|
||||||
packages = ["ssh/terminal"]
|
|
||||||
revision = "88942b9c40a4c9d203b82b3731787b672d6e809b"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/net"
|
|
||||||
packages = [
|
|
||||||
"context",
|
|
||||||
"context/ctxhttp",
|
|
||||||
"proxy"
|
|
||||||
]
|
|
||||||
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/sys"
|
|
||||||
packages = [
|
|
||||||
"unix",
|
|
||||||
"windows"
|
|
||||||
]
|
|
||||||
revision = "13d03a9a82fba647c21a0ef8fba44a795d0f0835"
|
|
||||||
|
|
||||||
[solve-meta]
|
|
||||||
analyzer-name = "dep"
|
|
||||||
analyzer-version = 1
|
|
||||||
inputs-digest = "c792836365447209421d5dc68a75fa77063408b8a6a2f9325b976581a0d60107"
|
|
||||||
solver-name = "gps-cdcl"
|
|
||||||
solver-version = 1
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2019
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
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,7 +34,7 @@ import (
|
|||||||
func TestDevGoldenPath(t *testing.T) {
|
func TestDevGoldenPath(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,7 @@ func TestDevGoldenPath(t *testing.T) {
|
|||||||
Env: []string{
|
Env: []string{
|
||||||
"LICENSE=accept",
|
"LICENSE=accept",
|
||||||
"MQ_QMGR_NAME=" + qm,
|
"MQ_QMGR_NAME=" + qm,
|
||||||
|
"DEBUG=true",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
||||||
@@ -68,7 +69,7 @@ func TestDevGoldenPath(t *testing.T) {
|
|||||||
func TestDevSecure(t *testing.T) {
|
func TestDevSecure(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -82,6 +83,8 @@ func TestDevSecure(t *testing.T) {
|
|||||||
"MQ_QMGR_NAME=" + qm,
|
"MQ_QMGR_NAME=" + qm,
|
||||||
"MQ_APP_PASSWORD=" + appPassword,
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
|
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
|
||||||
},
|
},
|
||||||
Image: imageName(),
|
Image: imageName(),
|
||||||
}
|
}
|
||||||
@@ -128,7 +131,7 @@ func TestDevSecure(t *testing.T) {
|
|||||||
func TestDevWebDisabled(t *testing.T) {
|
func TestDevWebDisabled(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -159,7 +162,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// +build mqdev
|
// +build mqdev
|
||||||
|
|
||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2019
|
© Copyright IBM Corporation 2018, 2021
|
||||||
|
|
||||||
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.
|
||||||
@@ -48,8 +48,9 @@ var insecureTLSConfig *tls.Config = &tls.Config{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
|
func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
|
||||||
|
t.Logf("%s Waiting for web server to be ready", time.Now().Format(time.RFC3339))
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(3 * time.Second),
|
Timeout: time.Duration(10 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
@@ -63,13 +64,13 @@ func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls
|
|||||||
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", defaultAdminPassword)
|
req.SetBasicAuth("admin", defaultAdminPassword)
|
||||||
resp, err := httpClient.Do(req.WithContext(ctx))
|
resp, err := httpClient.Do(req)
|
||||||
if err == nil && resp.StatusCode == http.StatusOK {
|
if err == nil && resp.StatusCode == http.StatusOK {
|
||||||
t.Log("MQ web server is ready")
|
t.Logf("%s MQ web server is ready", time.Now().Format(time.RFC3339))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
t.Fatal("Timed out waiting for web server to become ready")
|
t.Fatalf("%s Timed out waiting for web server to become ready", time.Now().Format(time.RFC3339))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2020
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
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.
|
||||||
@@ -38,7 +38,7 @@ import (
|
|||||||
func TestLicenseNotSet(t *testing.T) {
|
func TestLicenseNotSet(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ func TestLicenseNotSet(t *testing.T) {
|
|||||||
func TestLicenseView(t *testing.T) {
|
func TestLicenseView(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ func TestLicenseView(t *testing.T) {
|
|||||||
//Check that when the container is stopped that the command endmqm has option -tp and x
|
//Check that when the container is stopped that the command endmqm has option -tp and x
|
||||||
func TestEndMQMOpts(t *testing.T) {
|
func TestEndMQMOpts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ func TestGoldenPathNoMetrics(t *testing.T) {
|
|||||||
|
|
||||||
// Actual test function for TestGoldenPathNoMetrics & TestGoldenPathWithMetrics
|
// Actual test function for TestGoldenPathNoMetrics & TestGoldenPathWithMetrics
|
||||||
func goldenPath(t *testing.T, metric bool) {
|
func goldenPath(t *testing.T, metric bool) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ func goldenPath(t *testing.T, metric bool) {
|
|||||||
func TestSecurityVulnerabilities(t *testing.T) {
|
func TestSecurityVulnerabilities(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ func TestSecurityVulnerabilities(t *testing.T) {
|
|||||||
|
|
||||||
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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,7 @@ func TestWithVolumeNoMetrics(t *testing.T) {
|
|||||||
|
|
||||||
// Actual test function for TestWithVolumeNoMetrics & TestWithVolumeAndMetrics
|
// Actual test function for TestWithVolumeNoMetrics & TestWithVolumeAndMetrics
|
||||||
func withVolume(t *testing.T, metric bool) {
|
func withVolume(t *testing.T, metric bool) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -261,7 +261,7 @@ func withVolume(t *testing.T, metric bool) {
|
|||||||
|
|
||||||
// TestWithSplitVolumesLogsData starts a queue manager with separate log/data mounts
|
// TestWithSplitVolumesLogsData starts a queue manager with separate log/data mounts
|
||||||
func TestWithSplitVolumesLogsData(t *testing.T) {
|
func TestWithSplitVolumesLogsData(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ func TestWithSplitVolumesLogsData(t *testing.T) {
|
|||||||
|
|
||||||
// TestWithSplitVolumesLogsOnly starts a queue manager with a separate log mount
|
// TestWithSplitVolumesLogsOnly starts a queue manager with a separate log mount
|
||||||
func TestWithSplitVolumesLogsOnly(t *testing.T) {
|
func TestWithSplitVolumesLogsOnly(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -299,7 +299,7 @@ func TestWithSplitVolumesLogsOnly(t *testing.T) {
|
|||||||
|
|
||||||
// TestWithSplitVolumesDataOnly starts a queue manager with a separate data mount
|
// TestWithSplitVolumesDataOnly starts a queue manager with a separate data mount
|
||||||
func TestWithSplitVolumesDataOnly(t *testing.T) {
|
func TestWithSplitVolumesDataOnly(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ func TestWithSplitVolumesDataOnly(t *testing.T) {
|
|||||||
func TestNoVolumeWithRestart(t *testing.T) {
|
func TestNoVolumeWithRestart(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -340,7 +340,7 @@ func TestNoVolumeWithRestart(t *testing.T) {
|
|||||||
// where `runmqserver -i` is run to initialize the storage. Then the
|
// where `runmqserver -i` is run to initialize the storage. Then the
|
||||||
// container can be run as normal.
|
// container can be run as normal.
|
||||||
func TestVolumeRequiresRoot(t *testing.T) {
|
func TestVolumeRequiresRoot(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -403,7 +403,7 @@ func TestVolumeRequiresRoot(t *testing.T) {
|
|||||||
func TestCreateQueueManagerFail(t *testing.T) {
|
func TestCreateQueueManagerFail(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -436,7 +436,7 @@ func TestCreateQueueManagerFail(t *testing.T) {
|
|||||||
func TestStartQueueManagerFail(t *testing.T) {
|
func TestStartQueueManagerFail(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -472,7 +472,7 @@ func TestStartQueueManagerFail(t *testing.T) {
|
|||||||
func TestVolumeUnmount(t *testing.T) {
|
func TestVolumeUnmount(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -521,7 +521,7 @@ func TestVolumeUnmount(t *testing.T) {
|
|||||||
func TestZombies(t *testing.T) {
|
func TestZombies(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -558,7 +558,7 @@ func TestZombies(t *testing.T) {
|
|||||||
func TestMQSC(t *testing.T) {
|
func TestMQSC(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -605,7 +605,7 @@ func TestMQSC(t *testing.T) {
|
|||||||
func TestLargeMQSC(t *testing.T) {
|
func TestLargeMQSC(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -657,7 +657,7 @@ func TestLargeMQSC(t *testing.T) {
|
|||||||
func TestRedactValidMQSC(t *testing.T) {
|
func TestRedactValidMQSC(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -735,7 +735,7 @@ func TestRedactValidMQSC(t *testing.T) {
|
|||||||
func TestRedactInvalidMQSC(t *testing.T) {
|
func TestRedactInvalidMQSC(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -808,7 +808,7 @@ func TestRedactInvalidMQSC(t *testing.T) {
|
|||||||
// tries to start a container based on that image, and checks that container terminates
|
// tries to start a container based on that image, and checks that container terminates
|
||||||
func TestInvalidMQSC(t *testing.T) {
|
func TestInvalidMQSC(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -842,7 +842,7 @@ func TestInvalidMQSC(t *testing.T) {
|
|||||||
|
|
||||||
func TestSimpleMQIniMerge(t *testing.T) {
|
func TestSimpleMQIniMerge(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -880,7 +880,7 @@ func TestSimpleMQIniMerge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
func TestMultipleIniMerge(t *testing.T) {
|
func TestMultipleIniMerge(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -929,7 +929,7 @@ func TestMultipleIniMerge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) {
|
func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -991,7 +991,7 @@ func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) {
|
|||||||
RUN chmod 0660 /etc/mqm/test1.ini
|
RUN chmod 0660 /etc/mqm/test1.ini
|
||||||
USER 1001`, imageName())},
|
USER 1001`, imageName())},
|
||||||
{"test1.ini",
|
{"test1.ini",
|
||||||
"Log:\n LogFilePages=5000"},
|
"Log:\n LogBufferPages=128"},
|
||||||
}
|
}
|
||||||
|
|
||||||
secondImage := createImage(t, cli, filesSecondContainer)
|
secondImage := createImage(t, cli, filesSecondContainer)
|
||||||
@@ -1011,7 +1011,7 @@ func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) {
|
|||||||
waitForReady(t, cli, ctr2.ID)
|
waitForReady(t, cli, ctr2.ID)
|
||||||
|
|
||||||
_, test2 := execContainer(t, cli, ctr2.ID, "", []string{"bash", "-c", catIniFileCommand})
|
_, test2 := execContainer(t, cli, ctr2.ID, "", []string{"bash", "-c", catIniFileCommand})
|
||||||
changedStanza := strings.Contains(test2, "LogFilePages=5000")
|
changedStanza := strings.Contains(test2, "LogBufferPages=128")
|
||||||
//check if stanza that was merged in the first container doesnt exist in this one.
|
//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")
|
firstMergedStanza := strings.Contains(test2, "ApplicationTrace:\n ApplName=amqsact*\n Trace=OFF")
|
||||||
|
|
||||||
@@ -1027,7 +1027,7 @@ func TestMQIniMergeOnTheSameVolumeButTwoContainers(t *testing.T) {
|
|||||||
func TestReadiness(t *testing.T) {
|
func TestReadiness(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1087,9 +1087,10 @@ func TestReadiness(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorLogRotation(t *testing.T) {
|
func TestErrorLogRotation(t *testing.T) {
|
||||||
|
t.Skipf("Skipping %v until test defect fixed", t.Name())
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1179,7 +1180,7 @@ func TestJSONLogFormatNoMetrics(t *testing.T) {
|
|||||||
|
|
||||||
// Actual test function for TestJSONLogFormatWithMetrics & TestJSONLogFormatNoMetrics
|
// Actual test function for TestJSONLogFormatWithMetrics & TestJSONLogFormatNoMetrics
|
||||||
func jsonLogFormat(t *testing.T, metric bool) {
|
func jsonLogFormat(t *testing.T, metric bool) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1215,7 +1216,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1239,7 +1240,7 @@ func TestBadLogFormat(t *testing.T) {
|
|||||||
func TestMQJSONDisabled(t *testing.T) {
|
func TestMQJSONDisabled(t *testing.T) {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1267,7 +1268,7 @@ func TestCorrectLicense(t *testing.T) {
|
|||||||
t.Fatal("Required test environment variable 'EXPECTED_LICENSE' was not set.")
|
t.Fatal("Required test environment variable 'EXPECTED_LICENSE' was not set.")
|
||||||
}
|
}
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1292,7 +1293,7 @@ func TestCorrectLicense(t *testing.T) {
|
|||||||
func TestVersioning(t *testing.T) {
|
func TestVersioning(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1413,7 +1414,7 @@ func TestVersioning(t *testing.T) {
|
|||||||
func TestTraceStrmqm(t *testing.T) {
|
func TestTraceStrmqm(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1438,7 +1439,7 @@ func TestTraceStrmqm(t *testing.T) {
|
|||||||
// privileges enabled or disabled. Otherwise the same as the golden path tests.
|
// privileges enabled or disabled. Otherwise the same as the golden path tests.
|
||||||
func utilTestHealthCheck(t *testing.T, nonewpriv bool) {
|
func utilTestHealthCheck(t *testing.T, nonewpriv bool) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1474,3 +1475,44 @@ func TestHealthCheckWithNoNewPrivileges(t *testing.T) {
|
|||||||
func TestHealthCheckWithNewPrivileges(t *testing.T) {
|
func TestHealthCheckWithNewPrivileges(t *testing.T) {
|
||||||
utilTestHealthCheck(t, false)
|
utilTestHealthCheck(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utilTestStartedCheck is used by TestStartedCheck* to run a container with
|
||||||
|
// privileges enabled or disabled. Otherwise the same as the golden path tests.
|
||||||
|
func utilTestStartedCheck(t *testing.T, nonewpriv bool) {
|
||||||
|
t.Parallel()
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||||
|
}
|
||||||
|
hostConfig := getDefaultHostConfig(t, cli)
|
||||||
|
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("no-new-privileges:%v", nonewpriv))
|
||||||
|
id := runContainerWithHostConfig(t, cli, &containerConfig, hostConfig)
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
waitForReady(t, cli, id)
|
||||||
|
rc, out := execContainer(t, cli, id, "", []string{"chkmqstarted"})
|
||||||
|
t.Log(out)
|
||||||
|
if rc != 0 {
|
||||||
|
t.Errorf("Expected chkmqstarted to return with exit code 0; got \"%v\"", rc)
|
||||||
|
t.Logf("Output from chkmqstarted:\n%v", out)
|
||||||
|
}
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestStartedCheckWithNoNewPrivileges tests golden path start/stop plus
|
||||||
|
// chkmqstarted, when running in a container where no new privileges are
|
||||||
|
// allowed (i.e. setuid is disabled)
|
||||||
|
func TestStartedCheckWithNoNewPrivileges(t *testing.T) {
|
||||||
|
utilTestStartedCheck(t, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestStartedCheckWithNoNewPrivileges tests golden path start/stop plus
|
||||||
|
// chkmqstarted when running in a container where new privileges are
|
||||||
|
// allowed (i.e. setuid is allowed)
|
||||||
|
// See https://github.com/ibm-messaging/mq-container/issues/428
|
||||||
|
func TestStartedCheckWithNewPrivileges(t *testing.T) {
|
||||||
|
utilTestStartedCheck(t, false)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2020
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
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.
|
||||||
@@ -313,6 +313,31 @@ func runContainerWithHostConfig(t *testing.T, cli *client.Client, containerConfi
|
|||||||
return ctr.ID
|
return ctr.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
||||||
|
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
||||||
|
func runContainerWithAllConfig(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) string {
|
||||||
|
if containerName == "" {
|
||||||
|
containerName = t.Name()
|
||||||
|
}
|
||||||
|
if containerConfig.Image == "" {
|
||||||
|
containerConfig.Image = imageName()
|
||||||
|
}
|
||||||
|
// Always run as a random user, unless the test has specified otherwise
|
||||||
|
if containerConfig.User == "" {
|
||||||
|
containerConfig.User = generateRandomUID()
|
||||||
|
}
|
||||||
|
// if coverage
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
|
t.Logf("Running container (%s)", containerConfig.Image)
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkingConfig, containerName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
return ctr.ID
|
||||||
|
}
|
||||||
|
|
||||||
// runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
|
// 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
|
// If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
|
||||||
// environment variable.
|
// environment variable.
|
||||||
@@ -523,9 +548,14 @@ func getCoverageExitCode(t *testing.T, orig int64) int64 {
|
|||||||
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.Duration) int64 {
|
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout time.Duration) int64 {
|
||||||
c, cancel := context.WithTimeout(context.Background(), timeout)
|
c, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
rc, err := cli.ContainerWait(c, ID)
|
t.Logf("Waiting for container for %s", timeout)
|
||||||
if err != nil {
|
okC, errC := cli.ContainerWait(c, ID, container.WaitConditionNotRunning)
|
||||||
|
var rc int64
|
||||||
|
select {
|
||||||
|
case err := <-errC:
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
case ok := <-okC:
|
||||||
|
rc = ok.StatusCode
|
||||||
}
|
}
|
||||||
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,
|
||||||
@@ -554,7 +584,7 @@ func execContainer(t *testing.T, cli *client.Client, ID string, user string, cmd
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
hijack, err := cli.ContainerExecAttach(context.Background(), resp.ID, config)
|
hijack, err := cli.ContainerExecAttach(context.Background(), resp.ID, types.ExecStartCheck{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -622,6 +652,9 @@ func waitForReady(t *testing.T, cli *client.Client, ID string) {
|
|||||||
} else if rc == 10 {
|
} else if rc == 10 {
|
||||||
t.Log("MQ Readiness: Queue Manager Running as Standby")
|
t.Log("MQ Readiness: Queue Manager Running as Standby")
|
||||||
return
|
return
|
||||||
|
} else if rc == 20 {
|
||||||
|
t.Log("MQ Readiness: Queue Manager Running as Replica")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
t.Fatal("Timed out waiting for container to become ready")
|
t.Fatal("Timed out waiting for container to become ready")
|
||||||
@@ -658,7 +691,7 @@ func removeNetwork(t *testing.T, cli *client.Client, ID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createVolume(t *testing.T, cli *client.Client, name string) types.Volume {
|
func createVolume(t *testing.T, cli *client.Client, name string) types.Volume {
|
||||||
v, err := cli.VolumeCreate(context.Background(), volume.VolumesCreateBody{
|
v, err := cli.VolumeCreate(context.Background(), volume.VolumeCreateBody{
|
||||||
Driver: "local",
|
Driver: "local",
|
||||||
DriverOpts: map[string]string{},
|
DriverOpts: map[string]string{},
|
||||||
Labels: map[string]string{},
|
Labels: map[string]string{},
|
||||||
@@ -798,12 +831,23 @@ func copyFromContainer(t *testing.T, cli *client.Client, id string, file string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPort(t *testing.T, cli *client.Client, ID string, port int) string {
|
func getPort(t *testing.T, cli *client.Client, ID string, port int) string {
|
||||||
i, err := cli.ContainerInspect(context.Background(), ID)
|
var inspectInfo types.ContainerJSON
|
||||||
if err != nil {
|
var err error
|
||||||
t.Fatal(err)
|
for attemptsRemaining := 3; attemptsRemaining > 0; attemptsRemaining-- {
|
||||||
|
inspectInfo, err = cli.ContainerInspect(context.Background(), ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
portNat := nat.Port(fmt.Sprintf("%d/tcp", port))
|
||||||
|
if inspectInfo.NetworkSettings.Ports[portNat] == nil || len(inspectInfo.NetworkSettings.Ports[portNat]) == 0 {
|
||||||
|
t.Log("Container port not yet bound")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return inspectInfo.NetworkSettings.Ports[portNat][0].HostPort
|
||||||
}
|
}
|
||||||
portNat := nat.Port(fmt.Sprintf("%d/tcp", port))
|
t.Fatal("Failed to get port")
|
||||||
return i.NetworkSettings.Ports[portNat][0].HostPort
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func countLines(t *testing.T, r io.Reader) int {
|
func countLines(t *testing.T, r io.Reader) int {
|
||||||
@@ -836,3 +880,12 @@ func countTarLines(t *testing.T, b []byte) int {
|
|||||||
}
|
}
|
||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMQVersion(t *testing.T, cli *client.Client) (string, error) {
|
||||||
|
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
version := inspect.ContainerConfig.Labels["version"]
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
|||||||
40
test/docker/go.mod
Normal file
40
test/docker/go.mod
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
module github.com/ibm-messaging/mq-container/test/docker
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
// Note: This is not actually Docker v17.12!
|
||||||
|
// Go modules require the use of semver, but Docker does not use semver and has not
|
||||||
|
// [opted-in to use Go modules](https://github.com/golang/go/wiki/Modules#can-a-module-consume-a-package-that-has-not-opted-in-to-modules)
|
||||||
|
// This means that when you `go get` Docker, you need to do so based on a commit,
|
||||||
|
// e.g. `go get -v github.com/docker/docker@420b1d36250f9cfdc561f086f25a213ecb669b6f`,
|
||||||
|
// which uses the commit for [Docker v19.03.15](https://github.com/moby/moby/releases/tag/v19.03.15)
|
||||||
|
// Go will then find the latest tag with a semver-compatible tag. In Docker's case,
|
||||||
|
// v17.12.0 is valid semver, but v18.09 and v19.03 are not.
|
||||||
|
// Also note: Docker v20.10 is valid semver, but the v20.10 client API requires use of Docker API
|
||||||
|
// version 1.41 on the server, which is currently too new for the version of Docker in Travis (Ubuntu Bionic)
|
||||||
|
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible
|
||||||
|
github.com/docker/go-connections v0.4.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
|
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||||
|
github.com/containerd/containerd v1.6.3 // indirect
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||||
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||||
|
google.golang.org/grpc v1.46.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
gotest.tools v2.2.0+incompatible // indirect
|
||||||
|
)
|
||||||
199
test/docker/go.sum
Normal file
199
test/docker/go.sum
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
||||||
|
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/containerd/containerd v1.6.3 h1:JfgUEIAH07xDWk6kqz0P3ArZt+KJ9YeihSC9uyFtSKg=
|
||||||
|
github.com/containerd/containerd v1.6.3/go.mod h1:gCVGrYRYFm2E8GmuUIbj/NGD7DLZQLzSJQazjVKDOig=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
|
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible h1:nhVo1udYfMj0Jsw0lnqrTjjf33aLpdgW9Wve9fHVzhQ=
|
||||||
|
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
|
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||||
|
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
|
||||||
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||||
|
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
||||||
|
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
|
||||||
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
|
google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
|
||||||
|
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||||
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
@@ -32,7 +32,8 @@ var miEnv = []string{
|
|||||||
// TestMultiInstanceStartStop creates 2 containers in a multi instance queue manager configuration
|
// TestMultiInstanceStartStop creates 2 containers in a multi instance queue manager configuration
|
||||||
// and starts/stop them checking we always have an active and standby
|
// and starts/stop them checking we always have an active and standby
|
||||||
func TestMultiInstanceStartStop(t *testing.T) {
|
func TestMultiInstanceStartStop(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
t.Skipf("Skipping %v until test defect fixed", t.Name())
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -74,7 +75,7 @@ func TestMultiInstanceStartStop(t *testing.T) {
|
|||||||
// TestMultiInstanceContainerStop starts 2 containers in a multi instance queue manager configuration,
|
// TestMultiInstanceContainerStop starts 2 containers in a multi instance queue manager configuration,
|
||||||
// stops the active queue manager, then checks to ensure the backup queue manager becomes active
|
// stops the active queue manager, then checks to ensure the backup queue manager becomes active
|
||||||
func TestMultiInstanceContainerStop(t *testing.T) {
|
func TestMultiInstanceContainerStop(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -108,7 +109,7 @@ func TestMultiInstanceContainerStop(t *testing.T) {
|
|||||||
func TestMultiInstanceRace(t *testing.T) {
|
func TestMultiInstanceRace(t *testing.T) {
|
||||||
t.Skipf("Skipping %v until file lock is implemented", t.Name())
|
t.Skipf("Skipping %v until file lock is implemented", t.Name())
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -154,7 +155,7 @@ func TestMultiInstanceRace(t *testing.T) {
|
|||||||
// mounts, then checks to ensure that the container terminates with the expected message
|
// mounts, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -173,7 +174,7 @@ func TestMultiInstanceNoSharedMounts(t *testing.T) {
|
|||||||
// TestMultiInstanceNoSharedLogs starts 2 multi instance queue managers without providing a shared log
|
// TestMultiInstanceNoSharedLogs starts 2 multi instance queue managers without providing a shared log
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -195,7 +196,7 @@ func TestMultiInstanceNoSharedLogs(t *testing.T) {
|
|||||||
// TestMultiInstanceNoSharedData starts 2 multi instance queue managers without providing a shared data
|
// TestMultiInstanceNoSharedData starts 2 multi instance queue managers without providing a shared data
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoSharedData(t *testing.T) {
|
func TestMultiInstanceNoSharedData(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -217,7 +218,7 @@ func TestMultiInstanceNoSharedData(t *testing.T) {
|
|||||||
// TestMultiInstanceNoMounts starts 2 multi instance queue managers without providing a shared data
|
// TestMultiInstanceNoMounts starts 2 multi instance queue managers without providing a shared data
|
||||||
// mount, then checks to ensure that the container terminates with the expected message
|
// mount, then checks to ensure that the container terminates with the expected message
|
||||||
func TestMultiInstanceNoMounts(t *testing.T) {
|
func TestMultiInstanceNoMounts(t *testing.T) {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
219
test/docker/mq_native_ha_test.go
Normal file
219
test/docker/mq_native_ha_test.go
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021, 2022
|
||||||
|
|
||||||
|
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 (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestNativeHABasic creates 3 containers in a Native HA queue manager configuration
|
||||||
|
// and ensures the queue manger and replicas start as expected
|
||||||
|
func TestNativeHABasic(t *testing.T) {
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := getMQVersion(t, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if version < "9.2.2.0" {
|
||||||
|
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
|
qmReplicaIDs := [3]string{}
|
||||||
|
qmVolumes := []string{}
|
||||||
|
qmNetwork, err := createBridgeNetwork(cli, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
||||||
|
|
||||||
|
for i := 0; i <= 2; i++ {
|
||||||
|
vol := createVolume(t, cli, containerNames[i])
|
||||||
|
defer removeVolume(t, cli, vol.Name)
|
||||||
|
qmVolumes = append(qmVolumes, vol.Name)
|
||||||
|
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
|
hostConfig := getHostConfig(t, 1, "", "", vol.Name)
|
||||||
|
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
||||||
|
|
||||||
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
|
defer cleanContainer(t, cli, ctr)
|
||||||
|
qmReplicaIDs[i] = ctr
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForReadyHA(t, cli, qmReplicaIDs)
|
||||||
|
|
||||||
|
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNativeHAFailover creates 3 containers in a Native HA queue manager configuration,
|
||||||
|
// stops the active queue manager, checks a replica becomes active, and ensures the stopped
|
||||||
|
// queue manager comes back as a replica
|
||||||
|
func TestNativeHAFailover(t *testing.T) {
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := getMQVersion(t, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if version < "9.2.2.0" {
|
||||||
|
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
|
qmReplicaIDs := [3]string{}
|
||||||
|
qmVolumes := []string{}
|
||||||
|
qmNetwork, err := createBridgeNetwork(cli, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
||||||
|
|
||||||
|
for i := 0; i <= 2; i++ {
|
||||||
|
vol := createVolume(t, cli, containerNames[i])
|
||||||
|
defer removeVolume(t, cli, vol.Name)
|
||||||
|
qmVolumes = append(qmVolumes, vol.Name)
|
||||||
|
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
|
hostConfig := getHostConfig(t, 1, "", "", vol.Name)
|
||||||
|
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
||||||
|
|
||||||
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
|
defer cleanContainer(t, cli, ctr)
|
||||||
|
qmReplicaIDs[i] = ctr
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForReadyHA(t, cli, qmReplicaIDs)
|
||||||
|
|
||||||
|
haStatus, err := getActiveReplicaInstances(t, cli, qmReplicaIDs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stopContainer(t, cli, haStatus.Active)
|
||||||
|
waitForFailoverHA(t, cli, haStatus.Replica)
|
||||||
|
startContainer(t, cli, haStatus.Active)
|
||||||
|
waitForReady(t, cli, haStatus.Active)
|
||||||
|
|
||||||
|
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
|
||||||
|
// with HA TLS enabled, and ensures the queue manger and replicas start as expected
|
||||||
|
func TestNativeHASecure(t *testing.T) {
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := getMQVersion(t, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if version < "9.2.2.0" {
|
||||||
|
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
|
qmReplicaIDs := [3]string{}
|
||||||
|
qmNetwork, err := createBridgeNetwork(cli, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
||||||
|
|
||||||
|
for i := 0; i <= 2; i++ {
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true")
|
||||||
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
|
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
||||||
|
|
||||||
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
|
defer cleanContainer(t, cli, ctr)
|
||||||
|
qmReplicaIDs[i] = ctr
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForReadyHA(t, cli, qmReplicaIDs)
|
||||||
|
|
||||||
|
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
|
||||||
|
// with HA TLS enabled, overrides the default CipherSpec, and ensures the queue manger
|
||||||
|
// and replicas start as expected
|
||||||
|
func TestNativeHASecureCipherSpec(t *testing.T) {
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := getMQVersion(t, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if version < "9.2.2.0" {
|
||||||
|
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
|
qmReplicaIDs := [3]string{}
|
||||||
|
qmNetwork, err := createBridgeNetwork(cli, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
||||||
|
|
||||||
|
for i := 0; i <= 2; i++ {
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_AES_256_GCM_SHA384")
|
||||||
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
|
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
||||||
|
|
||||||
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
|
defer cleanContainer(t, cli, ctr)
|
||||||
|
qmReplicaIDs[i] = ctr
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForReadyHA(t, cli, qmReplicaIDs)
|
||||||
|
|
||||||
|
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
149
test/docker/mq_native_ha_test_util.go
Normal file
149
test/docker/mq_native_ha_test_util.go
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2021
|
||||||
|
|
||||||
|
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 (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/api/types/network"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultHAPort = 9414
|
||||||
|
|
||||||
|
// HAReplicaStatus represents the Active/Replica/Replica container status of the queue manager
|
||||||
|
type HAReplicaStatus struct {
|
||||||
|
Active string
|
||||||
|
Replica [2]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBridgeNetwork(cli *client.Client, t *testing.T) (types.NetworkCreateResponse, error) {
|
||||||
|
return cli.NetworkCreate(context.Background(), t.Name(), types.NetworkCreate{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeBridgeNetwork(cli *client.Client, networkID string) error {
|
||||||
|
return cli.NetworkRemove(context.Background(), networkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNativeHAContainerConfig(containerName string, replicaNames [3]string, haPort int) container.Config {
|
||||||
|
return container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"AMQ_CLOUD_PAK=true",
|
||||||
|
"MQ_NATIVE_HA=true",
|
||||||
|
fmt.Sprintf("HOSTNAME=%s", containerName),
|
||||||
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_NAME=%s", replicaNames[0]),
|
||||||
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_NAME=%s", replicaNames[1]),
|
||||||
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_NAME=%s", replicaNames[2]),
|
||||||
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_0_REPLICATION_ADDRESS=%s(%d)", replicaNames[0], haPort),
|
||||||
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_1_REPLICATION_ADDRESS=%s(%d)", replicaNames[1], haPort),
|
||||||
|
fmt.Sprintf("MQ_NATIVE_HA_INSTANCE_2_REPLICATION_ADDRESS=%s(%d)", replicaNames[2], haPort),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNativeHASecureHostConfig(t *testing.T) container.HostConfig {
|
||||||
|
return container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
filepath.Join(getCwd(t, true), "../tls") + ":/etc/mqm/ha/pki/keys/ha",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNativeHANetworkConfig(networkID string) network.NetworkingConfig {
|
||||||
|
return network.NetworkingConfig{
|
||||||
|
EndpointsConfig: map[string]*network.EndpointSettings{
|
||||||
|
networkID: &network.EndpointSettings{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getActiveReplicaInstances(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) (HAReplicaStatus, error) {
|
||||||
|
|
||||||
|
var actives []string
|
||||||
|
var replicas []string
|
||||||
|
|
||||||
|
for _, id := range qmReplicaIDs {
|
||||||
|
qmReplicaStatus := getQueueManagerStatus(t, cli, id, "QM1")
|
||||||
|
if qmReplicaStatus == "Running" {
|
||||||
|
actives = append(actives, id)
|
||||||
|
} else if qmReplicaStatus == "Replica" {
|
||||||
|
replicas = append(replicas, id)
|
||||||
|
} else {
|
||||||
|
err := fmt.Errorf("Expected status to be Running or Replica, got status: %s", qmReplicaStatus)
|
||||||
|
return HAReplicaStatus{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(actives) != 1 || len(replicas) != 2 {
|
||||||
|
err := fmt.Errorf("Expected 1 Active and 2 Replicas, got: %d Active and %d Replica", len(actives), len(replicas))
|
||||||
|
return HAReplicaStatus{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return HAReplicaStatus{actives[0], [2]string{replicas[0], replicas[1]}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForReadyHA(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) {
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
for _, id := range qmReplicaIDs {
|
||||||
|
rc, _ := execContainer(t, cli, id, "", []string{"chkmqready"})
|
||||||
|
if rc == 0 {
|
||||||
|
t.Log("MQ is ready")
|
||||||
|
rc, _ := execContainer(t, cli, id, "", []string{"chkmqstarted"})
|
||||||
|
if rc == 0 {
|
||||||
|
t.Log("MQ has started")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.Fatal("Timed out waiting for HA Queue Manager to become ready")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForFailoverHA(t *testing.T, cli *client.Client, replicas [2]string) {
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
for _, id := range replicas {
|
||||||
|
if status := getQueueManagerStatus(t, cli, id, "QM1"); status == "Running" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.Fatal("Timed out waiting for Native HA Queue Manager to failover to an available replica")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2019
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
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.
|
||||||
@@ -28,7 +28,7 @@ import (
|
|||||||
func TestGoldenPathMetric(t *testing.T) {
|
func TestGoldenPathMetric(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ func TestMetricLabels(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
requiredLabels := []string{"qmgr"}
|
requiredLabels := []string{"qmgr"}
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -261,7 +261,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -319,7 +319,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -355,7 +355,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.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# © Copyright IBM Corporation 2018, 2019
|
# © Copyright IBM Corporation 2018, 2022
|
||||||
#
|
#
|
||||||
# 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,22 +15,24 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# Application build environment (Maven)
|
# Application build environment (Maven)
|
||||||
###############################################################################
|
###############################################################################
|
||||||
FROM docker.io/maven:3-ibmjava as builder
|
FROM registry.access.redhat.com/ubi8/openjdk-8 as builder
|
||||||
COPY pom.xml /usr/src/mymaven/
|
COPY pom.xml .
|
||||||
WORKDIR /usr/src/mymaven
|
#WORKDIR /usr/src/mymaven
|
||||||
# Download dependencies separately, so Docker caches them
|
# Download dependencies separately, so Docker caches them
|
||||||
RUN mvn dependency:go-offline install
|
RUN mvn dependency:go-offline install
|
||||||
# Copy source
|
# Copy source
|
||||||
COPY src /usr/src/mymaven/src
|
COPY src .
|
||||||
# Run the main build
|
# Run the main build
|
||||||
RUN mvn --offline install
|
RUN mvn --offline install
|
||||||
# Print a list of all the files (useful for debugging)
|
# Print a list of all the files (useful for debugging)
|
||||||
RUN find /usr/src/mymaven
|
RUN find .
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Application runtime (JRE only, no build environment)
|
# Application runtime (JRE only, no build environment)
|
||||||
###############################################################################
|
###############################################################################
|
||||||
FROM docker.io/ibmjava:8-jre
|
# OpenJDK is not technically supported with the MQ client, but is good enough for these tests
|
||||||
COPY --from=builder /usr/src/mymaven/target/*.jar /opt/app/
|
FROM registry.access.redhat.com/ubi8/openjdk-8-runtime
|
||||||
COPY --from=builder /usr/src/mymaven/target/lib/*.jar /opt/app/
|
COPY --from=builder /home/jboss/target/*.jar /opt/app/
|
||||||
|
COPY --from=builder /home/jboss/target/lib/*.jar /opt/app/
|
||||||
|
USER 1001
|
||||||
ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]
|
ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
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.
|
||||||
@@ -26,25 +26,25 @@ limitations under the License.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ibm.mq</groupId>
|
<groupId>com.ibm.mq</groupId>
|
||||||
<artifactId>com.ibm.mq.allclient</artifactId>
|
<artifactId>com.ibm.mq.allclient</artifactId>
|
||||||
<version>9.1.3.0</version>
|
<version>9.3.0.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<version>5.5.2</version>
|
<version>5.8.2</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<version>5.5.2</version>
|
<version>5.8.2</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.platform</groupId>
|
<groupId>org.junit.platform</groupId>
|
||||||
<artifactId>junit-platform-console-standalone</artifactId>
|
<artifactId>junit-platform-console-standalone</artifactId>
|
||||||
<version>1.5.2</version>
|
<version>1.8.2</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -65,5 +65,9 @@ limitations under the License.
|
|||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018
|
© Copyright IBM Corporation 2018, 2021
|
||||||
|
|
||||||
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 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
package com.ibm.mqcontainer.test;
|
package com.ibm.mqcontainer.test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -32,9 +32,12 @@ import javax.net.ssl.SSLContext;
|
|||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
|
import com.ibm.mq.MQException;
|
||||||
|
import com.ibm.mq.constants.MQConstants;
|
||||||
import com.ibm.mq.jms.MQConnectionFactory;
|
import com.ibm.mq.jms.MQConnectionFactory;
|
||||||
import com.ibm.mq.jms.MQQueue;
|
import com.ibm.mq.jms.MQQueue;
|
||||||
import com.ibm.msg.client.wmq.WMQConstants;
|
import com.ibm.msg.client.wmq.WMQConstants;
|
||||||
|
import com.ibm.msg.client.jms.DetailedJMSSecurityRuntimeException;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@@ -57,27 +60,18 @@ class JMSTests {
|
|||||||
static SSLSocketFactory createSSLSocketFactory() throws IOException, GeneralSecurityException {
|
static SSLSocketFactory createSSLSocketFactory() throws IOException, GeneralSecurityException {
|
||||||
KeyStore ts=KeyStore.getInstance("jks");
|
KeyStore ts=KeyStore.getInstance("jks");
|
||||||
ts.load(new FileInputStream(TRUSTSTORE), PASSPHRASE.toCharArray());
|
ts.load(new FileInputStream(TRUSTSTORE), PASSPHRASE.toCharArray());
|
||||||
// KeyManagerFactory kmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
|
||||||
TrustManagerFactory tmf=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory tmf=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
tmf.init(ts);
|
tmf.init(ts);
|
||||||
// tmf.init();
|
|
||||||
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
|
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
|
||||||
// Security.setProperty("crypto.policy", "unlimited");
|
|
||||||
ctx.init(null, tmf.getTrustManagers(), null);
|
ctx.init(null, tmf.getTrustManagers(), null);
|
||||||
return ctx.getSocketFactory();
|
return ctx.getSocketFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
static JMSContext create(String channel, String addr, String user, String password) throws JMSException, IOException, GeneralSecurityException {
|
static MQConnectionFactory createMQConnectionFactory(String channel, String addr) throws JMSException, IOException, GeneralSecurityException {
|
||||||
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as %s", channel, addr, user));
|
|
||||||
MQConnectionFactory factory = new MQConnectionFactory();
|
MQConnectionFactory factory = new MQConnectionFactory();
|
||||||
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);
|
|
||||||
if (TRUSTSTORE == null) {
|
if (TRUSTSTORE == null) {
|
||||||
LOGGER.info("Not using TLS");
|
LOGGER.info("Not using TLS");
|
||||||
}
|
}
|
||||||
@@ -94,12 +88,33 @@ class JMSTests {
|
|||||||
factory.setSSLCipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA256");
|
factory.setSSLCipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA256");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Give up if unable to reconnect for 10 minutes
|
return factory;
|
||||||
// factory.setClientReconnectTimeout(600);
|
}
|
||||||
// LOGGER.info(String.format("user=%s pw=%s", user, password));
|
|
||||||
|
/**
|
||||||
|
* Create a JMSContext with the supplied user and password.
|
||||||
|
*/
|
||||||
|
static JMSContext create(String channel, String addr, String user, String password) throws JMSException, IOException, GeneralSecurityException {
|
||||||
|
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as %s", channel, addr, user));
|
||||||
|
MQConnectionFactory factory = createMQConnectionFactory(channel, 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);
|
||||||
|
}
|
||||||
|
LOGGER.info(String.format("CSP authentication: %s", factory.getBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP)));
|
||||||
return factory.createContext(user, password);
|
return factory.createContext(user, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a JMSContext with the default user identity (from the OS)
|
||||||
|
*/
|
||||||
|
static JMSContext create(String channel, String addr) throws JMSException, IOException, GeneralSecurityException {
|
||||||
|
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as OS user '%s'", channel, addr, System.getProperty("user.name")));
|
||||||
|
MQConnectionFactory factory = createMQConnectionFactory(channel, addr);
|
||||||
|
LOGGER.info(String.format("CSP authentication: %s", factory.getBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP)));
|
||||||
|
return factory.createContext();
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
private static void waitForQueueManager() {
|
private static void waitForQueueManager() {
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
@@ -116,28 +131,34 @@ class JMSTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void connect() throws Exception {
|
|
||||||
context = create(CHANNEL, ADDR, USER, PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void succeedingTest(TestInfo t) throws JMSException {
|
void putGetTest(TestInfo t) throws Exception {
|
||||||
|
context = create(CHANNEL, ADDR, USER, PASSWORD);
|
||||||
Queue queue = new MQQueue("DEV.QUEUE.1");
|
Queue queue = new MQQueue("DEV.QUEUE.1");
|
||||||
context.createProducer().send(queue, t.getDisplayName());
|
context.createProducer().send(queue, t.getDisplayName());
|
||||||
Message m = context.createConsumer(queue).receive();
|
Message m = context.createConsumer(queue).receive();
|
||||||
assertNotNull(m.getBody(String.class));
|
assertNotNull(m.getBody(String.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
|
||||||
// void failingTest() {
|
|
||||||
// fail("a failing test");
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled("for demonstration purposes")
|
void defaultIdentityTest(TestInfo t) throws Exception {
|
||||||
void skippedTest() {
|
LOGGER.info(String.format("Password='%s'", PASSWORD));
|
||||||
// not executed
|
try {
|
||||||
|
// Don't pass a user/password, which should cause the default identity to be used
|
||||||
|
context = create(CHANNEL, ADDR);
|
||||||
|
} catch (DetailedJMSSecurityRuntimeException ex) {
|
||||||
|
Throwable cause = ex.getCause();
|
||||||
|
assertNotNull(cause);
|
||||||
|
assertTrue(cause instanceof MQException);
|
||||||
|
assertEquals(MQConstants.MQRC_NOT_AUTHORIZED, ((MQException)cause).getReason());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// The default developer config allows any user to appear as "app", and use a blank password. This is done with the MCAUSER on the channel.
|
||||||
|
// If this test is run on a queue manager without a password set, then it should be possible to connect without exception.
|
||||||
|
// If this test is run on a queue manager with a password set, then an exception should be thrown, because this test doesn't send a password.
|
||||||
|
if ((PASSWORD != null) && (PASSWORD != "")) {
|
||||||
|
fail("Exception not thrown");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
@@ -146,9 +167,4 @@ class JMSTests {
|
|||||||
context.close();
|
context.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
static void tearDownAll() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash -ex
|
||||||
# -*- mode: sh -*-
|
# -*- mode: sh -*-
|
||||||
# © Copyright IBM Corporation 2018
|
# © Copyright IBM Corporation 2018, 2021
|
||||||
#
|
#
|
||||||
# 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,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" \
|
||||||
|
-addext "subjectAltName = DNS:localhost" \
|
||||||
-x509 -days 3650 -out ${CERT}
|
-x509 -days 3650 -out ${CERT}
|
||||||
|
|
||||||
# Add the key and certificate to a PKCS #12 key store, for the server to use
|
# Add the key and certificate to a PKCS #12 key store, for the server to use
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIICpDCCAYwCCQC6vpJFnfYO6TANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
MIICwzCCAaugAwIBAgIJAKnwG0VGiDelMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
|
||||||
b2NhbGhvc3QwHhcNMTkwMzIxMTYxMzUxWhcNMjkwMzE4MTYxMzUxWjAUMRIwEAYD
|
BAMMCWxvY2FsaG9zdDAeFw0yMTA5MDYxNTIyMDlaFw0zMTA5MDQxNTIyMDlaMBQx
|
||||||
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCu
|
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
48qtIDwmihFqj2HY3dZjPfROA1MJ+D0c6aEA08ooOczthLB7XdZBQDapj8LFldyt
|
ggEBALLmDX3OB/4DlzJzKz/Edc5qVdjdIN/u8pApSQPevT0mAsSK1uw2MObeOo4C
|
||||||
4ZMbTkqtF5QtPXmJY0wi39foLYlcGXPL1b7y3mypaFou88BcSM3VmfILKXhNeAlt
|
DCBmabYeuvGzZ4t3SiejdsHK+qAYMFW51lxTbulv5kUPvTBOY2JCENkVDFjqcK8S
|
||||||
rXevnuT5kDU7sLVgKGhGwas20T1MU7d0I3bQ5z5c7egL76Hk9fYucjN6RkbwlrJ3
|
9ItI/UzTmnBolvZmUKzROHzA/pFb/jkhlzqJO+TqIBXKLF5gdFFTiHHcqfoUyVOV
|
||||||
TrCXrGIziofn3Zq1t51ygv21c80JD3XJ44YmuCrede4rhOS/4NpwRuZyiwpJ6tlv
|
n+49V8z6W2rokz4QIWa5Dlh6VS1B6VXdihJv5P9HV8P8FOtefhA85yaSVKlFS/AC
|
||||||
0L0QSDGCmt2JT3ty28UAsGznFzC5Qu9KyaR+9Gk4aftiyKxrYWZkgtJmMRU+C1X2
|
XRb5FmtmYHBnghLktHS71s/KcPeX27Q1NcKhmZMvHRH95hqEcP25S6SGu69eiCLk
|
||||||
kFLOHsucGmJswjwubSR7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEdlmXVGy86P
|
xpbJKqG3fntfooLUDfR2PHQUJ7UCAwEAAaMYMBYwFAYDVR0RBA0wC4IJbG9jYWxo
|
||||||
XIX5a4ZmHQ5Ns4wm7rY8vzUxlymEQ86En1PN1zAO9gV94tLyNeMptjsFEEo/uJhC
|
b3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBamIH23oDh1XxOeMPUEyPLHm5M8LM8FNhT
|
||||||
Yvg3l5TIr/WCiY2+2XsSHvnbXrlbF3S0fRHa9VaCMRKjzRT68uq2Y891906YGtUE
|
GEpf1ICy4TSLipSFhIs3hGzVt22zBBzU59apQ8rXUME5SK+9PLag/t/48rG1SfUA
|
||||||
m6fCjHqVzX8qaplDf79aVkPydYaYOIZ1a/mCfQcD9XMZ/v5zI9IUDhdoq97bgPhB
|
VyYvaeu/cA5NQMWwuyCLqZL1MWn+BLsdAiNtbNHANesnl0i+vUb0GPzSP8soe3PP
|
||||||
gBOzWLI+hkzyU8jxKAFw1Hwi9lD/P6RXL5arNb/+arOgA3vTW+xGWGevgjVK1Ay9
|
N7Fh8SO3Qq6e9zT3iE2tP2OFxzcpg538Xn3qoVPJwmLIfBtvsiK07zqAWdqBWtt6
|
||||||
81beWiQmn0KbeLZxj+WJ9Nntlf1M4EqPYgsSYs/IlJTYS8W1B0mDJEoovPdFTryY
|
cBXyagnmgKvOyv6sKAlTpwP9HqVem3XxZVrhm1KiPHs4Dnks6e79txmB8lqzvWu5
|
||||||
GyIuQEVcjUE=
|
tu4h2ePGJjqUy5JkkoDY0j6hALwEe3ZXBvJ6XUQDi9Hou2k+MaQd
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu48qtIDwmihFq
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCy5g19zgf+A5cy
|
||||||
j2HY3dZjPfROA1MJ+D0c6aEA08ooOczthLB7XdZBQDapj8LFldyt4ZMbTkqtF5Qt
|
cys/xHXOalXY3SDf7vKQKUkD3r09JgLEitbsNjDm3jqOAgwgZmm2Hrrxs2eLd0on
|
||||||
PXmJY0wi39foLYlcGXPL1b7y3mypaFou88BcSM3VmfILKXhNeAltrXevnuT5kDU7
|
o3bByvqgGDBVudZcU27pb+ZFD70wTmNiQhDZFQxY6nCvEvSLSP1M05pwaJb2ZlCs
|
||||||
sLVgKGhGwas20T1MU7d0I3bQ5z5c7egL76Hk9fYucjN6RkbwlrJ3TrCXrGIziofn
|
0Th8wP6RW/45IZc6iTvk6iAVyixeYHRRU4hx3Kn6FMlTlZ/uPVfM+ltq6JM+ECFm
|
||||||
3Zq1t51ygv21c80JD3XJ44YmuCrede4rhOS/4NpwRuZyiwpJ6tlv0L0QSDGCmt2J
|
uQ5YelUtQelV3YoSb+T/R1fD/BTrXn4QPOcmklSpRUvwAl0W+RZrZmBwZ4IS5LR0
|
||||||
T3ty28UAsGznFzC5Qu9KyaR+9Gk4aftiyKxrYWZkgtJmMRU+C1X2kFLOHsucGmJs
|
u9bPynD3l9u0NTXCoZmTLx0R/eYahHD9uUukhruvXogi5MaWySqht357X6KC1A30
|
||||||
wjwubSR7AgMBAAECggEAH9t6teKjUlngJksMBdcTEGzerb9JRw2jBDtCisYJkx5E
|
djx0FCe1AgMBAAECggEAagD5A49+mtwjzigB+4H80Def8KVuomIi5psgAaQM+9u3
|
||||||
SBfdlftX5fbufiCj2B4eXsYyZ8zxKWqcIUmLdA1Udx3TVIXG+bHhOAYtjEwb+xf5
|
DiC6ozKlHVeW2KiL6PLmNpzU5v0IINKpZP1uE/yjLxPGKDW6t/BUKww8JLXjw2jf
|
||||||
JYhdR/IzHG+4eXQKaAIvpXztyl3lU9iC+eaMg4GYzRrGN2wSAG9XgZ5cLF2TLJYU
|
aMx+0TKwo0sfRA32S0YPmWNVAsBmm1AbA5vhXcK51QXuiInH406H5+d25ZJrYevF
|
||||||
jPxp7goz9X6V57aL2G/EFlbFsMaI/6cW7+XoRdo0I4N2Z766gz7GgyxtTVwR5Peq
|
liKWSjx9CM/0XO7t20j18mCa8RjBEdsZoHxHsoWNvFJ6DCR25cFShAhR7s4OtkUk
|
||||||
LjOpqSNS0W57KJxReURfySok9CP1DfyigopsYW8O4jGVDDRLdiN3I8+JhWya2E0j
|
yELm1tYYrFOffUM0Q/Fp9uSlCHWMSqPtf/6NEfnszfFEtzDh/N+YqC1Bexv0XPsD
|
||||||
96hHpN04Oz6HnMm7bdZDVtkZCOiu6xIzLJJxZ4o+kQKBgQDYqOA/hSod7s7w4LBE
|
dBPOkUZjWA2Sc8Se1t2GLfrRURzj3GvWH1+GssjsAQKBgQDeIdyzQSqce4Kn0opa
|
||||||
A6Mp+e0//PYH6/N9SKmSIgQNec9bMGI4yanoblMbg4GM1g7pkvjlC0nTdjnUbLkB
|
vdS5moCiv3pyfNd0nYe0awgVos4kHY7/nBq0eyMZAatRHeD3DunVsw3LmvWyEw53
|
||||||
vIvtVh3XwTIlrZ/4lc7VB23/hmKU+lRc+NJP5fgasAQu0W3+qp2cXo0pnHVwBEku
|
app7MTTjVrYaadoBlB6jy2elyF5RcW2jGchZExoNh+0ZQWUiMbYEozPLQTy9ZxMz
|
||||||
Z7FwDPX0JNDIi/Or2I7dt8JojQKBgQDOpU1AnIXv1/cToYK4nz8BWLxRxwLTxy5A
|
t0OcZ1hHPngGgmj5TELZKkwEtQKBgQDOLLh7pdKrdudtim+o4H20jl5yYKl25Iq/
|
||||||
ucafNKacPlxb5luZRCExiPZwAM8Z3zI9o99rYXOPQmsnknZWJV66Zx0Vo0yTD1CT
|
DKVodwUd94cM7xAIOQJrx2XK/YPCfRkKRN1wxzAhYdIVkaaKDVhI8Jeu+H18QOa6
|
||||||
DWMUj0ugI1wORNMhwZP6YBYWjAeupyU9a7FyU1Geg4sdQt5rMyAEQOoECc8x8foP
|
5OlzzZcqJCtACpbVqLaDcmq8pRrAYekiwMIKwC95llvktjilvLfoUnQoXAaX8E8B
|
||||||
rySHuO/TJwKBgBjMM2ZxymFErQDa5rHSLMGoLmRtgodjlSnYwDfOluIn9/i67/MJ
|
yCSUvDh3AQKBgQCxa0h04DLho4Da/D3HdmHHERF3bAqoEPCh0wTF5MsjRNLzY6yI
|
||||||
+d11iyOSCKji8y/+t2gXw6plVLcgfohZWTaf7ah9H006sx2Tn+m4APoHGo9sm21M
|
mq11w/hni77C3mOF0SKRrh7xpcZiQfhHBx12EfpVLjfq5uraYe0LFHanol87G6bf
|
||||||
uV2Vt7DuRnxJUiqcwo9cLxH9K1/Xzbx299MYWKpJ8G+TvR8FGUz9NE4dAoGAM5gs
|
I8Oy6Z/geNW2W1YktqHUGGpRCL0z5nUe1FyrOpv2431Ibbbcj73A6JipFQKBgHdl
|
||||||
KKSsAE1QwFMEG2qPRZvNMTHaL9w8XSbFQ7zWmI4tazihyCutifujZCWfj9sdZSyE
|
vJyWpk73+AQe1JUnFIU4oYd5ZQpeRd9n8m5x5ru4+jPKSi2I3lcOTWvlrqU2Dwc8
|
||||||
PQBQ5QT1UiUMbMfZ1fqm1V83YERjnsOp6Fk6zZnmgx2GBZiahNn2ydxekqni72nz
|
ZEUIhV3/qUsmYxy1p7ft5NnGO912NGhtYqjWmcEk2wsmVr17C99JpniC4OAik4G1
|
||||||
HRNWfphjZIPsmqFiLg2zIBz+4X6EK+RT35s6LeMCgYEAwF/9jX8kONW5KKZdoNHa
|
wWm6bIPsSGFGCb4pcROQlIY+7O6WkxqEDnM4ITcBAoGAHXBKmadFpupUeGSkCwEo
|
||||||
opkLpa9qkwTGQ9M3AZiRUjM4rtvggYt8FBEP+3BLDLHqfUOkPq82MCRXm+6Cz+sT
|
/VjeI4QoKKcWj9K8z8ifCVPz1FiQ1AJ91WMTM7PAmpEDX058Hor9xxJ2bEtQFwUS
|
||||||
gyPnsPlAh/sr3Pys3olJbUDE9H24k1LU0CI/sSwAFkka0+Q7PVTTe/Dcavitrcrm
|
QKvjeU+/Ig0TWjsJBgBPvc0xYLaJptAbjvG4a5nBn7hwbRzLTcKx2OVTmdAkz00H
|
||||||
+fyiT2oSPZeHSjQE9iIW3OY=
|
1lq8cwizfwNgt8ldFFDDRvw=
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|||||||
Binary file not shown.
249
travis-build-scripts/artifact-util.sh
Executable file
249
travis-build-scripts/artifact-util.sh
Executable file
@@ -0,0 +1,249 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# © Copyright IBM Corporation 2020
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
usage="
|
||||||
|
Usage: artifact-util.sh -c my-registry.com/artifacts/my-project/builds/123 -u me@org.com -p top-secret -f tagcache -l ./.tagcache --upload \"
|
||||||
|
|
||||||
|
Where:
|
||||||
|
-c - Full artifact destination hostname and path
|
||||||
|
-u - The username to access repository
|
||||||
|
-p - The password or api-key to access repository
|
||||||
|
-f - Name of the file in repository
|
||||||
|
-l - The path and name to the file whose contents is to be pushed or retrieved into
|
||||||
|
Then one action of either
|
||||||
|
--check - Check if the file exists
|
||||||
|
--upload - Upload the contents of a file [-l must be specified]
|
||||||
|
--get - Get a file and write to a local file [-l must be specified]
|
||||||
|
--delete - Delet the remote file from repository
|
||||||
|
"
|
||||||
|
|
||||||
|
GREEN="\033[32m"
|
||||||
|
RED="\033[31m"
|
||||||
|
|
||||||
|
END="\033[0m"
|
||||||
|
|
||||||
|
|
||||||
|
RIGHTARROW="\xE2\x96\xB6"
|
||||||
|
BLUERIGHTARROW=${BLUE}${RIGHTARROW}${END}
|
||||||
|
GREENRIGHTARROW=${GREEN}${RIGHTARROW}${END}
|
||||||
|
|
||||||
|
ERROR=${RED}
|
||||||
|
|
||||||
|
TICK="\xE2\x9C\x94"
|
||||||
|
CROSS="\xE2\x9C\x97"
|
||||||
|
GREENTICK=${GREEN}${TICK}${END}
|
||||||
|
REDCROSS=${RED}${CROSS}${END}
|
||||||
|
|
||||||
|
|
||||||
|
SPACER="\n\n"
|
||||||
|
|
||||||
|
USER=
|
||||||
|
CREDENTIAL=
|
||||||
|
FILE_NAME=
|
||||||
|
BUILD_ID=
|
||||||
|
REGISTRY_HOSTNAME=
|
||||||
|
FILE_LOCATION=
|
||||||
|
PROPERTY_NAME=
|
||||||
|
|
||||||
|
CHECK=false
|
||||||
|
UPLOAD=false
|
||||||
|
GET=false
|
||||||
|
GET_PROPERTY=false
|
||||||
|
DELETE=false
|
||||||
|
DELETE_NAMESPACE=false
|
||||||
|
num_commands_selected=0
|
||||||
|
while getopts "f:u:p:c:l:n:-:" flag
|
||||||
|
do
|
||||||
|
case "${flag}" in
|
||||||
|
f) FILE_NAME=${OPTARG};;
|
||||||
|
u) USER=${OPTARG};;
|
||||||
|
p) CREDENTIAL=${OPTARG};;
|
||||||
|
c) CACHE_PATH=${OPTARG};;
|
||||||
|
l) FILE_LOCATION=${OPTARG};;
|
||||||
|
n) PROPERTY_NAME=${OPTARG};;
|
||||||
|
-)
|
||||||
|
case "${OPTARG}" in
|
||||||
|
check)
|
||||||
|
CHECK=true
|
||||||
|
num_commands_selected=$((num_commands_selected+1))
|
||||||
|
;;
|
||||||
|
upload)
|
||||||
|
UPLOAD=true
|
||||||
|
num_commands_selected=$((num_commands_selected+1))
|
||||||
|
;;
|
||||||
|
get)
|
||||||
|
GET=true
|
||||||
|
num_commands_selected=$((num_commands_selected+1))
|
||||||
|
;;
|
||||||
|
get-property)
|
||||||
|
GET_PROPERTY=true
|
||||||
|
num_commands_selected=$((num_commands_selected+1))
|
||||||
|
;;
|
||||||
|
delete)
|
||||||
|
DELETE=true
|
||||||
|
num_commands_selected=$((num_commands_selected+1))
|
||||||
|
;;
|
||||||
|
delete-namespace)
|
||||||
|
DELETE_NAMESPACE=true
|
||||||
|
num_commands_selected=$((num_commands_selected+1))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
|
||||||
|
echo "Unknown option --${OPTARG}" >&2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $num_commands_selected == 0 || $num_commands_selected -gt 1 ]]; then
|
||||||
|
printf "${REDCROSS} ${ERROR}Too many actions specified. Should be one of ${END}--check${ERROR},${END} --get${ERROR},${END} --upload${ERROR} or${END} --delete${ERROR}!${END}\n"
|
||||||
|
printf $SPACER
|
||||||
|
printf "${ERROR}$usage${END}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DELETE_NAMESPACE" != "true" ]; then
|
||||||
|
if [[ -z $CACHE_PATH|| -z $USER || -z $CREDENTIAL || -z $FILE_NAME ]] ; then
|
||||||
|
printf "${REDCROSS} ${ERROR}Missing parameter!${END}\n"
|
||||||
|
printf "Cache Path:"$CACHE_PATH"\n"
|
||||||
|
printf "File name:"$FILE_NAME"\n"
|
||||||
|
printf "User":$USER"\n"
|
||||||
|
printf $SPACER
|
||||||
|
printf "${ERROR}$usage${END}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
REMOTE_PATH="https://${CACHE_PATH}/$TRAVIS_BUILD_ID"
|
||||||
|
|
||||||
|
if [ "$CHECK" == "true" ]; then
|
||||||
|
printf "${GREENRIGHTARROW} Checking to see if file ${FILE_NAME} exists in repository ${REMOTE_PATH}\n"
|
||||||
|
FILE_FOUND=`curl -u ${USER}:${CREDENTIAL} -X GET "${REMOTE_PATH}/${FILE_NAME}" -o /dev/null -w "%{http_code}" -s`
|
||||||
|
if [ "$FILE_FOUND" != "200" ]; then
|
||||||
|
printf "${REDCROSS} File ${FILE_NAME} was not found\n"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} File ${FILE_NAME} was found\n"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$UPLOAD" == "true" ]; then
|
||||||
|
printf "${GREENRIGHTARROW} Attempting to upload the file ${FILE_NAME} to repository ${REMOTE_PATH}\n"
|
||||||
|
if [[ -z $FILE_LOCATION ]]; then
|
||||||
|
printf "${REDCROSS} Location for ${FILE_NAME} was not supplied please do so\n"
|
||||||
|
printf $SPACER
|
||||||
|
printf "${ERROR}$usage${END}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -f "$FILE_LOCATION" ]; then
|
||||||
|
printf "${REDCROSS} Location supplied ${FILE_LOCATION } for file ${FILE_NAME} did not resolve to a file with contents to upload\n"
|
||||||
|
printf $SPACER
|
||||||
|
printf "${ERROR}$usage${END}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
curl -u ${USER}:${CREDENTIAL} -X PUT "$REMOTE_PATH/${FILE_NAME}" -T ${FILE_LOCATION}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GET" == "true" ]; then
|
||||||
|
printf "${GREENRIGHTARROW} Attempting to download file ${FILE_NAME} from repository ${REMOTE_PATH} to ${FILE_LOCATION}\n"
|
||||||
|
if [[ -z $FILE_LOCATION ]]; then
|
||||||
|
printf "${REDCROSS} Location for ${FILE_NAME} was not supplied please do so\n"
|
||||||
|
printf $SPACER
|
||||||
|
printf "${ERROR}$usage${END}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
curl -u ${USER}:${CREDENTIAL} "$REMOTE_PATH/${FILE_NAME}" -o ${FILE_LOCATION} -s
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
printf "${REDCROSS} Failed download\n"
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} File ${FILE_NAME} was downloaded to ${FILE_LOCATION}\n"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GET_PROPERTY" == "true" ]; then
|
||||||
|
if [[ -z $PROPERTY_NAME ]]; then
|
||||||
|
printf "${REDCROSS} Property name to retrieve from '${FILE_NAME}' was not supplied please do so\n"
|
||||||
|
printf $SPACER
|
||||||
|
printf "${ERROR}$usage${END}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -z $FILE_LOCATION ]]; then
|
||||||
|
printf "${REDCROSS} File location to store property value in was not supplied please do so\n"
|
||||||
|
printf $SPACER
|
||||||
|
printf "${ERROR}$usage${END}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf "${GREENRIGHTARROW} Attempting to retrieve ${PROPERTY_NAME} of ${FILE_NAME} from repository ${REMOTE_PATH} and store it in ${FILE_LOCATION}\n"
|
||||||
|
|
||||||
|
query_url="${FILE_NAME}"
|
||||||
|
query_url="${query_url/\/artifactory\//\/artifactory\/api\/storage\//}?properties=${PROPERTY_NAME}"
|
||||||
|
request_result="$(curl -s -u ${USER}:${CREDENTIAL} "${query_url}")"
|
||||||
|
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
printf "Unable to retrieve properties from ${query_url}"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} Properties retrieved from ${query_url}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -r '.properties.snapshot|first' <<<"$request_result" > ${FILE_LOCATION}
|
||||||
|
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
printf "Unable to write snapshot property to ${FILE_LOCATION}"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} Property written to ${FILE_LOCATION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DELETE" == "true" ]; then
|
||||||
|
printf "${GREENRIGHTARROW} Checking to see if file ${FILE_NAME} exists in repository ${REMOTE_PATH} before delete\n"
|
||||||
|
FILE_FOUND=`curl -u ${USER}:${CREDENTIAL} -X GET "${REMOTE_PATH}/${FILE_NAME}" -o /dev/null -w "%{http_code}" -s`
|
||||||
|
if [ "$FILE_FOUND" != "200" ]; then
|
||||||
|
printf "${REDCROSS} File ${FILE_NAME} was not found to delete\n"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} File ${FILE_NAME} was found\n"
|
||||||
|
printf "${GREENRIGHTARROW} Attempting the delete of ${REMOTE_PATH}/${FILE_NAME}"
|
||||||
|
curl -u ${USER}:${CREDENTIAL} -X DELETE "${REMOTE_PATH}/${FILE_NAME}" -s
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
printf "${REDCROSS} Failed delete\n"
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} File ${FILE_NAME} was deleted from "${REMOTE_PATH}"\n"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DELETE_NAMESPACE" == "true" ]; then
|
||||||
|
printf "${GREENRIGHTARROW} Checking to see if repository ${REMOTE_PATH} exists before delete\n"
|
||||||
|
DIR_FOUND=`curl -u ${USER}:${CREDENTIAL} -X GET "${REMOTE_PATH}" -o /dev/null -w "%{http_code}" -s`
|
||||||
|
if [ "$DIR_FOUND" != "200" ]; then
|
||||||
|
printf "${REDCROSS} Namespace ${REMOTE_PATH} was not found to delete\n"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} Namespace ${REMOTE_PATH} was found\n"
|
||||||
|
printf "${GREENRIGHTARROW} Attempting the delete of ${REMOTE_PATH}"
|
||||||
|
curl -u ${USER}:${CREDENTIAL} -X DELETE "${REMOTE_PATH}" -s
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
printf "${REDCROSS} Failed delete\n"
|
||||||
|
else
|
||||||
|
printf "${GREENTICK} Namespace ${REMOTE_PATH} deleted \n"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
@@ -16,16 +16,68 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo 'Building Developer JMS test image...' && echo -en 'travis_fold:start:build-devjmstest\\r'
|
archive_level_cache_dir="$(mktemp -d)"
|
||||||
make build-devjmstest
|
|
||||||
echo -en 'travis_fold:end:build-devjmstest\\r'
|
get_archive_level() {
|
||||||
echo 'Building Developer image...' && echo -en 'travis_fold:start:build-devserver\\r'
|
local level_path
|
||||||
make build-devserver
|
local archive_variable
|
||||||
echo -en 'travis_fold:end:build-devserver\\r'
|
archive_variable="$1"
|
||||||
if [ "$BUILD_ALL" = true ] ; then
|
MQ_ARCHIVE_LEVEL=""
|
||||||
if [[ "$ARCH" = "amd64" || "$ARCH" = "s390x" ]] ; then
|
level_path="${archive_level_cache_dir}/${archive_variable}.level"
|
||||||
echo 'Building Production image...' && echo -en 'travis_fold:start:build-advancedserver\\r'
|
|
||||||
make build-advancedserver
|
if [[ ! -f "$level_path" ]]; then
|
||||||
echo -en 'travis_fold:end:build-advancedserver\\r'
|
if [[ -z "${REPOSITORY_USER}" || -z "${REPOSITORY_CREDENTIAL}" ]]; then
|
||||||
|
echo 'Skipping level lookup as repository credentials not set'
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
|
if [[ -z "${!archive_variable}" ]]; then
|
||||||
|
echo "Skipping level lookup as '\$${archive_variable}' is not set"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
./travis-build-scripts/artifact-util.sh -f "${!archive_variable}" -u "${REPOSITORY_USER}" -p "${REPOSITORY_CREDENTIAL}" -l "$level_path" -n snapshot --get-property
|
||||||
|
fi
|
||||||
|
read -r MQ_ARCHIVE_LEVEL < "$level_path"
|
||||||
|
export MQ_ARCHIVE_LEVEL
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$TRAVIS_BRANCH" = "$MAIN_BRANCH" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||||
|
echo 'Retrieving global tagcache' && echo -en 'travis_fold:start:tag-cache-retrieve\\r'
|
||||||
|
./travis-build-scripts/artifact-util.sh -c ${CACHE_PATH} -u ${REPOSITORY_USER} -p ${REPOSITORY_CREDENTIAL} -f cache/${TAGCACHE_FILE} -l ./.tagcache --check
|
||||||
|
./travis-build-scripts/artifact-util.sh -c ${CACHE_PATH} -u ${REPOSITORY_USER} -p ${REPOSITORY_CREDENTIAL} -f cache/${TAGCACHE_FILE} -l ./.tagcache --get
|
||||||
|
echo -en 'travis_fold:end:tag-cache-retrieve\\r'
|
||||||
|
fi
|
||||||
|
if [ -z "$BUILD_INTERNAL_LEVEL" ] ; then
|
||||||
|
if [ "$LTS" != true ] ; then
|
||||||
|
echo 'Building Developer JMS test image...' && echo -en 'travis_fold:start:build-devjmstest\\r'
|
||||||
|
make build-devjmstest
|
||||||
|
echo -en 'travis_fold:end:build-devjmstest\\r'
|
||||||
|
echo 'Building Developer image...' && echo -en 'travis_fold:start:build-devserver\\r'
|
||||||
|
get_archive_level MQ_ARCHIVE_REPOSITORY_DEV
|
||||||
|
make build-devserver
|
||||||
|
echo -en 'travis_fold:end:build-devserver\\r'
|
||||||
|
fi
|
||||||
|
if [ "$BUILD_ALL" = true ] || [ "$LTS" = true ] ; then
|
||||||
|
if [[ "$ARCH" = "amd64" || "$ARCH" = "s390x" || "$ARCH" = "ppc64le" ]] ; then
|
||||||
|
echo 'Building Production image...' && echo -en 'travis_fold:start:build-advancedserver\\r'
|
||||||
|
get_archive_level MQ_ARCHIVE_REPOSITORY
|
||||||
|
make build-advancedserver
|
||||||
|
echo -en 'travis_fold:end:build-advancedserver\\r'
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'Building Developer JMS test image...' && echo -en 'travis_fold:start:build-devjmstest\\r'
|
||||||
|
make build-devjmstest
|
||||||
|
echo -en 'travis_fold:end:build-devjmstest\\r'
|
||||||
|
|
||||||
|
if [[ "$BUILD_INTERNAL_LEVEL" == *".DE"* ]]; then
|
||||||
|
echo 'Building Developer image...' && echo -en 'travis_fold:start:build-devserver\\r'
|
||||||
|
get_archive_level MQ_ARCHIVE_REPOSITORY_DEV
|
||||||
|
make build-devserver
|
||||||
|
echo -en 'travis_fold:end:build-devserver\\r'
|
||||||
|
else
|
||||||
|
echo 'Building Production image...' && echo -en 'travis_fold:start:build-advancedserver\\r'
|
||||||
|
get_archive_level MQ_ARCHIVE_REPOSITORY
|
||||||
|
make build-advancedserver
|
||||||
|
echo -en 'travis_fold:end:build-advancedserver\\r'
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
17
test/docker/Gopkg.toml → travis-build-scripts/cleanup-cache.sh
Normal file → Executable file
17
test/docker/Gopkg.toml → travis-build-scripts/cleanup-cache.sh
Normal file → Executable file
@@ -1,4 +1,6 @@
|
|||||||
# © Copyright IBM Corporation 2017, 2018
|
#!/bin/bash
|
||||||
|
|
||||||
|
# © Copyright IBM Corporation 2020
|
||||||
#
|
#
|
||||||
# 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,13 +14,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
[[constraint]]
|
echo 'Cleaning up remote cache' && echo -en 'travis_fold:start:cleanup\\r'
|
||||||
name = "github.com/docker/docker"
|
./travis-build-scripts/artifact-util.sh -c ${CACHE_PATH} -u ${REPOSITORY_USER} -p ${REPOSITORY_CREDENTIAL} -f cache/${TAGCACHE_FILE} --delete
|
||||||
version = "=v17.03.2-ce"
|
echo -en 'travis_fold:end:cleanup\\r'
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/docker/go-connections"
|
|
||||||
version = "0.4.0"
|
|
||||||
|
|
||||||
[prune]
|
|
||||||
go-tests = true
|
|
||||||
@@ -84,7 +84,7 @@ for digest in $DIGESTS ; do \
|
|||||||
done
|
done
|
||||||
|
|
||||||
docker login $REGISTRY -u $USER -p $CREDENTIAL
|
docker login $REGISTRY -u $USER -p $CREDENTIAL
|
||||||
docker manifest create $REGISTRY/$NAMESPACE/$IMAGE:$TAG $MANIFESTS > /dev/null
|
docker manifest create $REGISTRY/$NAMESPACE/$IMAGE:$TAG $MANIFESTS
|
||||||
MANIFEST_DIGEST=$(docker manifest push --purge $REGISTRY/$NAMESPACE/$IMAGE:$TAG)
|
MANIFEST_DIGEST=$(docker manifest push --purge $REGISTRY/$NAMESPACE/$IMAGE:$TAG)
|
||||||
|
|
||||||
echo $MANIFEST_DIGEST
|
echo $MANIFEST_DIGEST
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
|
# © Copyright IBM Corporation 2020
|
||||||
#
|
#
|
||||||
# Copyright 2018 The Prometheus Authors
|
|
||||||
# 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.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
@@ -13,17 +14,11 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
check_license() {
|
set -e
|
||||||
local file=""
|
|
||||||
for file in $(find . -type f -iname '*.go' ! -path './vendor/*'); do
|
|
||||||
head -n3 "${file}" | grep -Eq "(Copyright|generated|GENERATED)" || echo " ${file}"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
licRes=$(check_license)
|
echo 'Cacheing MQ tag...' && echo -en 'travis_fold:start:build-cache-mq-tag\\r'
|
||||||
|
make cache-mq-tag
|
||||||
if [ -n "${licRes}" ]; then
|
echo -en 'travis_fold:end:cache-mq-tag\\r'
|
||||||
echo "license header checking failed:"
|
echo 'Caching tagcache for future stages' && echo -en 'travis_fold:start:tag-cache\\r'
|
||||||
echo "${licRes}"
|
./travis-build-scripts/artifact-util.sh -c ${CACHE_PATH} -u ${REPOSITORY_USER} -p ${REPOSITORY_CREDENTIAL} -f cache/${TAGCACHE_FILE} -l ./.tagcache --upload
|
||||||
exit 255
|
echo -en 'travis_fold:end:tag-cache\\r'
|
||||||
fi
|
|
||||||
@@ -19,15 +19,32 @@ sudo add-apt-repository "deb [arch=$ARCH] https://download.docker.com/linux/ubun
|
|||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt -y install docker-ce pass
|
sudo apt -y install docker-ce pass
|
||||||
|
|
||||||
|
echo "default-cache-ttl 1200" > /home/travis/.gnupg/gpg-agent.conf
|
||||||
|
gpg-connect-agent reloadagent /bye
|
||||||
|
|
||||||
mkdir -p $GOPATH/src/github.com/docker
|
mkdir -p $GOPATH/src/github.com/docker
|
||||||
cd $GOPATH/src/github.com/docker
|
cd $GOPATH/src/github.com/docker
|
||||||
git clone https://github.com/docker/docker-credential-helpers
|
git clone https://github.com/docker/docker-credential-helpers
|
||||||
cd docker-credential-helpers
|
cd docker-credential-helpers
|
||||||
make pass
|
|
||||||
cp bin/docker-credential-pass $GOPATH/bin/docker-credential-pass
|
# After https://github.com/docker/docker-credential-helpers/commit/fd0197473f0ecb29e73ccef9028057194ff463bc go 1.18 is required... Pin commit if earlier go installed
|
||||||
|
go_version="$(go version | cut -f3 -d' ')"
|
||||||
|
IFS=. read -a go_version_parts <<<"$go_version"
|
||||||
|
go_major="${go_version_parts[0]##go}"
|
||||||
|
go_minor="${go_version_parts[1]}"
|
||||||
|
if [[ "$go_major" -eq 1 && "$go_minor" -lt 18 ]]; then
|
||||||
|
echo "Go version ${go_major}.${go_minor} < 1.18... Pinning credential-helper commit"
|
||||||
|
git checkout ab7fd12c67d83193072fa91e5648b036547f6323
|
||||||
|
make pass
|
||||||
|
cp bin/docker-credential-pass $GOPATH/bin/docker-credential-pass
|
||||||
|
else
|
||||||
|
make pass
|
||||||
|
cp bin/build/docker-credential-pass $GOPATH/bin/docker-credential-pass
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p /home/travis/.docker
|
mkdir -p /home/travis/.docker
|
||||||
echo '{ "credsStore": "pass" }' | tee /home/travis/.docker/config.json
|
echo '{ "credsStore": "pass" }' | tee /home/travis/.docker/config.json
|
||||||
gpg --batch --gen-key <<-EOF
|
gpg2 --batch --gen-key <<-EOF
|
||||||
%echo generating a standard key
|
%echo generating a standard key
|
||||||
Key-Type: DSA
|
Key-Type: DSA
|
||||||
Key-Length: 1024
|
Key-Length: 1024
|
||||||
@@ -36,13 +53,14 @@ Subkey-Length: 1024
|
|||||||
Name-Real: Travis CI
|
Name-Real: Travis CI
|
||||||
Name-Email: travis@osism.io
|
Name-Email: travis@osism.io
|
||||||
Expire-Date: 0
|
Expire-Date: 0
|
||||||
|
Passphrase: $REGISTRY_PASS
|
||||||
%commit
|
%commit
|
||||||
%echo done
|
%echo done
|
||||||
EOF
|
EOF
|
||||||
key=$(gpg --no-auto-check-trustdb --list-secret-keys | grep ^sec | cut -d/ -f2 | cut -d" " -f1)
|
key=$(gpg2 --list-secret-keys | grep uid -B 1 | head -n 1 | sed 's/^ *//g')
|
||||||
gpg --export-secret-keys | gpg2 --import -
|
|
||||||
pass init $key
|
pass init $key
|
||||||
pass insert docker-credential-helpers/docker-pass-initialized-check <<-EOF
|
pass insert docker-credential-helpers/docker-pass-initialized-check <<-EOF
|
||||||
pass is initialized
|
pass is initialized
|
||||||
pass is initialized
|
pass is initialized
|
||||||
EOF
|
EOF
|
||||||
|
gpg2 --passphrase $REGISTRY_PASS --pinentry-mode=loopback --output doc --decrypt ~/.password-store/docker-credential-helpers/docker-pass-initialized-check.gpg
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# © Copyright IBM Corporation 2019, 2020
|
# © Copyright IBM Corporation 2019, 2021
|
||||||
#
|
#
|
||||||
# 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,7 @@ if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -z $2 ]; then
|
if [ ! -z $2 ]; then
|
||||||
export ARCH=$2
|
export ARCH=$2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -32,11 +32,9 @@ function push_developer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function push_production {
|
function push_production {
|
||||||
if [[ "$ARCH" = "amd64" || "$ARCH" = "s390x" ]] ; then
|
echo 'Pushing Production image...' && echo -en 'travis_fold:start:push-advancedserver\\r'
|
||||||
echo 'Pushing Production image...' && echo -en 'travis_fold:start:push-advancedserver\\r'
|
make push-advancedserver
|
||||||
make push-advancedserver
|
echo -en 'travis_fold:end:push-advancedserver\\r'
|
||||||
echo -en 'travis_fold:end:push-advancedserver\\r'
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# call relevant push function
|
# call relevant push function
|
||||||
@@ -50,7 +48,7 @@ if [ ! -z $1 ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
else
|
||||||
echo "ERROR: Type ( developer | production ) must be passed to push.sh"
|
echo "ERROR: Type ( developer | production ) must be passed to push.sh"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -18,6 +18,18 @@ set -e
|
|||||||
|
|
||||||
if [ "$(uname -m)" = "x86_64" ] ; then export ARCH="amd64" ; else export ARCH=$(uname -m) ; fi
|
if [ "$(uname -m)" = "x86_64" ] ; then export ARCH="amd64" ; else export ARCH=$(uname -m) ; fi
|
||||||
|
|
||||||
|
# if DOCKER_USER is set, authenticate with docker.io to mitigate rate limit (https://www.docker.com/increase-rate-limits)
|
||||||
|
if [ -n "$DOCKER_USER" ] ; then echo 'Authenticating with docker.io...' && docker login -u $DOCKER_USER -p $DOCKER_PASS docker.io ; fi
|
||||||
|
|
||||||
|
if [ "$PUSH_MANIFEST_ONLY" = true ] ; then
|
||||||
|
echo 'Retrieving remote tagcache' && echo -en 'travis_fold:start:retrieve-tag-cache\\r'
|
||||||
|
./travis-build-scripts/artifact-util.sh -c ${CACHE_PATH} -u ${REPOSITORY_USER} -p ${REPOSITORY_CREDENTIAL} -f cache/${TAGCACHE_FILE} -l ./.tagcache --get
|
||||||
|
echo -en 'travis_fold:end:retrieve-tag-cache\\r'
|
||||||
|
make push-manifest
|
||||||
|
./travis-build-scripts/cleanup-cache.sh
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
echo 'Downgrading Docker (if necessary)...' && echo -en 'travis_fold:start:docker-downgrade\\r'
|
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 -en 'travis_fold:end:docker-downgrade\\r'
|
||||||
@@ -29,7 +41,19 @@ echo -en 'travis_fold:end:docker-downgrade\\r'
|
|||||||
./travis-build-scripts/test.sh
|
./travis-build-scripts/test.sh
|
||||||
|
|
||||||
## Push images
|
## Push images
|
||||||
if [ "$BUILD_ALL" = true ] ; then
|
if [ -z "$BUILD_INTERNAL_LEVEL" ] ; then
|
||||||
|
if [ "$BUILD_ALL" = true ] ; then
|
||||||
./travis-build-scripts/push.sh developer
|
./travis-build-scripts/push.sh developer
|
||||||
./travis-build-scripts/push.sh production
|
./travis-build-scripts/push.sh production
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$BUILD_INTERNAL_LEVEL" == *".DE"* ]]; then
|
||||||
|
./travis-build-scripts/push.sh developer
|
||||||
|
else
|
||||||
|
./travis-build-scripts/push.sh production
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$LTS" = true ] ; then
|
||||||
|
printf '\nIn CD stream but building LTS image. Do not push LTS image to artifactory\n'
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -16,18 +16,29 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Use verbose test output
|
if [ -z "$BUILD_INTERNAL_LEVEL" ] ; then
|
||||||
export TEST_OPTS_DOCKER="-v"
|
if [ "$LTS" != true ] ; then
|
||||||
|
echo 'Testing Developer image...' && echo -en 'travis_fold:start:test-devserver\\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'
|
||||||
echo -en 'travis_fold:end:test-devserver\\r'
|
fi
|
||||||
if [ "$BUILD_ALL" = true ] ; then
|
if [ "$BUILD_ALL" = true ] || [ "$LTS" = true ] ; then
|
||||||
if [[ "$ARCH" = "amd64" || "$ARCH" = "s390x" ]] ; then
|
if [[ "$ARCH" = "amd64" || "$ARCH" = "s390x" || "$ARCH" = "ppc64le" ]] ; then
|
||||||
echo 'Testing Production image...' && echo -en 'travis_fold:start:test-advancedserver\\r'
|
echo 'Testing Production image...' && echo -en 'travis_fold:start:test-advancedserver\\r'
|
||||||
make test-advancedserver
|
make test-advancedserver
|
||||||
echo -en 'travis_fold:end:test-advancedserver\\r'
|
echo -en 'travis_fold:end:test-advancedserver\\r'
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$BUILD_INTERNAL_LEVEL" == *".DE"* ]]; then
|
||||||
|
echo 'Testing Developer image...' && echo -en 'travis_fold:start:test-devserver\\r'
|
||||||
|
make test-devserver
|
||||||
|
echo -en 'travis_fold:end:test-devserver\\r'
|
||||||
|
else
|
||||||
|
echo 'Testing Production image...' && echo -en 'travis_fold:start:test-advancedserver\\r'
|
||||||
|
make test-advancedserver
|
||||||
|
echo -en 'travis_fold:end:test-advancedserver\\r'
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
echo 'Running gosec scan...' && echo -en 'travis_fold:start:gosec-scan\\r'
|
echo 'Running gosec scan...' && echo -en 'travis_fold:start:gosec-scan\\r'
|
||||||
if [ "$ARCH" = "amd64" ] ; then
|
if [ "$ARCH" = "amd64" ] ; then
|
||||||
|
|||||||
2
vendor/github.com/beorn7/perks/.gitignore
generated
vendored
2
vendor/github.com/beorn7/perks/.gitignore
generated
vendored
@@ -1,2 +0,0 @@
|
|||||||
*.test
|
|
||||||
*.prof
|
|
||||||
31
vendor/github.com/beorn7/perks/README.md
generated
vendored
31
vendor/github.com/beorn7/perks/README.md
generated
vendored
@@ -1,31 +0,0 @@
|
|||||||
# Perks for Go (golang.org)
|
|
||||||
|
|
||||||
Perks contains the Go package quantile that computes approximate quantiles over
|
|
||||||
an unbounded data stream within low memory and CPU bounds.
|
|
||||||
|
|
||||||
For more information and examples, see:
|
|
||||||
http://godoc.org/github.com/bmizerany/perks
|
|
||||||
|
|
||||||
A very special thank you and shout out to Graham Cormode (Rutgers University),
|
|
||||||
Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and
|
|
||||||
Divesh Srivastava (AT&T Labs–Research) for their research and publication of
|
|
||||||
[Effective Computation of Biased Quantiles over Data Streams](http://www.cs.rutgers.edu/~muthu/bquant.pdf)
|
|
||||||
|
|
||||||
Thank you, also:
|
|
||||||
* Armon Dadgar (@armon)
|
|
||||||
* Andrew Gerrand (@nf)
|
|
||||||
* Brad Fitzpatrick (@bradfitz)
|
|
||||||
* Keith Rarick (@kr)
|
|
||||||
|
|
||||||
FAQ:
|
|
||||||
|
|
||||||
Q: Why not move the quantile package into the project root?
|
|
||||||
A: I want to add more packages to perks later.
|
|
||||||
|
|
||||||
Copyright (C) 2013 Blake Mizerany
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
26
vendor/github.com/beorn7/perks/histogram/bench_test.go
generated
vendored
26
vendor/github.com/beorn7/perks/histogram/bench_test.go
generated
vendored
@@ -1,26 +0,0 @@
|
|||||||
package histogram
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkInsert10Bins(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
h := New(10)
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
f := rand.ExpFloat64()
|
|
||||||
h.Insert(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInsert100Bins(b *testing.B) {
|
|
||||||
b.StopTimer()
|
|
||||||
h := New(100)
|
|
||||||
b.StartTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
f := rand.ExpFloat64()
|
|
||||||
h.Insert(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
108
vendor/github.com/beorn7/perks/histogram/histogram.go
generated
vendored
108
vendor/github.com/beorn7/perks/histogram/histogram.go
generated
vendored
@@ -1,108 +0,0 @@
|
|||||||
// Package histogram provides a Go implementation of BigML's histogram package
|
|
||||||
// for Clojure/Java. It is currently experimental.
|
|
||||||
package histogram
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/heap"
|
|
||||||
"math"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Bin struct {
|
|
||||||
Count int
|
|
||||||
Sum float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Bin) Update(x *Bin) {
|
|
||||||
b.Count += x.Count
|
|
||||||
b.Sum += x.Sum
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Bin) Mean() float64 {
|
|
||||||
return b.Sum / float64(b.Count)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bins []*Bin
|
|
||||||
|
|
||||||
func (bs Bins) Len() int { return len(bs) }
|
|
||||||
func (bs Bins) Less(i, j int) bool { return bs[i].Mean() < bs[j].Mean() }
|
|
||||||
func (bs Bins) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] }
|
|
||||||
|
|
||||||
func (bs *Bins) Push(x interface{}) {
|
|
||||||
*bs = append(*bs, x.(*Bin))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bs *Bins) Pop() interface{} {
|
|
||||||
return bs.remove(len(*bs) - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bs *Bins) remove(n int) *Bin {
|
|
||||||
if n < 0 || len(*bs) < n {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
x := (*bs)[n]
|
|
||||||
*bs = append((*bs)[:n], (*bs)[n+1:]...)
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
type Histogram struct {
|
|
||||||
res *reservoir
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(maxBins int) *Histogram {
|
|
||||||
return &Histogram{res: newReservoir(maxBins)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Histogram) Insert(f float64) {
|
|
||||||
h.res.insert(&Bin{1, f})
|
|
||||||
h.res.compress()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Histogram) Bins() Bins {
|
|
||||||
return h.res.bins
|
|
||||||
}
|
|
||||||
|
|
||||||
type reservoir struct {
|
|
||||||
n int
|
|
||||||
maxBins int
|
|
||||||
bins Bins
|
|
||||||
}
|
|
||||||
|
|
||||||
func newReservoir(maxBins int) *reservoir {
|
|
||||||
return &reservoir{maxBins: maxBins}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reservoir) insert(bin *Bin) {
|
|
||||||
r.n += bin.Count
|
|
||||||
i := sort.Search(len(r.bins), func(i int) bool {
|
|
||||||
return r.bins[i].Mean() >= bin.Mean()
|
|
||||||
})
|
|
||||||
if i < 0 || i == r.bins.Len() {
|
|
||||||
// TODO(blake): Maybe use an .insert(i, bin) instead of
|
|
||||||
// performing the extra work of a heap.Push.
|
|
||||||
heap.Push(&r.bins, bin)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r.bins[i].Update(bin)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reservoir) compress() {
|
|
||||||
for r.bins.Len() > r.maxBins {
|
|
||||||
minGapIndex := -1
|
|
||||||
minGap := math.MaxFloat64
|
|
||||||
for i := 0; i < r.bins.Len()-1; i++ {
|
|
||||||
gap := gapWeight(r.bins[i], r.bins[i+1])
|
|
||||||
if minGap > gap {
|
|
||||||
minGap = gap
|
|
||||||
minGapIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev := r.bins[minGapIndex]
|
|
||||||
next := r.bins.remove(minGapIndex + 1)
|
|
||||||
prev.Update(next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func gapWeight(prev, next *Bin) float64 {
|
|
||||||
return next.Mean() - prev.Mean()
|
|
||||||
}
|
|
||||||
38
vendor/github.com/beorn7/perks/histogram/histogram_test.go
generated
vendored
38
vendor/github.com/beorn7/perks/histogram/histogram_test.go
generated
vendored
@@ -1,38 +0,0 @@
|
|||||||
package histogram
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHistogram(t *testing.T) {
|
|
||||||
const numPoints = 1e6
|
|
||||||
const maxBins = 3
|
|
||||||
|
|
||||||
h := New(maxBins)
|
|
||||||
for i := 0; i < numPoints; i++ {
|
|
||||||
f := rand.ExpFloat64()
|
|
||||||
h.Insert(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
bins := h.Bins()
|
|
||||||
if g := len(bins); g > maxBins {
|
|
||||||
t.Fatalf("got %d bins, wanted <= %d", g, maxBins)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, b := range bins {
|
|
||||||
t.Logf("%+v", b)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g := count(h.Bins()); g != numPoints {
|
|
||||||
t.Fatalf("binned %d points, wanted %d", g, numPoints)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func count(bins Bins) int {
|
|
||||||
binCounts := 0
|
|
||||||
for _, b := range bins {
|
|
||||||
binCounts += b.Count
|
|
||||||
}
|
|
||||||
return binCounts
|
|
||||||
}
|
|
||||||
63
vendor/github.com/beorn7/perks/quantile/bench_test.go
generated
vendored
63
vendor/github.com/beorn7/perks/quantile/bench_test.go
generated
vendored
@@ -1,63 +0,0 @@
|
|||||||
package quantile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkInsertTargeted(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
|
|
||||||
s := NewTargeted(Targets)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := float64(0); i < float64(b.N); i++ {
|
|
||||||
s.Insert(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInsertTargetedSmallEpsilon(b *testing.B) {
|
|
||||||
s := NewTargeted(TargetsSmallEpsilon)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := float64(0); i < float64(b.N); i++ {
|
|
||||||
s.Insert(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInsertBiased(b *testing.B) {
|
|
||||||
s := NewLowBiased(0.01)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := float64(0); i < float64(b.N); i++ {
|
|
||||||
s.Insert(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInsertBiasedSmallEpsilon(b *testing.B) {
|
|
||||||
s := NewLowBiased(0.0001)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := float64(0); i < float64(b.N); i++ {
|
|
||||||
s.Insert(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkQuery(b *testing.B) {
|
|
||||||
s := NewTargeted(Targets)
|
|
||||||
for i := float64(0); i < 1e6; i++ {
|
|
||||||
s.Insert(i)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
n := float64(b.N)
|
|
||||||
for i := float64(0); i < n; i++ {
|
|
||||||
s.Query(i / n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkQuerySmallEpsilon(b *testing.B) {
|
|
||||||
s := NewTargeted(TargetsSmallEpsilon)
|
|
||||||
for i := float64(0); i < 1e6; i++ {
|
|
||||||
s.Insert(i)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
n := float64(b.N)
|
|
||||||
for i := float64(0); i < n; i++ {
|
|
||||||
s.Query(i / n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
121
vendor/github.com/beorn7/perks/quantile/example_test.go
generated
vendored
121
vendor/github.com/beorn7/perks/quantile/example_test.go
generated
vendored
@@ -1,121 +0,0 @@
|
|||||||
// +build go1.1
|
|
||||||
|
|
||||||
package quantile_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/beorn7/perks/quantile"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Example_simple() {
|
|
||||||
ch := make(chan float64)
|
|
||||||
go sendFloats(ch)
|
|
||||||
|
|
||||||
// Compute the 50th, 90th, and 99th percentile.
|
|
||||||
q := quantile.NewTargeted(map[float64]float64{
|
|
||||||
0.50: 0.005,
|
|
||||||
0.90: 0.001,
|
|
||||||
0.99: 0.0001,
|
|
||||||
})
|
|
||||||
for v := range ch {
|
|
||||||
q.Insert(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("perc50:", q.Query(0.50))
|
|
||||||
fmt.Println("perc90:", q.Query(0.90))
|
|
||||||
fmt.Println("perc99:", q.Query(0.99))
|
|
||||||
fmt.Println("count:", q.Count())
|
|
||||||
// Output:
|
|
||||||
// perc50: 5
|
|
||||||
// perc90: 16
|
|
||||||
// perc99: 223
|
|
||||||
// count: 2388
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_mergeMultipleStreams() {
|
|
||||||
// Scenario:
|
|
||||||
// We have multiple database shards. On each shard, there is a process
|
|
||||||
// collecting query response times from the database logs and inserting
|
|
||||||
// them into a Stream (created via NewTargeted(0.90)), much like the
|
|
||||||
// Simple example. These processes expose a network interface for us to
|
|
||||||
// ask them to serialize and send us the results of their
|
|
||||||
// Stream.Samples so we may Merge and Query them.
|
|
||||||
//
|
|
||||||
// NOTES:
|
|
||||||
// * These sample sets are small, allowing us to get them
|
|
||||||
// across the network much faster than sending the entire list of data
|
|
||||||
// points.
|
|
||||||
//
|
|
||||||
// * For this to work correctly, we must supply the same quantiles
|
|
||||||
// a priori the process collecting the samples supplied to NewTargeted,
|
|
||||||
// even if we do not plan to query them all here.
|
|
||||||
ch := make(chan quantile.Samples)
|
|
||||||
getDBQuerySamples(ch)
|
|
||||||
q := quantile.NewTargeted(map[float64]float64{0.90: 0.001})
|
|
||||||
for samples := range ch {
|
|
||||||
q.Merge(samples)
|
|
||||||
}
|
|
||||||
fmt.Println("perc90:", q.Query(0.90))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_window() {
|
|
||||||
// Scenario: We want the 90th, 95th, and 99th percentiles for each
|
|
||||||
// minute.
|
|
||||||
|
|
||||||
ch := make(chan float64)
|
|
||||||
go sendStreamValues(ch)
|
|
||||||
|
|
||||||
tick := time.NewTicker(1 * time.Minute)
|
|
||||||
q := quantile.NewTargeted(map[float64]float64{
|
|
||||||
0.90: 0.001,
|
|
||||||
0.95: 0.0005,
|
|
||||||
0.99: 0.0001,
|
|
||||||
})
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case t := <-tick.C:
|
|
||||||
flushToDB(t, q.Samples())
|
|
||||||
q.Reset()
|
|
||||||
case v := <-ch:
|
|
||||||
q.Insert(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendStreamValues(ch chan float64) {
|
|
||||||
// Use your imagination
|
|
||||||
}
|
|
||||||
|
|
||||||
func flushToDB(t time.Time, samples quantile.Samples) {
|
|
||||||
// Use your imagination
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a stub for the above example. In reality this would hit the remote
|
|
||||||
// servers via http or something like it.
|
|
||||||
func getDBQuerySamples(ch chan quantile.Samples) {}
|
|
||||||
|
|
||||||
func sendFloats(ch chan<- float64) {
|
|
||||||
f, err := os.Open("exampledata.txt")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
sc := bufio.NewScanner(f)
|
|
||||||
for sc.Scan() {
|
|
||||||
b := sc.Bytes()
|
|
||||||
v, err := strconv.ParseFloat(string(b), 64)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
ch <- v
|
|
||||||
}
|
|
||||||
if sc.Err() != nil {
|
|
||||||
log.Fatal(sc.Err())
|
|
||||||
}
|
|
||||||
close(ch)
|
|
||||||
}
|
|
||||||
215
vendor/github.com/beorn7/perks/quantile/stream_test.go
generated
vendored
215
vendor/github.com/beorn7/perks/quantile/stream_test.go
generated
vendored
@@ -1,215 +0,0 @@
|
|||||||
package quantile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"math/rand"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Targets = map[float64]float64{
|
|
||||||
0.01: 0.001,
|
|
||||||
0.10: 0.01,
|
|
||||||
0.50: 0.05,
|
|
||||||
0.90: 0.01,
|
|
||||||
0.99: 0.001,
|
|
||||||
}
|
|
||||||
TargetsSmallEpsilon = map[float64]float64{
|
|
||||||
0.01: 0.0001,
|
|
||||||
0.10: 0.001,
|
|
||||||
0.50: 0.005,
|
|
||||||
0.90: 0.001,
|
|
||||||
0.99: 0.0001,
|
|
||||||
}
|
|
||||||
LowQuantiles = []float64{0.01, 0.1, 0.5}
|
|
||||||
HighQuantiles = []float64{0.99, 0.9, 0.5}
|
|
||||||
)
|
|
||||||
|
|
||||||
const RelativeEpsilon = 0.01
|
|
||||||
|
|
||||||
func verifyPercsWithAbsoluteEpsilon(t *testing.T, a []float64, s *Stream) {
|
|
||||||
sort.Float64s(a)
|
|
||||||
for quantile, epsilon := range Targets {
|
|
||||||
n := float64(len(a))
|
|
||||||
k := int(quantile * n)
|
|
||||||
if k < 1 {
|
|
||||||
k = 1
|
|
||||||
}
|
|
||||||
lower := int((quantile - epsilon) * n)
|
|
||||||
if lower < 1 {
|
|
||||||
lower = 1
|
|
||||||
}
|
|
||||||
upper := int(math.Ceil((quantile + epsilon) * n))
|
|
||||||
if upper > len(a) {
|
|
||||||
upper = len(a)
|
|
||||||
}
|
|
||||||
w, min, max := a[k-1], a[lower-1], a[upper-1]
|
|
||||||
if g := s.Query(quantile); g < min || g > max {
|
|
||||||
t.Errorf("q=%f: want %v [%f,%f], got %v", quantile, w, min, max, g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyLowPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) {
|
|
||||||
sort.Float64s(a)
|
|
||||||
for _, qu := range LowQuantiles {
|
|
||||||
n := float64(len(a))
|
|
||||||
k := int(qu * n)
|
|
||||||
|
|
||||||
lowerRank := int((1 - RelativeEpsilon) * qu * n)
|
|
||||||
upperRank := int(math.Ceil((1 + RelativeEpsilon) * qu * n))
|
|
||||||
w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1]
|
|
||||||
if g := s.Query(qu); g < min || g > max {
|
|
||||||
t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyHighPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) {
|
|
||||||
sort.Float64s(a)
|
|
||||||
for _, qu := range HighQuantiles {
|
|
||||||
n := float64(len(a))
|
|
||||||
k := int(qu * n)
|
|
||||||
|
|
||||||
lowerRank := int((1 - (1+RelativeEpsilon)*(1-qu)) * n)
|
|
||||||
upperRank := int(math.Ceil((1 - (1-RelativeEpsilon)*(1-qu)) * n))
|
|
||||||
w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1]
|
|
||||||
if g := s.Query(qu); g < min || g > max {
|
|
||||||
t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func populateStream(s *Stream) []float64 {
|
|
||||||
a := make([]float64, 0, 1e5+100)
|
|
||||||
for i := 0; i < cap(a); i++ {
|
|
||||||
v := rand.NormFloat64()
|
|
||||||
// Add 5% asymmetric outliers.
|
|
||||||
if i%20 == 0 {
|
|
||||||
v = v*v + 1
|
|
||||||
}
|
|
||||||
s.Insert(v)
|
|
||||||
a = append(a, v)
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTargetedQuery(t *testing.T) {
|
|
||||||
rand.Seed(42)
|
|
||||||
s := NewTargeted(Targets)
|
|
||||||
a := populateStream(s)
|
|
||||||
verifyPercsWithAbsoluteEpsilon(t, a, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTargetedQuerySmallSampleSize(t *testing.T) {
|
|
||||||
rand.Seed(42)
|
|
||||||
s := NewTargeted(TargetsSmallEpsilon)
|
|
||||||
a := []float64{1, 2, 3, 4, 5}
|
|
||||||
for _, v := range a {
|
|
||||||
s.Insert(v)
|
|
||||||
}
|
|
||||||
verifyPercsWithAbsoluteEpsilon(t, a, s)
|
|
||||||
// If not yet flushed, results should be precise:
|
|
||||||
if !s.flushed() {
|
|
||||||
for φ, want := range map[float64]float64{
|
|
||||||
0.01: 1,
|
|
||||||
0.10: 1,
|
|
||||||
0.50: 3,
|
|
||||||
0.90: 5,
|
|
||||||
0.99: 5,
|
|
||||||
} {
|
|
||||||
if got := s.Query(φ); got != want {
|
|
||||||
t.Errorf("want %f for φ=%f, got %f", want, φ, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLowBiasedQuery(t *testing.T) {
|
|
||||||
rand.Seed(42)
|
|
||||||
s := NewLowBiased(RelativeEpsilon)
|
|
||||||
a := populateStream(s)
|
|
||||||
verifyLowPercsWithRelativeEpsilon(t, a, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHighBiasedQuery(t *testing.T) {
|
|
||||||
rand.Seed(42)
|
|
||||||
s := NewHighBiased(RelativeEpsilon)
|
|
||||||
a := populateStream(s)
|
|
||||||
verifyHighPercsWithRelativeEpsilon(t, a, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BrokenTestTargetedMerge is broken, see Merge doc comment.
|
|
||||||
func BrokenTestTargetedMerge(t *testing.T) {
|
|
||||||
rand.Seed(42)
|
|
||||||
s1 := NewTargeted(Targets)
|
|
||||||
s2 := NewTargeted(Targets)
|
|
||||||
a := populateStream(s1)
|
|
||||||
a = append(a, populateStream(s2)...)
|
|
||||||
s1.Merge(s2.Samples())
|
|
||||||
verifyPercsWithAbsoluteEpsilon(t, a, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BrokenTestLowBiasedMerge is broken, see Merge doc comment.
|
|
||||||
func BrokenTestLowBiasedMerge(t *testing.T) {
|
|
||||||
rand.Seed(42)
|
|
||||||
s1 := NewLowBiased(RelativeEpsilon)
|
|
||||||
s2 := NewLowBiased(RelativeEpsilon)
|
|
||||||
a := populateStream(s1)
|
|
||||||
a = append(a, populateStream(s2)...)
|
|
||||||
s1.Merge(s2.Samples())
|
|
||||||
verifyLowPercsWithRelativeEpsilon(t, a, s2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BrokenTestHighBiasedMerge is broken, see Merge doc comment.
|
|
||||||
func BrokenTestHighBiasedMerge(t *testing.T) {
|
|
||||||
rand.Seed(42)
|
|
||||||
s1 := NewHighBiased(RelativeEpsilon)
|
|
||||||
s2 := NewHighBiased(RelativeEpsilon)
|
|
||||||
a := populateStream(s1)
|
|
||||||
a = append(a, populateStream(s2)...)
|
|
||||||
s1.Merge(s2.Samples())
|
|
||||||
verifyHighPercsWithRelativeEpsilon(t, a, s2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUncompressed(t *testing.T) {
|
|
||||||
q := NewTargeted(Targets)
|
|
||||||
for i := 100; i > 0; i-- {
|
|
||||||
q.Insert(float64(i))
|
|
||||||
}
|
|
||||||
if g := q.Count(); g != 100 {
|
|
||||||
t.Errorf("want count 100, got %d", g)
|
|
||||||
}
|
|
||||||
// Before compression, Query should have 100% accuracy.
|
|
||||||
for quantile := range Targets {
|
|
||||||
w := quantile * 100
|
|
||||||
if g := q.Query(quantile); g != w {
|
|
||||||
t.Errorf("want %f, got %f", w, g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUncompressedSamples(t *testing.T) {
|
|
||||||
q := NewTargeted(map[float64]float64{0.99: 0.001})
|
|
||||||
for i := 1; i <= 100; i++ {
|
|
||||||
q.Insert(float64(i))
|
|
||||||
}
|
|
||||||
if g := q.Samples().Len(); g != 100 {
|
|
||||||
t.Errorf("want count 100, got %d", g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUncompressedOne(t *testing.T) {
|
|
||||||
q := NewTargeted(map[float64]float64{0.99: 0.01})
|
|
||||||
q.Insert(3.14)
|
|
||||||
if g := q.Query(0.90); g != 3.14 {
|
|
||||||
t.Error("want PI, got", g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDefaults(t *testing.T) {
|
|
||||||
if g := NewTargeted(map[float64]float64{0.99: 0.001}).Query(0.99); g != 0 {
|
|
||||||
t.Errorf("want 0, got %f", g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
90
vendor/github.com/beorn7/perks/topk/topk.go
generated
vendored
90
vendor/github.com/beorn7/perks/topk/topk.go
generated
vendored
@@ -1,90 +0,0 @@
|
|||||||
package topk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// http://www.cs.ucsb.edu/research/tech_reports/reports/2005-23.pdf
|
|
||||||
|
|
||||||
type Element struct {
|
|
||||||
Value string
|
|
||||||
Count int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Samples []*Element
|
|
||||||
|
|
||||||
func (sm Samples) Len() int {
|
|
||||||
return len(sm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm Samples) Less(i, j int) bool {
|
|
||||||
return sm[i].Count < sm[j].Count
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm Samples) Swap(i, j int) {
|
|
||||||
sm[i], sm[j] = sm[j], sm[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stream struct {
|
|
||||||
k int
|
|
||||||
mon map[string]*Element
|
|
||||||
|
|
||||||
// the minimum Element
|
|
||||||
min *Element
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(k int) *Stream {
|
|
||||||
s := new(Stream)
|
|
||||||
s.k = k
|
|
||||||
s.mon = make(map[string]*Element)
|
|
||||||
s.min = &Element{}
|
|
||||||
|
|
||||||
// Track k+1 so that less frequenet items contended for that spot,
|
|
||||||
// resulting in k being more accurate.
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) Insert(x string) {
|
|
||||||
s.insert(&Element{x, 1})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) Merge(sm Samples) {
|
|
||||||
for _, e := range sm {
|
|
||||||
s.insert(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) insert(in *Element) {
|
|
||||||
e := s.mon[in.Value]
|
|
||||||
if e != nil {
|
|
||||||
e.Count++
|
|
||||||
} else {
|
|
||||||
if len(s.mon) < s.k+1 {
|
|
||||||
e = &Element{in.Value, in.Count}
|
|
||||||
s.mon[in.Value] = e
|
|
||||||
} else {
|
|
||||||
e = s.min
|
|
||||||
delete(s.mon, e.Value)
|
|
||||||
e.Value = in.Value
|
|
||||||
e.Count += in.Count
|
|
||||||
s.min = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if e.Count < s.min.Count {
|
|
||||||
s.min = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) Query() Samples {
|
|
||||||
var sm Samples
|
|
||||||
for _, e := range s.mon {
|
|
||||||
sm = append(sm, e)
|
|
||||||
}
|
|
||||||
sort.Sort(sort.Reverse(sm))
|
|
||||||
|
|
||||||
if len(sm) < s.k {
|
|
||||||
return sm
|
|
||||||
}
|
|
||||||
|
|
||||||
return sm[:s.k]
|
|
||||||
}
|
|
||||||
57
vendor/github.com/beorn7/perks/topk/topk_test.go
generated
vendored
57
vendor/github.com/beorn7/perks/topk/topk_test.go
generated
vendored
@@ -1,57 +0,0 @@
|
|||||||
package topk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTopK(t *testing.T) {
|
|
||||||
stream := New(10)
|
|
||||||
ss := []*Stream{New(10), New(10), New(10)}
|
|
||||||
m := make(map[string]int)
|
|
||||||
for _, s := range ss {
|
|
||||||
for i := 0; i < 1e6; i++ {
|
|
||||||
v := fmt.Sprintf("%x", int8(rand.ExpFloat64()))
|
|
||||||
s.Insert(v)
|
|
||||||
m[v]++
|
|
||||||
}
|
|
||||||
stream.Merge(s.Query())
|
|
||||||
}
|
|
||||||
|
|
||||||
var sm Samples
|
|
||||||
for x, s := range m {
|
|
||||||
sm = append(sm, &Element{x, s})
|
|
||||||
}
|
|
||||||
sort.Sort(sort.Reverse(sm))
|
|
||||||
|
|
||||||
g := stream.Query()
|
|
||||||
if len(g) != 10 {
|
|
||||||
t.Fatalf("got %d, want 10", len(g))
|
|
||||||
}
|
|
||||||
for i, e := range g {
|
|
||||||
if sm[i].Value != e.Value {
|
|
||||||
t.Errorf("at %d: want %q, got %q", i, sm[i].Value, e.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQuery(t *testing.T) {
|
|
||||||
queryTests := []struct {
|
|
||||||
value string
|
|
||||||
expected int
|
|
||||||
}{
|
|
||||||
{"a", 1},
|
|
||||||
{"b", 2},
|
|
||||||
{"c", 2},
|
|
||||||
}
|
|
||||||
|
|
||||||
stream := New(2)
|
|
||||||
for _, tt := range queryTests {
|
|
||||||
stream.Insert(tt.value)
|
|
||||||
if n := len(stream.Query()); n != tt.expected {
|
|
||||||
t.Errorf("want %d, got %d", tt.expected, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.x"
|
||||||
|
- master
|
||||||
|
env:
|
||||||
|
- TAGS=""
|
||||||
|
- TAGS="-tags purego"
|
||||||
|
script: go test $TAGS -v ./...
|
||||||
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
Normal file
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Copyright (c) 2016 Caleb Spare
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
67
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
Normal file
67
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# xxhash
|
||||||
|
|
||||||
|
[](https://godoc.org/github.com/cespare/xxhash)
|
||||||
|
[](https://travis-ci.org/cespare/xxhash)
|
||||||
|
|
||||||
|
xxhash is a Go implementation of the 64-bit
|
||||||
|
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
||||||
|
high-quality hashing algorithm that is much faster than anything in the Go
|
||||||
|
standard library.
|
||||||
|
|
||||||
|
This package provides a straightforward API:
|
||||||
|
|
||||||
|
```
|
||||||
|
func Sum64(b []byte) uint64
|
||||||
|
func Sum64String(s string) uint64
|
||||||
|
type Digest struct{ ... }
|
||||||
|
func New() *Digest
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Digest` type implements hash.Hash64. Its key methods are:
|
||||||
|
|
||||||
|
```
|
||||||
|
func (*Digest) Write([]byte) (int, error)
|
||||||
|
func (*Digest) WriteString(string) (int, error)
|
||||||
|
func (*Digest) Sum64() uint64
|
||||||
|
```
|
||||||
|
|
||||||
|
This implementation provides a fast pure-Go implementation and an even faster
|
||||||
|
assembly implementation for amd64.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
This package is in a module and the latest code is in version 2 of the module.
|
||||||
|
You need a version of Go with at least "minimal module compatibility" to use
|
||||||
|
github.com/cespare/xxhash/v2:
|
||||||
|
|
||||||
|
* 1.9.7+ for Go 1.9
|
||||||
|
* 1.10.3+ for Go 1.10
|
||||||
|
* Go 1.11 or later
|
||||||
|
|
||||||
|
I recommend using the latest release of Go.
|
||||||
|
|
||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
Here are some quick benchmarks comparing the pure-Go and assembly
|
||||||
|
implementations of Sum64.
|
||||||
|
|
||||||
|
| input size | purego | asm |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
||||||
|
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
||||||
|
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
||||||
|
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
||||||
|
|
||||||
|
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
||||||
|
the following commands under Go 1.11.2:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||||
|
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Projects using this package
|
||||||
|
|
||||||
|
- [InfluxDB](https://github.com/influxdata/influxdb)
|
||||||
|
- [Prometheus](https://github.com/prometheus/prometheus)
|
||||||
|
- [FreeCache](https://github.com/coocood/freecache)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user