Compare commits

...

489 Commits

Author SHA1 Message Date
Luke Powlett
8a40b6a5dd Curl manifest tool 2019-12-06 14:23:17 +00:00
Luke Powlett
dd62bc39f4 Release changes for dockerhub/store 2019-12-06 14:02:56 +00:00
Luke J Powlett
61c909f551 Override default makefile image name and tag for release (#46)
* Override default makefile image name and tag for release
2019-12-05 18:31:02 +00:00
Luke J Powlett
ffda647cdf Fixed docker images labels (#45) 2019-12-05 16:07:11 +00:00
Luke Powlett
5897d6a644 Update the license information in the readme 2019-12-05 11:44:33 +00:00
Luke J Powlett
34f7a57c5d Pipeline changes for travis release (#43)
* Added changes for travis release process

* Renamed build scripts directory

* Don't run basic build if tag is set

* Pull production images from staging on production-release
2019-12-04 19:45:57 +00:00
Luke Powlett
5b5951ec3c Changed sed for password minlen replacement due to change in UBI8 2019-12-04 10:18:23 +00:00
Amrit K Kandola
b20761cea0 Removed error code logic and replaced with library function (#39)
* Removed error code logic and replaced with library function

* Added the gosecignore comment to prevent gosec failing
2019-12-03 16:13:36 +00:00
Amrit K Kandola
5449622d2a Remove developer listener and remove actions to stop and alter system listener (#41) 2019-12-03 16:13:00 +00:00
Luke J Powlett
dd31fb37c3 Changes for MQ 9.1.4.0 (#37)
* Changes for MQ 9.1.4.0

* Only run p and z builds for production build
2019-12-03 15:58:02 +00:00
Stephen Marshall
2e453f2257 Fix web certificate for dev image 2019-12-03 15:24:05 +00:00
Luke J Powlett
1f4528d597 Pipeline changes for Entitled Registry (#38)
* Added makefile targets/variables to pull mq archive from remote

* Updated makefile and travis build for multi arch dev/prod builds

* Updated build deps to use arch specific dep

* Removed glide for dependency management

* Removed `MQ_SDK_ARCHIVE` download target

* Make ARCH overridable in makefile

* Only run golden path test on Power and Z builds

* Only run gosec on amd64 build

* Increased go to 1.12 in travis
2019-12-03 13:16:30 +00:00
Amrit Kandola
c83aeb17c0 Updated toolset 2019-11-28 11:30:27 +00:00
Amrit K Kandola
5a18280057 Updated UBI to UBI8 (#35)
* Updated UBI to UBI8

* Updated the README to include the redhat login

* Updated to use non-deprecated registry

* Added sed filter into docker file to remove ubi7

* Added automatic login into the makefile based on env variables, also removed nodocs from mq-explorer

* Minor typo fix
2019-11-27 09:32:38 +00:00
Amrit K Kandola
8e380b94f4 Closes #242 - update jmstests to use latest version (#33)
* Closes #242 - update jmstests to use latest version
* added class files to git ignore
2019-10-23 15:59:04 +01:00
Stephen Marshall
ebe8b7a6f0 Add required security settings when creating self-signed certificates 2019-10-21 13:13:00 +01:00
Stephen Marshall
ed4466d934 Remove iFrame support, now using header-as-a-service 2019-10-17 17:31:09 +01:00
Luke Powlett
37601187b2 Removed release from makefile, will be set on internal build only 2019-10-11 10:48:20 +01:00
Luke Powlett
366d406f57 Updated manifest for r3 fix release 2019-10-03 15:06:41 +01:00
Arthur Barr
68ad98fc49 Enable INI merging 2019-09-30 14:37:40 +01:00
Luke Powlett
65edac267e Removed ARGs for go-toolset 2019-09-27 13:20:04 +01:00
Arthur Barr
ad0046ab01 Fix gosec for writeFileIfChanged 2019-09-26 16:47:48 +01:00
Arthur Barr
c3fbc5816e Only write INI file if changed 2019-09-26 16:47:48 +01:00
Luke Powlett
11890d887b Added args for go toolset image and tag, fixed issue with logger 2019-09-23 17:08:40 +01:00
Arthur Barr
ac50d46c78 Don't call INI merging code 2019-09-19 11:03:40 +01:00
Arthur Barr
de298a4aad Don't run dspmqinf before crtmqdir 2019-09-19 09:29:04 +01:00
KIRAN DARBHA
4de32ab8d2 fix for double merge issue
update unit-test data

fix gosec

fix gosec

fix gosec
2019-09-18 16:36:47 +01:00
Arthur Barr
8505579b37 Move some packages to pkg directory 2019-09-17 11:08:42 +01:00
Luke Powlett
7c59d647f5 Added gosec scan to end of travis build, upgraded travis go to v1.11 2019-09-12 16:17:50 +01:00
Luke Powlett
8d8e4e4403 error handling and gosec fixes 2019-09-10 15:22:46 +01:00
Stephen Marshall
52b4eeea32 Fix MIQM 2019-08-30 11:44:45 +01:00
Rob Parker
28291306cb set CipherSpec to ANY_TLS12 and refresh security (#362) 2019-08-29 11:58:51 +01:00
Luke Powlett
4da7c60aee Update to UBI 7.7-98 2019-08-29 11:58:51 +01:00
Arthur Barr
1ae24263ad Temporarily remove Docker 1.12 test in Travis 2019-08-29 11:58:51 +01:00
Arthur Barr
d6248424a1 Use podman build if available 2019-08-29 11:58:51 +01:00
Luke Powlett
455c67ad3d increment release in makefile 2019-08-29 11:58:51 +01:00
Luke Powlett
f6ea588349 release tags in fat manifest 2019-08-06 18:00:33 +01:00
Luke Powlett
60fe631616 specify base image as arg 2019-08-06 11:39:23 +01:00
Luke Powlett
221796f746 build image from specified UBI base tag 2019-08-06 11:39:23 +01:00
KiranDarbha
97941bc87c Add initial support for INI file merging (#349) 2019-08-06 09:17:28 +01:00
LPowlett
b8a7167c4e MQ V9.1.3.0 (#348)
* MQ 9.1.3 changes

* Use crtmqdir -a

* Allow generation of TLS certificate with given hostname

* Remove check for certificate env variable

* Updated manifests and changelog for 913

* Use MQ externals to configure console frame ancestors

* Create /run/mqm

* Go sec fixes

* Set SAN when generating certificates

* Remove image source and commit
2019-07-24 12:01:21 +01:00
LPowlett
dc00231ec1 changelog for v912-UBI (#344)
* changelog for v912-UBI
2019-06-25 10:27:40 +01:00
Rob Parker
8a8ea6c6a9 Merge pull request #336 from mamgainp/windows
Windows
2019-06-13 09:39:10 +01:00
mamgainp
9714d0d513 fixes ifelse ladder 2019-06-12 15:39:41 +01:00
Paras Mamgain
6691438fa1 fixes DOWNLOAD_DIR variable for windows 2019-06-11 15:13:10 +01:00
Paras Mamgain
426c6c3b9a fixes DOWNLOAD_DIR variable for windows 2019-06-11 13:59:38 +01:00
Paras Mamgain
8088cb2902 fixes DOWNLOAD_DIR variable for windows 2019-06-11 13:59:22 +01:00
Rob Parker
a2ce23aa96 Merge pull request #334 from parrobe/capifix
use capicmd for renaming certs
2019-06-10 10:58:24 +01:00
Arthur Barr
95ba16cdb2 Merge branch 'master' into capifix 2019-06-10 10:30:50 +01:00
Rob Parker
83fe77b222 Labels and Licenses for RedHat Certification (#329)
* Add required red hat labels

* Add licenses into correct location for RedHat

* Remove reference to CIP

* PR Comments
2019-06-10 10:29:51 +01:00
Robert Parker
7ab30723cd use capicmd for renaming certs 2019-06-07 16:15:42 +01:00
Stephen Marshall
3f9fc0eaa5 Updates to resolve issues identified by gosec (#330)
* Updates to resolve issues identified by gosec
2019-06-07 11:51:34 +01:00
Arthur Barr
ee4351e55d Remove custom RPM notices file 2019-06-04 15:08:24 +01:00
Rob Parker
ebf55608d7 Merge pull request #324 from parrobe/pwfix
Set password length to meet VA scan requirements
2019-05-31 13:11:40 +01:00
Robert Parker
b3fd5f7562 typos 2019-05-31 11:47:02 +01:00
Robert Parker
3c9ec5f14c Add fix for OIDC error 2019-05-31 11:36:04 +01:00
Robert Parker
81c0b70a6f Set password length to meet VA scan requirements 2019-05-31 10:21:14 +01:00
Robert Parker
a6f307c6b5 Remove openssl 2019-05-30 16:53:27 +01:00
Robert Parker
6f677e2a59 Remove old Integration TLS function 2019-05-30 15:24:48 +01:00
Rob Parker
612fe3a9ec Merge pull request #319 from parrobe/tls
Add TLS Support
2019-05-30 10:40:51 +01:00
Robert Parker
0a9c745d96 PR comments 2019-05-30 10:09:24 +01:00
Robert Parker
b64c060ef4 Refactor TLS code 2019-05-30 09:16:40 +01:00
Robert Parker
8e22763f16 Add TLS Support 2019-05-30 09:16:40 +01:00
Stephen Marshall
40b64e620e Change image tag to amd64 2019-05-30 09:15:45 +01:00
LPowlett
700cc53c07 Handle /var/mqm/ permissions in upgrade to ubi (#316)
* handle /var/mqm/ permissions in upgrade to ubi
2019-05-29 11:40:19 +01:00
Arthur Barr
44d75b169c Remove old icon from README 2019-05-22 16:21:04 +01:00
Rob Parker
c0bf371b9e Merge pull request #314 from parrobe/makefix
Fix makefile targets
2019-05-17 12:53:24 +01:00
Robert Parker
e362644a55 Fix makefile targets 2019-05-17 08:29:32 +01:00
Stephen Marshall
c079c1b60d Merge CIP code 2019-05-16 08:58:02 +01:00
Arthur Barr
4a3bdf3b53 Containerized build 2019-05-10 09:24:36 +01:00
Arthur Barr
5ff269d2e3 Use Universal Base Image 2019-05-10 09:24:36 +01:00
Stephen Marshall
3fb2d3fe61 Fix liveness probe for miqm (#308)
* Fix liveness probe for miqm
2019-05-02 10:16:42 +01:00
Stephen Marshall
6c72c894f7 add multi-instance Queue Managers (#307)
* Initial code to implement multi-instance queue manager

* alter default mqsc to prevent race between listeners on standby startup

* Updates to multi-instance queue manager code

* initial multi instance test

* Multi-instance code improvements

* Multi instance fixes and first test

* configure queue manager

* Add mirror log filtering for mult-instance QMs

* Add log message for multi-instance enabled

* Improvements to container runtime logging

* refactor test

* Test active standby switch

* Improve createQueueManager function

* Test multi instance race

* wait

* multi instance mount tests

* skip race test

* mount tests

* no mount test

* single instance split mount tests

* readiness check

* More updates for handling standby queue manager

* Improve standby checks

* Minor fixes to miqm

* Fix logging of JSON errors

* Update copyrights

* Fix log includes
2019-05-01 14:42:25 +01:00
Rob Parker
63af43f19d Expand redaction system to handle uncommon MQSC cases (#304)
* Expand redaction system to handle uncommon MQSC cases

* add invalidMQSC fixes

* address PR comments
2019-04-17 10:34:29 +01:00
Stephen Marshall
64bb5aed8a Remove debug information 2019-04-12 13:15:02 +01:00
Rob Parker
f05a7d3eaf Merge pull request #300 from sdmarshall79/redact-mqsc-more
Handle multiple-spaces when redacting MQSC output
2019-04-09 15:43:49 +01:00
Stephen Marshall
723fe2b998 Handle multiple-spaces when redacting MQSC output 2019-04-09 15:06:25 +01:00
Stephen Marshall
44d0e0a432 Redact sensitive MQSC logs 2019-04-08 08:49:06 +01:00
LPowlett
33defc0fc9 Handle large mqsc files (#295)
* buffer mqsc input to runmqsc

* imports

* error handling on runmqsc
2019-04-04 16:46:07 +01:00
LPowlett
d69befed71 Version 9.1.2.0 (#294)
* Version 9.1.2.0
2019-03-21 18:25:08 +00:00
Rob Parker
0934289b61 Merge pull request #292 from LPowlett/912-release
912 release manifest update
2019-03-21 16:41:11 +00:00
Luke Powlett
f6231cd51c cert expiry 2019-03-21 16:15:31 +00:00
Luke Powlett
d5f04bc470 copyright notice update 2019-03-21 09:57:59 +00:00
Luke Powlett
d8cbf4566e 9.1.2 manifest update 2019-03-21 09:56:14 +00:00
Rob Parker
493bc7bfd4 Merge pull request #286 from parrobe/gosec
fix gosec failures
2019-03-08 13:36:54 +00:00
Robert Parker
1fa4f6f148 fix gosec failures 2019-03-08 12:59:54 +00:00
Rob Parker
ce664dd654 Merge pull request #285 from parrobe/redistdownload
Fixes for builds
2019-03-08 12:47:11 +00:00
Robert Parker
f8e057a1d6 Fix test breaks from unused code 2019-03-08 11:37:45 +00:00
Robert Parker
efd550822d merge latest from master 2019-03-08 11:13:14 +00:00
Robert Parker
d4df05fd2a Add test fixes and fix mq-explorer build 2019-03-08 11:07:44 +00:00
LPowlett
194b04ac13 Revert MQSC error check (#283)
* Revert MQSC error check
2019-03-08 09:13:26 +00:00
Robert Parker
6848038165 hard code the redist client version 2019-03-06 10:03:38 +00:00
Rob Parker
0d3e177147 Merge pull request #282 from arthurbarr/master
Fix POWER and z/Linux builds
2019-03-06 09:58:15 +00:00
Arthur Barr
13f620f21a Increase test timeouts 2019-03-05 15:08:07 +00:00
Arthur Barr
d4a81741cc Prevent re-download of image during build 2019-03-05 15:07:51 +00:00
Arthur Barr
0047301335 Use Makefile target build-sdk-ex 2019-03-05 11:31:27 +00:00
Arthur Barr
5ef532d2c1 Don't use redist client for Go SDK because of P+Z support 2019-03-05 10:19:21 +00:00
Arthur Barr
281cdc4578 Update RHEL build README 2019-03-05 09:47:58 +00:00
Rob Parker
d68c051104 Merge pull request #280 from parrobe/rhelpackages
Add in system to generate licenses on RHEL
2019-03-04 16:00:49 +00:00
Rob Parker
c5a52e616c Merge branch 'master' into rhelpackages 2019-02-27 15:35:11 +00:00
Arthur Barr
c441de7d26 Fixes for tests on RHEL and test log output 2019-02-27 15:32:34 +00:00
Arthur Barr
a194545f08 Don't add root user into mqm group 2019-02-27 15:32:34 +00:00
Arthur Barr
4f57d1bae2 Tidy up commented code 2019-02-27 15:32:34 +00:00
Arthur Barr
cc0f072908 Change for running as a non-root user (#276)
* Enable running container as mqm

* Fix merge problem

* Don't force root usage

* RHEL image runs as mqm instead of root

* Build on host with SELinux enabled

* Enable building on node in an OpenShift cluster

* Enable running container as mqm

* Fix merge problem

* Don't force root usage

* Merge lastest changes from master

* RHEL image runs as mqm instead of root

* Fix merge issues

* Test changes for non-root

* Make timeout properly, and more non-root test fixes

* Run tests with fewer/no capabilities

* Correct usage docs for non-root

* Add security docs

* Add temporary debug output

* Remove debug code

* Fixes for termination-log

* Allow init container to run as root

* Fixes for CentOS build

* Fixes for RHEL build

* Logging improvements

* Fix Dockerfile RHEL/CentOS build

* Fix bash error

* Make all builds specify UID

* Use redist client for Go SDK

* Inspect image before running tests

* New test for init container

* Log container runtime in runmqdevserver

* Add extra capabilities if using a RHEL image
2019-02-27 15:32:34 +00:00
Robert Parker
d834ac7c9c Add in system to generate licenses on RHEL 2019-02-27 15:06:09 +00:00
Rob Parker
2dbee560fe Merge pull request #272 from parrobe/master
fix dockerfile reference to build explorer
2019-02-12 11:33:20 +00:00
Arthur Barr
17d3238161 Merge branch 'master' into master 2019-02-07 17:07:45 +00:00
Luke Powlett
c08ca2e79f update travis to use Ubuntu 16.04 2019-02-07 16:47:32 +00:00
Rob Parker
84df0e8362 Merge branch 'master' into master 2019-02-07 11:41:51 +00:00
Rob Parker
cc213f429f Merge pull request #273 from arthurbarr/make
Fixes for RHEL build
2019-02-07 11:41:34 +00:00
Rob Parker
c29159dd38 Merge branch 'master' into make 2019-02-07 10:49:02 +00:00
Rob Parker
f345ccf920 Merge branch 'master' into master 2019-02-07 10:48:51 +00:00
Rob Parker
d1b1cfc5d8 Merge pull request #274 from parrobe/golint
Use documented way to install golint
2019-02-07 10:48:39 +00:00
Robert Parker
a19c455ea4 up the copyright date 2019-02-07 10:29:41 +00:00
Robert Parker
694b31d6e8 Use documented way to install golint 2019-02-07 10:09:53 +00:00
Arthur Barr
33f82d76ff Use variable for uid and gid 2019-02-06 16:12:18 +00:00
Arthur Barr
77319629fe Update copyright dates 2019-02-06 16:11:52 +00:00
Arthur Barr
d9c70c48c5 Fix subscription checking logic 2019-02-06 14:23:25 +00:00
Arthur Barr
599f5f4b53 Build on host with SELinux enabled 2019-02-06 13:39:42 +00:00
Arthur Barr
6840a575f9 Fix for building on subscribed and unsubscribed hosts 2019-02-06 13:29:44 +00:00
Robert Parker
1b8c816f57 fix dockerfile reference to build explorer 2019-02-05 15:54:31 +00:00
Arthur Barr
9a8ff9b524 copy sub-directories under /etc/yum.repos.d 2019-02-05 13:53:59 +00:00
Arthur Barr
f3c858184f use correct download files in RHEL build process 2019-02-05 13:51:15 +00:00
LPowlett
43676049b7 RHEL Security Vulnerability Test (#270)
* check for security vulnerabilities on rhel

* import

* check host is red hat

* filepath join

* imports
2019-02-04 10:25:55 +00:00
LPowlett
df6ce917c2 endmqm -r try to reconnect (#268) 2019-01-28 11:03:54 +00:00
Rob Parker
d3eb6e0d3d Merge pull request #267 from arthurbarr/master
RHEL build uses redist client and RHEL minimal
2019-01-25 13:49:46 +00:00
Arthur Barr
2bfdd51a01 RHEL build uses redist client and RHEL minimal 2019-01-24 13:51:10 +00:00
LPowlett
be11b3cda1 Dependancy upgrades (#264)
* dependancy upgrades

* revert dep to 0.4.1

* revert file changes
2019-01-10 14:55:22 +00:00
LPowlett
525ff82fe7 Error checking invalid mqsc commands (#261)
* testRepeatingMqsc

* testInvalidMqsc

* 9.1.1 Makefile

* testRepeatingMqsc

* testInvalidMqsc

* update copyright 2019

* update invalid mqsc error message

* update changelog to reflect MQSC changes
2019-01-10 13:41:43 +00:00
Rob Parker
3e07814bf6 update travis build stages to remove duplicate build and label (#263)
* update travis build stages to remove duplicate build and label

* update copyright to 2019
2019-01-10 10:21:20 +00:00
Rob Parker
b1daacf377 Merge pull request #256 from parrobe/releasetag
Add image tag into info output, add ability to print info output on d…
2018-12-12 13:51:26 +00:00
Robert Parker
9c8b3825be Add image tag into info output, add ability to print info output on demand and prevent multiple instances of runmqserver being run 2018-12-12 13:11:47 +00:00
Rob Parker
4145f077b6 update perl-base to fix security vulnerability (#253) 2018-12-05 13:01:31 +00:00
Robert Parker
c063ddd67d remove deprecated tag manifest 2018-12-03 11:31:24 +00:00
Rob Parker
5f000ff891 Update to IBM MQ version 9.1.1.0 (#251)
* Update to MQ v9.1.1

* update incubating to 911

* check docker version on travis

* travis docker version is now high enough
2018-11-30 17:26:19 +00:00
Luke Powlett
e33710eb00 remove create qm option from console 2018-11-09 17:06:36 +00:00
LPowlett
2fdd2c51ff Merge pull request #244 from parrobe/master
Security fixes, Nov 2018
2018-11-07 13:21:26 +00:00
Robert Parker
b73ad12011 Security fixes, Nov 2018 2018-11-07 11:36:04 +00:00
LPowlett
b276e0b4ef move image builds to before_script (#237) 2018-10-24 09:19:39 +01:00
Robert Parker
a3c0af9648 Add sudo to groupadd 2018-10-18 16:15:07 +01:00
Rob Parker
1208a5d08b add RHEL into the docker tag for RHEL builds (#234) 2018-10-18 13:50:20 +01:00
Robert Parker
fe8a87b39f Fix build failure in RHEL makefile 2018-10-18 11:54:26 +01:00
Arthur Barr
9a34e9b15c Clarify docs and fix links (#226) 2018-10-12 11:26:24 +01:00
Rob Parker
78ce84b3a1 Implement GOSec for security scanning Fix vulnerabilities (#227)
* Implement GOSec for security scanning Fix vulnerabilities

* Fix lint failure

* address PR comments and fix build break

* Fix test break in mqsc
2018-10-11 15:39:22 +01:00
Robert Parker
6d11b0d8ae update apparmor 2018-10-09 10:00:30 +01:00
Arthur Barr
d0fce28ef3 build Ubuntu image on non-RHEL hosts 2018-10-02 13:59:39 +01:00
Arthur Barr
31f604cc47 Document build prereqs for RHEL 2018-10-01 16:20:08 +01:00
Arthur Barr
c6a921efee Tidy up Travis output (#213)
* Ignore generated Prometheus files

* Tidy up Travis output

* Use relative path for script

* Futher tidying of Travis output
2018-10-01 10:14:35 +01:00
Stephen Marshall
822a073c4e Fix RTC ppcle_linux build (#211) 2018-09-21 09:30:53 +01:00
Rob Parker
a854c4c627 explicitly set root user for RHEL containers (#208) 2018-09-12 16:32:39 +01:00
Rob Parker
3989661778 Add Diagnostics (#203)
* Add container suplimentary groups support

* Add diagnostic gathering

* Fix incorrect userid group searching

* one last tiny fix

* one last tiny fix
2018-09-03 17:08:26 +01:00
Robert Parker
9a7d44fef6 Add container suplimentary groups support 2018-09-03 15:01:26 +01:00
Rob Parker
f73347a9cf Merge pull request #201 from parrobe/master
Further RHEL fixes
2018-08-30 09:13:33 +01:00
Robert Parker
ad1b2db1fd Further RHEL fixes 2018-08-29 11:25:44 +01:00
Stephen Marshall
11b94de1c0 Merge pull request #199 from parrobe/master
Various fixes for the RHEL image and tests
2018-08-24 10:07:04 +01:00
Robert Parker
1906896038 Fix TestDevSecure on RHEL 2018-08-24 09:32:41 +01:00
Robert Parker
d5ec1fa505 correct the useradd command 2018-08-23 10:26:28 +01:00
Robert Parker
e03ceff7c9 Fix dev image uid and build off rhel7 2018-08-23 10:16:14 +01:00
Robert Parker
64f5ce3624 specify tag for JMS image 2018-08-21 15:56:56 +01:00
Robert Parker
b921bb82d3 Create RHEL test make targets 2018-08-21 15:40:32 +01:00
Robert Parker
92e57f2cb1 correctly set up volume directory 2018-08-21 14:33:00 +01:00
Robert Parker
0281e52b47 Test fixes for RHEL image 2018-08-21 11:49:56 +01:00
Rob Parker
8bdba41f75 Merge pull request #193 from parrobe/buildah
Restructure makefile to add common targets and auto-detect which target to call when using defaults
2018-08-21 08:53:30 +01:00
Robert Parker
aa04229d85 Call correct make target when using default make targets 2018-08-20 15:50:48 +01:00
Robert Parker
9e04bfc68a Create MQ RHEL buildah build 2018-08-20 15:50:48 +01:00
Robert Parker
8fcdfeb1c4 Move and rename files for RHEL build 2018-08-20 15:50:48 +01:00
Arthur Barr
a2d3abfb86 Minor fixes to buildah build 2018-08-20 15:50:09 +01:00
Arthur Barr
e66bcfd77f Buildah containerized Go build 2018-08-20 15:48:42 +01:00
Rob Parker
d2ea8d4f06 Create IBM MQ RHEL Buildah build (#192)
* Buildah containerized Go build

* Minor fixes to buildah build

* Move and rename files for RHEL build

* Create MQ RHEL buildah build
2018-08-20 13:49:10 +01:00
Stephen Marshall
fc19776c04 Fix lint error 2018-08-13 12:31:47 +01:00
Arthur Barr
3f07b1e77f Fix logo in README 2018-08-07 15:51:02 +01:00
Arthur Barr
00568adc6d Remove unused variable in Dockerfiles 2018-08-07 15:15:45 +01:00
Arthur Barr
ba1b4f8ef9 Remove debug statements 2018-08-07 15:15:45 +01:00
Arthur Barr
9b98555886 Enable only app user to do REST messaging 2018-08-07 15:15:45 +01:00
Arthur Barr
dbfc47591e Fix Mac incompatibility of image creation date 2018-08-07 15:15:45 +01:00
Arthur Barr
b087f37505 Add master branch warning to README 2018-08-07 15:15:45 +01:00
Arthur Barr
08299dd0d1 Enable admin and app users to do REST messaging 2018-08-07 15:15:45 +01:00
Rob Parker
b8f96d0148 Merge pull request #181 from parrobe/master
make sure to use -aG not -G
2018-08-06 10:46:04 +01:00
Robert Parker
6bb669d6ac make sure to use -aG not -G 2018-08-06 10:16:23 +01:00
Rob Parker
80384a65a2 force string output in chkmqhealthy (#174) 2018-08-02 13:53:22 +01:00
Rob Parker
c11c0a2bf4 check explicitly for /mnt/mqm (#175) 2018-08-02 11:42:14 +01:00
Rob Parker
29dfe38d32 Merge pull request #176 from parrobe/dlfix
only download the sdk image if we need to
2018-07-27 13:31:15 +01:00
Robert Parker
89eae35724 only download the sdk image if we need to 2018-07-27 12:23:08 +01:00
Robert Parker
b751640b79 Update license to 9.1 2018-07-25 12:37:09 +01:00
Rob Parker
0bef0e224e Merge pull request #165 from parrobe/9.1prep
9.1 updates
2018-07-23 15:51:02 +01:00
Robert Parker
7166727528 address Arthurs PR comments 2018-07-23 15:31:31 +01:00
Robert Parker
cafa841f63 remove centos build 2018-07-23 15:05:28 +01:00
Robert Parker
f2a9bb4e9d 9.1 updates 2018-07-23 11:20:30 +01:00
Rob Parker
e4f02d55cf Use v2.0.0 of mq-golang now it has been created (#159)
* Use v2.0.0 of mq-golang now it has been created

* do a strip vendor
2018-07-13 10:51:54 +01:00
Rob Parker
59eaa9c7d2 Merge pull request #158 from parrobe/master
Build SDK with same archive as Dev image
2018-07-12 11:04:57 +01:00
Robert Parker
79bfd99911 Build SDK with same archive as Dev image 2018-07-12 10:36:56 +01:00
Rob Parker
5583cc6fac Merge pull request #157 from parrobe/master
Fix method to get git repo
2018-07-11 16:49:45 +01:00
Robert Parker
75efeae51b Fix method to get git repo 2018-07-11 16:12:43 +01:00
Rob Parker
7822c2c3bc Add basic versioning into main golang file (#151)
* Add basic versioning into main golang file

* Add versioning set test

* address Arthur's comments
2018-07-05 11:44:16 +01:00
Rob Parker
f0e681e23f Merge pull request #150 from parrobe/master
Allow building of latest versions
2018-07-03 14:21:09 +01:00
Rob Parker
4b1b417b8b default SDK build tag 2018-07-03 13:45:28 +01:00
Rob Parker
be0ce898d7 Allow building of latest versions 2018-07-03 10:36:30 +01:00
Rob Parker
1800482934 Ensure SDK is downloaded when versions are different (#149) 2018-06-29 11:12:25 +01:00
Rob Parker
65449ffea8 Merge pull request #145 from sdmarshall79/master
Master - Security upgrade for gcc-5-base & libstdc++6
2018-06-28 12:59:44 +01:00
Stephen Marshall
3a2efabdb7 Security upgrade for gcc-5-base & libstdc++6 2018-06-28 12:14:30 +01:00
Stephen Marshall
bf330ee926 Merge pull request #143 from parrobe/sdkv
Add seperate SDK version number
2018-06-28 10:05:05 +01:00
Rob Parker
fcbb241f07 Add seperate SDK version number 2018-06-27 10:49:57 +01:00
Rob Parker
1e2ced3594 Merge pull request #134 from parrobe/master
Fix MQ Developer scripts to allow centos image building
2018-06-27 10:49:12 +01:00
Rob Parker
626fc05d78 correct comment in Makefile 2018-06-26 15:51:56 +01:00
Rob Parker
ea7105c82c Fix MQ Developer scripts to allow centos image building 2018-06-26 15:51:56 +01:00
Stephen Marshall
5c176cce15 Merge pull request #142 from sdmarshall79/disable-metric
Disable metric system_ram_size_bytes
2018-06-26 14:40:41 +01:00
Stephen Marshall
854a0119de Disable metric system_ram_size_bytes 2018-06-26 13:40:56 +01:00
Stephen Marshall
4d4051312e Merge pull request #141 from arthurbarr/master
Improvements for RHEL-based images
2018-06-26 12:52:18 +01:00
Arthur Barr
4ad8f269ee Make AppArmor message applicabel to SELinux too 2018-06-26 11:07:03 +01:00
Arthur Barr
9624d7eeb0 Merge remote-tracking branch 'upstream/master' 2018-06-26 10:26:40 +01:00
Stephen Marshall
7f51184821 Merge pull request #137 from sdmarshall79/remove-watermark-metrics
Remove watermark metrics
2018-06-25 17:32:50 +01:00
Arthur Barr
62c7516465 Merge branch 'master' into remove-watermark-metrics 2018-06-25 15:47:11 +01:00
Stephen Marshall
ecace2b033 Change package security updates to use install 2018-06-25 15:46:33 +01:00
Stephen Marshall
5a63591b18 Remove watermark metrics 2018-06-25 12:13:11 +01:00
Stephen Marshall
29dcccad32 Merge pull request #135 from sdmarshall79/metrics-counter
Change delta type metrics to counters
2018-06-21 09:25:13 +01:00
Rob Parker
0769ebd309 Merge branch 'master' into metrics-counter 2018-06-20 15:32:05 +01:00
Rob Parker
1358b32f66 Merge pull request #133 from riccardobiraghi/master
Extend fs type list for linux
2018-06-20 15:30:50 +01:00
Stephen Marshall
4ec2887047 Security upgrade for libgcrypt20 2018-06-20 15:21:31 +01:00
Stephen Marshall
74659dbf59 Change delta type metrics to counters 2018-06-20 14:49:09 +01:00
Riccardo Biraghi
0b9a9186cf Extend fs type list for linux 2018-06-20 10:30:28 +01:00
Rob Parker
cd46078d2a Merge pull request #132 from riccardobiraghi/master
Add sfx filesystem and unknown fs handling
2018-06-19 16:26:10 +01:00
Riccardo Biraghi
0f9cd3f204 Add sfx filesystem and unknown fs handling 2018-06-19 15:28:28 +01:00
Rob Parker
bff2f6bfae Merge pull request #131 from sdmarshall79/metrics-names
Update metric names and allow skipping of specific metrics
2018-06-18 16:00:42 +01:00
Stephen Marshall
a1ae6b3a97 Improve metrics name mapping code 2018-06-18 14:28:46 +01:00
Stephen Marshall
2e0aad0318 Update metric names and allow skipping of specific metrics 2018-06-18 13:28:49 +01:00
Arthur Barr
d6f689d515 Initial RHEL image build 2018-06-14 16:51:41 +01:00
Stephen Marshall
4984beb139 Merge pull request #127 from sdmarshall79/metrics-doc
Doc changes for metrics
2018-06-14 15:35:48 +01:00
Rob Parker
6ded21daac Merge branch 'master' into metrics-doc 2018-06-14 14:22:04 +01:00
Rob Parker
32a3fdf2fd Merge pull request #124 from riccardobiraghi/master
Fix ExecContainer executing commands twice (master)
2018-06-14 14:20:30 +01:00
Stephen Marshall
616cb179d6 Doc changes for metrics 2018-06-14 12:51:16 +01:00
Riccardo Biraghi
d4d5e09a02 Add waitForReady to TestCorrectLicense 2018-06-14 12:41:06 +01:00
Riccardo Biraghi
16e244427b Fix timing in execContainer 2018-06-14 11:55:15 +01:00
Rob Parker
f0faac6af7 Merge branch 'master' into master 2018-06-14 10:12:26 +01:00
Rob Parker
aaa86d65e5 Merge pull request #122 from arthurbarr/master
Add manifests, and improve tests
2018-06-14 09:54:36 +01:00
Riccardo Biraghi
b887c1a277 Fix ExecContainer executing commands twice 2018-06-13 17:45:27 +01:00
Rob Parker
4660c0622c Merge branch 'master' into master 2018-06-13 16:52:57 +01:00
Rob Parker
b570a9f019 Add License test to verify correct license 2018-06-13 16:52:24 +01:00
Arthur Barr
9805c1eaf8 Add fat manifests for Docker Hub 2018-06-13 16:46:26 +01:00
Arthur Barr
63ce0b3377 Add timeout while waiting for ready in tests 2018-06-13 16:42:00 +01:00
Arthur Barr
2e3dee931c Ignore .git in Docker context 2018-06-13 16:41:16 +01:00
Arthur Barr
dae2a65e8b change tests to use Maven instead of Gradle 2018-06-13 14:13:43 +01:00
Rob Parker
19f22cd994 Merge pull request #117 from sdmarshall79/master
Map metric names based on description
2018-06-13 10:18:05 +01:00
Stephen Marshall
172a4b0420 Security upgrade for gpgv and gnupg 2018-06-12 17:17:34 +01:00
Stephen Marshall
53fdfe55de Improvements to metrics code 2018-06-12 16:56:44 +01:00
Stephen Marshall
16abf50f9a Fix intermittent timing issue with metric values test 2018-06-08 16:22:32 +01:00
Stephen Marshall
c409179f4a Add docker test to check metric names 2018-06-08 10:06:34 +01:00
Stephen Marshall
7551ce3812 Map metric names based on description 2018-06-07 10:25:16 +01:00
Stephen Marshall
4dfe8ed855 Improve metrics error handling (#114)
* Improve metrics error handling

* Updates to metrics error handling
2018-06-06 13:50:48 +01:00
Arthur Barr
2939a9fd1a Use string value for pid in JSON log (#110) 2018-06-04 16:37:50 +01:00
Stephen Marshall
5d0a87ae0a Improve prometheus error handling (#108) 2018-06-04 15:31:03 +01:00
Rob Parker
2af6953b2b Add more metric tests for value testing (#104) 2018-06-04 14:56:18 +01:00
Rob Parker
0f4e79c0a6 Use correct url for non-x8664 platforms 2018-06-04 13:44:53 +01:00
Stephen Marshall
f8b500e0a1 Add check for duplicate metric keys (#106)
* Remove vet of test code

* Add check for duplicate metric keys
2018-06-01 15:29:18 +01:00
Stephen Marshall
bcfef94b08 Remove vet of test code (#103) 2018-06-01 10:49:13 +01:00
Stephen Marshall
ab01d124a9 Merge pull request #102 from arthurbarr/master
Merge dev branch
2018-05-31 16:24:28 +01:00
Arthur Barr
be9c759a1c Merge build-devserver target conflict 2018-05-31 15:23:06 +01:00
Arthur Barr
70f45d58bf Fixes #84
* Change apt URL for non-x86_64 platforms

* Convert statfs.Type for s390x

* Includes more links to docs

* Remove extra words
2018-05-31 15:11:42 +01:00
Rob Parker
143649deb6 More metric tests and fix reconnect
* more metric test and fix reconnect

* remove build-devjmstest as dependency
2018-05-31 11:56:39 +01:00
Arthur Barr
0b36edae58 Convert statfs.Type for s390x (#98)
* Change apt URL for non-x86_64 platforms

* Convert statfs.Type for s390x
2018-05-31 11:55:32 +01:00
Arthur Barr
45e970e18a Change apt URL for non-x86_64 platforms (#97) 2018-05-31 10:52:54 +01:00
Arthur Barr
9f3032f014 Log extra environment information (#95)
* Make metrics tests use a host port

* fix port forwarding in devconfig tests

* Log extra environment information at startup
2018-05-31 09:35:16 +01:00
Rob Parker
54f0ae65a6 Add MQIPT Sample (#93) 2018-05-30 16:24:03 +01:00
Arthur Barr
6996f2b9b3 Make metrics tests use a host port (#94)
* Make metrics tests use a host port

* fix port forwarding in devconfig tests
2018-05-30 15:38:19 +01:00
Stephen Marshall
987b629a27 Merge pull request #92 from parrobe/issue91
Fix lint failures in mqmetric tests
2018-05-29 11:39:19 +01:00
Rob Parker
00a0b1574b Fix lint failures in mqmetric tests 2018-05-29 09:14:04 +01:00
Rob Parker
531f2710c7 Add Docker FV tests for metric gathering (#90)
* initial metric tests

* Add FV tests for metrics

* correct comment in test
2018-05-25 13:09:48 +01:00
Rob Parker
1ce796a9e2 Merge pull request #83 from sdmarshall79/master
master - Security upgrade for libprocps4 and procps
2018-05-25 09:54:18 +01:00
Rob Parker
91e20f0f98 Merge pull request #82 from sdmarshall79/unit-tests
Unit tests
2018-05-25 09:21:19 +01:00
Stephen Marshall
6f079ca0bb Security upgrade for libprocps4 and procps 2018-05-25 09:10:17 +01:00
Stephen Marshall
7f78ba89bf Security upgrade for libprocps4 and procps 2018-05-25 08:54:20 +01:00
Stephen Marshall
4bbdb36da0 Skip metrics collect on first pass and more unit tests 2018-05-24 17:10:16 +01:00
Stephen Marshall
a4b9a9abaf Initial delivery of metrics code (#81)
* Initial delivery of metrics code

* Fix build issues

* Fix build issue with go vet
2018-05-24 09:15:12 +01:00
Stephen Marshall
e251839639 Merge pull request #80 from parrobe/dev
Check err when calling ImageInspectWithRaw
2018-05-17 12:13:27 +01:00
Rob Parker
9b595a0e01 Check err when calling ImageInspectWithRaw 2018-05-16 13:41:18 +01:00
Rob Parker
6493e82fa6 Merge branch 'dev' of github.com:parrobe/mq-container into dev 2018-05-16 13:36:27 +01:00
Rob Parker
3127abd5ad correctly configure the GO environment (#78) 2018-05-16 10:09:24 +01:00
Rob Parker
adad573f99 correctly configure the GO environment 2018-05-16 09:45:43 +01:00
Rob Parker
5d3519d9bb Merge pull request #77 from arthurbarr/dev
Add MQ and Go SDK images
2018-05-15 11:47:39 +02:00
Arthur Barr
36a24d8864 Merge branch 'master' of https://github.com/ibm-messaging/mq-container into dev 2018-05-15 09:38:57 +01:00
Arthur Barr
e18dcbd8e8 Add MQ and Go SDK images 2018-05-15 09:38:50 +01:00
Rob Parker
5da57489e2 Merge pull request #75 from sdmarshall79/config-webserver-error
Surface errors from configuring the webserver
2018-05-10 11:22:57 +02:00
Stephen Marshall
c389886d3c Surface errors from configuring the webserver 2018-05-04 10:58:12 +01:00
Rob Parker
6775264bcc Merge pull request #73 from parrobe/tlsfixes
Tlsfixes
2018-04-30 17:18:27 +02:00
Arthur Barr
77c0cfa221 Merge branch 'master' into tlsfixes 2018-04-30 16:00:11 +01:00
Rob Parker
04bb404eee Fix TLS logic so containers can be started multiple times 2018-04-30 15:57:19 +01:00
Rob Parker
d8b6b78d66 Fix license to include copyright - master (#66)
* Fix license to include copyright

* Fix copyright line
2018-04-30 15:54:15 +01:00
Rob Parker
8eb937b8e0 ensure we use '' round blank for SSLCIPH 2018-04-30 10:36:55 +01:00
Rob Parker
f051325deb Merge pull request #65 from sdmarshall79/issue64
This will replace hard-coded values with calls to LookupMQM
2018-04-26 10:14:42 +02:00
Stephen Marshall
3aa46e0793 When pushed, this commit will replace hard-coded values with calls to LookupMQM 2018-04-25 16:24:46 +01:00
Rob Parker
bf36f8bb2c Merge pull request #59 from riccardobiraghi/test-coverage
Fix test coverage in docker containers
2018-04-25 17:21:06 +02:00
Riccardo Biraghi
2be0501904 Merge branch 'test-coverage' of https://github.com/riccardobiraghi/mq-container into test-coverage 2018-04-24 16:32:33 +01:00
Riccardo Biraghi
6895097d36 Remove unused import 2018-04-24 16:31:21 +01:00
Riccardo Biraghi
d7633d8313 Fix test coverage in docker containers 2018-04-24 16:31:21 +01:00
Rob Parker
818cbaca8d Merge pull request #60 from riccardobiraghi/travis
Ensure compatibility with Docker 1.12
2018-04-24 17:24:39 +02:00
Riccardo Biraghi
60d098d86d Correct images tar archive name 2018-04-23 17:43:17 +01:00
Riccardo Biraghi
0075b5b727 Delete useless file 2018-04-23 17:29:02 +01:00
Riccardo Biraghi
13981cef86 Set DOCKER_API_VERSION in DOCKER_DOWNGRADE 2018-04-23 17:27:19 +01:00
Riccardo Biraghi
363c8487df Set DOCKER_API_VERSION in travis 2018-04-23 16:37:03 +01:00
Riccardo Biraghi
9d46e6e25a Fix makefile 2018-04-23 15:41:31 +01:00
Riccardo Biraghi
4826e83c9e Use ?= for NUM_CPU 2018-04-23 15:27:22 +01:00
Riccardo Biraghi
1cba663922 Minor corrections 2018-04-23 15:07:36 +01:00
Riccardo Biraghi
c9e7ae194e Fix quotes escape in .travis.yml 2018-04-23 12:50:11 +01:00
Riccardo Biraghi
d61cc9c686 Add quotes to env command 2018-04-23 12:34:11 +01:00
Riccardo Biraghi
20a2b3f593 Test on docker 1.12 with Travis 2018-04-23 12:01:54 +01:00
Arthur Barr
a382984ab9 Merge pull request #58 from riccardobiraghi/travis
Cache MQ advanced in Travis
2018-04-23 08:31:25 +01:00
Riccardo Biraghi
477d39da9f Remove unused import 2018-04-20 17:58:45 +02:00
Riccardo Biraghi
a6f4bdb598 Fix test coverage in docker containers 2018-04-20 17:34:37 +02:00
Riccardo Biraghi
e478f8cc67 Cache MQ advanced in Travis 2018-04-20 10:43:26 +02:00
Arthur Barr
2a858abff8 Merge pull request #57 from arthurbarr/master
security upgrade for perl-base
2018-04-19 15:48:41 +01:00
Arthur Barr
57b4eab2b6 security upgrade for perl-base 2018-04-19 15:04:15 +01:00
Arthur Barr
55cfb59c75 Merge pull request #56 from parrobe/master
correct naming of variable
2018-04-17 10:59:58 +01:00
Rob Parker
88ca989b41 correct naming of variable 2018-04-17 10:37:42 +01:00
Arthur Barr
3be0d0d1dd Merge pull request #54 from riccardobiraghi/master
Add go vet, go fmt and golint to makefile
2018-04-12 16:52:12 +01:00
Rob Parker
a69c06dbf3 Merge pull request #52 from arthurbarr/master
Update JMS client for tests to 9.0.5
2018-04-12 09:48:59 +01:00
Riccardo Biraghi
49e90d2e54 Update copyright statement in capabilities.go 2018-04-12 09:06:05 +01:00
Riccardo Biraghi
1affe991cc Add go get golint to travis yaml 2018-04-11 16:46:52 +01:00
Riccardo Biraghi
cde2a5186e Have Travis run golint after build 2018-04-11 16:05:37 +01:00
Riccardo Biraghi
c55d8f3956 Use /... instead of listing packages 2018-04-11 15:52:09 +01:00
Riccardo Biraghi
460aec3863 Correct go_import_path in .travis.yml 2018-04-11 15:00:43 +01:00
Riccardo Biraghi
3d569b3e8c Fix make vet in Travis 2018-04-11 14:44:58 +01:00
Riccardo Biraghi
831f0695a9 Add vetting, formatting and vetting make commands and fix related errors 2018-04-11 13:43:57 +01:00
Arthur Barr
81e921162b Update JMS client for tests to 9.0.5 2018-04-11 13:30:04 +01:00
Rob Parker
f96304ae8f Merge pull request #49 from riccardobiraghi/issue36
Use template for TLS MQSC commands
2018-04-11 10:10:06 +01:00
Riccardo Biraghi
1752e45934 Copy template files all at once 2018-04-11 09:35:45 +01:00
Riccardo Biraghi
9851743ae2 Fix TLS directory path on WSL 2018-04-11 09:25:08 +01:00
Arthur Barr
ff016cf2be Merge pull request #46 from riccardobiraghi/issue32
Bubble up errors instead of using log.Fatal
2018-04-10 16:29:29 +01:00
Riccardo Biraghi
d56fce65c2 Fix tls template file 2018-04-10 16:29:14 +01:00
Riccardo Biraghi
faea308506 Use fmt.Errorf instead of errors.New 2018-04-10 15:18:03 +01:00
Riccardo Biraghi
6773496d99 Use template for MQSC commands for TLS config 2018-04-10 15:03:36 +01:00
Riccardo Biraghi
3fcc7b4c6e Return nil in checkFS 2018-04-10 13:42:44 +01:00
Arthur Barr
516c8ecc41 Merge pull request #44 from riccardobiraghi/issue38
Update to Go 1.10
2018-04-10 13:38:20 +01:00
Arthur Barr
eea80d139a Merge pull request #42 from riccardobiraghi/issue33
Fix timing problem in mirroring tests
2018-04-10 13:38:07 +01:00
Riccardo Biraghi
2397966a86 Remove log.Fatal() calls and bubble up errors 2018-04-10 13:27:24 +01:00
Riccardo Biraghi
3449dc31ad Quote Go version in travis.yml 2018-04-10 12:13:58 +01:00
Riccardo Biraghi
9a02ddfa48 Update to Go 1.10 2018-04-10 11:48:33 +01:00
Riccardo Biraghi
7009f3a392 Wait for log file after rotation 2018-04-10 10:01:47 +01:00
Arthur Barr
7c36a9ceea Merge pull request #40 from riccardobiraghi/issue37
Replace logDebug with log.Debug
2018-04-09 16:38:23 +01:00
Arthur Barr
bec2e4457d Merge pull request #31 from riccardobiraghi/master
Fix build and tests in Windows Subsystem for Linux
2018-04-09 16:36:24 +01:00
Riccardo Biraghi
9c71fa1c6c Merge branch 'issue33' of https://github.com/riccardobiraghi/mq-container into issue33 2018-04-09 15:55:30 +01:00
Riccardo Biraghi
b41a58645b Apply mirroring delay to last iteration 2018-04-09 15:54:05 +01:00
Riccardo Biraghi
6f3672df4f Apply mirroring delay to last iteration 2018-04-09 15:50:12 +01:00
Rob Parker
28f2076882 Merge pull request #41 from parrobe/master
patch libssl1.0.0
2018-04-09 15:10:27 +01:00
Rob Parker
fd0f0e0b3a patch libssl1.0.0 2018-04-09 13:17:14 +01:00
Riccardo Biraghi
ef04949036 Replace logDebug with log.Debug 2018-04-09 12:45:45 +01:00
Riccardo Biraghi
f9ef635f37 Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2018-04-09 11:51:05 +01:00
Riccardo Biraghi
6287a25156 Better error reporting for runmqsc 2018-04-09 11:41:28 +01:00
Arthur Barr
ab5d7ca1d1 Merge pull request #35 from parrobe/master
Fix intermittent docker exec already running problem. Move to docker …
2018-03-28 16:14:53 +01:00
Rob Parker
b02d8d27b2 Fix intermittant docker exec already running problem. Move to docker api 17.03.02 2018-03-28 15:57:07 +01:00
13e41aeb37 Tidy up code 2018-03-28 11:47:59 +01:00
f5beed0bef Update guide to reference instructions for docker in WSL 2018-03-28 11:23:50 +01:00
778cd07400 Merge branch 'master' of https://github.com/riccardobiraghi/mq-container 2018-03-28 11:17:10 +01:00
96311df366 Fix build and test in WSL 2018-03-28 11:15:51 +01:00
Arthur Barr
89ee583336 Merge pull request #30 from parrobe/master
stop different default listener so dev listener can start
2018-03-27 15:09:29 +01:00
Rob Parker
4968ba2516 Remove unneeded PROFILE from QMGR authrec 2018-03-27 14:00:54 +01:00
Rob Parker
7e8c8b1f0f stop different default listener so dev listener can start 2018-03-27 13:45:30 +01:00
Arthur Barr
2910ae363c Merge pull request #29 from arthurbarr/master
Fix MQ developer image to use 9.0.5 as base
2018-03-26 16:30:11 +01:00
Arthur Barr
a525c8c380 Fix MQ developer image to use 9.0.5 as base 2018-03-26 16:09:44 +01:00
Arthur Barr
9fb0170f1f Merge pull request #28 from arthurbarr/master
Default developer configuration
2018-03-26 12:13:20 +01:00
Arthur Barr
189637e518 Add admin.json to configure web console 2018-03-26 12:08:53 +01:00
Arthur Barr
b40db6b816 Update docs with developer defaults 2018-03-26 12:04:56 +01:00
Arthur Barr
3479455449 Update developer image to V9.0.5 2018-03-21 16:44:47 +00:00
Arthur Barr
fa8867b9bd Remove Helm charts from this repo 2018-03-21 13:50:38 +00:00
Arthur Barr
fcb7377575 Add more dev config tests 2018-03-21 13:40:53 +00:00
Arthur Barr
0e71468826 Remove HTTP redirect message 2018-03-21 13:40:16 +00:00
Arthur Barr
749a459f33 Add precommit Makefile target 2018-03-21 10:36:43 +00:00
Arthur Barr
2d59a94168 Remove unused code 2018-03-21 10:36:26 +00:00
Arthur Barr
54885597fa Build JMS tests from Makefile 2018-03-21 10:12:36 +00:00
Arthur Barr
94a4eac2ca Fix copyright message 2018-03-21 10:11:50 +00:00
Arthur Barr
357cfcba66 Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2018-03-20 16:47:41 +00:00
Arthur Barr
ab3b44e84b TLS and HTTPS configuration in default developer config 2018-03-20 16:47:24 +00:00
Arthur Barr
913465620b Fix test logs appearing twice 2018-03-19 17:12:04 +00:00
Arthur Barr
6ef3bfa28d Merge pull request #27 from arthurbarr/master
Change mq_log to mq_containerlog
2018-03-19 10:14:09 +00:00
Arthur Barr
401306b3ab Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2018-03-19 09:53:29 +00:00
Arthur Barr
e809d0959b Changed mq_log to mq_containerlog 2018-03-19 09:53:02 +00:00
Arthur Barr
ef4232dee5 Merge pull request #26 from arthurbarr/master
Log missing termination errors
2018-03-14 14:50:12 +00:00
Arthur Barr
37b650c367 Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2018-03-14 14:22:17 +00:00
Arthur Barr
4fc5460ac8 Log termination errors 2018-03-14 14:20:32 +00:00
Arthur Barr
01331b0203 Merge pull request #25 from arthurbarr/master
Latest updates
2018-03-12 16:42:37 +00:00
Arthur Barr
b240a84ce0 Fix occasional timing error in tests 2018-03-12 16:28:40 +00:00
Arthur Barr
c75aed0851 Fix typo in README 2018-03-12 16:28:12 +00:00
Arthur Barr
d495b3640e Add extra fields to runmqserver JSON log 2018-03-12 16:27:57 +00:00
Arthur Barr
98c594c91e Fix log message in Makefile 2018-03-12 11:19:55 +00:00
Arthur Barr
6b4720a07c Merge branch 'dev' 2018-03-12 11:16:00 +00:00
Arthur Barr
10e448056b Add web server to dev image 2018-03-12 11:14:59 +00:00
Arthur Barr
1b350549cc Merge pull request #24 from arthurbarr/master
Logging updates
2018-03-06 14:55:11 +00:00
Arthur Barr
104098c7b4 Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2018-03-06 13:48:19 +00:00
Arthur Barr
a14da7aaa8 Change LOG_FORMAT to basic 2018-03-06 13:47:52 +00:00
Arthur Barr
ab60a8975f Remove logrus (MIT license) from notices file 2018-03-05 14:55:48 +00:00
Arthur Barr
9c072060df Remove alpha docs 2018-03-05 14:48:43 +00:00
Arthur Barr
6f8b47a670 Merge pull request #23 from arthurbarr/master
Latest updates
2018-03-05 14:38:20 +00:00
Arthur Barr
8710721fe3 Prevent pruning of test deps 2018-03-05 13:20:12 +00:00
Arthur Barr
37e07fc0b0 Merge conflict 2018-03-05 10:59:41 +00:00
Arthur Barr
97f5f44b92 Clarify creation of downloads dir 2018-03-05 10:57:22 +00:00
Arthur Barr
e07110108f Mirror MQ system logs 2018-03-05 10:57:05 +00:00
Arthur Barr
1e0ba3d897 Use mutex for logger 2018-03-05 10:15:09 +00:00
Arthur Barr
782fe367a5 Latest security fixes 2018-03-05 10:14:26 +00:00
Rob Parker
e1829f3f47 do make deps in travis and apply security fixes 2018-02-23 12:58:01 +00:00
Arthur Barr
91bf65ab57 Remove logrus to allow for easier customization 2018-02-22 17:29:06 +00:00
Arthur Barr
b497a04dcb Update to use LOG_FORMAT environment variable 2018-02-22 13:21:16 +00:00
Arthur Barr
c9cc1741c7 Write termination message 2018-02-22 11:31:42 +00:00
Arthur Barr
d70bbe4dfa Log output from chk commands 2018-02-22 11:22:30 +00:00
Arthur Barr
cb475e8dde Run chk commands as mqm 2018-02-21 12:55:58 +00:00
Arthur Barr
c30a8e4223 Avoid hard-coded mqm uid/gid 2018-02-21 10:19:29 +00:00
Arthur Barr
02cce7ab96 Tidy up debug logging 2018-02-21 09:58:49 +00:00
Arthur Barr
8c92e02a23 Additional logging tests 2018-02-21 09:58:26 +00:00
Arthur Barr
0845025cf8 Latest security fixes 2018-02-21 09:58:00 +00:00
Arthur Barr
3600841e2b Clean up commented code 2018-02-20 14:44:24 +00:00
Arthur Barr
05d1c6f0de Move qmgr code to its own file 2018-02-20 14:41:35 +00:00
Arthur Barr
ace6e6364c Use context and waitgroup for mirroring 2018-02-20 14:35:58 +00:00
Arthur Barr
b23ec084fa Rename logging to mirror 2018-02-19 15:03:39 +00:00
Arthur Barr
e65d679a21 Put variable data in /run instead of /tmp 2018-02-19 10:34:53 +00:00
Arthur Barr
b62a883d4c Improvements to log mirroring 2018-02-15 14:59:14 +00:00
Arthur Barr
9b8e32cbf0 Update CHANGELOG 2018-02-14 14:21:08 +00:00
Arthur Barr
4cdf03a77c Mirror error logs by default 2018-02-14 14:16:00 +00:00
Arthur Barr
2312842a9f Add initial internals doc 2018-02-14 11:29:21 +00:00
Arthur Barr
911f9db2fd Update readiness check 2018-02-14 11:18:20 +00:00
Arthur Barr
54a5052631 Add DEV.LISTENER.TCP to dev config 2018-02-14 11:14:32 +00:00
Arthur Barr
1d223f3157 Require Docker V17.06.1 or greater to build 2018-02-14 11:07:59 +00:00
Arthur Barr
cf687196b7 Ignore .vscode 2018-02-14 11:06:56 +00:00
Arthur Barr
47c865d497 Simplify text log output 2018-02-13 12:49:49 +00:00
Arthur Barr
40c7ab927e Fix typo for missing 'make' command 2018-02-12 16:44:39 +00:00
Arthur Barr
3f4dd2dd3a Limit apt to main/updates/security only 2018-02-07 16:28:16 +00:00
Arthur Barr
b24e375912 Fix copyright dates 2018-02-06 12:02:02 +00:00
Arthur Barr
48185668af Only mirror messages, not whole error log 2018-02-06 12:00:05 +00:00
Arthur Barr
cbfa24a267 Use TEST_OPTS_DOCKER for dev server tests 2018-02-06 11:58:35 +00:00
Arthur Barr
0459880a65 Initial developer config 2018-02-06 11:57:56 +00:00
Arthur Barr
741aa18da9 Upgrade to dep 0.4.1 2018-02-06 11:44:34 +00:00
Arthur Barr
eab783f3c5 Security fixes 2018-02-06 11:26:42 +00:00
Arthur Barr
a03bad9ee7 Improve build docs 2018-01-30 08:56:08 +00:00
Arthur Barr
81bba0db32 Add mirrorFunc to handle mirrored messages 2018-01-29 17:05:19 +00:00
Arthur Barr
753612530f MQ error logs in JSON by default 2018-01-29 12:34:54 +00:00
Arthur Barr
f565e9fe66 Change Bluemix to IBM Cloud 2018-01-29 11:09:17 +00:00
Arthur Barr
ce40e207a4 Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2018-01-29 11:06:11 +00:00
Arthur Barr
ed1154c881 Alpha logging support (JSON+mirroring) 2018-01-29 11:04:01 +00:00
Arthur Barr
d1852d9af4 Allow unit tests on non-Linux OS 2018-01-29 09:35:02 +00:00
Rob Parker
0eacad5848 Fix docker version check to do both major and minor checks at same time 2018-01-12 15:37:09 +00:00
Arthur Barr
bf4cdfc906 Merge pull request #21 from arthurbarr/master
Helm charts V1.1, plus Makefile and test improvements
2018-01-02 14:14:51 +00:00
Arthur Barr
238529918c Switch from Moby to Docker import 2018-01-02 13:52:20 +00:00
Arthur Barr
20b54f35ce Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2018-01-02 11:10:31 +00:00
Arthur Barr
bf31513b99 Update charts to V1.1.0 2018-01-02 11:09:40 +00:00
Arthur Barr
451ea00aed Update README with new defaults 2017-12-19 16:28:21 +00:00
Arthur Barr
095009dba0 New MQ logo 2017-12-19 15:01:06 +00:00
Arthur Barr
fe23ec9aaa Add metadata for ICP UI 2017-12-19 14:59:56 +00:00
Arthur Barr
45f53082aa Add nodeAffinity for mixed clusters 2017-12-19 11:22:57 +00:00
Arthur Barr
f6c583df0b Move chart tests to sub-directory 2017-12-19 10:59:42 +00:00
Arthur Barr
ee94b1702a Add a default nameOverride 2017-12-19 10:47:08 +00:00
Arthur Barr
64867944a3 Add selector for dev chart 2017-12-19 10:44:01 +00:00
Arthur Barr
b938a5eb95 Updates for coverage 2017-12-18 15:38:05 +00:00
Arthur Barr
b6b72952e4 Add TestMQSC 2017-12-18 12:00:19 +00:00
Arthur Barr
aeefd0a9fc Improve version checking in charts 2017-12-13 14:13:59 +00:00
Arthur Barr
a2326dc0f6 Add ability to use different base image 2017-12-11 09:12:39 +00:00
Arthur Barr
93389309f4 Merge pull request #20 from arthurbarr/master
Latest build and test changes
2017-12-06 11:23:28 +00:00
Arthur Barr
d6182bf2fc Fix build problems 2017-12-06 10:19:47 +00:00
Arthur Barr
499c6d4b18 Correct architecture test 2017-12-05 17:54:32 +00:00
Arthur Barr
18635b704c Additional fix for Travis 2017-12-05 16:08:35 +00:00
Arthur Barr
878442905d Fix Travis download of dep 2017-12-05 15:39:32 +00:00
Arthur Barr
b66a799d7f Fix Makefile error checking 2017-12-05 15:27:07 +00:00
Arthur Barr
584a4f2eb4 Fixes for running on older Docker versions 2017-12-05 13:22:36 +00:00
Arthur Barr
c297e1bf5d Improve docs 2017-12-05 11:49:44 +00:00
Arthur Barr
abbc8ce852 Remove unnecessary TTY usage 2017-12-05 10:57:08 +00:00
Arthur Barr
176543e100 Run Docker tests in parallel 2017-12-05 10:27:36 +00:00
Arthur Barr
f5515d72a3 Test for security vulnerabilities 2017-12-05 10:17:31 +00:00
Arthur Barr
70f1a43fd8 More license tweaks 2017-11-30 15:20:00 +00:00
Arthur Barr
81b5db4969 Add unit test for license resolution 2017-11-29 17:25:35 +00:00
Arthur Barr
2f3ca70d7b Document running a single test 2017-11-29 16:08:12 +00:00
Arthur Barr
a80b839c14 Add TestZombies and improve exec output handling 2017-11-29 15:50:10 +00:00
Arthur Barr
5b0259ec6e Add test comments 2017-11-29 12:36:48 +00:00
Arthur Barr
0ad595dc99 Improve dependency handling 2017-11-29 12:31:04 +00:00
Arthur Barr
0823fd1cea Add TestVolumeUnmount 2017-11-29 12:29:31 +00:00
Arthur Barr
f3a1f94445 Merge pull request #19 from arthurbarr/master
Miscellaneous improvements
2017-11-28 15:58:45 +00:00
Arthur Barr
5780ec2a26 Easier multi-arch or multi-version builds 2017-11-28 14:52:41 +00:00
Arthur Barr
7ea6b4c610 Detect arch for image tag 2017-11-28 12:08:19 +00:00
Arthur Barr
4aa8918745 MQ Advanced for Developers V9.0.4 2017-11-28 12:05:47 +00:00
Arthur Barr
4200d9df1b Enable coverage for failure cases 2017-11-22 17:20:57 +00:00
Arthur Barr
f492171276 Test extra error paths 2017-11-22 16:14:34 +00:00
Arthur Barr
d674334574 Improvements to coverage reporting 2017-11-22 16:14:16 +00:00
Arthur Barr
fef9ab4f06 Fix runmqserver error handling 2017-11-22 16:13:30 +00:00
Arthur Barr
46110436b8 Change command exit status handling 2017-11-21 15:53:14 +00:00
Arthur Barr
5e787ba4cf Clean up build network on failure 2017-11-21 15:51:12 +00:00
Arthur Barr
099397442b Restructure packages for reuse 2017-11-21 14:32:09 +00:00
Arthur Barr
3848c39147 Add build section to docs 2017-11-21 10:48:19 +00:00
Arthur Barr
3bbdeec3f0 Merge pull request #18 from parrobe/master
Fix README install file name and add MQ package install hook
2017-11-16 12:49:16 +00:00
Rob Parker
faf6c4bc08 Correct indentation of new build-arg 2017-11-16 11:22:31 +00:00
Rob Parker
15acd8ccdc Correct installer package file name 2017-11-15 13:09:23 +00:00
Rob Parker
fceac2d4b8 Add hook into Makefile to allow MQ_PACKAGES to be specified 2017-11-15 13:08:07 +00:00
Arthur Barr
3da06b27a5 Merge pull request #16 from arthurbarr/master
Updates to code coverage and Explorer
2017-11-13 14:57:19 +00:00
Arthur Barr
f65b06be3c Merge branch 'master' of https://github.com/ibm-messaging/mq-container 2017-11-13 13:54:05 +00:00
Arthur Barr
35043ee488 Update instructions for Explorer 2017-11-13 13:52:55 +00:00
Arthur Barr
4874483f9c Get code coverage working 2017-11-08 16:46:14 +00:00
976 changed files with 182557 additions and 25078 deletions

View File

@@ -1,3 +1,2 @@
charts
downloads downloads
test .git

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
# Fore LF line endings to prevent errors in Bash on Windows
* text=auto
*.sh text eol=lf

7
.gitignore vendored
View File

@@ -1,7 +1,14 @@
.DS_Store .DS_Store
.vscode
test/docker/coverage test/docker/coverage
test/docker/vendor test/docker/vendor
test/kubernetes/vendor test/kubernetes/vendor
build build
coverage coverage
downloads downloads
incubating/mqipt/ms81*
vendor/github.com/prometheus/client_model/bin/
vendor/github.com/prometheus/client_model/.classpath
vendor/github.com/prometheus/client_model/.project
vendor/github.com/prometheus/client_model/.settings*
gosec_results.json

View File

@@ -1,29 +1,88 @@
# © Copyright IBM Corporation 2018, 2019
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
dist: xenial
sudo: required sudo: required
language: go language: go
go: go:
- 1.9 - "1.12"
services: services:
- docker - docker
go_import_path: "github.com/ibm-messaging/mq-container"
cache:
directories:
- downloads
env:
global:
- RELEASE=""
jobs:
include:
- stage: build
name: "Basic build"
if: branch != private-master AND tag IS blank
os: linux
env:
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_AMD64
script: bash -e travis-build-scripts/run.sh
- if: branch = private-master OR tag =~ ^pre-release*
name: "Multi-Arch AMD64 build"
os: linux
env:
- BUILD_ALL=true
- MQ_ARCHIVE_REPOSITORY=$MQ_914_ARCHIVE_REPOSITORY_AMD64
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_AMD64
script: bash -e travis-build-scripts/run.sh
- if: branch = private-master OR tag =~ ^pre-release*
name: "Multi-Arch PPC64LE build"
os: linux-ppc64le
env:
- BUILD_ALL=true
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
- MQ_ARCHIVE_REPOSITORY=$MQ_914_ARCHIVE_REPOSITORY_PPC64LE
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_PPC64LE
script: bash -e travis-build-scripts/run.sh
- if: branch = private-master OR tag =~ ^pre-release*
name: "Multi-Arch S390X build"
os: linux-s390
env:
- BUILD_ALL=true
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
- MQ_ARCHIVE_REPOSITORY=$MQ_914_ARCHIVE_REPOSITORY_S390X
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_914_ARCHIVE_REPOSITORY_DEV_S390X
script: bash -e travis-build-scripts/run.sh
- stage: deploy
name: "Pre-release deploy"
if: tag =~ ^pre-release*
script: bash -e travis-build-scripts/release.sh staging
- name: "Production release deploy"
if: tag =~ ^production-release*
script: bash -e travis-build-scripts/release.sh production
before_install: before_install:
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - make install-build-deps
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- sudo apt-get update
- sudo apt-get -y install docker-ce
- curl https://glide.sh/get | sh
- curl -LO https://github.com/golang/dep/releases/download/v0.3.0/dep-linux-amd64.zip
- unzip dep-linux-amd64.zip
- sudo mv dep /usr/local/bin
- rm dep-linux-amd64.zip
install: install:
- echo nothing - echo nothing
before_script: before_script: echo nothing
- make deps
script: after_success:
- make build-devserver - make lint
- make test-devserver

View File

@@ -1,6 +1,89 @@
# Change log # Change log
## 9.1.4.0 (2019-12-06)
* Updated to MQ version 9.1.4.0
* Updated to use UBI8 as base image
* Added required security settings to self signed certificates to align with macOS Catalina requirements
## 9.1.3.0 (2019-07-19)
* Updated to MQ version 9.1.3.0
* Allow generation of TLS certificate with given hostname
* Fixes for the following issues:
* `MQ_EPHEMERAL_PREFIX` UNIX sockets fix
* Fix Makefile for Windows
* Use -a option on crtmqdir
* Remove check for certificate environment variable
## 9.1.2.0-UBI (2019-06-21)
**Breaking changes**:
* UID of the mqm user is now 888. You need to run the container with an entrypoint of `runmqserver -i` under the root user to update any existing files.
* MQSC files supplied will be verified before being run. Files containing invalid MQSC will cause the container to fail to start
**Other changes**:
* Security fixes
* Web console added to production image
* Container built on RedHat host
## 9.1.2.0 (2019-03-21)
* Updated to MQ version 9.1.2.0
* Now runs using the "mqm" user instead of root. See new [security doc](https://github.com/ibm-messaging/mq-container/blob/master/docs/security.md)
* New [IGNSTATE](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.pro.doc/q132310_.htm#q132310___ignstateparm) parameter used in default developer config
* Termination log moved from `/dev/termination-log` to `/run/termination-log`, to make permissions easier to handle
* Fixes for the following issues:
* Brackets no longer appear in termination log
* Test timeouts weren't being used correctly
* Building on subscribed and unsubscribed hosts ([#273](https://github.com/ibm-messaging/mq-container/pull/273))
* Gosec failures ([#286](https://github.com/ibm-messaging/mq-container/pull/286))
* Security fix for perl-base ([#253](https://github.com/ibm-messaging/mq-container/pull/253))
## 9.1.1.0 (2018-11-30)
* Updated to MQ version 9.1.1.0
* Created seperate RedHat Makefile for building images on RedHat machines with buildah
* Enabled REST messaging capability for app user.
* Added support for container supplementary groups
* Removed IBM MQ version 9.0.5 details.
* Added additional Diagnostics ([#203](https://github.com/ibm-messaging/mq-container/pull/203))
* Implementted GOSec to perform code scans for security vulnerabilities. (([#227](https://github.com/ibm-messaging/mq-container/pull/227)))
* Removed Queue manager create option from the MQ Console.
* Fixes for the following issues:
* Check explicitly for `/mnt/mqm` ([#175](https://github.com/ibm-messaging/mq-container/pull/175))
* Force string output in chkmqhealthy ([#174](https://github.com/ibm-messaging/mq-container/pull/174))
* Use -aG not -G when adding a group for a user
* Security fixes for libsystemd0 systemd systemd-sysv & libudev1
## 9.1.0.0 (2018-07-23)
* Updated to MQ version 9.1.0.0
* Added Docker 1.12 tests
* Added MQ SDK Docker image sample
* Added MQ Golang SDK Docker image sample
* Added Prometheus metric gathering implementation
* Added MQ Internet Pass-Thru (MS81) Docker image sample
* Added POWER & z/Linux image builds
* `devjmstest` image now built with Maven instead of gradle
* Added FAT manifests for Docker Hub/Docker Store
* Added Red Hat Enterprise Linux image build
* Added basic versioning debug information into golang programs
* Removed 9.0.4
## 9.0.5.0 (2018-03-13)
* Updated to MQ version 9.0.5.0
* Container's stdout can now be set to JSON format (set LOG_FORMAT=json)
* MQ error logs (in JSON or plain text) are now mirrored on stdout for the container.
* `chkmqready` now waits until MQSC scripts in `/etc/mqm` have been applied
* `chkmqready` and `chkmqhealthy` now run as the "mqm" user
* Added ability to optionally use an alternative base image
* Various build and test improvements
* Removed 9.0.3
## 9.0.4 (2017-11-06) ## 9.0.4 (2017-11-06)
* Updated to MQ version 9.0.4.0 * Updated to MQ version 9.0.4.0
* Updated to Go version 9 * Updated to Go version 9
* Removed packages `curl`, `ca-certificates`, and their dependencies, which were only used at build time * Removed packages `curl`, `ca-certificates`, and their dependencies, which were only used at build time
@@ -10,4 +93,5 @@
* Updated to use multi-stage Docker build, so that Go code is built inside a container * Updated to use multi-stage Docker build, so that Go code is built inside a container
## 9.0.3 (2017-10-17) ## 9.0.3 (2017-10-17)
* Initial version * Initial version

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2017 # © Copyright IBM Corporation 2015, 2019
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -12,49 +12,143 @@
# 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_TAG=8.1-279
###############################################################################
# Build stage to build Go code # Build stage to build Go code
FROM golang:1.9 as builder ###############################################################################
WORKDIR /go/src/github.com/ibm-messaging/mq-container/ FROM registry.redhat.io/rhel8/go-toolset:1.12.8-11 as builder
# FROM docker.io/centos/go-toolset-7-centos7 as builder
# The URL to download the MQ installer from in tar.gz format
# This assumes an archive containing the MQ RPM install packages
ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev912_linux_x86-64.tar.gz"
ARG IMAGE_REVISION="Not specified"
ARG IMAGE_SOURCE="Not specified"
ARG IMAGE_TAG="Not specified"
ARG MQM_UID=888
USER 0
COPY install-mq.sh /usr/local/bin/
RUN chmod a+x /usr/local/bin/install-mq.sh \
&& sleep 1 \
&& MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm" install-mq.sh $MQM_UID
WORKDIR /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/
COPY cmd/ ./cmd COPY cmd/ ./cmd
COPY internal/ ./internal
COPY pkg/ ./pkg COPY pkg/ ./pkg
COPY vendor/ ./vendor COPY vendor/ ./vendor
RUN go build ./cmd/runmqserver/ ENV PATH="${PATH}:/opt/rh/go-toolset-1.11/root/usr/bin" \
CGO_CFLAGS="-I/opt/mqm/inc/" \
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/
RUN go build ./cmd/chkmqready/ RUN go build ./cmd/chkmqready/
RUN go build ./cmd/chkmqhealthy/ RUN go build ./cmd/chkmqhealthy/
RUN go build ./cmd/runmqdevserver/
RUN go test -v ./cmd/runmqdevserver/...
RUN go test -v ./cmd/runmqserver/
RUN go test -v ./cmd/chkmqready/
RUN go test -v ./cmd/chkmqhealthy/
RUN go test -v ./pkg/...
RUN go test -v ./internal/...
RUN go vet ./cmd/... ./internal/...
# Build stage to run Go unit tests ###############################################################################
FROM golang:1.9 as tester
COPY pkg/ ./pkg
RUN cd pkg/name && go test
RUN cd pkg/linux/capabilities && go test
# Main build stage, to build MQ image # Main build stage, to build MQ image
FROM ubuntu:16.04 ###############################################################################
FROM $BASE_IMAGE:$BASE_TAG AS mq-server
# The URL to download the MQ installer from in tar.gz format # The MQ packages to install - see install-mq.sh for default value
# This assumes an archive containing the MQ Debian (.deb) install packages ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev914_linux_x86-64.tar.gz"
ARG MQ_URL ARG MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesWeb*.rpm MQSeriesAMS-*.rpm"
#ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-web ibmmq-ams"
# The MQ packages to install ARG MQM_UID=888
ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams" ARG BASE_IMAGE
ARG BASE_TAG
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 worlds most successful enterprises"
LABEL vendor="IBM"
LABEL distribution-scope="private"
LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/"
LABEL url="https://www.ibm.com/products/mq/advanced"
LABEL io.openshift.tags="mq messaging"
LABEL 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 worlds most successful enterprises"
LABEL base-image=$BASE_IMAGE
LABEL 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/
# Install MQ. To avoid a "text file busy" error here, we sleep before installing. # Install MQ. To avoid a "text file busy" error here, we sleep before installing.
RUN chmod u+x /usr/local/bin/install-mq.sh \ RUN env && chmod u+x /usr/local/bin/install-*.sh \
&& sleep 1 \ && sleep 1 \
&& install-mq.sh && install-mq-server-prereqs.sh $MQM_UID \
&& install-mq.sh $MQM_UID
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqserver /usr/local/bin/ # Create a directory for runtime data from runmqserver
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/chkmq* /usr/local/bin/ RUN mkdir -p /run/runmqserver \
&& chown mqm:mqm /run/runmqserver
COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/runmqserver /usr/local/bin/
COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/chkmq* /usr/local/bin/
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
# Copy web XML files
RUN chmod +x /usr/local/bin/runmqserver \ COPY web /etc/mqm/web
&& chmod +x /usr/local/bin/chkmq* COPY etc/mqm/*.tpl /etc/mqm/
RUN chmod ug+x /usr/local/bin/runmqserver \
# Always use port 1414 && chown mqm:mqm /usr/local/bin/*mq* \
EXPOSE 1414 && chmod ug+xs /usr/local/bin/chkmq* \
&& chown -R mqm:mqm /etc/mqm/* \
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 && install --directory --mode 0775 --owner mqm --group root /run/runmqserver \
&& touch /run/termination-log \
&& chown mqm:root /run/termination-log \
&& chmod 0660 /run/termination-log
# Always use port 1414 for MQ & 9157 for the metrics
EXPOSE 1414 9157 9443
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1 LOG_FORMAT=basic
USER $MQM_UID
ENTRYPOINT ["runmqserver"] ENTRYPOINT ["runmqserver"]
###############################################################################
# Add default developer config
###############################################################################
FROM mq-server AS mq-dev-server
ARG MQM_UID=888
ARG BASE_IMAGE
ARG BASE_TAG
# Enable MQ developer default configuration
ENV MQ_DEV=true
# Default administrator password
ENV MQ_ADMIN_PASSWORD=passw0rd
LABEL summary="IBM MQ Advanced for Developers Server"
LABEL description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL vendor="IBM"
LABEL distribution-scope="private"
LABEL authoritative-source-url="https://www.ibm.com/software/passportadvantage/"
LABEL url="https://www.ibm.com/products/mq/advanced"
LABEL io.openshift.tags="mq messaging"
LABEL io.k8s.display-name="IBM MQ Advanced for Developers Server"
LABEL io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the worlds most successful enterprises"
LABEL base-image=$BASE_IMAGE
LABEL base-image-release=$BASE_TAG
USER 0
COPY incubating/mqadvanced-server-dev/install-extra-packages.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/install-extra-packages.sh \
&& sleep 1 \
&& install-extra-packages.sh
# WARNING: This is what allows the mqm user to change the password of any other user
# It's used by runmqdevserver to change the admin/app passwords.
RUN echo "mqm ALL = NOPASSWD: /usr/sbin/chpasswd" > /etc/sudoers.d/mq-dev-config
## Add admin and app users, and set a default password for admin
RUN useradd admin -G mqm \
&& groupadd mqclient \
&& useradd app -G mqclient \
&& echo admin:$MQ_ADMIN_PASSWORD | chpasswd
# Create a directory for runtime data from runmqserver
RUN mkdir -p /run/runmqdevserver \
&& chown mqm:mqm /run/runmqdevserver
COPY --from=builder /opt/app-root/src/go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/
# Copy template files
COPY incubating/mqadvanced-server-dev/*.tpl /etc/mqm/
# Copy web XML files for default developer configuration
COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
RUN chown -R mqm:mqm /etc/mqm/* \
&& chmod +x /usr/local/bin/runmq* \
&& install --directory --mode 0775 --owner mqm --group root /run/runmqdevserver
ENV MQ_ENABLE_EMBEDDED_WEB_SERVER=1 MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost
USER $MQM_UID
ENTRYPOINT ["runmqdevserver"]

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2017 # © Copyright IBM Corporation 2017, 2018
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -12,11 +12,21 @@
# 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.
FROM mqadvanced:latest-x86_64 ARG BASE_IMAGE
# Build stage to build Go code
FROM golang:1.10 as builder
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
COPY cmd/ ./cmd
COPY internal/ ./internal
COPY vendor/ ./vendor
RUN go test -c -covermode=count -coverpkg $(go list ./cmd/runmqserver ./internal/... | paste -s -d, -) ./cmd/runmqserver
FROM $BASE_IMAGE
# Copy in the version of the code instrumented for code coverage # Copy in the version of the code instrumented for code coverage
COPY build/runmqserver.test /usr/local/bin/runmqserver.test COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqserver.test /usr/local/bin/
RUN chmod +x /usr/local/bin/runmqserver.test \ RUN chmod +x /usr/local/bin/runmqserver.test \
&& mkdir -p /var/coverage/ && mkdir -p /var/coverage/
ENTRYPOINT ["runmqserver.test", "-test", "-test.coverprofile", "/var/coverage/coverage.cov"] ENTRYPOINT ["runmqserver.test", "-test", "-test.coverprofile", "/var/coverage/container.cov"]

13
LICENSE
View File

@@ -176,18 +176,7 @@
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work. © Copyright IBM Corporation. 2015, 2019
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

502
Makefile
View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2017 # © Copyright IBM Corporation 2017, 2019
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -12,151 +12,419 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
BUILD_SERVER_CONTAINER=build-server ###############################################################################
# Set architecture for Go code. Don't set GOOS globally, so that tests can be run locally # Conditional variables - you can override the values of these variables from
export GOARCH ?= amd64 # the command line
DOCKER_TAG_ARCH ?= x86_64 ###############################################################################
# By default, all Docker client commands are run inside a Docker container. # RELEASE shows what release of the container code has been built
# This means that newer features of the client can be used, even with an older daemon. RELEASE ?=
DOCKER ?= docker run --tty --interactive --rm --volume /var/run/docker.sock:/var/run/docker.sock --volume "$(CURDIR)":/var/src --workdir /var/src docker:stable docker # MQ_VERSION is the fully qualified MQ version number to build
DOCKER_TAG ?= latest-$(DOCKER_TAG_ARCH) MQ_VERSION ?= 9.1.4.0
DOCKER_REPO_DEVSERVER ?= mq-devserver # MQ_ARCHIVE_REPOSITORY is a remote repository from which to pull the MQ_ARCHIVE (if required)
DOCKER_REPO_ADVANCEDSERVER ?= mq-advancedserver MQ_ARCHIVE_REPOSITORY ?=
DOCKER_FULL_DEVSERVER = $(DOCKER_REPO_DEVSERVER):$(DOCKER_TAG) # MQ_ARCHIVE_REPOSITORY_DEV is a remote repository from which to pull the MQ_ARCHIVE_DEV (if required)
DOCKER_FULL_ADVANCEDSERVER = $(DOCKER_REPO_ADVANCEDSERVER):$(DOCKER_TAG) MQ_ARCHIVE_REPOSITORY_DEV ?=
# MQ_ARCHIVE_REPOSITORY_USER is the user for the remote repository (if required)
MQ_ARCHIVE_REPOSITORY_USER ?=
# MQ_ARCHIVE_REPOSITORY_CREDENTIAL is the password/API key for the remote repository (if required)
MQ_ARCHIVE_REPOSITORY_CREDENTIAL ?=
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
# Does not apply to MQ Advanced for Developers.
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH).tar.gz
# MQ_ARCHIVE_DEV is the name of the file, under the downloads directory, from which MQ Advanced
# for Developers can be installed
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
# MQ_SDK_ARCHIVE specifies the archive to use for building the golang programs. Defaults vary on developer or advanced.
MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
# Options to `go test` for the Docker tests # Options to `go test` for the Docker tests
TEST_OPTS_DOCKER ?= TEST_OPTS_DOCKER ?=
# Options to `go test` for the Kubernetes tests # MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
TEST_OPTS_KUBERNETES ?= MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
MQ_IMAGE_DEVSERVER ?=mqadvanced-server-dev
# MQ_TAG is the tag of the built MQ Advanced image & MQ Advanced for Developers image
MQ_TAG ?=$(MQ_VERSION)-$(ARCH)
# MQ_PACKAGES specifies the MQ packages (.deb or .rpm) to install. Defaults vary on base image.
MQ_PACKAGES ?=MQSeriesRuntime-*.rpm MQSeriesServer-*.rpm MQSeriesJava*.rpm MQSeriesJRE*.rpm MQSeriesGSKit*.rpm MQSeriesMsg*.rpm MQSeriesSamples*.rpm MQSeriesWeb*.rpm MQSeriesAMS-*.rpm
# MQM_UID is the UID to use for the "mqm" user
MQM_UID ?= 888
# COMMAND is the container command to run. "podman" or "docker"
COMMAND ?=$(shell type -p podman 2>&1 >/dev/null && echo podman || echo docker)
# MQ_DELIVERY_REGISTRY_HOSTNAME is a remote registry to push the MQ Image to (if required)
MQ_DELIVERY_REGISTRY_HOSTNAME ?=
# MQ_DELIVERY_REGISTRY_NAMESPACE is the namespace/path on the delivery registry (if required)
MQ_DELIVERY_REGISTRY_NAMESPACE ?=
# MQ_DELIVERY_REGISTRY_USER is the user for the remote registry (if required)
MQ_DELIVERY_REGISTRY_USER ?=
# MQ_DELIVERY_REGISTRY_CREDENTIAL is the password/API key for the remote registry (if required)
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 ?= $(if $(findstring x86_64,$(shell uname -m)),amd64,$(shell uname -m))
###############################################################################
# Other variables
###############################################################################
GO_PKG_DIRS = ./cmd ./internal ./test
MQ_ARCHIVE_TYPE=LINUX
MQ_ARCHIVE_DEV_PLATFORM=linux
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
BUILD_SERVER_CONTAINER=build-server
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
# test run in parallel
NUM_CPU = $(or $(shell docker info --format "{{ .NCPU }}"),2)
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
BASE_IMAGE_TAG=$(lastword $(subst /, ,$(subst :,-,$(BASE_IMAGE))))
#BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base
# Docker image name to use for JMS tests
DEV_JMS_IMAGE=mq-dev-jms-test
# Variables for versioning
IMAGE_REVISION=$(shell git rev-parse HEAD)
IMAGE_SOURCE=$(shell git config --get remote.origin.url)
EMPTY:=
SPACE:= $(EMPTY) $(EMPTY)
# MQ_VERSION_VRM is MQ_VERSION with only the Version, Release and Modifier fields (no Fix field). e.g. 9.1.4 instead of 9.1.4.0
MQ_VERSION_VRM=$(subst $(SPACE),.,$(wordlist 1,3,$(subst .,$(SPACE),$(MQ_VERSION))))
ifneq (,$(findstring Microsoft,$(shell uname -r)))
DOWNLOADS_DIR=$(patsubst /mnt/c%,C:%,$(realpath ./downloads/))
else ifneq (,$(findstring Windows,$(shell echo ${OS})))
DOWNLOADS_DIR=$(shell pwd)/downloads/
else
DOWNLOADS_DIR=$(realpath ./downloads/)
endif
# Try to figure out which archive to use from the architecture
ifeq "$(ARCH)" "amd64"
MQ_ARCHIVE_ARCH=X86-64
MQ_DEV_ARCH=x86-64
else ifeq "$(ARCH)" "ppc64le"
MQ_ARCHIVE_ARCH=LE_POWER
MQ_DEV_ARCH=ppcle
else ifeq "$(ARCH)" "s390x"
MQ_ARCHIVE_ARCH=SYSTEM_Z
MQ_DEV_ARCH=s390x
endif
# Archive names for IBM MQ Advanced for Developers
MQ_ARCHIVE_DEV_9.1.0.0=mqadv_dev910_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
MQ_ARCHIVE_DEV_9.1.1.0=mqadv_dev911_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
MQ_ARCHIVE_DEV_9.1.2.0=mqadv_dev912_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
MQ_ARCHIVE_DEV_9.1.3.0=mqadv_dev913_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
MQ_ARCHIVE_DEV_9.1.4.0=mqadv_dev914_$(MQ_ARCHIVE_DEV_PLATFORM)_$(MQ_DEV_ARCH).tar.gz
ifneq "$(MQ_DELIVERY_REGISTRY_NAMESPACE)" "$(EMPTY)"
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_DELIVERY_REGISTRY_NAMESPACE)
else
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)
endif
ifneq "$(RELEASE)" "$(EMPTY)"
MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server
MQ_IMAGE_DEVSERVER=ibm-mqadvanced-server-dev
MQ_TAG=$(MQ_VERSION)-$(RELEASE)-$(ARCH)
EXTRA_LABELS=--label release=$(RELEASE)
endif
MQ_IMAGE_FULL_RELEASE_NAME=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
MQ_IMAGE_DEV_FULL_RELEASE_NAME=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
ifeq "$(MQ_DELIVERY_REGISTRY_HOSTNAME)" "ibmcom"
MQ_IMAGE_DEVSERVER_DOCKERHUB=mq
else ifeq "$(MQ_DELIVERY_REGISTRY_HOSTNAME)" "ibmcorp"
MQ_IMAGE_DEVSERVER_DOCKERHUB=mqadvanced-server-dev
endif
###############################################################################
# Build targets
###############################################################################
.PHONY: default .PHONY: default
default: build-devserver test default: build-devserver
# Build all components (except incubating ones) # Build all components (except incubating ones)
.PHONY: all .PHONY: all
all: build-devserver build-advancedserver all: build-devserver build-advancedserver
.PHONY: test-all
test-all: build-devjmstest test-devserver test-advancedserver
.PHONY: devserver .PHONY: devserver
devserver: build-devserver test-devserver devserver: build-devserver build-devjmstest test-devserver
# Build incubating components # Build incubating components
.PHONY: incubating .PHONY: incubating
incubating: build-explorer incubating: build-explorer
downloads/$(MQ_ARCHIVE_DEV):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
mkdir -p downloads
ifneq "$(MQ_ARCHIVE_REPOSITORY_DEV)" "$(EMPTY)"
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" -o downloads/$(MQ_ARCHIVE_DEV)
else
curl -L https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV) -o downloads/$(MQ_ARCHIVE_DEV)
endif
downloads/$(MQ_ARCHIVE):
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced "$(MQ_VERSION)$(END)))
mkdir -p downloads
ifneq "$(MQ_ARCHIVE_REPOSITORY)" "$(EMPTY)"
curl -u $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -X GET "$(MQ_ARCHIVE_REPOSITORY)" -o downloads/$(MQ_ARCHIVE)
endif
.PHONY: downloads
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
# Vendor Go dependencies for the Docker tests
test/docker/vendor:
cd test/docker && dep ensure -vendor-only
# Shortcut to just run the unit tests
.PHONY: test-unit
test-unit:
docker build --target builder --file Dockerfile-server .
.PHONY: test-advancedserver
test-advancedserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
docker inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
.PHONY: build-devjmstest
build-devjmstest:
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
.PHONY: test-devserver
test-devserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell docker --version)"$(END)))
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 go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER)
.PHONY: coverage
coverage:
mkdir coverage
.PHONY: test-advancedserver-cover
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)))
rm -f ./coverage/unit*.cov
# Run unit tests with coverage, for each package under 'internal'
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
# ls -1 ./cmd | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./cmd/{}/...
echo 'mode: count' > ./coverage/unit.cov
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
rm -f ./test/docker/coverage/*.cov
rm -f ./coverage/docker.*
mkdir -p ./test/docker/coverage/
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true go test $(TEST_OPTS_DOCKER)
echo 'mode: count' > ./coverage/docker.cov
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
echo 'mode: count' > ./coverage/combined.cov
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
# Build an MQ image. The commands used are slightly different between Docker and Podman
define build-mq
$(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))
# Build the new image
$(COMMAND) build \
--tag $1:$2 \
--file $3 \
$(EXTRA_ARGS) \
--build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
--build-arg IMAGE_TAG="$1:$2" \
--build-arg MQM_UID=$(MQM_UID) \
--label version=$(MQ_VERSION) \
--label name=$1 \
--label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \
--label architecture="$(ARCH)" \
--label run="docker run -d -e LICENSE=accept $1:$2" \
--label vcs-ref=$(IMAGE_REVISION) \
--label vcs-type=git \
--label vcs-url=$(IMAGE_SOURCE) \
$(EXTRA_LABELS) \
--target $5 \
.
$(if $(findstring docker,$(COMMAND)), @docker kill $(BUILD_SERVER_CONTAINER))
$(if $(findstring docker,$(COMMAND)), @docker network rm build)
endef
DOCKER_SERVER_VERSION=$(shell docker version --format "{{ .Server.Version }}")
DOCKER_CLIENT_VERSION=$(shell docker 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 ., ,$(DOCKER_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
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
.PHONY: build-advancedserver-host
build-advancedserver-host: build-advancedserver
.PHONY: build-advancedserver
build-advancedserver: registry-login log-build-env downloads/$(MQ_ARCHIVE) command-version
$(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)
.PHONY: build-devserver-host
build-devserver-host: build-devserver
.PHONY: build-devserver
build-devserver: registry-login log-build-env downloads/$(MQ_ARCHIVE_DEV) command-version
$(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)
.PHONY: build-advancedserver-cover
build-advancedserver-cover: registry-login command-version
$(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
build-explorer: registry-login downloads/$(MQ_ARCHIVE_DEV)
$(call build-mq,mq-explorer,latest-$(ARCH),incubating/mq-explorer/Dockerfile,$(MQ_ARCHIVE_DEV),mq-explorer)
.PHONY: build-sdk
build-sdk: registry-login downloads/$(MQ_ARCHIVE_DEV)
$(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)
.PHONY: registry-login
registry-login:
ifneq ($(REGISTRY_USER),)
$(COMMAND) login -u $(REGISTRY_USER) -p $(REGISTRY_PASS) registry.redhat.io
endif
.PHONY: log-build-env
log-build-vars:
$(info $(SPACER)$(shell printf $(TITLE)"Build environment"$(END)))
@echo ARCH=$(ARCH)
@echo MQ_VERSION=$(MQ_VERSION)
@echo MQ_ARCHIVE=$(MQ_ARCHIVE)
@echo MQ_ARCHIVE_DEV=$(MQ_ARCHIVE_DEV)
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
@echo COMMAND=$(COMMAND)
@echo MQM_UID=$(MQM_UID)
@echo REGISTRY_USER=$(REGISTRY_USER)
.PHONY: log-build-env
log-build-env: log-build-vars
$(info $(SPACER)$(shell printf $(TITLE)"Build environment - $(COMMAND) info"$(END)))
@echo Command version: $(shell $(COMMAND) --version)
$(COMMAND) info
include formatting.mk
.PHONY: 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)
.PHONY: 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)
.PHONY: push-advancedserver
push-advancedserver:
$(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) tag $(MQ_IMAGE_ADVANCEDSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
$(COMMAND) push $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
.PHONY: push-devserver
push-devserver:
$(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) tag $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
$(COMMAND) push $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
.PHONY: push-devserver-dockerhub
push-devserver-dockerhub:
$(info $(SPACER)$(shell printf $(TITLE)"Push developer image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) tag $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG) $(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_IMAGE_DEVSERVER_DOCKERHUB):$(MQ_TAG)
$(COMMAND) push $(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_IMAGE_DEVSERVER_DOCKERHUB):$(MQ_TAG)
.PHONY: pull-advancedserver
pull-advancedserver:
$(info $(SPACER)$(shell printf $(TITLE)"Pull production image from $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) pull $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME)
$(COMMAND) tag $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_FULL_RELEASE_NAME) $(MQ_IMAGE_ADVANCEDSERVER)\:$(MQ_TAG)
.PHONY: pull-devserver
pull-devserver:
$(info $(SPACER)$(shell printf $(TITLE)"Pull developer image from $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
$(COMMAND) login $(MQ_DELIVERY_REGISTRY_HOSTNAME) -u $(MQ_DELIVERY_REGISTRY_USER) -p $(MQ_DELIVERY_REGISTRY_CREDENTIAL)
$(COMMAND) pull $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME)
$(COMMAND) tag $(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEV_FULL_RELEASE_NAME) $(MQ_IMAGE_DEVSERVER)\:$(MQ_TAG)
.PHONY: clean .PHONY: clean
clean: clean:
rm -rf ./coverage rm -rf ./coverage
rm -rf ./build rm -rf ./build
rm -rf ./deps rm -rf ./deps
downloads/mqadv_dev903_ubuntu_x86-64.tar.gz: .PHONY: install-build-deps
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers"$(END))) install-build-deps:
mkdir -p downloads ARCH=$(ARCH) ./install-build-deps.sh
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz
.PHONY: downloads
downloads: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
.PHONY: deps
deps:
glide install --strip-vendor
cd test/docker && dep ensure -vendor-only
cd test/kubernetes && dep ensure -vendor-only
.PHONY: build-cov .PHONY: build-cov
build-cov: build-cov:
mkdir -p build mkdir -p build
cd build; go test -c -covermode=count ../cmd/runmqserver cd build; go test -c -covermode=count ../cmd/runmqserver
.PHONY: test-advancedserver .PHONY: precommit
test-advancedserver: precommit: fmt lint
cd pkg/name && go test
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_ADVANCEDSERVER) go test $(TEST_OPTS_DOCKER)
.PHONY: test-devserver .PHONY: fmt
test-devserver: fmt: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_DEVSERVER)"$(END))) go fmt $(addsuffix /..., $(GO_PKG_DIRS))
cd pkg/name && go test
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_DEVSERVER) go test
.PHONY: test-kubernetes-devserver .PHONY: lint
test-kubernetes-devserver: lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
$(call test-kubernetes,$(DOCKER_REPO_DEVSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-dev") @# This expression is necessary because /... includes the vendor directory in golint
@# As of 11/04/2018 there is an open issue to fix it: https://github.com/golang/lint/issues/320
golint -set_exit_status $(sort $(dir $(wildcard $(addsuffix /*/*.go, $(GO_PKG_DIRS)))))
.PHONY: test-kubernetes-advancedserver .PHONY: gosec
test-kubernetes-advancedserver: gosec: $(info $(SPACER)$(shell printf "Running gosec test"$(END)))
$(call test-kubernetes,$(DOCKER_REPO_ADVANCEDSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-prod") @gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null ;\
cat "gosec_results.json" ;\
define test-kubernetes cat gosec_results.json | grep HIGH | grep severity > /dev/null ;\
$(info $(SPACER)$(shell printf $(TITLE)"Test $1:$2 on Kubernetes"$(END))) if [ $$? -eq 0 ]; then \
cd test/kubernetes && TEST_REPO=$1 TEST_TAG=$2 TEST_CHART=$3 go test $(TEST_OPTS_KUBERNETES) printf "\nFAILURE: gosec found files containing HIGH severity issues - see results.json\n" ;\
endef exit 1 ;\
else \
define docker-build-mq printf "\ngosec found no HIGH severity issues\n" ;\
# Create a temporary network to use for the build fi ;\
$(DOCKER) network create build cat gosec_results.json | grep MEDIUM | grep severity > /dev/null ;\
# Start a web server to host the MQ downloadable (tar.gz) file if [ $$? -eq 0 ]; then \
$(DOCKER) run \ printf "\nFAILURE: gosec found files containing MEDIUM severity issues - see results.json\n" ;\
--rm \ exit 1 ;\
--name $(BUILD_SERVER_CONTAINER) \ else \
--network build \ printf "\ngosec found no MEDIUM severity issues\n" ;\
--network-alias build \ fi ;\
--volume "$(realpath ./downloads/)":/usr/share/nginx/html:ro \ cat gosec_results.json | grep LOW | grep severity > /dev/null;\
--detach \ if [ $$? -eq 0 ]; then \
nginx:alpine printf "\nFAILURE: gosec found files containing LOW severity issues - see results.json\n" ;\
# Build the new image exit 1;\
$(DOCKER) build \ else \
--pull \ printf "\ngosec found no LOW severity issues\n" ;\
--tag $1 \ fi ;\
--file $2 \
--network build \
--build-arg MQ_URL=http://build:80/$3 \
--label IBM_PRODUCT_ID=$4 \
--label IBM_PRODUCT_NAME=$5 \
--label IBM_PRODUCT_VERSION=$6 \
.
# Stop the web server (will also remove the container)
$(DOCKER) kill $(BUILD_SERVER_CONTAINER)
# Delete the temporary network
$(DOCKER) network rm build
endef
# .PHONY: build-advancedserver-903
# build-advancedserver-903: build downloads/CNJR7ML.tar.gz
# $(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
# $(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,CNJR7ML.tar.gz,"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced","9.0.3")
# $(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):9.0.3-$(DOCKER_TAG_ARCH)
.PHONY: build-advancedserver-904
build-advancedserver-904: downloads/CNLE4ML.tar.gz
$(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
$(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,CNLE4ML.tar.gz,"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced","9.0.4")
$(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):9.0.4-$(DOCKER_TAG_ARCH)
.PHONY: build-advancedserver
build-advancedserver: build-advancedserver-904
.PHONY: build-devserver
build-devserver: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
$(info $(shell printf $(TITLE)"Build $(DOCKER_FULL_DEVSERVER)"$(END)))
$(call docker-build-mq,$(DOCKER_FULL_DEVSERVER),Dockerfile-server,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
$(DOCKER) tag $(DOCKER_FULL_DEVSERVER) $(DOCKER_REPO_DEVSERVER):9.0.3-$(DOCKER_TAG_ARCH)
# .PHONY: build-server
# build-server: build downloads/CNJR7ML.tar.gz
# $(call docker-build-mq,mq-server:latest-$(DOCKER_TAG_ARCH),Dockerfile-server,"79afd716d55b4f149a87bec52c9dc1aa","IBM MQ","9.0.3")
# $(DOCKER) tag mq-server:latest-$(DOCKER_TAG_ARCH) mq-server:9.0.3-$(DOCKER_TAG_ARCH)
.PHONY: build-advancedserver-cover
build-advancedserver-cover: build-advanced-server build-cov
$(DOCKER) build -t mq-advancedserver:cover -f Dockerfile-server.cover .
# .PHONY: build-web
# build-web: build downloads/CNJR7ML.tar.gz
# $(call docker-build-mq,mq-web:latest-$(DOCKER_TAG_ARCH),Dockerfile-mq-web)
.PHONY: build-explorer
build-explorer: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
$(call docker-build-mq,mq-explorer:latest-$(DOCKER_TAG_ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
include formatting.mk include formatting.mk

View File

@@ -1,4 +1,4 @@
=============================================================================== ===============================================================================
THE FOLLOWING SECTIONS IDENTIFY VARIOUS COMPONENTS CONTAINED IN THE PROGRAM, AND SPECIFY CERTAIN NOTICES AND OTHER INFORMATION REGARDING THOSE COMPONENTS THAT IBM IS REQUIRED TO PROVIDE TO YOU. THE FOLLOWING SECTIONS IDENTIFY VARIOUS COMPONENTS CONTAINED IN THE PROGRAM, AND SPECIFY CERTAIN NOTICES AND OTHER INFORMATION REGARDING THOSE COMPONENTS THAT IBM IS REQUIRED TO PROVIDE TO YOU.
NOTWITHSTANDING ANY PROVISION CONTAINED IN ANY OF THE NOTICES AND OTHER INFORMATION SET FORTH BELOW, YOUR USE OF THESE PROGRAM COMPONENTS REMAINS SUBJECT TO THE TERMS AND CONDITIONS SET FORTH IN: NOTWITHSTANDING ANY PROVISION CONTAINED IN ANY OF THE NOTICES AND OTHER INFORMATION SET FORTH BELOW, YOUR USE OF THESE PROGRAM COMPONENTS REMAINS SUBJECT TO THE TERMS AND CONDITIONS SET FORTH IN:
@@ -13,23 +13,20 @@ A. SUMMARY
=============================================================================== ===============================================================================
Section B. below contains provisions relating to certain other components of the Program, as follows:- Section B. below contains provisions relating to certain other components of the Program, as follows:-
B.1 MIT license B.1 BSD 3-Clause license
Affected Components:
* github.com/hpcloud/tail
Copyright 2015 Hewlett Packard Enterprise Development LP
Copyright (c) 2014 ActiveState
B.2 BSD 3-Clause license
Affected Components: Affected Components:
* golang.org/x/crypto * golang.org/x/crypto
Copyright (c) 2009 The Go Authors. All rights reserved. Copyright (c) 2009 The Go Authors. All rights reserved.
* golang.org/x/sys * golang.org/x/sys
Copyright (c) 2009 The Go Authors. All rights reserved. Copyright (c) 2009 The Go Authors. All rights reserved.
* gopkg.in/fsnotify.v1
Copyright (c) 2012 The Go Authors. All rights reserved. B.2 MIT license
Copyright (c) 2012 fsnotify Authors. All rights reserved. * github.com/genuinetools/amicontained
* gopkg.in/tomb.v1 Copyright (c) 2018 The Genuinetools Authors
Copyright (c) 2010-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>. All rights reserved.
B.3 BSD 2-Clause license
* github.com/syndtr/gocapability/
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
=============================================================================== ===============================================================================
END OF A. SUMMARY END OF A. SUMMARY
@@ -38,30 +35,7 @@ END OF A. SUMMARY
B. LICENSE FILES AND OTHER INFORMATION B. LICENSE FILES AND OTHER INFORMATION
========================================================================== ==========================================================================
========================================================================== ==========================================================================
B.1 MIT license B.1 BSD 3-Clause 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.
==========================================================================
END OF B.1 MIT license
==========================================================================
==========================================================================
B.2 BSD 3-Clause license
========================================================================== ==========================================================================
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -89,7 +63,59 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
========================================================================== ==========================================================================
END OF B.2 BSD 3-Clause license END OF B.1 BSD 3-Clause license
==========================================================================
==========================================================================
B.2 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.
==========================================================================
END OF B.2 MIT license
==========================================================================
==========================================================================
B.3 BSD 2-Clause license
==========================================================================
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==========================================================================
END OF B.3 BSD 2-Clause license
========================================================================== ==========================================================================
========================================================================== ==========================================================================

View File

@@ -1,50 +1,54 @@
![IBM MQ logo](https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png) # IBM MQ container
# Overview [![Build Status](https://travis-ci.org/ibm-messaging/mq-container.svg?branch=master)](https://travis-ci.org/ibm-messaging/mq-container)
Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container. The supplied [Helm](https://helm.sh/) chart can be used to run the container on a [Kubernetes](https://kubernetes.io) cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Bluemix Container Service](https://www.ibm.com/cloud-computing/bluemix/containers). **Note**: The `master` branch may be in an *unstable or even broken state* during development.
To get a stable version, please use the correct [branch](https://github.com/ibm-messaging/mq-container/branches) for your MQ version, instead of the `master` branch.
# Current status ## Overview
MQ Advanced for Developers image - [![Build Status](https://travis-ci.org/ibm-messaging/mq-container.svg?branch=master)](https://travis-ci.org/ibm-messaging/mq-container)
# Build Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container.
After extracting the code from this repository, you can build an image with the latest version of MQ using the following command:
## Building MQ Advanced You can build an image containing either IBM MQ Advanced, or IBM MQ Advanced for Developers. The developer image includes a [default developer configuration](docs/developer-config.md), to make it easier to get started. There is also an [incubating](incubating) folder for additional images for other MQ components, which you might find useful.
You can build an image for MQ Advanced, follow these steps:
1. Clone this repository into the correct location in your [`GOPATH`](https://github.com/golang/go/wiki/GOPATH) ## Build
2. Create a directory called `downloads` under the cloned directory tree
3. Download the MQ Advanced for Ubuntu (debs) installer package file `CNJR7ML.tar.gz` into the `downloads` directory
4. Run `make build-advancedserver`
# Usage After extracting the code from this repository, you can follow the [build documentation](docs/building.md) to build an image.
In order to use the image, it is necessary to accept the terms of the IBM MQ license. This is achieved by specifying the environment variable `LICENSE` equal to `accept` when running the image. You can also view the license terms by setting this variable to `view`. Failure to set the variable will result in the termination of the container with a usage statement. You can view the license in a different language by also setting the `LANG` environment variable.
## Usage
## List of all Environment variables supported by this image See the [usage documentation](docs/usage.md) for details on how to run a container.
* **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`. Note that in order to use the image, it is necessary to accept the terms of the [IBM MQ license](#license).
* **LANG** - Set this to the language you would like the license to be printed in.
* **MQ_QMGR_NAME** - Set this to the name you want your Queue Manager to be created with.
### Environment variables supported by this image
# Issues and contributions - **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
- **LANG** - Set this to the language you would like the license to be printed in.
- **MQ_QMGR_NAME** - Set this to the name you want your Queue Manager to be created with.
- **LOG_FORMAT** - Set this to change the format of the logs which are printed on the container's stdout. Set to "json" to use JSON format (JSON object per line); set to "basic" to use a simple human-readable format. Defaults to "basic".
- **MQ_ENABLE_METRICS** - Set this to `true` to generate Prometheus metrics for your Queue Manager.
See the [default developer configuration docs](docs/developer-config.md) for the extra environment variables supported by the MQ Advanced for Developers image.
### Kubernetes
If you want to use IBM MQ in [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM charts](https://github.com/IBM/charts). This can be used to run the container on a cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
## Issues and contributions
For issues relating specifically to the container image or Helm chart, please use the [GitHub issue tracker](https://github.com/ibm-messaging/mq-container/issues). If you do submit a Pull Request related to this Docker image, please indicate in the Pull Request that you accept and agree to be bound by the terms of the [IBM Contributor License Agreement](CLA.md). For issues relating specifically to the container image or Helm chart, please use the [GitHub issue tracker](https://github.com/ibm-messaging/mq-container/issues). If you do submit a Pull Request related to this Docker image, please indicate in the Pull Request that you accept and agree to be bound by the terms of the [IBM Contributor License Agreement](CLA.md).
## License
# License
The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). The Dockerfiles and associated code and scripts are licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
Licenses for the products installed within the images are as follows: Licenses for the products installed within the images are as follows:
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-AKHJY4) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above. - [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-BBZHCQ) (International License Agreement for Non-Warranted Programs). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
- [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-AKHJJP) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above. - [IBM MQ Advanced](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-APIG-BGMHFW) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
- License information for Ubuntu packages may be found in `/usr/share/doc/${package}/copyright`
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine. 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, 2017 © Copyright IBM Corporation 2015, 2019

View File

@@ -1,739 +0,0 @@
The translated license terms can be viewed here: https://www-03.ibm.com/software/sla/sladb.nsf/displaylis/1CF4B88EAF6FB60B8525812F005F71E2?OpenDocument
LICENSE INFORMATION
The Programs listed below are licensed under the following License Information terms and conditions in addition to the Program license terms previously agreed to by Client and IBM. If Client does not have previously agreed to license terms in effect for the Program, the International License Agreement for Non-Warranted Programs (Z125-5589-05) applies.
Program Name (Program Number):
IBM MQ Advanced for Developers (Non-Warranted) V9.0.3 (5724-H72)
The following standard terms apply to Licensee's use of the Program.
Bundled Programs
The Program is licensed as a multi-product package consisting of the Bundled Programs identified below. Licensee is authorized to install and use such Bundled Programs within the limits of the Proofs of Entitlement for the Program and as stated in this License Information document. Licensee is not authorized to transfer or remarket the Bundled Programs separate from the multi-product package. A Bundled Program may be accompanied by license terms, and those terms, if any, apply to Licensee's use of that Bundled Program. In the event of conflict, the terms in this License Information document supersede the Bundled Program's terms. When Licensee's right to use the Program expires or terminates, Licensee must discontinue use, destroy or promptly return all copies of the Bundled Programs to the party from whom Licensee acquired the Program. If Licensee downloaded the Bundled Programs, Licensee should contact the party from whom Licensee acquired the Program. If Licensee wishes to license the Bundled Programs for any use beyond the limits set forth above, please contact an IBM Sales Representative or the party from whom Licensee acquired the Program to obtain the appropriate license.
The following are Bundled Programs licensed with the Program:
IBM MQ V9.0.3
Developer Limitation
If the Program is designated as for "Developers", the Program can only be deployed as part of Licensee's internal development and unit testing on a developer machine. A developer machine is a physical or virtual desktop environment, running a primary operating system and the Program, both of which are accessible and used by no more than one specified developer. Licensee is not authorized to use the Program for processing production workloads, simulating production workloads or testing scalability of any code, application or system. Licensee is not authorized to use any part of the Program for any other purposes without acquiring the appropriate production entitlements.
Components Not Used for Establishing Required Entitlements
When determining the number of entitlements required for Licensee's installation or use of the Program, the installation or use of the following Program components are not taken into consideration. In other words, Licensee may install and use the following Program components, under the license terms, but these components are not used to determine the number of entitlements required for the Program.
IBM MQ Managed File Transfer Agent V9.0.1
IBM MQ Telemetry V9.0.1
Source Components and Sample Materials
The Program may include some components in source code form ("Source Components") and other materials identified as Sample Materials. Licensee may copy and modify Source Components and Sample Materials for internal use only provided such use is within the limits of the license rights under this Agreement, provided however that Licensee may not alter or delete any copyright information or notices contained in the Source Components or Sample Materials. IBM provides the Source Components and Sample Materials without obligation of support and "AS IS", WITH NO WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTY OF TITLE, NON-INFRINGEMENT OR NON-INTERFERENCE AND THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
L/N: L-APIG-AKHJY4
D/N: L-APIG-AKHJY4
P/N: L-APIG-AKHJY4
International License Agreement for Non-Warranted Programs
Part 1 - General Terms
BY DOWNLOADING, INSTALLING, COPYING, ACCESSING, CLICKING ON AN "ACCEPT" BUTTON, OR OTHERWISE USING THE PROGRAM, LICENSEE AGREES TO THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCEPTING THESE TERMS ON BEHALF OF LICENSEE, YOU REPRESENT AND WARRANT THAT YOU HAVE FULL AUTHORITY TO BIND LICENSEE TO THESE TERMS. IF YOU DO NOT AGREE TO THESE TERMS,
* DO NOT DOWNLOAD, INSTALL, COPY, ACCESS, CLICK ON AN "ACCEPT" BUTTON, OR USE THE PROGRAM; AND
* PROMPTLY RETURN THE UNUSED MEDIA AND DOCUMENTATION TO THE PARTY FROM WHOM IT WAS OBTAINED FOR A REFUND OF THE AMOUNT PAID. IF THE PROGRAM WAS DOWNLOADED, DESTROY ALL COPIES OF THE PROGRAM.
1. Definitions
"Authorized Use" - the specified level at which Licensee is authorized to execute or run the Program. That level may be measured by number of users, millions of service units ("MSUs"), Processor Value Units ("PVUs"), or other level of use specified by IBM.
"IBM" - International Business Machines Corporation or one of its subsidiaries.
"License Information" ("LI") - a document that provides information and any additional terms specific to a Program. The Program's LI is available at www.ibm.com/software/sla. The LI can also be found in the Program's directory, by the use of a system command, or as a booklet included with the Program.
"Program" - the following, including the original and all whole or partial copies: 1) machine-readable instructions and data, 2) components, files, and modules, 3) audio-visual content (such as images, text, recordings, or pictures), and 4) related licensed materials (such as keys and documentation).
2. Agreement Structure
This Agreement includes Part 1 - General Terms, Part 2 - Country-unique Terms (if any) and the LI and is the complete agreement between Licensee and IBM regarding the use of the Program. It replaces any prior oral or written communications between Licensee and IBM concerning Licensee's use of the Program. The terms of Part 2 may replace or modify those of Part 1. To the extent of any conflict, the LI prevails over both Parts.
3. License Grant
The Program is owned by IBM or an IBM supplier, and is copyrighted and licensed, not sold.
IBM grants Licensee a nonexclusive license to 1) use the Program up to the Authorized Use specified in the invoice, 2) make and install copies to support such Authorized Use, and 3) make a backup copy, all provided that
a. Licensee has lawfully obtained the Program and complies with the terms of this Agreement;
b. the backup copy does not execute unless the backed-up Program cannot execute;
c. Licensee reproduces all copyright notices and other legends of ownership on each copy, or partial copy, of the Program;
d. Licensee ensures that anyone who uses the Program (accessed either locally or remotely) 1) does so only on Licensee's behalf and 2) complies with the terms of this Agreement;
e. Licensee does not 1) use, copy, modify, or distribute the Program except as expressly permitted in this Agreement; 2) reverse assemble, reverse compile, otherwise translate, or reverse engineer the Program, except as expressly permitted by law without the possibility of contractual waiver; 3) use any of the Program's components, files, modules, audio-visual content, or related licensed materials separately from that Program; or 4) sublicense, rent, or lease the Program; and
f. if Licensee obtains this Program as a Supporting Program, Licensee uses this Program only to support the Principal Program and subject to any limitations in the license to the Principal Program, or, if Licensee obtains this Program as a Principal Program, Licensee uses all Supporting Programs only to support this Program, and subject to any limitations in this Agreement. For purposes of this Item "f," a "Supporting Program" is a Program that is part of another IBM Program ("Principal Program") and identified as a Supporting Program in the Principal Program's LI. (To obtain a separate license to a Supporting Program without these restrictions, Licensee should contact the party from whom Licensee obtained the Supporting Program.)
This license applies to each copy of the Program that Licensee makes.
3.1 Trade-ups, Updates, Fixes, and Patches
3.1.1 Trade-ups
If the Program is replaced by a trade-up Program, the replaced Program's license is promptly terminated.
3.1.2 Updates, Fixes, and Patches
When Licensee receives an update, fix, or patch to a Program, Licensee accepts any additional or different terms that are applicable to such update, fix, or patch that are specified in its LI. If no additional or different terms are provided, then the update, fix, or patch is subject solely to this Agreement. If the Program is replaced by an update, Licensee agrees to promptly discontinue use of the replaced Program.
3.2 Fixed Term Licenses
If IBM licenses the Program for a fixed term, Licensee's license is terminated at the end of the fixed term, unless Licensee and IBM agree to renew it.
3.3 Term and Termination
This Agreement is effective until terminated.
IBM may terminate Licensee's license if Licensee fails to comply with the terms of this Agreement.
If the license is terminated for any reason by either party, Licensee agrees to promptly discontinue use of and destroy all of Licensee's copies of the Program. Any terms of this Agreement that by their nature extend beyond termination of this Agreement remain in effect until fulfilled, and apply to both parties' respective successors and assignees.
4. Charges
Charges, if any, are based on Authorized Use obtained, which is specified in the invoice. IBM does not give credits or refunds for charges already due or paid, except as specified elsewhere in this Agreement.
If Licensee wishes to increase its Authorized Use, Licensee must notify IBM or an authorized IBM reseller in advance and pay any applicable charges.
5. Taxes
If any authority imposes on the Program a duty, tax, levy, or fee, excluding those based on IBM's net income, then Licensee agrees to pay that amount, as specified in an invoice, or supply exemption documentation. Licensee is responsible for any personal property taxes for the Program from the date that Licensee obtains it. If any authority imposes a customs duty, tax, levy, or fee for the import into or the export, transfer, access, or use of the Program outside the country in which the original Licensee was granted the license, then Licensee agrees that it is responsible for, and will pay, any amount imposed.
6. Money-back Guarantee
If Licensee is dissatisfied with the Program for any reason and is the original Licensee, Licensee may terminate the license and obtain a refund of the amount Licensee paid, if any, for the Program, provided that Licensee returns the Program to the party from whom Licensee obtained it within 30 days of the invoice date. If the license is for a fixed term that is subject to renewal, then Licensee may obtain a refund only if the Program is returned within the first 30 days of the initial term. If Licensee downloaded the Program, Licensee should contact the party from whom Licensee obtained it for instructions on how to obtain the refund.
7. Program Transfer
Licensee may transfer the Program and all of Licensee's license rights and obligations to another party only if that party agrees to the terms of this Agreement. If the license is terminated for any reason by either party, Licensee is prohibited from transferring the Program to another party. Licensee may not transfer a portion of 1) the Program or 2) the Program's Authorized Use. When Licensee transfers the Program, Licensee must also transfer a hard copy of this Agreement, including the LI. Immediately after the transfer, Licensee's license terminates.
8. No Warranties
SUBJECT TO ANY STATUTORY WARRANTIES THAT CANNOT BE EXCLUDED, IBM MAKES NO WARRANTIES OR CONDITIONS, EXPRESS OR IMPLIED, REGARDING THE PROGRAM OR SUPPORT, IF ANY, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, AND TITLE, AND ANY WARRANTY OR CONDITION OF NON-INFRINGEMENT.
SOME STATES OR JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF EXPRESS OR IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO LICENSEE. IN THAT EVENT, SUCH WARRANTIES ARE LIMITED IN DURATION TO THE MINIMUM PERIOD REQUIRED BY LAW. NO WARRANTIES APPLY AFTER THAT PERIOD. SOME STATES OR JURISDICTIONS DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY LASTS, SO THE ABOVE LIMITATION MAY NOT APPLY TO LICENSEE. LICENSEE MAY HAVE OTHER RIGHTS THAT VARY FROM STATE TO STATE OR JURISDICTION TO JURISDICTION.
THE DISCLAIMERS AND EXCLUSIONS IN THIS SECTION 8 ALSO APPLY TO ANY OF IBM'S PROGRAM DEVELOPERS AND SUPPLIERS.
MANUFACTURERS, SUPPLIERS, OR PUBLISHERS OF NON-IBM PROGRAMS MAY PROVIDE THEIR OWN WARRANTIES.
IBM DOES NOT PROVIDE SUPPORT OF ANY KIND, UNLESS IBM SPECIFIES OTHERWISE. IN SUCH EVENT, ANY SUPPORT PROVIDED BY IBM IS SUBJECT TO THE DISCLAIMERS AND EXCLUSIONS IN THIS SECTION 8.
9. Licensee Data and Databases
To assist Licensee in isolating the cause of a problem with the Program, IBM may request that Licensee 1) allow IBM to remotely access Licensee's system or 2) send Licensee information or system data to IBM. However, IBM is not obligated to provide such assistance unless IBM and Licensee enter a separate written agreement under which IBM agrees to provide to Licensee that type of support, which is beyond IBM's obligations in this Agreement. In any event, IBM uses information about errors and problems to improve its products and services, and assist with its provision of related support offerings. For these purposes, IBM may use IBM entities and subcontractors (including in one or more countries other than the one in which Licensee is located), and Licensee authorizes IBM to do so.
Licensee remains responsible for 1) any data and the content of any database Licensee makes available to IBM, 2) the selection and implementation of procedures and controls regarding access, security, encryption, use, and transmission of data (including any personally-identifiable data), and 3) backup and recovery of any database and any stored data. Licensee will not send or provide IBM access to any personally-identifiable information, whether in data or any other form, and will be responsible for reasonable costs and other amounts that IBM may incur relating to any such information mistakenly provided to IBM or the loss or disclosure of such information by IBM, including those arising out of any third party claims.
10. Limitation of Liability
The limitations and exclusions in this Section 10 (Limitation of Liability) apply to the full extent they are not prohibited by applicable law without the possibility of contractual waiver.
10.1 Items for Which IBM May Be Liable
Circumstances may arise where, because of a default on IBM's part or other liability, Licensee is entitled to recover damages from IBM. Regardless of the basis on which Licensee is entitled to claim damages from IBM (including fundamental breach, negligence, misrepresentation, or other contract or tort claim), IBM's entire liability for all claims in the aggregate arising from or related to each Program or otherwise arising under this Agreement will not exceed the amount of any 1) damages for bodily injury (including death) and damage to real property and tangible personal property and 2) other actual direct damages up to the charges (if the Program is subject to fixed term charges, up to twelve months' charges) Licensee paid for the Program that is the subject of the claim.
This limit also applies to any of IBM's Program developers and suppliers. It is the maximum for which IBM and its Program developers and suppliers are collectively responsible.
10.2 Items for Which IBM Is Not Liable
UNDER NO CIRCUMSTANCES IS IBM, ITS PROGRAM DEVELOPERS OR SUPPLIERS LIABLE FOR ANY OF THE FOLLOWING, EVEN IF INFORMED OF THEIR POSSIBILITY:
a. LOSS OF, OR DAMAGE TO, DATA;
b. SPECIAL, INCIDENTAL, EXEMPLARY, OR INDIRECT DAMAGES, OR FOR ANY ECONOMIC CONSEQUENTIAL DAMAGES; OR
c. LOST PROFITS, BUSINESS, REVENUE, GOODWILL, OR ANTICIPATED SAVINGS.
11. Compliance Verification
For purposes of this Section 11 (Compliance Verification), "ILAN Program Terms" means 1) this Agreement and applicable amendments and transaction documents provided by IBM, and 2) IBM software policies that may be found at the IBM Software Policy website (www.ibm.com/softwarepolicies), including but not limited to those policies concerning backup, sub-capacity pricing, and migration.
The rights and obligations set forth in this Section 11 remain in effect during the period the Program is licensed to Licensee, and for two years thereafter.
11.1 Verification Process
Licensee agrees to create, retain, and provide to IBM and its auditors accurate written records, system tool outputs, and other system information sufficient to provide auditable verification that Licensee's use of all Programs is in compliance with the ILAN Program Terms, including, without limitation, all of IBM's applicable licensing and pricing qualification terms. Licensee is responsible for 1) ensuring that it does not exceed its Authorized Use, and 2) remaining in compliance with ILAN Program Terms.
Upon reasonable notice, IBM may verify Licensee's compliance with ILAN Program Terms at all sites and for all environments in which Licensee uses (for any purpose) Programs subject to ILAN Program Terms. Such verification will be conducted in a manner that minimizes disruption to Licensee's business, and may be conducted on Licensee's premises, during normal business hours. IBM may use an independent auditor to assist with such verification, provided IBM has a written confidentiality agreement in place with such auditor.
11.2 Resolution
IBM will notify Licensee in writing if any such verification indicates that Licensee has used any Program in excess of its Authorized Use or is otherwise not in compliance with the ILAN Program Terms. Licensee agrees to promptly pay directly to IBM the charges that IBM specifies in an invoice for 1) any such excess use, 2) support for such excess use for the lesser of the duration of such excess use or two years, and 3) any additional charges and other liabilities determined as a result of such verification.
12. Third Party Notices
The Program may include third party code that IBM, not the third party, licenses to Licensee under this Agreement. Notices, if any, for the third party code ("Third Party Notices") are included for Licensee's information only. These notices can be found in the Program's NOTICES file(s). Information on how to obtain source code for certain third party code can be found in the Third Party Notices. If in the Third Party Notices IBM identifies third party code as "Modifiable Third Party Code," IBM authorizes Licensee to 1) modify the Modifiable Third Party Code and 2) reverse engineer the Program modules that directly interface with the Modifiable Third Party Code provided that it is only for the purpose of debugging Licensee's modifications to such third party code. IBM's service and support obligations, if any, apply only to the unmodified Program.
13. General
a. Nothing in this Agreement affects any statutory rights of consumers that cannot be waived or limited by contract.
b. For Programs IBM provides to Licensee in tangible form, IBM fulfills its shipping and delivery obligations upon the delivery of such Programs to the IBM-designated carrier, unless otherwise agreed to in writing by Licensee and IBM.
c. If any provision of this Agreement is held to be invalid or unenforceable, the remaining provisions of this Agreement remain in full force and effect.
d. Licensee agrees to comply with all applicable export and import laws and regulations, including U.S. embargo and sanctions regulations and prohibitions on export for certain end uses or to certain users.
e. Licensee authorizes International Business Machines Corporation and its subsidiaries (and their successors and assigns, contractors and IBM Business Partners) to store and use Licensee's business contact information wherever they do business, in connection with IBM products and services, or in furtherance of IBM's business relationship with Licensee.
f. Each party will allow the other reasonable opportunity to comply before it claims that the other has not met its obligations under this Agreement. The parties will attempt in good faith to resolve all disputes, disagreements, or claims between the parties relating to this Agreement.
g. Unless otherwise required by applicable law without the possibility of contractual waiver or limitation: 1) neither party will bring a legal action, regardless of form, for any claim arising out of or related to this Agreement more than two years after the cause of action arose; and 2) upon the expiration of such time limit, any such claim and all respective rights related to the claim lapse.
h. Neither Licensee nor IBM is responsible for failure to fulfill any obligations due to causes beyond its control.
i. No right or cause of action for any third party is created by this Agreement, nor is IBM responsible for any third party claims against Licensee, except as permitted in Subsection 10.1 (Items for Which IBM May Be Liable) above for bodily injury (including death) or damage to real or tangible personal property for which IBM is legally liable to that third party.
j. In entering into this Agreement, neither party is relying on any representation not specified in this Agreement, including but not limited to any representation concerning: 1) the performance or function of the Program; 2) the experiences or recommendations of other parties; or 3) any results or savings that Licensee may achieve.
k. IBM has signed agreements with certain organizations (called "IBM Business Partners") to promote, market, and support certain Programs. IBM Business Partners remain independent and separate from IBM. IBM is not responsible for the actions or statements of IBM Business Partners or obligations they have to Licensee.
l. The license and intellectual property indemnification terms of Licensee's other agreements with IBM (such as the IBM Customer Agreement) do not apply to Program licenses granted under this Agreement.
m. Both parties agree that all information exchanged is nonconfidential. If either party requires the exchange of confidential information, it will be made under a signed confidentiality agreement.
14. Geographic Scope and Governing Law
14.1 Governing Law
Both parties agree to the application of the laws of the country in which Licensee obtained the Program license to govern, interpret, and enforce all of Licensee's and IBM's respective rights, duties, and obligations arising from, or relating in any manner to, the subject matter of this Agreement, without regard to conflict of law principles.
The United Nations Convention on Contracts for the International Sale of Goods does not apply.
14.2 Jurisdiction
All rights, duties, and obligations are subject to the courts of the country in which Licensee obtained the Program license.
Part 2 - Country-unique Terms
For licenses granted in the countries specified below, the following terms replace or modify the referenced terms in Part 1. All terms in Part 1 that are not changed by these amendments remain unchanged and in effect. This Part 2 is organized as follows:
* Multiple country amendments to Part 1, Section 14 (Governing Law and Jurisdiction);
* Americas country amendments to other Agreement terms;
* Asia Pacific country amendments to other Agreement terms; and
* Europe, Middle East, and Africa country amendments to other Agreement terms.
Multiple country amendments to Part 1, Section 14 (Governing Law and Jurisdiction)
14.1 Governing Law
The phrase "the laws of the country in which Licensee obtained the Program license" in the first paragraph of 14.1 Governing Law is replaced by the following phrases in the countries below:
AMERICAS
(1) In Canada: the laws in the Province of Ontario;
(2) in Mexico: the federal laws of the Republic of Mexico;
(3) in the United States, Anguilla, Antigua/Barbuda, Aruba, British Virgin Islands, Cayman Islands, Dominica, Grenada, Guyana, Saint Kitts and Nevis, Saint Lucia, Saint Maarten, and Saint Vincent and the Grenadines: the laws of the State of New York, United States;
(4) in Venezuela: the laws of the Bolivarian Republic of Venezuela;
ASIA PACIFIC
(5) in Cambodia and Laos: the laws of the State of New York, United States;
(6) in Australia: the laws of the State or Territory in which the transaction is performed;
(7) in Hong Kong SAR and Macau SAR: the laws of Hong Kong Special Administrative Region ("SAR");
(8) in Taiwan: the laws of Taiwan;
EUROPE, MIDDLE EAST, AND AFRICA
(9) in Albania, Armenia, Azerbaijan, Belarus, Bosnia-Herzegovina, Bulgaria, Croatia, Former Yugoslav Republic of Macedonia, Georgia, Hungary, Kazakhstan, Kyrgyzstan, Moldova, Montenegro, Poland, Romania, Russia, Serbia, Slovakia, Tajikistan, Turkmenistan, Ukraine, and Uzbekistan: the laws of Austria;
(10) in Algeria, Andorra, Benin, Burkina Faso, Cameroon, Cape Verde, Central African Republic, Chad, Comoros, Congo Republic, Djibouti, Democratic Republic of Congo, Equatorial Guinea, French Guiana, French Polynesia, Gabon, Gambia, Guinea, Guinea-Bissau, Ivory Coast, Lebanon, Madagascar, Mali, Mauritania, Mauritius, Mayotte, Morocco, New Caledonia, Niger, Reunion, Senegal, Seychelles, Togo, Tunisia, Vanuatu, and Wallis and Futuna: the laws of France;
(11) in Estonia, Latvia, and Lithuania: the laws of Finland;
(12) in Angola, Bahrain, Botswana, Burundi, Egypt, Eritrea, Ethiopia, Ghana, Jordan, Kenya, Kuwait, Liberia, Malawi, Malta, Mozambique, Nigeria, Oman, Pakistan, Qatar, Rwanda, Sao Tome and Principe, Saudi Arabia, Sierra Leone, Somalia, Tanzania, Uganda, United Arab Emirates, the United Kingdom, West Bank/Gaza, Yemen, Zambia, and Zimbabwe: the laws of England; and
(13) in South Africa, Namibia, Lesotho, and Swaziland: the laws of the Republic of South Africa.
14.2 Jurisdiction
The following paragraph pertains to jurisdiction and replaces Subsection 14.2 (Jurisdiction) as it applies for those countries identified below:
All rights, duties, and obligations are subject to the courts of the country in which Licensee obtained the Program license except that in the countries identified below all disputes arising out of or related to this Agreement, including summary proceedings, will be brought before and subject to the exclusive jurisdiction of the following courts of competent jurisdiction:
AMERICAS
(1) In Argentina: the Ordinary Commercial Court of the city of Buenos Aires;
(2) in Brazil: the court of Rio de Janeiro, RJ;
(3) in Chile: the Civil Courts of Justice of Santiago;
(4) in Ecuador: the civil judges of Quito for executory or summary proceedings (as applicable);
(5) in Mexico: the courts located in Mexico City, Federal District;
(6) in Peru: the judges and tribunals of the judicial district of Lima, Cercado;
(7) in Uruguay: the courts of the city of Montevideo;
(8) in Venezuela: the courts of the metropolitan area of the city of Caracas;
EUROPE, MIDDLE EAST, AND AFRICA
(9) in Austria: the court of law in Vienna, Austria (Inner-City);
(10) in Algeria, Andorra, Benin, Burkina Faso, Cameroon, Cape Verde, Central African Republic, Chad, Comoros, Congo Republic, Djibouti, Democratic Republic of Congo, Equatorial Guinea, France, French Guiana, French Polynesia, Gabon, Gambia, Guinea, Guinea-Bissau, Ivory Coast, Lebanon, Madagascar, Mali, Mauritania, Mauritius, Mayotte, Monaco, Morocco, New Caledonia, Niger, Reunion, Senegal, Seychelles, Togo, Tunisia, Vanuatu, and Wallis and Futuna: the Commercial Court of Paris;
(11) in Angola, Bahrain, Botswana, Burundi, Egypt, Eritrea, Ethiopia, Ghana, Jordan, Kenya, Kuwait, Liberia, Malawi, Malta, Mozambique, Nigeria, Oman, Pakistan, Qatar, Rwanda, Sao Tome and Principe, Saudi Arabia, Sierra Leone, Somalia, Tanzania, Uganda, United Arab Emirates, the United Kingdom, West Bank/Gaza, Yemen, Zambia, and Zimbabwe: the English courts;
(12) in South Africa, Namibia, Lesotho, and Swaziland: the High Court in Johannesburg;
(13) in Greece: the competent court of Athens;
(14) in Israel: the courts of Tel Aviv-Jaffa;
(15) in Italy: the courts of Milan;
(16) in Portugal: the courts of Lisbon;
(17) in Spain: the courts of Madrid; and
(18) in Turkey: the Istanbul Central Courts and Execution Directorates of Istanbul, the Republic of Turkey.
14.3 Arbitration
The following paragraph is added as a new Subsection 14.3 (Arbitration) as it applies for those countries identified below. The provisions of this Subsection 14.3 prevail over those of Subsection 14.2 (Jurisdiction) to the extent permitted by the applicable governing law and rules of procedure:
ASIA PACIFIC
(1) In Cambodia, India, Laos, Philippines, and Vietnam:
Disputes arising out of or in connection with this Agreement will be finally settled by arbitration which will be held in Singapore in accordance with the Arbitration Rules of Singapore International Arbitration Center ("SIAC Rules") then in effect. The arbitration award will be final and binding for the parties without appeal and will be in writing and set forth the findings of fact and the conclusions of law.
The number of arbitrators will be three, with each side to the dispute being entitled to appoint one arbitrator. The two arbitrators appointed by the parties will appoint a third arbitrator who will act as chairman of the proceedings. Vacancies in the post of chairman will be filled by the president of the SIAC. Other vacancies will be filled by the respective nominating party. Proceedings will continue from the stage they were at when the vacancy occurred.
If one of the parties refuses or otherwise fails to appoint an arbitrator within 30 days of the date the other party appoints its, the first appointed arbitrator will be the sole arbitrator, provided that the arbitrator was validly and properly appointed.
All proceedings will be conducted, including all documents presented in such proceedings, in the English language. The English language version of this Agreement prevails over any other language version.
(2) In the People's Republic of China:
In case no settlement can be reached, the disputes will be submitted to China International Economic and Trade Arbitration Commission for arbitration according to the then effective rules of the said Arbitration Commission. The arbitration will take place in Beijing and be conducted in Chinese. The arbitration award will be final and binding on both parties. During the course of arbitration, this agreement will continue to be performed except for the part which the parties are disputing and which is undergoing arbitration.
(3) In Indonesia:
Each party will allow the other reasonable opportunity to comply before it claims that the other has not met its obligations under this Agreement. The parties will attempt in good faith to resolve all disputes, disagreements, or claims between the parties relating to this Agreement. Unless otherwise required by applicable law without the possibility of contractual waiver or limitation, i) neither party will bring a legal action, regardless of form, arising out of or related to this Agreement or any transaction under it more than two years after the cause of action arose; and ii) after such time limit, any legal action arising out of this Agreement or any transaction under it and all respective rights related to any such action lapse.
Disputes arising out of or in connection with this Agreement shall be finally settled by arbitration that shall be held in Jakarta, Indonesia in accordance with the rules of Board of the Indonesian National Board of Arbitration (Badan Arbitrase Nasional Indonesia or "BANI") then in effect. The arbitration award shall be final and binding for the parties without appeal and shall be in writing and set forth the findings of fact and the conclusions of law.
The number of arbitrators shall be three, with each side to the dispute being entitled to appoint one arbitrator. The two arbitrators appointed by the parties shall appoint a third arbitrator who shall act as chairman of the proceedings. Vacancies in the post of chairman shall be filled by the chairman of the BANI. Other vacancies shall be filled by the respective nominating party. Proceedings shall continue from the stage they were at when the vacancy occurred.
If one of the parties refuses or otherwise fails to appoint an arbitrator within 30 days of the date the other party appoints its, the first appointed arbitrator shall be the sole arbitrator, provided that the arbitrator was validly and properly appointed.
All proceedings shall be conducted, including all documents presented in such proceedings, in the English and/or Indonesian language.
EUROPE, MIDDLE EAST, AND AFRICA
(4) In Albania, Armenia, Azerbaijan, Belarus, Bosnia-Herzegovina, Bulgaria, Croatia, Former Yugoslav Republic of Macedonia, Georgia, Hungary, Kazakhstan, Kyrgyzstan, Moldova, Montenegro, Poland, Romania, Russia, Serbia, Slovakia, Tajikistan, Turkmenistan, Ukraine, and Uzbekistan:
All disputes arising out of this Agreement or related to its violation, termination or nullity will be finally settled under the Rules of Arbitration and Conciliation of the International Arbitral Center of the Federal Economic Chamber in Vienna (Vienna Rules) by three arbitrators appointed in accordance with these rules. The arbitration will be held in Vienna, Austria, and the official language of the proceedings will be English. The decision of the arbitrators will be final and binding upon both parties. Therefore, pursuant to paragraph 598 (2) of the Austrian Code of Civil Procedure, the parties expressly waive the application of paragraph 595 (1) figure 7 of the Code. IBM may, however, institute proceedings in a competent court in the country of installation.
(5) In Estonia, Latvia, and Lithuania:
All disputes arising in connection with this Agreement will be finally settled in arbitration that will be held in Helsinki, Finland in accordance with the arbitration laws of Finland then in effect. Each party will appoint one arbitrator. The arbitrators will then jointly appoint the chairman. If arbitrators cannot agree on the chairman, then the Central Chamber of Commerce in Helsinki will appoint the chairman.
AMERICAS COUNTRY AMENDMENTS
CANADA
10.1 Items for Which IBM May Be Liable
The following replaces Item 1 in the first paragraph of this Subsection 10.1 (Items for Which IBM May Be Liable):
1) damages for bodily injury (including death) and physical harm to real property and tangible personal property caused by IBM's negligence; and
13. General
The following replaces Item 13.d:
d. Licensee agrees to comply with all applicable export and import laws and regulations, including those of that apply to goods of United States origin and that prohibit or limit export for certain uses or to certain users.
The following replaces Item 13.i:
i. No right or cause of action for any third party is created by this Agreement or any transaction under it, nor is IBM responsible for any third party claims against Licensee except as permitted by the Limitation of Liability section above for bodily injury (including death) or physical harm to real or tangible personal property caused by IBM's negligence for which IBM is legally liable to that third party.
The following is added as Item 13.n:
n. For purposes of this Item 13.n, "Personal Data" refers to information relating to an identified or identifiable individual made available by one of the parties, its personnel or any other individual to the other in connection with this Agreement. The following provisions apply in the event that one party makes Personal Data available to the other:
(1) General
(a) Each party is responsible for complying with any obligations applying to it under applicable Canadian data privacy laws and regulations ("Laws").
(b) Neither party will request Personal Data beyond what is necessary to fulfill the purpose(s) for which it is requested. The purpose(s) for requesting Personal Data must be reasonable. Each party will agree in advance as to the type of Personal Data that is required to be made available.
(2) Security Safeguards
(a) Each party acknowledges that it is solely responsible for determining and communicating to the other the appropriate technological, physical and organizational security measures required to protect Personal Data.
(b) Each party will ensure that Personal Data is protected in accordance with the security safeguards communicated and agreed to by the other.
(c) Each party will ensure that any third party to whom Personal Data is transferred is bound by the applicable terms of this section.
(d) Additional or different services required to comply with the Laws will be deemed a request for new services.
(3) Use
Each party agrees that Personal Data will only be used, accessed, managed, transferred, disclosed to third parties or otherwise processed to fulfill the purpose(s) for which it was made available.
(4) Access Requests
(a) Each party agrees to reasonably cooperate with the other in connection with requests to access or amend Personal Data.
(b) Each party agrees to reimburse the other for any reasonable charges incurred in providing each other assistance.
(c) Each party agrees to amend Personal Data only upon receiving instructions to do so from the other party or its personnel.
(5) Retention
Each party will promptly return to the other or destroy all Personal Data that is no longer necessary to fulfill the purpose(s) for which it was made available, unless otherwise instructed by the other or its personnel or required by law.
(6) Public Bodies Who Are Subject to Public Sector Privacy Legislation
For Licensees who are public bodies subject to public sector privacy legislation, this Item 13.n applies only to Personal Data made available to Licensee in connection with this Agreement, and the obligations in this section apply only to Licensee, except that: 1) section (2)(a) applies only to IBM; 2) sections (1)(a) and (4)(a) apply to both parties; and 3) section (4)(b) and the last sentence in (1)(b) do not apply.
PERU
10. Limitation of Liability
The following is added to the end of this Section 10 (Limitation of Liability):
Except as expressly required by law without the possibility of contractual waiver, Licensee and IBM intend that the limitation of liability in this Limitation of Liability section applies to damages caused by all types of claims and causes of action. If any limitation on or exclusion from liability in this section is held by a court of competent jurisdiction to be unenforceable with respect to a particular claim or cause of action, the parties intend that it nonetheless apply to the maximum extent permitted by applicable law to all other claims and causes of action.
10.1 Items for Which IBM May Be Liable
The following is added to the end of this Subsection 10.1:
In accordance with Article 1328 of the Peruvian Civil Code, the limitations and exclusions specified in this section will not apply to damages caused by IBM's willful misconduct ("dolo") or gross negligence ("culpa inexcusable").
UNITED STATES OF AMERICA
5. Taxes
The following is added to the end of this Section 5 (Taxes):
For Programs delivered electronically in the United States for which Licensee claims a state sales and use tax exemption, Licensee agrees not to receive any tangible personal property (e.g., media and publications) associated with the electronic program.
Licensee agrees to be responsible for any sales and use tax liabilities that may arise as a result of Licensee's subsequent redistribution of Programs after delivery by IBM.
13. General
The following is added to Section 13 as Item 13.n:
n. U.S. Government Users Restricted Rights - Use, duplication or disclosure is restricted by the GSA IT Schedule 70 Contract with the IBM Corporation.
The following is added to Item 13.f:
Each party waives any right to a jury trial in any proceeding arising out of or related to this Agreement.
ASIA PACIFIC COUNTRY AMENDMENTS
AUSTRALIA
5. Taxes
The following sentences replace the first two sentences of Section 5 (Taxes):
If any government or authority imposes a duty, tax (other than income tax), levy, or fee, on this Agreement or on the Program itself, that is not otherwise provided for in the amount payable, Licensee agrees to pay it when IBM invoices Licensee. If the rate of GST changes, IBM may adjust the charge or other amount payable to take into account that change from the date the change becomes effective.
8. No Warranties
The following is added to the first paragraph of Section 8 (No Warranties):
Although IBM specifies that there are no warranties, Licensee may have certain rights under the Competition and Consumer Act 2010 or other legislation and are only limited to the extent permitted by the applicable legislation.
10.1 Items for Which IBM May Be Liable
The following is added to Subsection 10.1 (Items for Which IBM Maybe Liable):
Where IBM is in breach of a condition or warranty implied by the Competition and Consumer Act 2010, IBM's liability is limited to the repair or replacement of the goods, or the supply of equivalent goods. Where that condition or warranty relates to right to sell, quiet possession or clear title, or the goods are of a kind ordinarily obtained for personal, domestic or household use or consumption, then none of the limitations in this paragraph apply.
HONG KONG SAR, MACAU SAR, AND TAIWAN
As applies to licenses obtained in Taiwan and the special administrative regions, phrases throughout this Agreement containing the word "country" (for example, "the country in which the original Licensee was granted the license" and "the country in which Licensee obtained the Program license") are replaced with the following:
(1) In Hong Kong SAR: "Hong Kong SAR"
(2) In Macau SAR: "Macau SAR" except in the Governing Law clause (Section 14.1)
(3) In Taiwan: "Taiwan."
INDIA
10.1 Items for Which IBM May Be Liable
The following replaces the terms of Items 1 and 2 of the first paragraph:
1) liability for bodily injury (including death) or damage to real property and tangible personal property will be limited to that caused by IBM's negligence; and 2) as to any other actual damage arising in any situation involving nonperformance by IBM pursuant to, or in any way related to the subject of this Agreement, IBM's liability will be limited to the charge paid by Licensee for the individual Program that is the subject of the claim.
13. General
The following replaces the terms of Item 13.g:
g. If no suit or other legal action is brought, within three years after the cause of action arose, in respect of any claim that either party may have against the other, the rights of the concerned party in respect of such claim will be forfeited and the other party will stand released from its obligations in respect of such claim.
INDONESIA
3.3 Term and Termination
The following is added to the last paragraph:
Both parties waive the provision of article 1266 of the Indonesian Civil Code, to the extent the article provision requires such court decree for the termination of an agreement creating mutual obligations.
JAPAN
13. General
The following is inserted as Item 13.n:
n. Any doubts concerning this Agreement will be initially resolved between us in good faith and in accordance with the principle of mutual trust.
MALAYSIA
10.2 Items for Which IBM Is Not Liable
The word "SPECIAL" in Item 10.2b is deleted.
NEW ZEALAND
8. No Warranties
The following is added to the first paragraph of this Section 8 (No Warranties):
Although IBM specifies that there are no warranties, Licensee may have certain rights under the Consumer Guarantees Act 1993 or other legislation which cannot be excluded or limited. The Consumer Guarantees Act 1993 will not apply in respect of any goods which IBM provides, if Licensee requires the goods for the purposes of a business as defined in that Act.
10. Limitation of Liability
The following is added:
Where Programs are not obtained for the purposes of a business as defined in the Consumer Guarantees Act 1993, the limitations in this Section are subject to the limitations in that Act.
PEOPLE'S REPUBLIC OF CHINA
4. Charges
The following is added:
All banking charges incurred in the People's Republic of China will be borne by Licensee and those incurred outside the People's Republic of China will be borne by IBM.
PHILIPPINES
10.2 Items for Which IBM Is Not Liable
The following replaces the terms of Item 10.2b:
b. special (including nominal and exemplary damages), moral, incidental, or indirect damages or for any economic consequential damages; or
SINGAPORE
10.2 Items for Which IBM Is Not Liable
The words "SPECIAL" and "ECONOMIC" are deleted from Item 10.2b.
13. General
The following replaces the terms of Item 13.i:
i. Subject to the rights provided to IBM's suppliers and Program developers as provided in Section 10 above (Limitation of Liability), a person who is not a party to this Agreement will have no right under the Contracts (Right of Third Parties) Act to enforce any of its terms.
TAIWAN
10.1 Items for Which IBM May Be Liable
The following sentences are deleted:
This limit also applies to any of IBM's subcontractors and Program developers. It is the maximum for which IBM and its subcontractors and Program developers are collectively responsible.
EUROPE, MIDDLE EAST, AFRICA (EMEA) COUNTRY AMENDMENTS
EUROPEAN UNION MEMBER STATES
8. No Warranties
The following is added to Section 8 (No Warranties):
In the European Union ("EU"), consumers have legal rights under applicable national legislation governing the sale of consumer goods. Such rights are not affected by the provisions set out in this Section 8 (No Warranties).
EU MEMBER STATES AND THE COUNTRIES IDENTIFIED BELOW
Iceland, Liechtenstein, Norway, Switzerland, Turkey, and any other European country that has enacted local data privacy or protection legislation similar to the EU model.
13. General
The following replaces Item 13.e:
(1) Definitions - For the purposes of this Item 13.e, the following additional definitions apply:
(a) Business Contact Information - business-related contact information disclosed by Licensee to IBM, including names, job titles, business addresses, telephone numbers and email addresses of Licensee's employees and contractors. For Austria, Italy and Switzerland, Business Contact Information also includes information about Licensee and its contractors as legal entities (for example, Licensee's revenue data and other transactional information)
(b) Business Contact Personnel - Licensee employees and contractors to whom the Business Contact Information relates.
(c) Data Protection Authority - the authority established by the Data Protection and Electronic Communications Legislation in the applicable country or, for non-EU countries, the authority responsible for supervising the protection of personal data in that country, or (for any of the foregoing) any duly appointed successor entity thereto.
(d) Data Protection & Electronic Communications Legislation - (i) the applicable local legislation and regulations in force implementing the requirements of EU Directive 95/46/EC (on the protection of individuals with regard to the processing of personal data and on the free movement of such data) and of EU Directive 2002/58/EC (concerning the processing of personal data and the protection of privacy in the electronic communications sector); or (ii) for non-EU countries, the legislation and/or regulations passed in the applicable country relating to the protection of personal data and the regulation of electronic communications involving personal data, including (for any of the foregoing) any statutory replacement or modification thereof.
(e) IBM Group - International Business Machines Corporation of Armonk, New York, USA, its subsidiaries, and their respective Business Partners and subcontractors.
(2) Licensee authorizes IBM:
(a) to process and use Business Contact Information within IBM Group in support of Licensee including the provision of support services, and for the purpose of furthering the business relationship between Licensee and IBM Group, including, without limitation, contacting Business Contact Personnel (by email or otherwise) and marketing IBM Group products and services (the "Specified Purpose"); and
(b) to disclose Business Contact Information to other members of IBM Group in pursuit of the Specified Purpose only.
(3) IBM agrees that all Business Contact Information will be processed in accordance with the Data Protection & Electronic Communications Legislation and will be used only for the Specified Purpose.
(4) To the extent required by the Data Protection & Electronic Communications Legislation, Licensee represents that (a) it has obtained (or will obtain) any consents from (and has issued (or will issue) any notices to) the Business Contact Personnel as are necessary in order to enable IBM Group to process and use the Business Contact Information for the Specified Purpose.
(5) Licensee authorizes IBM to transfer Business Contact Information outside the European Economic Area, provided that the transfer is made on contractual terms approved by the Data Protection Authority or the transfer is otherwise permitted under the Data Protection & Electronic Communications Legislation.
AUSTRIA
8. No Warranties
In Austria (and Germany) the following replaces Section 8 (No Warranties) in its entirety, including its title, if Licensee paid a charge to obtain the Program.
8. Warranties and Exclusions
The warranty period is twelve months from the date of delivery. The limitation period for consumers in action for breach of warranty is the statutory period as a minimum.
The warranty for an IBM Program covers the functionality of the Program for its normal use and the Program's conformity to its specifications.
IBM warrants that when the Program is used in the specified operating environment it will conform to its specifications. IBM does not warrant uninterrupted or error-free operation of the Program or that IBM will correct all Program defects. Licensee is responsible for the results obtained from the use of the Program.
The warranty applies only to the unmodified portion of the Program.
If the Program does not function as warranted during the warranty period and the problem cannot be resolved with information available, Licensee may return the Program to the party from whom Licensee acquired it and receive a refund of the amount Licensee paid. If Licensee down loaded the Program, Licensee may contact the party from whom Licensee acquired it to obtain the refund.
This is IBM's sole obligation to Licensee, except as otherwise required by applicable statutory law.
10. Limitation of Liability
The following is added:
The following limitations and exclusions of IBM's liability do not apply for damages caused by gross negligence or willful misconduct.
10.1 Items for Which IBM May Be Liable
The following replaces the first sentence in the first paragraph:
Circumstances may arise where, because of a default by IBM in the performance of its obligations under this Agreement or other liability, Licensee is entitled to recover damages from IBM.
In the second sentence of the first paragraph, delete entirely the parenthetical phrase:
"(including fundamental breach, negligence, misrepresentation, or other contract or tort claim)".
10.2 Items for Which IBM Is Not Liable
The following replaces Item 10.2b:
b. indirect damages or consequential damages; or
BELGIUM, FRANCE, ITALY, AND LUXEMBOURG
10. Limitation of Liability
The following replaces the terms of Section 10 (Limitation of Liability) in its entirety:
Except as otherwise provided by mandatory law:
10.1 Items for Which IBM May Be Liable
IBM's entire liability for all claims in the aggregate for any damages and losses that may arise as a consequence of the fulfillment of its obligations under or in connection with this Agreement or due to any other cause related to this Agreement is limited to the compensation of only those damages and losses proved and actually arising as an immediate and direct consequence of the non-fulfillment of such obligations (if IBM is at fault) or of such cause, for a maximum amount equal to the charges (if the Program is subject to fixed term charges, up to twelve months' charges) Licensee paid for the Program that has caused the damages.
The above limitation will not apply to damages for bodily injuries (including death) and damages to real property and tangible personal property for which IBM is legally liable.
10.2 Items for Which IBM Is Not Liable
UNDER NO CIRCUMSTANCES IS IBM OR ANY OF ITS PROGRAM DEVELOPERS LIABLE FOR ANY OF THE FOLLOWING, EVEN IF INFORMED OF THEIR POSSIBILITY: 1) LOSS OF, OR DAMAGE TO, DATA; 2) INCIDENTAL, EXEMPLARY OR INDIRECT DAMAGES, OR FOR ANY ECONOMIC CONSEQUENTIAL DAMAGES; AND / OR 3) LOST PROFITS, BUSINESS, REVENUE, GOODWILL, OR ANTICIPATED SAVINGS, EVEN IF THEY ARISE AS AN IMMEDIATE CONSEQUENCE OF THE EVENT THAT GENERATED THE DAMAGES.
10.3 Suppliers and Program Developers
The limitation and exclusion of liability herein agreed applies not only to the activities performed by IBM but also to the activities performed by its suppliers and Program developers, and represents the maximum amount for which IBM as well as its suppliers and Program developers are collectively responsible.
GERMANY
8. No Warranties
This Section 8 (No Warranties) is amended as specified for AUSTRIA.
10. Limitation of Liability
The following replaces this Section 10 (Limitation of Liability) in its entirety:
a. IBM will be liable without limit for 1) loss or damage caused by a breach of an express guarantee; 2) damages or losses resulting in bodily injury (including death); and 3) damages caused intentionally or by gross negligence.
b. In the event of loss, damage and frustrated expenditures caused by slight negligence or in breach of essential contractual obligations, IBM will be liable, regardless of the basis on which Licensee is entitled to claim damages from IBM (including fundamental breach, negligence, misrepresentation, or other contract or tort claim), per claim only up to the greater of 500,000 euro or the charges (if the Program is subject to fixed term charges, up to 12 months' charges) Licensee paid for the Program that caused the loss or damage. A number of defaults which together result in, or contribute to, substantially the same loss or damage will be treated as one default.
c. In the event of loss, damage and frustrated expenditures caused by slight negligence, IBM will not be liable for indirect or consequential damages, even if IBM was informed about the possibility of such loss or damage.
d. In case of delay on IBM's part: 1) IBM will pay to Licensee an amount not exceeding the loss or damage caused by IBM's delay and 2) IBM will be liable only in respect of the resulting damages that Licensee suffers, subject to the provisions of Items a and b above.
13. General
The following replaces the provisions of 13.g:
g. Any claims resulting from this Agreement are subject to a limitation period of three years, except as stated in Section 8 (No Warranties) of this Agreement.
The following replaces the provisions of 13.i:
i. No right or cause of action for any third party is created by this Agreement, nor is IBM responsible for any third party claims against Licensee, except (to the extent permitted in Section 10 (Limitation of Liability)) for: i) bodily injury (including death); or ii) damage to real or tangible personal property for which (in either case) IBM is legally liable to that third party.
IRELAND
8. No Warranties
The following sentence is added to the second paragraph of this Section 8 (No Warranties):
Except as expressly provided in these terms and conditions, or Section 12 of the Sale of Goods Act 1893 as amended by the Sale of Goods and Supply of Services Act, 1980 (the "1980 Act"), all conditions or warranties (express or implied, statutory or otherwise) are hereby excluded including, without limitation, any warranties implied by the Sale of Goods Act 1893 as amended by the 1980 Act (including, for the avoidance of doubt, Section 39 of the 1980 Act).
IRELAND AND UNITED KINGDOM
2. Agreement Structure
The following sentence is added:
Nothing in this paragraph shall have the effect of excluding or limiting liability for fraud.
10.1 Items for Which IBM May Be Liable
The following replaces the first paragraph of the Subsection:
For the purposes of this section, a "Default" means any act, statement, omission or negligence on the part of IBM in connection with, or in relation to, the subject matter of an Agreement in respect of which IBM is legally liable to Licensee, whether in contract or in tort. A number of Defaults which together result in, or contribute to, substantially the same loss or damage will be treated as one Default.
Circumstances may arise where, because of a Default by IBM in the performance of its obligations under this Agreement or other liability, Licensee is entitled to recover damages from IBM. Regardless of the basis on which Licensee is entitled to claim damages from IBM and except as expressly required by law without the possibility of contractual waiver, IBM's entire liability for any one Default will not exceed the amount of any direct damages, to the extent actually suffered by Licensee as an immediate and direct consequence of the Default, up to the greater of (1) 500,000 euro (or the equivalent in local currency) or (2) 125% of the charges (if the Program is subject to fixed term charges, up to 12 months' charges) for the Program that is the subject of the claim. Notwithstanding the foregoing, the amount of any damages for bodily injury (including death) and damage to real property and tangible personal property for which IBM is legally liable is not subject to such limitation.
10.2 Items for Which IBM Is Not Liable
The following replaces Items 10.2b and 10.2c:
b. special, incidental, exemplary, or indirect damages or consequential damages; or
c. wasted management time or lost profits, business, revenue, goodwill, or anticipated savings.
Z125-5589-05 (07/2011)

View File

@@ -1 +0,0 @@
License information for Ubuntu packages may be found inside the image: /usr/share/doc/${package}/copyright

View File

@@ -1,89 +0,0 @@
![IBM MQ logo](https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png)
# IBM MQ
IBM® MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments.
# Introduction
This chart deploys a single IBM MQ Advanced for Developers server (queue manager) into an IBM Cloud private or other Kubernetes environment.
## Prerequisites
- Kubernetes 1.6 or greater, with beta APIs enabled
- If persistence is enabled (see [configuration](#configuration)), then you either need to create a PersistentVolume, or specify a Storage Class if classes are defined in your cluster.
## Installing the Chart
To install the chart with the release name `foo`:
```sh
helm install --name foo stable/ibm-mqadvanced-server-dev --set license=accept
```
This command accepts the [IBM MQ Advanced for Developers license](LICENSE) and deploys an MQ Advanced for Developers server on the Kubernetes cluster. The [configuration](#configuration) section lists the parameters that can be configured during installation.
> **Tip**: See all the resources deployed by the chart using `kubectl get all -l release=foo`
## Uninstalling the Chart
To uninstall/delete the `foo` release:
```sh
helm delete foo
```
The command removes all the Kubernetes components associated with the chart, except any Persistent Volume Claims (PVCs). This is the default behavior of Kubernetes, and ensures that valuable data is not deleted. In order to delete the Queue Manager's data, you can delete the PVC using the following command:
```sh
kubectl delete pvc -l release=foo
```
## Configuration
The following table lists the configurable parameters of the `ibm-mqadvanced-server-dev` chart and their default values.
| Parameter | Description | Default |
| -------------------------------- | ----------------------------------------------- | ---------------------------------------------------------- |
| `license` | Set to `accept` to accept the terms of the IBM license | `not accepted` |
| `image.repository` | Image full name including repository | `ibmcom/mq` |
| `image.tag` | Image tag | `9` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `image.pullSecret` | Image pull secret, if you are using a private Docker registry | `nil` |
| `persistence.enabled` | Use persistent volumes for all defined volumes | `true` |
| `persistence.useDynamicProvisioning` | Use dynamic provisioning (storage classes) for all volumes | `true` |
| `dataPVC.name` | Suffix for the PVC name | `"data"` |
| `dataPVC.storageClassName` | Storage class of volume for main MQ data (under `/var/mqm`) | `""` |
| `dataPVC.size` | Size of volume for main MQ data (under `/var/mqm`) | `2Gi` |
| `service.name` | Name of the Kubernetes service to create | `qmgr` |
| `service.type` | Kubernetes service type exposing ports, e.g. `NodePort` | `ClusterIP` |
| `resources.limits.cpu` | Kubernetes CPU limit for the Queue Manager container | `500m` |
| `resources.limits.memory` | Kubernetes memory limit for the Queue Manager container | `512Mi` |
| `resources.requests.cpu` | Kubernetes CPU request for the Queue Manager container | `500m` |
| `resources.requests.memory` | Kubernetes memory request for the Queue Manager container | `512Mi` |
| `queueManager.name` | MQ Queue Manager name | Helm release name |
| `queueManager.dev.adminPassword` | Developer defaults - administrator password | Random generated string. See the notes that appear when you install for how to retrieve this. |
| `queueManager.dev.appPassword` | Developer defaults - app password | `nil` (no password required to connect an MQ client) |
| `nameOverride` | Set to partially override the resource names used in this chart | `nil` |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`.
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart.
> **Tip**: You can use the default [values.yaml](values.yaml)
## Persistence
The chart mounts a [Persistent Volume](http://kubernetes.io/docs/user-guide/persistent-volumes/).
# Troubleshooting
## Cannot create a GlusterFS PersistentVolumeClaim
The generated PVC name can be too long when using GlusterFS. See [here](https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/troubleshoot/cannot_create_pvc.html) for more information. The PVC name is generated from three things:
1. The Helm release name, which is set by you at deployment time
2. A short PVC label, which defaults to "data" and can be changed using the `dataPVC.name` parameter.
3. The name of the chart you are using, which can be changed using the `nameOverride` parameter.
# Copyright
© Copyright IBM Corporation 2017

View File

@@ -1,10 +0,0 @@
MQ can be accessed via port 1414 on the following DNS name from within your cluster:
{{ template "fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local
To get your admin password run:
MQ_ADMIN_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath="{.data.adminPassword}" | base64 --decode; echo)
If you set an app password, you can retrieve it by running the following:
MQ_APP_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath="{.data.appPassword}" | base64 --decode; echo)

View File

@@ -1,29 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,34 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
apiVersion: v1
kind: Secret
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
{{ if .Values.queueManager.dev.adminPassword }}
adminPassword: {{ .Values.queueManager.dev.adminPassword | b64enc | quote }}
{{ else }}
adminPassword: {{ randAlphaNum 10 | b64enc | quote }}
{{ end }}
{{ if .Values.queueManager.dev.appPassword }}
appPassword: {{ .Values.queueManager.dev.appPassword | b64enc | quote }}
{{ end }}

View File

@@ -1,32 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
type: {{ .Values.service.type }}
ports:
- port: 1414
name: {{ .Values.service.name }}-server
- port: 9443
name: {{ .Values.service.name }}-web
selector:
app: {{ template "fullname" . }}

View File

@@ -1,104 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
serviceName: {{ .Values.service.name }}
replicas: 1
{{- if and (ge (.Capabilities.KubeVersion.Major | int) 1) (ge (.Capabilities.KubeVersion.Minor | int) 7) }}
updateStrategy:
type: RollingUpdate
{{- end }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
QM_IDENTIFIER: "{{ .Release.Name }}"
spec:
{{- if .Values.image.pullSecret }}
imagePullSecrets:
- name: {{ .Values.image.pullSecret }}
{{- end }}
containers:
- name: qmgr
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 1414
- containerPort: 9443
env:
- name: LICENSE
value: {{ .Values.license }}
- name: MQ_QMGR_NAME
value: {{ .Values.queueManager.name | default .Release.Name | replace "-" "" }}
#- name: MQ_DISABLE_WEB_CONSOLE
# value: "true"
- name: MQ_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: adminPassword
{{- if .Values.queueManager.dev.appPassword }}
- name: MQ_APP_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: appPassword
{{- end }}
{{- if .Values.persistence.enabled }}
volumeMounts:
- mountPath: "/mnt/mqm"
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
{{- end }}
resources:
limits:
{{ toYaml .Values.resources.limits | indent 14 }}
requests:
{{ toYaml .Values.resources.requests | indent 14 }}
volumeClaimTemplates:
{{- if .Values.persistence.enabled }}
- metadata:
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
{{- if .Values.persistence.useDynamicProvisioning }}
# If present, use the storageClassName from the values.yaml, else use the
# default storageClass setup by Kubernetes Administrator
#
# Setting storageClassName to nil means use the default storage class
storageClassName: {{ default nil .Values.dataPVC.storageClassName | quote }}
{{- else }}
# Disable dynamic provisioning
storageClassName: ""
{{- end }}
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: {{ .Values.dataPVC.size | quote }}
{{- end }}

View File

@@ -1,40 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
apiVersion: v1
kind: Pod
metadata:
name: "{{.Release.Name}}-test"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{.Release.Name}}-test
image: alpine:latest
env:
# Host name for the service running an MQ queue manager
- name: MQ_HOST
value: {{ template "fullname" . }}
# Time to try before giving up and failing the test (in seconds)
- name: TIMEOUT
value: "10"
command: ["sh"]
# Check that port 1414 is listening
args: ["-xc", "nc -v -z -w$(TIMEOUT) $(MQ_HOST) 1414"]
restartPolicy: Never

View File

@@ -1,68 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
# license must be set to "accept" to accept the terms of the IBM license
license: "not accepted"
image:
# repository is the container repository to use, which must contain IBM MQ Advanced for Developers
repository: ibmcom/mq
# tag is the tag to use for the container repository
tag: 9
# pullSecret is the secret to use when pulling the image from a private registry
pullSecret:
# pullPolicy is either IfNotPresent or Always (https://kubernetes.io/docs/concepts/containers/images/)
pullPolicy: IfNotPresent
# persistence section specifies persistence settings which apply to the whole chart
persistence:
# enabled is whether to use Persistent Volumes or not
enabled: true
# useDynamicProvisioning is whether or not to use Storage Classes to dynamically create Persistent Volumes
useDynamicProvisioning: true
# dataPVC section specifies settings for the main Persistent Volume Claim, which is used for data in /var/mqm
dataPVC:
# name sets part of the name for this Persistent Volume Claim
name: "data"
## storageClassName is the name of the Storage Class to use, or an empty string for no Storage Class
storageClassName: ""
## size is the minimum size of the Persistent Volume
size: 2Gi
service:
name: qmgr
type: ClusterIP
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 500m
memory: 512Mi
# queueManager section specifies settings for the MQ Queue Manager
queueManager:
# name allows you to specify the name to use for the queue manager. Defaults to the Helm release name.
name:
# dev section specifies settings for the MQ developer defaults available in the MQ Advanced for Developers image.
dev:
# adminPassword sets the password of the admin user
adminPassword:
# appPassword sets the password of the app user
appPassword:
# nameOverride can be set to partially override the name of the resources created by this chart
nameOverride:

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
License information for Ubuntu packages may be found inside the image: /usr/share/doc/${package}/copyright

View File

@@ -1,198 +0,0 @@
![IBM MQ logo](https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png)
# IBM MQ
IBM® MQ is messaging middleware that simplifies and accelerates the integration of diverse applications and business data across multiple platforms. It uses message queues to facilitate the exchanges of information and offers a single messaging solution for cloud, mobile, Internet of Things (IoT) and on-premises environments.
# Introduction
This chart deploys a single IBM MQ Advanced server (queue manager) into an IBM Cloud private or other Kubernetes environment.
## Prerequisites
- Kubernetes 1.6 or greater, with beta APIs enabled
- If persistence is enabled (see [configuration](#configuration)), then you either need to create a PersistentVolume, or specify a Storage Class if classes are defined in your cluster.
## Installing the Chart
To install the chart with the release name `foo`:
```sh
helm install --name foo stable/ibm-mqadvanced-server-prod --set license=accept
```
This command accepts the [IBM MQ Advanced license](LICENSE) and deploys an MQ Advanced server on the Kubernetes cluster. The [configuration](#configuration) section lists the parameters that can be configured during installation.
> **Tip**: See all the resources deployed by the chart using `kubectl get all -l release=foo`
## Uninstalling the Chart
To uninstall/delete the `foo` release:
```sh
helm delete foo
```
The command removes all the Kubernetes components associated with the chart, except any Persistent Volume Claims (PVCs). This is the default behavior of Kubernetes, and ensures that valuable data is not deleted. In order to delete the Queue Manager's data, you can delete the PVC using the following command:
```sh
kubectl delete pvc -l release=foo
```
## Configuration
The following table lists the configurable parameters of the `ibm-mqadvanced-server-prod` chart and their default values.
| Parameter | Description | Default |
| ------------------------------- | --------------------------------------------------------------- | ------------------------------------------ |
| `license` | Set to `accept` to accept the terms of the IBM license | `"not accepted"` |
| `image.repository` | Image full name including repository | `nil` |
| `image.tag` | Image tag | `nil` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `image.pullSecret` | Image pull secret, if you are using a private Docker registry | `nil` |
| `persistence.enabled` | Use persistent volumes for all defined volumes | `true` |
| `persistence.useDynamicProvisioning` | Use dynamic provisioning (storage classes) for all volumes | `true` |
| `dataPVC.name` | Suffix for the PVC name | `"data"` |
| `dataPVC.storageClassName` | Storage class of volume for main MQ data (under `/var/mqm`) | `""` |
| `dataPVC.size` | Size of volume for main MQ data (under `/var/mqm`) | `2Gi` |
| `service.name` | Name of the Kubernetes service to create | `"qmgr"` |
| `service.type` | Kubernetes service type exposing ports, e.g. `NodePort` | `ClusterIP` |
| `resources.limits.cpu` | Kubernetes CPU limit for the Queue Manager container | `1` |
| `resources.limits.memory` | Kubernetes memory limit for the Queue Manager container | `1Gi` |
| `resources.requests.cpu` | Kubernetes CPU request for the Queue Manager container | `1` |
| `resources.requests.memory` | Kubernetes memory request for the Queue Manager container | `1Gi` |
| `queueManager.name` | MQ Queue Manager name | Helm release name |
| `nameOverride` | Set to partially override the resource names used in this chart | `nil` |
| `livenessProbe.initialDelaySeconds` | The initial delay before starting the liveness probe. Useful for slower systems that take longer to start the Queue Manager. | 60 |
| `livenessProbe.periodSeconds` | How often to run the probe | 10 |
| `livenessProbe.timeoutSeconds` | Number of seconds after which the probe times out | 5 |
| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded | 1 |
| `readinessProbe.initialDelaySeconds` | The initial delay before starting the readiness probe | 10 |
| `readinessProbe.periodSeconds` | How often to run the probe | 5 |
| `readinessProbe.timeoutSeconds` | Number of seconds after which the probe times out | 3 |
| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded | 1 |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`.
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart.
> **Tip**: You can use the default [values.yaml](values.yaml)
## Persistence
The chart mounts a [Persistent Volume](http://kubernetes.io/docs/user-guide/persistent-volumes/).
# Configuring MQ objects
You have two major options for configuring the MQ queue manager itself:
1. Use existing tools, such as `runmqsc`, MQ Explorer or the MQ Command Server to configure your queue manager directly.
2. Create a new image layer with your configuration baked-in
## Configuring MQ using existing tools
You will need to create any administrative entry point to your Queue Manager. This can be completed by either manually running kubectl commands to execute `runmqsc` and configure your entry point or creating a new image which automatically does this. At a minimum you will need to:
* Create a user with MQ administrative permissions (is a member of the `mqm` group) which you can use to log into your Queue Manager.
* Enable `ADOPTCTX` so we use the user for authorization as well as authentication when connecting a MQ Application.
* Refresh the security configuration so the new `ADOPTCTX` value becomes active
* Create a channel to use as our entrypoint.
* Create a channel authentication rule to allow access for administrative users to connect through the channel.
For the above minimum you, should execute the following commands through a shell prompt on the pod. If you choose to do this then you should replace `mquser` with your own username:
```sh
useradd --gid mqm mquser
passwd mquser
runmqsc <QM Name>
```
Then in the `runmqsc` program, you could execute the following MQSC commands:
```
DEFINE CHANNEL('EXAMPLE.ENTRYPOINT') CHLTYPE(SVRCONN)
ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) ADOPTCTX(YES)
REFRESH SECURITY(*) TYPE(CONNAUTH)
SET CHLAUTH('EXAMPLE.ENTRYPOINT') TYPE(BLOCKUSER) USERLIST('nobody')
```
At this point you could now connect a MQ Explorer or other remote MQ administrative client using the channel `EXAMPLE.ENTRYPOINT` and user `mquser`.
> **Tip**: If you are using a client that has a compatibility mode option for user authentication to connect to your IBM MQ Queue Manager. Make sure you have compatibility mode turned off.
## Configuring MQ using a new image layer
You can create a new container image layer, on top of the IBM MQ Advanced base image. You can add MQSC files to define MQ objects such as queues and topics, and place these files into `/etc/mqm` in your image. When the MQ pod starts, it will run any MQSC files found in this directory (in sorted order).
### Example Dockerfile and MQSC script for creating a new image
In this example you will create a Dockerfile that creates two users:
* `admin` - Administrator user which is a member of the `mqm` group
* `app` - Client application user which is a member of the `mqclient` group. (You will also create this group)
You will also create a MQSC Script file called `config.mqsc` that will be run automatically when your container starts. This script will do the following:
* Create default local queues for my applications
* Create channels for use by the `admin` and `app` users
* Configure security to allow use of the channels by remote applications
* Create authority records to allow members of the `mqclient` group to access the Queue Manager and the default local queues.
First create a file called `config.mqsc`. This the MQSC file that will be run when an MQ container starts. It should contain the following:
```
* Create Local Queues that my application(s) can use.
DEFINE QLOCAL('EXAMPLE.QUEUE.1') REPLACE
DEFINE QLOCAL('EXAMPLE.QUEUE.2') REPLACE
* Create a Dead Letter Queue for undeliverable messages and set the Queue Manager to use it.
DEFINE QLOCAL('EXAMPLE.DEAD.LETTER.QUEUE') REPLACE
ALTER QMGR DEADQ('EXAMPLE.DEAD.LETTER.QUEUE')
* Set ADOPTCTX to YES so we use the same userid passed for authentication as the one for authorization and refresh the security configuration
ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) ADOPTCTX(YES)
REFRESH SECURITY(*) TYPE(CONNAUTH)
* Create a entry channel for the Admin user and Application user
DEFINE CHANNEL('EXAMP.ADMIN.SVRCONN') CHLTYPE(SVRCONN) REPLACE
DEFINE CHANNEL('EXAMP.APP.SVRCONN') CHLTYPE(SVRCONN) MCAUSER('app') REPLACE
* Set Channel authentication rules to only allow access through the two channels we created and only allow admin users to connect through EXAMPLE.ADMIN.SVRCONN
SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('Back-stop rule - Blocks everyone') ACTION(REPLACE)
SET CHLAUTH('EXAMP.APP.SVRCONN') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) DESCR('Allows connection via APP channel') ACTION(REPLACE)
SET CHLAUTH('EXAMP.ADMIN.SVRCONN') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) DESCR('Allows connection via ADMIN channel') ACTION(REPLACE)
SET CHLAUTH('EXAMP.ADMIN.SVRCONN') TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allows admins on ADMIN channel') ACTION(REPLACE)
* Set Authority records to allow the members of the mqclient group to connect to the Queue Manager and access the Local Queues which start with "EXAMPLE."
SET AUTHREC OBJTYPE(QMGR) GROUP('mqclient') AUTHADD(CONNECT,INQ)
SET AUTHREC PROFILE('EXAMPLE.**') OBJTYPE(QUEUE) GROUP('mqclient') AUTHADD(INQ,PUT,GET,BROWSE)
```
Next create a `Dockerfile` that expands on the MQ Advanced Server image to create the users and groups. It should contain the following, replacing `<IMAGE NAME>` with the MQ image you want to use as a base:
```dockerfile
FROM <IMAGE NAME>
# Add the admin user as a member of the mqm group and set their password
RUN useradd admin -G mqm \
&& echo admin:passw0rd | chpasswd \
# Create the mqclient group
&& groupadd mqclient \
# Create the app user as a member of the mqclient group and set their password
&& useradd app -G mqclient \
&& echo app:passw0rd | chpasswd
# Copy the configuration script to /etc/mqm where it will be picked up automatically
COPY config.mqsc /etc/mqm/
```
Finally, build and push the image to your registry.
You can then use the new image when you deploy MQ into your cluster. You will find that once you have run the image you will be able to see your new default objects and users.
# Troubleshooting
## Cannot create a GlusterFS PersistentVolumeClaim
The generated PVC name can be too long when using GlusterFS. See [here](https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/troubleshoot/cannot_create_pvc.html) for more information. The PVC name is
generated from three things:
1. The Helm release name, which is set by you at deployment time
2. A short PVC label, which defaults to "data" and can be changed using the `dataPVC.name` parameter.
3. The name of the chart you are using, which can be changed using the `nameOverride` parameter.
# Copyright
© Copyright IBM Corporation 2017

View File

@@ -1,3 +0,0 @@
MQ can be accessed via port 1414 on the following DNS name from within your cluster:
{{ template "fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local

View File

@@ -1,29 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,107 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
serviceName: {{ .Values.service.name }}
replicas: 1
{{- if and (ge (.Capabilities.KubeVersion.Major | int) 1) (ge (.Capabilities.KubeVersion.Minor | int) 7) }}
updateStrategy:
type: RollingUpdate
{{- end }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
QM_IDENTIFIER: "{{ .Release.Name }}"
spec:
{{- if .Values.image.pullSecret }}
imagePullSecrets:
- name: {{ .Values.image.pullSecret }}
{{- end }}
containers:
- name: qmgr
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 1414
env:
- name: LICENSE
value: {{ .Values.license }}
- name: MQ_QMGR_NAME
value: {{ .Values.queueManager.name | default .Release.Name | replace "-" "" }}
{{- if .Values.persistence.enabled }}
volumeMounts:
- mountPath: "/mnt/mqm"
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
{{- end }}
# Set liveness probe to determine if the queue manager is running
livenessProbe:
exec:
command:
- chkmqhealthy
initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
# Set readiness probe to determine if the MQ listener is running
readinessProbe:
exec:
command:
- chkmqready
initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
resources:
limits:
{{ toYaml .Values.resources.limits | indent 14 }}
requests:
{{ toYaml .Values.resources.requests | indent 14 }}
volumeClaimTemplates:
{{- if .Values.persistence.enabled }}
- metadata:
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
{{- if .Values.persistence.useDynamicProvisioning }}
## If present, use the storageClassName from the values.yaml, else use the
## default storageClass setup by Kubernetes Administrator
##
## Setting storageClassName to nil means use the default storage class
storageClassName: {{ default nil .Values.dataPVC.storageClassName | quote }}
{{- else }}
## Disable dynamic provisioning
storageClassName: ""
{{- end }}
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: {{ .Values.dataPVC.size | quote }}
{{- end }}

View File

@@ -1,40 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
apiVersion: v1
kind: Pod
metadata:
name: "{{.Release.Name}}-test"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{.Release.Name}}-test
image: alpine:latest
env:
# Host name for the service running an MQ queue manager
- name: MQ_HOST
value: {{ template "fullname" . }}
# Time to try before giving up and failing the test (in seconds)
- name: TIMEOUT
value: "10"
command: ["sh"]
# Check that port 1414 is listening
args: ["-xc", "nc -v -z -w$(TIMEOUT) $(MQ_HOST) 1414"]
restartPolicy: Never

View File

@@ -1,77 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
# license must be set to "accept" to accept the terms of the IBM license
license: "not accepted"
image:
# repository is the container repository to use, which must contain IBM MQ Advanced
repository: ibm-mqadvanced-server
# tag is the tag to use for the container repository
tag: 9.0.4.0-x86_64
# pullSecret is the secret to use when pulling the image from a private registry
pullSecret:
# pullPolicy is either IfNotPresent or Always (https://kubernetes.io/docs/concepts/containers/images/)
pullPolicy: IfNotPresent
# persistence section specifies persistence settings which apply to the whole chart
persistence:
# enabled is whether to use Persistent Volumes or not
enabled: true
# useDynamicProvisioning is whether or not to use Storage Classes to dynamically create Persistent Volumes
useDynamicProvisioning: true
# dataPVC section specifies settings for the main Persistent Volume Claim, which is used for data in /var/mqm
dataPVC:
# name sets part of the name for this Persistent Volume Claim
name: "data"
# storageClassName is the name of the Storage Class to use, or an empty string for no Storage Class
storageClassName: ""
# size is the minimum size of the Persistent Volume
size: 2Gi
service:
name: qmgr
type: ClusterIP
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
# queueManager section specifies settings for the MQ Queue Manager
queueManager:
# name allows you to specify the name to use for the queue manager. Defaults to the Helm release name.
name:
# nameOverride can be set to partially override the name of the resources created by this chart
nameOverride:
# livenessProbe section specifies setting for the MQ liveness probe, which checks for a running Queue Manager
livenessProbe:
# initialDelaySeconds should be raised if your system cannot start the Queue Manager in 60 seconds
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 1
# readinessProbe section specifies setting for the MQ readiness probe, which checks when the MQ listener is running
readinessProbe:
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 1

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017 © Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ limitations under the License.
package main package main
import ( import (
"fmt"
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
@@ -31,13 +32,16 @@ func queueManagerHealthy() (bool, error) {
return false, err return false, err
} }
// Specify the queue manager name, just in case someone's created a second queue manager // Specify the queue manager name, just in case someone's created a second queue manager
// #nosec G204
cmd := exec.Command("dspmq", "-n", "-m", name) cmd := exec.Command("dspmq", "-n", "-m", name)
// Run the command and wait for completion // Run the command and wait for completion
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
fmt.Println(err)
return false, err return false, err
} }
if !strings.Contains(string(out), "(RUNNING)") { fmt.Printf("%s", out)
if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") {
return false, nil return false, nil
} }
return true, nil return true, nil

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017 © Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -18,14 +18,39 @@ limitations under the License.
package main package main
import ( import (
"fmt"
"net" "net"
"os" "os"
"github.com/ibm-messaging/mq-container/internal/ready"
"github.com/ibm-messaging/mq-container/pkg/name"
) )
func main() { func main() {
conn, err := net.Dial("tcp", "127.0.0.1:1414") // Check if runmqserver has indicated that it's finished configuration
if err != nil { r, err := ready.Check()
if !r || err != nil {
os.Exit(1) os.Exit(1)
} }
conn.Close() name, err := name.GetQueueManagerName()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Check if the queue manager has a running listener
if standby, _ := ready.IsRunningAsStandbyQM(name); !standby {
conn, err := net.Dial("tcp", "127.0.0.1:1414")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = conn.Close()
if err != nil {
fmt.Println(err)
}
} else {
fmt.Printf("Detected queue manager running in standby mode")
os.Exit(10)
}
} }

179
cmd/runmqdevserver/main.go Normal file
View File

@@ -0,0 +1,179 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"syscall"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
"github.com/ibm-messaging/mq-container/pkg/containerruntimelogger"
"github.com/ibm-messaging/mq-container/pkg/logger"
"github.com/ibm-messaging/mq-container/pkg/name"
)
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 {
return os.Getenv("LOG_FORMAT")
}
func getDebug() bool {
debug := os.Getenv("DEBUG")
if debug == "true" || debug == "1" {
return true
}
return false
}
func configureLogger() error {
var err error
f := getLogFormat()
d := getDebug()
n, err := name.GetQueueManagerName()
if err != nil {
return err
}
switch f {
case "json":
log, err = logger.NewLogger(os.Stderr, d, true, n)
if err != nil {
return err
}
case "basic":
log, err = logger.NewLogger(os.Stderr, d, false, n)
if err != nil {
return err
}
default:
log, err = logger.NewLogger(os.Stdout, d, false, n)
return fmt.Errorf("invalid value for LOG_FORMAT: %v", f)
}
return nil
}
func configureWeb(qmName string) error {
out := "/etc/mqm/web/installations/Installation1/angular.persistence/admin.json"
return mqtemplate.ProcessTemplateFile("/etc/mqm/admin.json.tpl", out, map[string]string{"QueueManagerName": qmName}, log)
}
func logTerminationf(format string, args ...interface{}) {
logTermination(fmt.Sprintf(format, args...))
}
// TODO: Duplicated code
func logTermination(args ...interface{}) {
msg := fmt.Sprint(args...)
// Write the message to the termination log. This is not the default place
// that Kubernetes will look for termination information.
log.Debugf("Writing termination message: %v", msg)
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
if err != nil {
log.Debug(err)
}
log.Error(msg)
}
func doMain() error {
err := configureLogger()
if err != nil {
logTermination(err)
return err
}
err = containerruntimelogger.LogContainerDetails(log)
if err != nil {
logTermination(err)
return err
}
adminPassword, set := os.LookupEnv("MQ_ADMIN_PASSWORD")
if set {
err = setPassword("admin", adminPassword)
if err != nil {
logTerminationf("Error setting admin password: %v", err)
return err
}
}
appPassword, set := os.LookupEnv("MQ_APP_PASSWORD")
if set {
err = setPassword("app", appPassword)
if err != nil {
logTerminationf("Error setting app password: %v", err)
return err
}
}
err = updateMQSC(set)
if err != nil {
logTerminationf("Error updating MQSC: %v", err)
return err
}
name, err := name.GetQueueManagerName()
if err != nil {
logTerminationf("Error getting queue manager name: %v", err)
return err
}
err = configureWeb(name)
if err != nil {
logTermination("Error configuring admin.json")
return err
}
return nil
}
var osExit = os.Exit
func main() {
err := doMain()
if err != nil {
osExit(1)
} else {
// Replace this process with runmqserver
// #nosec G204
err = syscall.Exec("/usr/local/bin/runmqserver", []string{"runmqserver", "-nologruntime", "-dev"}, os.Environ())
if err != nil {
log.Errorf("Error replacing this process with runmqserver: %v", err)
}
}
}

View File

@@ -0,0 +1,50 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"os"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
)
func updateMQSC(appPasswordRequired bool) error {
var checkClient string
if appPasswordRequired {
checkClient = "REQUIRED"
} else {
checkClient = "ASQMGR"
}
const mqsc string = "/etc/mqm/10-dev.mqsc"
if os.Getenv("MQ_DEV") == "true" {
const mqscTemplate string = mqsc + ".tpl"
// Re-configure channel if app password not set
err := mqtemplate.ProcessTemplateFile(mqsc+".tpl", mqsc, map[string]string{"ChckClnt": checkClient}, log)
if err != nil {
return err
}
} else {
_, err := os.Stat(mqsc)
if !os.IsNotExist(err) {
err = os.Remove(mqsc)
if err != nil {
log.Errorf("Error removing file %s: %v", mqsc, err)
return err
}
}
}
return nil
}

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017 © Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -16,21 +16,18 @@ limitations under the License.
package main package main
import ( import (
"log"
"os" "os"
"path/filepath"
"runtime" "runtime"
"syscall" "syscall"
"github.com/ibm-messaging/mq-container/internal/command"
) )
const mqmUID uint32 = 999 func createVolume(dataPath string) error {
const mqmGID uint32 = 999
func createVolume(path string) error {
dataPath := filepath.Join(path, "data")
fi, err := os.Stat(dataPath) fi, err := os.Stat(dataPath)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
// #nosec G301
err = os.MkdirAll(dataPath, 0755) err = os.MkdirAll(dataPath, 0755)
if err != nil { if err != nil {
return err return err
@@ -46,8 +43,13 @@ func createVolume(path string) error {
sys := fi.Sys() sys := fi.Sys()
if sys != nil && runtime.GOOS == "linux" { if sys != nil && runtime.GOOS == "linux" {
stat := sys.(*syscall.Stat_t) stat := sys.(*syscall.Stat_t)
if stat.Uid != mqmUID || stat.Gid != mqmGID { mqmUID, mqmGID, err := command.LookupMQM()
err = os.Chown(dataPath, int(mqmUID), int(mqmGID)) if err != nil {
return err
}
log.Debugf("mqm user is %v (%v)", mqmUID, mqmGID)
if int(stat.Uid) != mqmUID || int(stat.Gid) != mqmGID {
err = os.Chown(dataPath, mqmUID, mqmGID)
if err != nil { if err != nil {
log.Printf("Error: Unable to change ownership of %v", dataPath) log.Printf("Error: Unable to change ownership of %v", dataPath)
return err return err

View File

@@ -0,0 +1,93 @@
/*
© Copyright IBM Corporation 2017, 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
// resolveLicenseFile returns the file name of the MQ license file, taking into
// account the language set by the LANG environment variable
func resolveLicenseFile() string {
lang, ok := os.LookupEnv("LANG")
if !ok {
return "English.txt"
}
switch {
case strings.HasPrefix(lang, "zh_TW"):
return "Chinese_TW.txt"
case strings.HasPrefix(lang, "zh"):
return "Chinese.txt"
// Differentiate Czech (cs) and Kashubian (csb)
case strings.HasPrefix(lang, "cs") && !strings.HasPrefix(lang, "csb"):
return "Czech.txt"
case strings.HasPrefix(lang, "fr"):
return "French.txt"
case strings.HasPrefix(lang, "de"):
return "German.txt"
case strings.HasPrefix(lang, "el"):
return "Greek.txt"
case strings.HasPrefix(lang, "id"):
return "Indonesian.txt"
case strings.HasPrefix(lang, "it"):
return "Italian.txt"
case strings.HasPrefix(lang, "ja"):
return "Japanese.txt"
// Differentiate Korean (ko) from Konkani (kok)
case strings.HasPrefix(lang, "ko") && !strings.HasPrefix(lang, "kok"):
return "Korean.txt"
case strings.HasPrefix(lang, "lt"):
return "Lithuanian.txt"
case strings.HasPrefix(lang, "pl"):
return "Polish.txt"
case strings.HasPrefix(lang, "pt"):
return "Portugese.txt"
case strings.HasPrefix(lang, "ru"):
return "Russian.txt"
case strings.HasPrefix(lang, "sl"):
return "Slovenian.txt"
case strings.HasPrefix(lang, "es"):
return "Spanish.txt"
case strings.HasPrefix(lang, "tr"):
return "Turkish.txt"
}
return "English.txt"
}
func checkLicense() (bool, error) {
lic, ok := os.LookupEnv("LICENSE")
switch {
case ok && lic == "accept":
return true, nil
case ok && lic == "view":
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
// #nosec G304
buf, err := ioutil.ReadFile(file)
if err != nil {
log.Println(err)
return false, err
}
log.Println(string(buf))
return false, nil
}
log.Println("Error: Set environment variable LICENSE=accept to indicate acceptance of license terms and conditions.")
log.Println("License agreements and information can be viewed by setting the environment variable LICENSE=view. You can also set the LANG environment variable to view the license in a different language.")
return false, errors.New("Set environment variable LICENSE=accept to indicate acceptance of license terms and conditions")
}

View File

@@ -0,0 +1,282 @@
/*
© Copyright IBM Corporation 2017
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 (
"os"
"testing"
)
var licenseTests = []struct {
in string
out string
}{
{"en_US.UTF_8", "English.txt"},
{"en_US.ISO-8859-15", "English.txt"},
{"es_GB", "Spanish.txt"},
{"el_ES.UTF_8", "Greek.txt"},
// Cover a wide variety of valid values
{"af", "English.txt"},
{"af_ZA", "English.txt"},
{"ar", "English.txt"},
{"ar_AE", "English.txt"},
{"ar_BH", "English.txt"},
{"ar_DZ", "English.txt"},
{"ar_EG", "English.txt"},
{"ar_IQ", "English.txt"},
{"ar_JO", "English.txt"},
{"ar_KW", "English.txt"},
{"ar_LB", "English.txt"},
{"ar_LY", "English.txt"},
{"ar_MA", "English.txt"},
{"ar_OM", "English.txt"},
{"ar_QA", "English.txt"},
{"ar_SA", "English.txt"},
{"ar_SY", "English.txt"},
{"ar_TN", "English.txt"},
{"ar_YE", "English.txt"},
{"az", "English.txt"},
{"az_AZ", "English.txt"},
{"az_AZ", "English.txt"},
{"be", "English.txt"},
{"be_BY", "English.txt"},
{"bg", "English.txt"},
{"bg_BG", "English.txt"},
{"bs_BA", "English.txt"},
{"ca", "English.txt"},
{"ca_ES", "English.txt"},
{"cs", "Czech.txt"},
{"cs_CZ", "Czech.txt"},
{"csb_PL", "English.txt"},
{"cy", "English.txt"},
{"cy_GB", "English.txt"},
{"da", "English.txt"},
{"da_DK", "English.txt"},
{"de", "German.txt"},
{"de_AT", "German.txt"},
{"de_CH", "German.txt"},
{"de_DE", "German.txt"},
{"de_LI", "German.txt"},
{"de_LU", "German.txt"},
{"dv", "English.txt"},
{"dv_MV", "English.txt"},
{"el", "Greek.txt"},
{"el_GR", "Greek.txt"},
{"en", "English.txt"},
{"en_AU", "English.txt"},
{"en_BZ", "English.txt"},
{"en_CA", "English.txt"},
{"en_CB", "English.txt"},
{"en_GB", "English.txt"},
{"en_IE", "English.txt"},
{"en_JM", "English.txt"},
{"en_NZ", "English.txt"},
{"en_PH", "English.txt"},
{"en_TT", "English.txt"},
{"en_US", "English.txt"},
{"en_ZA", "English.txt"},
{"en_ZW", "English.txt"},
{"eo", "English.txt"},
{"es", "Spanish.txt"},
{"es_AR", "Spanish.txt"},
{"es_BO", "Spanish.txt"},
{"es_CL", "Spanish.txt"},
{"es_CO", "Spanish.txt"},
{"es_CR", "Spanish.txt"},
{"es_DO", "Spanish.txt"},
{"es_EC", "Spanish.txt"},
{"es_ES", "Spanish.txt"},
{"es_ES", "Spanish.txt"},
{"es_GT", "Spanish.txt"},
{"es_HN", "Spanish.txt"},
{"es_MX", "Spanish.txt"},
{"es_NI", "Spanish.txt"},
{"es_PA", "Spanish.txt"},
{"es_PE", "Spanish.txt"},
{"es_PR", "Spanish.txt"},
{"es_PY", "Spanish.txt"},
{"es_SV", "Spanish.txt"},
{"es_UY", "Spanish.txt"},
{"es_VE", "Spanish.txt"},
{"et", "English.txt"},
{"et_EE", "English.txt"},
{"eu", "English.txt"},
{"eu_ES", "English.txt"},
{"fa", "English.txt"},
{"fa_IR", "English.txt"},
{"fi", "English.txt"},
{"fi_FI", "English.txt"},
{"fo", "English.txt"},
{"fo_FO", "English.txt"},
{"fr", "French.txt"},
{"fr_BE", "French.txt"},
{"fr_CA", "French.txt"},
{"fr_CH", "French.txt"},
{"fr_FR", "French.txt"},
{"fr_LU", "French.txt"},
{"fr_MC", "French.txt"},
{"gl", "English.txt"},
{"gl_ES", "English.txt"},
{"gu", "English.txt"},
{"gu_IN", "English.txt"},
{"he", "English.txt"},
{"he_IL", "English.txt"},
{"hi", "English.txt"},
{"hi_IN", "English.txt"},
{"hr", "English.txt"},
{"hr_BA", "English.txt"},
{"hr_HR", "English.txt"},
{"hu", "English.txt"},
{"hu_HU", "English.txt"},
{"hy", "English.txt"},
{"hy_AM", "English.txt"},
{"id", "Indonesian.txt"},
{"id_ID", "Indonesian.txt"},
{"is", "English.txt"},
{"is_IS", "English.txt"},
{"it", "Italian.txt"},
{"it_CH", "Italian.txt"},
{"it_IT", "Italian.txt"},
{"ja", "Japanese.txt"},
{"ja_JP", "Japanese.txt"},
{"ka", "English.txt"},
{"ka_GE", "English.txt"},
{"kk", "English.txt"},
{"kk_KZ", "English.txt"},
{"kn", "English.txt"},
{"kn_IN", "English.txt"},
{"ko", "Korean.txt"},
{"ko_KR", "Korean.txt"},
{"kok", "English.txt"},
{"kok_IN", "English.txt"},
{"ky", "English.txt"},
{"ky_KG", "English.txt"},
{"lt", "Lithuanian.txt"},
{"lt_LT", "Lithuanian.txt"},
{"lv", "English.txt"},
{"lv_LV", "English.txt"},
{"mi", "English.txt"},
{"mi_NZ", "English.txt"},
{"mk", "English.txt"},
{"mk_MK", "English.txt"},
{"mn", "English.txt"},
{"mn_MN", "English.txt"},
{"mr", "English.txt"},
{"mr_IN", "English.txt"},
{"ms", "English.txt"},
{"ms_BN", "English.txt"},
{"ms_MY", "English.txt"},
{"mt", "English.txt"},
{"mt_MT", "English.txt"},
{"nb", "English.txt"},
{"nb_NO", "English.txt"},
{"nl", "English.txt"},
{"nl_BE", "English.txt"},
{"nl_NL", "English.txt"},
{"nn_NO", "English.txt"},
{"ns", "English.txt"},
{"ns_ZA", "English.txt"},
{"pa", "English.txt"},
{"pa_IN", "English.txt"},
{"pl", "Polish.txt"},
{"pl_PL", "Polish.txt"},
{"ps", "English.txt"},
{"ps_AR", "English.txt"},
{"pt", "Portugese.txt"},
{"pt_BR", "Portugese.txt"},
{"pt_PT", "Portugese.txt"},
{"qu", "English.txt"},
{"qu_BO", "English.txt"},
{"qu_EC", "English.txt"},
{"qu_PE", "English.txt"},
{"ro", "English.txt"},
{"ro_RO", "English.txt"},
{"ru", "Russian.txt"},
{"ru_RU", "Russian.txt"},
{"sa", "English.txt"},
{"sa_IN", "English.txt"},
{"se", "English.txt"},
{"se_FI", "English.txt"},
{"se_FI", "English.txt"},
{"se_FI", "English.txt"},
{"se_NO", "English.txt"},
{"se_NO", "English.txt"},
{"se_NO", "English.txt"},
{"se_SE", "English.txt"},
{"se_SE", "English.txt"},
{"se_SE", "English.txt"},
{"sk", "English.txt"},
{"sk_SK", "English.txt"},
{"sl", "Slovenian.txt"},
{"sl_SI", "Slovenian.txt"},
{"sq", "English.txt"},
{"sq_AL", "English.txt"},
{"sr_BA", "English.txt"},
{"sr_BA", "English.txt"},
{"sr_SP", "English.txt"},
{"sr_SP", "English.txt"},
{"sv", "English.txt"},
{"sv_FI", "English.txt"},
{"sv_SE", "English.txt"},
{"sw", "English.txt"},
{"sw_KE", "English.txt"},
{"syr", "English.txt"},
{"syr_SY", "English.txt"},
{"ta", "English.txt"},
{"ta_IN", "English.txt"},
{"te", "English.txt"},
{"te_IN", "English.txt"},
{"th", "English.txt"},
{"th_TH", "English.txt"},
{"tl", "English.txt"},
{"tl_PH", "English.txt"},
{"tn", "English.txt"},
{"tn_ZA", "English.txt"},
{"tr", "Turkish.txt"},
{"tr_TR", "Turkish.txt"},
{"tt", "English.txt"},
{"tt_RU", "English.txt"},
{"ts", "English.txt"},
{"uk", "English.txt"},
{"uk_UA", "English.txt"},
{"ur", "English.txt"},
{"ur_PK", "English.txt"},
{"uz", "English.txt"},
{"uz_UZ", "English.txt"},
{"uz_UZ", "English.txt"},
{"vi", "English.txt"},
{"vi_VN", "English.txt"},
{"xh", "English.txt"},
{"xh_ZA", "English.txt"},
{"zh", "Chinese.txt"},
{"zh_CN", "Chinese.txt"},
{"zh_HK", "Chinese.txt"},
{"zh_MO", "Chinese.txt"},
{"zh_SG", "Chinese.txt"},
{"zh_TW", "Chinese_TW.txt"},
{"zu", "English.txt"},
{"zu_ZA", "English.txt"},
}
func TestResolveLicenseFile(t *testing.T) {
for _, table := range licenseTests {
os.Setenv("LANG", table.in)
f := resolveLicenseFile()
if f != table.out {
t.Errorf("resolveLicenseFile() with LANG=%v - expected %v, got %v", table.in, table.out, f)
}
}
}

194
cmd/runmqserver/logging.go Normal file
View File

@@ -0,0 +1,194 @@
/*
© Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/pkg/logger"
"github.com/ibm-messaging/mq-container/pkg/mqini"
)
// var debug = false
var log *logger.Logger
var collectDiagOnFail = false
func logTerminationf(format string, args ...interface{}) {
logTermination(fmt.Sprintf(format, args...))
}
func logTermination(args ...interface{}) {
msg := fmt.Sprint(args...)
// Write the message to the termination log. This is not the default place
// that Kubernetes will look for termination information.
log.Debugf("Writing termination message: %v", msg)
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
if err != nil {
log.Debug(err)
}
log.Error(msg)
if collectDiagOnFail {
logDiagnostics()
}
}
func getLogFormat() string {
return os.Getenv("LOG_FORMAT")
}
func formatSimple(datetime string, message string) string {
return fmt.Sprintf("%v %v\n", datetime, message)
}
// mirrorSystemErrorLogs starts a goroutine to mirror the contents of the MQ system error logs
func mirrorSystemErrorLogs(ctx context.Context, wg *sync.WaitGroup, mf mirrorFunc) (chan error, error) {
// Always use the JSON log as the source
return mirrorLog(ctx, wg, "/var/mqm/errors/AMQERR01.json", false, mf, false)
}
// mirrorQueueManagerErrorLogs starts a goroutine to mirror the contents of the MQ queue manager error logs
func mirrorQueueManagerErrorLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
// Always use the JSON log as the source
qm, err := mqini.GetQueueManager(name)
if err != nil {
log.Debug(err)
return nil, err
}
f := filepath.Join(mqini.GetErrorLogDirectory(qm), "AMQERR01.json")
return mirrorLog(ctx, wg, f, fromStart, mf, true)
}
func getDebug() bool {
debug := os.Getenv("DEBUG")
if debug == "true" || debug == "1" {
return true
}
return false
}
func configureLogger(name string) (mirrorFunc, error) {
var err error
f := getLogFormat()
d := getDebug()
switch f {
case "json":
log, err = logger.NewLogger(os.Stderr, d, true, name)
if err != nil {
return nil, err
}
return func(msg string, isQMLog bool) bool {
obj, err := processLogMessage(msg)
if err == nil && isQMLog && filterQMLogMessage(obj) {
return false
}
if err != nil {
log.Printf("Failed to unmarshall JSON - %v", msg)
} else {
fmt.Println(msg)
}
return true
}, nil
case "basic":
log, err = logger.NewLogger(os.Stderr, d, false, name)
if err != nil {
return nil, err
}
return func(msg string, isQMLog bool) bool {
// Parse the JSON message, and print a simplified version
obj, err := processLogMessage(msg)
if err == nil && isQMLog && filterQMLogMessage(obj) {
return false
}
if err != nil {
log.Printf("Failed to unmarshall JSON - %v", err)
} else {
fmt.Printf(formatSimple(obj["ibm_datetime"].(string), obj["message"].(string)))
}
return true
}, nil
default:
log, err = logger.NewLogger(os.Stdout, d, false, name)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("invalid value for LOG_FORMAT: %v", f)
}
}
func processLogMessage(msg string) (map[string]interface{}, error) {
var obj map[string]interface{}
err := json.Unmarshal([]byte(msg), &obj)
return obj, err
}
func filterQMLogMessage(obj map[string]interface{}) bool {
hostname, err := os.Hostname()
if os.Getenv("MQ_MULTI_INSTANCE") == "true" && err == nil && !strings.Contains(obj["host"].(string), hostname) {
return true
}
return false
}
func logDiagnostics() {
log.Debug("--- Start Diagnostics ---")
// show the directory ownership/permissions
// #nosec G104
out, _, _ := command.Run("ls", "-l", "/mnt/")
log.Debugf("/mnt/:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm")
log.Debugf("/mnt/mqm:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm/data")
log.Debugf("/mnt/mqm/data:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm-log/log")
log.Debugf("/mnt/mqm-log/log:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/mnt/mqm-data/qmgrs")
log.Debugf("/mnt/mqm-data/qmgrs:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/var/mqm")
log.Debugf("/var/mqm:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/var/mqm/errors")
log.Debugf("/var/mqm/errors:\n%s", out)
// #nosec G104
out, _, _ = command.Run("ls", "-l", "/etc/mqm")
log.Debugf("/etc/mqm:\n%s", out)
// Print out summary of any FDCs
// #nosec G204
cmd := exec.Command("/opt/mqm/bin/ffstsummary")
cmd.Dir = "/var/mqm/errors"
// #nosec G104
outB, _ := cmd.CombinedOutput()
log.Debugf("ffstsummary:\n%s", string(outB))
log.Debug("--- End Diagnostics ---")
}

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017 © Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -18,279 +18,213 @@ limitations under the License.
package main package main
import ( import (
"fmt" "context"
"io/ioutil" "errors"
"log" "flag"
"os" "os"
"os/exec" "sync"
"os/signal"
"path/filepath"
"regexp"
"runtime"
"strings"
"syscall"
"golang.org/x/sys/unix" "github.com/ibm-messaging/mq-container/internal/metrics"
"github.com/ibm-messaging/mq-container/internal/mqinimerge"
"github.com/ibm-messaging/mq-container/internal/ready"
"github.com/ibm-messaging/mq-container/internal/tls"
"github.com/ibm-messaging/mq-container/pkg/containerruntimelogger"
"github.com/ibm-messaging/mq-container/pkg/name"
) )
// resolveLicenseFile returns the file name of the MQ license file, taking into func doMain() error {
// account the language set by the LANG environment variable var initFlag = flag.Bool("i", false, "initialize volume only, then exit")
func resolveLicenseFile() string { var infoFlag = flag.Bool("info", false, "Display debug info, then exit")
lang, ok := os.LookupEnv("LANG") var noLogRuntimeFlag = flag.Bool("nologruntime", false, "used when running this program from another program, to control log output")
if !ok { var devFlag = flag.Bool("dev", false, "used when running this program from runmqdevserver to control how TLS is configured")
return "English.txt" flag.Parse()
}
switch {
case strings.HasPrefix(lang, "zh_TW"):
return "Chinese_TW.txt"
case strings.HasPrefix(lang, "zh"):
return "Chinese.txt"
case strings.HasPrefix(lang, "cs"):
return "Czech.txt"
case strings.HasPrefix(lang, "fr"):
return "French.txt"
case strings.HasPrefix(lang, "de"):
return "German.txt"
case strings.HasPrefix(lang, "el"):
return "Greek.txt"
case strings.HasPrefix(lang, "id"):
return "Indonesian.txt"
case strings.HasPrefix(lang, "it"):
return "Italian.txt"
case strings.HasPrefix(lang, "ja"):
return "Japanese.txt"
case strings.HasPrefix(lang, "ko"):
return "Korean.txt"
case strings.HasPrefix(lang, "lt"):
return "Lithuanian.txt"
case strings.HasPrefix(lang, "pl"):
return "Polish.txt"
case strings.HasPrefix(lang, "pt"):
return "Portugese.txt"
case strings.HasPrefix(lang, "ru"):
return "Russian.txt"
case strings.HasPrefix(lang, "sl"):
return "Slovenian.txt"
case strings.HasPrefix(lang, "es"):
return "Spanish.txt"
case strings.HasPrefix(lang, "tr"):
return "Turkish.txt"
}
return "English.txt"
}
func checkLicense() { name, nameErr := name.GetQueueManagerName()
lic, ok := os.LookupEnv("LICENSE") mf, err := configureLogger(name)
switch {
case ok && lic == "accept":
return
case ok && lic == "view":
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
buf, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
fmt.Println(err) logTermination(err)
os.Exit(1) return err
} }
fmt.Println(string(buf))
os.Exit(1)
}
fmt.Println("Error: Set environment variable LICENSE=accept to indicate acceptance of license terms and conditions.")
fmt.Println("License agreements and information can be viewed by setting the environment variable LICENSE=view. You can also set the LANG environment variable to view the license in a different language.")
os.Exit(1)
}
// sanitizeQueueManagerName removes any invalid characters from a queue manager name // Check whether they only want debug info
func sanitizeQueueManagerName(name string) string { if *infoFlag {
var re = regexp.MustCompile("[^a-zA-Z0-9._%/]") logVersionInfo()
return re.ReplaceAllString(name, "") err = containerruntimelogger.LogContainerDetails(log)
}
// GetQueueManagerName resolves the queue manager name to use. Resolved from
// either an environment variable, or the hostname.
func getQueueManagerName() (string, error) {
var name string
var err error
name, ok := os.LookupEnv("MQ_QMGR_NAME")
if !ok || name == "" {
name, err = os.Hostname()
if err != nil { if err != nil {
return "", err log.Printf("Error displaying container details: %v", err)
} }
name = sanitizeQueueManagerName(name) return nil
} }
// TODO: What if the specified env variable is an invalid name?
return name, nil
}
// runCommand runs an OS command. On Linux it waits for the command to err = verifySingleProcess()
// complete and returns the exit status (return code).
func runCommand(name string, arg ...string) (string, int, error) {
cmd := exec.Command(name, arg...)
// Run the command and wait for completion
out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
var rc int // We don't do the normal termination here as it would create a termination file.
// Only works on Linux log.Error(err)
if runtime.GOOS == "linux" { return err
var ws unix.WaitStatus
unix.Wait4(cmd.Process.Pid, &ws, 0, nil)
rc = ws.ExitStatus()
} else {
rc = -1
} }
if rc == 0 {
return string(out), rc, nil
}
return string(out), rc, err
}
return string(out), 0, nil
}
// createDirStructure creates the default MQ directory structure under /var/mqm if nameErr != nil {
func createDirStructure() { logTermination(err)
out, _, err := runCommand("/opt/mqm/bin/crtmqdir", "-f", "-s") return err
}
err = ready.Clear()
if err != nil { if err != nil {
log.Fatalf("Error creating directory structure: %v\n", string(out)) logTermination(err)
return err
} }
log.Println("Created directory structure under /var/mqm") accepted, err := checkLicense()
}
func createQueueManager(name string) {
log.Printf("Creating queue manager %v", name)
out, rc, err := runCommand("crtmqm", "-q", "-p", "1414", name)
if err != nil { if err != nil {
// 8=Queue manager exists, which is fine logTerminationf("Error checking license acceptance: %v", err)
if rc != 8 { return err
log.Printf("crtmqm returned %v", rc)
log.Fatalln(string(out))
} else {
log.Printf("Detected existing queue manager %v", name)
return
} }
} if !accepted {
} err = errors.New("License not accepted")
logTermination(err)
func updateCommandLevel() { return err
level, ok := os.LookupEnv("MQ_CMDLEVEL")
if ok && level != "" {
out, rc, err := runCommand("strmqm", "-e", "CMDLEVEL="+level)
if err != nil {
log.Fatalf("Error %v setting CMDLEVEL: %v", rc, string(out))
}
}
}
func startQueueManager() {
log.Println("Starting queue manager")
out, rc, err := runCommand("strmqm")
if err != nil {
log.Fatalf("Error %v starting queue manager: %v", rc, string(out))
}
log.Println("Started queue manager")
}
func configureQueueManager() {
const configDir string = "/etc/mqm"
files, err := ioutil.ReadDir(configDir)
if err != nil {
log.Fatal(err)
}
for _, file := range files {
if strings.HasSuffix(file.Name(), ".mqsc") {
abs := filepath.Join(configDir, file.Name())
mqsc, err := ioutil.ReadFile(abs)
if err != nil {
log.Fatal(err)
}
cmd := exec.Command("runmqsc")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
stdin.Write(mqsc)
stdin.Close()
// Run the command and wait for completion
out, err := cmd.CombinedOutput()
if err != nil {
log.Println(err)
}
// Print the runmqsc output, adding tab characters to make it more readable as part of the log
log.Printf("Output for \"runmqsc\" with %v:\n\t%v", abs, strings.Replace(string(out), "\n", "\n\t", -1))
}
}
}
func stopQueueManager() {
log.Println("Stopping queue manager")
out, _, err := runCommand("endmqm", "-w")
if err != nil {
log.Fatalf("Error stopping queue manager: %v", string(out))
}
log.Println("Stopped queue manager")
}
// createTerminateChannel creates a channel which will be closed when SIGTERM
// is received.
func createTerminateChannel() chan struct{} {
done := make(chan struct{})
// Handle SIGTERM
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
go func() {
sig := <-c
log.Printf("Signal received: %v", sig)
stopQueueManager()
close(done)
}()
return done
}
// createReaperChannel creates a channel which will be used to reap zombie
// (defunct) processes. This is a responsibility of processes running
// as PID 1.
func createReaper() {
// Handle SIGCHLD
c := make(chan os.Signal, 3)
signal.Notify(c, syscall.SIGCHLD)
go func() {
for {
<-c
for {
var ws unix.WaitStatus
_, err := unix.Wait4(-1, &ws, 0, nil)
// If err indicates "no child processes" left to reap, then
// wait for next SIGCHLD signal
if err == unix.ECHILD {
break
}
}
}
}()
}
func main() {
createReaper()
checkLicense()
// Start SIGTERM handler channel
done := createTerminateChannel()
name, err := getQueueManagerName()
if err != nil {
log.Fatalln(err)
} }
log.Printf("Using queue manager name: %v", name) log.Printf("Using queue manager name: %v", name)
logConfig() // Start signal handler
err = createVolume("/mnt/mqm") signalControl := signalHandler(name)
// Enable diagnostic collecting on failure
collectDiagOnFail = true
if *noLogRuntimeFlag == false {
err = containerruntimelogger.LogContainerDetails(log)
if err != nil { if err != nil {
log.Fatal(err) logTermination(err)
return err
}
}
err = createVolume("/mnt/mqm/data")
if err != nil {
logTermination(err)
return err
}
err = createVolume("/mnt/mqm-log/log")
if err != nil {
logTermination(err)
return err
}
err = createVolume("/mnt/mqm-data/qmgrs")
if err != nil {
logTermination(err)
return err
}
err = createDirStructure()
if err != nil {
logTermination(err)
return err
}
// If init flag is set, exit now
if *initFlag {
return nil
}
// Print out versioning information
logVersionInfo()
keylabel, cmsDB, p12Trust, _, err := tls.ConfigureTLSKeystores(keyDir, trustDir, keyStoreDir)
if err != nil {
logTermination(err)
return err
}
err = configureTLS(keylabel, cmsDB, *devFlag)
if err != nil {
logTermination(err)
return err
}
err = postInit(name, keylabel, p12Trust)
if err != nil {
logTermination(err)
return err
}
newQM, err := createQueueManager(name)
if err != nil {
logTermination(err)
return err
}
var wg sync.WaitGroup
defer func() {
log.Debug("Waiting for log mirroring to complete")
wg.Wait()
}()
ctx, cancelMirror := context.WithCancel(context.Background())
defer func() {
log.Debug("Cancel log mirroring")
cancelMirror()
}()
// TODO: Use the error channel
_, err = mirrorSystemErrorLogs(ctx, &wg, mf)
if err != nil {
logTermination(err)
return err
}
_, err = mirrorQueueManagerErrorLogs(ctx, &wg, name, newQM, mf)
if err != nil {
logTermination(err)
return err
}
err = updateCommandLevel()
if err != nil {
logTermination(err)
return err
}
err = mqinimerge.AddStanzas(name)
if err != nil {
logTermination(err)
return err
}
err = startQueueManager(name)
if err != nil {
logTermination(err)
return err
}
if standby, _ := ready.IsRunningAsStandbyQM(name); !standby {
err = configureQueueManager()
if err != nil {
logTermination(err)
return err
}
}
enableMetrics := os.Getenv("MQ_ENABLE_METRICS")
if enableMetrics == "true" || enableMetrics == "1" {
go metrics.GatherMetrics(name, log)
} else {
log.Println("Metrics are disabled")
}
// Start reaping zombies from now on.
// Start this here, so that we don't reap any sub-processes created
// by this process (e.g. for crtmqm or strmqm)
signalControl <- startReaping
// Reap zombies now, just in case we've already got some
signalControl <- reapNow
// Write a file to indicate that chkmqready should now work as normal
err = ready.Set()
if err != nil {
logTermination(err)
return err
} }
createDirStructure()
createQueueManager(name)
updateCommandLevel()
startQueueManager()
configureQueueManager()
// Wait for terminate signal // Wait for terminate signal
<-done <-signalControl
return nil
}
var osExit = os.Exit
func main() {
err := doMain()
if err != nil {
osExit(1)
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
© Copyright IBM Corporation 2017 © Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -17,18 +17,45 @@ package main
import ( import (
"flag" "flag"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"testing" "testing"
"github.com/ibm-messaging/mq-container/pkg/logger"
) )
var test *bool var test *bool
func init() { func init() {
test = flag.Bool("test", false, "Set to true when running tests for coverage") test = flag.Bool("test", false, "Set to true when running tests for coverage")
log, _ = logger.NewLogger(os.Stdout, true, false, "test")
} }
// Test started when the test binary is started. Only calls main. // Test started when the test binary is started. Only calls main.
func TestSystem(t *testing.T) { func TestSystem(t *testing.T) {
if *test { if *test {
var oldExit = osExit
defer func() {
osExit = oldExit
}()
filename, ok := os.LookupEnv("EXIT_CODE_FILE")
if !ok {
filename = "/var/coverage/exitCode"
} else {
filename = filepath.Join("/var/coverage/", filename)
}
osExit = func(rc int) {
// Write the exit code to a file instead
log.Printf("Writing exit code %v to file %v", strconv.Itoa(rc), filename)
err := ioutil.WriteFile(filename, []byte(strconv.Itoa(rc)), 0644)
if err != nil {
log.Print(err)
}
}
main() main()
} }
} }

197
cmd/runmqserver/mirror.go Normal file
View File

@@ -0,0 +1,197 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bufio"
"context"
"fmt"
"os"
"sync"
"time"
)
// waitForFile waits until the specified file exists
func waitForFile(ctx context.Context, path string) (os.FileInfo, error) {
var fi os.FileInfo
var err error
// Wait for file to exist
for {
select {
// Check to see if cancellation has been requested
case <-ctx.Done():
return os.Stat(path)
default:
fi, err = os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
time.Sleep(500 * time.Millisecond)
continue
} else {
return nil, fmt.Errorf("mirror: unable to get info on file %v", path)
}
}
return fi, nil
}
}
}
type mirrorFunc func(msg string, isQMLog bool) bool
// mirrorAvailableMessages prints lines from the file, until no more are available
func mirrorAvailableMessages(f *os.File, mf mirrorFunc, isQMLog bool) {
scanner := bufio.NewScanner(f)
count := 0
for scanner.Scan() {
t := scanner.Text()
if mf(t, isQMLog) {
count++
}
}
if count > 0 {
log.Debugf("Mirrored %v log entries from %v", count, f.Name())
}
err := scanner.Err()
if err != nil {
log.Errorf("Error reading file %v: %v", f.Name(), err)
return
}
}
// mirrorLog tails the specified file, and logs each line to stdout.
// This is useful for usability, as the container console log can show
// messages from the MQ error logs.
func mirrorLog(ctx context.Context, wg *sync.WaitGroup, path string, fromStart bool, mf mirrorFunc, isQMLog bool) (chan error, error) {
errorChannel := make(chan error, 1)
var offset int64 = -1
var f *os.File
var err error
var fi os.FileInfo
// Need to check if the file exists before returning, otherwise we have a
// race to see if the new file get created before we can test for it
fi, err = os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
// File doesn't exist, so ensure we start at the beginning
offset = 0
} else {
return nil, err
}
} else {
// If the file exists, open it now, before we return. This makes sure
// the file is open before the queue manager is created or started.
// Otherwise, there would be the potential for a nearly-full file to
// rotate before the goroutine had a chance to open it.
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
// File already exists, so start reading at the end
offset = fi.Size()
}
// Increment wait group counter, only if the goroutine gets started
wg.Add(1)
go func() {
// Notify the wait group when this goroutine ends
defer func() {
log.Debugf("Finished monitoring %v", path)
wg.Done()
}()
if f == nil {
// File didn't exist, so need to wait for it
fi, err = waitForFile(ctx, path)
if err != nil {
log.Error(err)
errorChannel <- err
return
}
if fi == nil {
return
}
log.Debugf("File exists: %v, %v", path, fi.Size())
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
log.Error(err)
errorChannel <- err
return
}
}
fi, err = f.Stat()
if err != nil {
log.Error(err)
errorChannel <- err
return
}
// The file now exists. If it didn't exist before we started, offset=0
// Always start at the beginning if we've been told to go from the start
if offset != 0 && !fromStart {
log.Debugf("Seeking offset %v in file %v", offset, path)
_, err = f.Seek(offset, 0)
if err != nil {
log.Errorf("Unable to return to offset %v: %v", offset, err)
}
}
closing := false
for {
// If there's already data there, mirror it now.
mirrorAvailableMessages(f, mf, isQMLog)
// Wait for the new log file (after rotation)
newFI, err := waitForFile(ctx, path)
if err != nil {
log.Error(err)
errorChannel <- err
return
}
if !os.SameFile(fi, newFI) {
log.Debugf("Detected log rotation in file %v", path)
// WARNING: There is a possible race condition here. If *another*
// log rotation happens before we can open the new file, then we
// could skip all those messages. This could happen with a very small
// MQ error log size.
mirrorAvailableMessages(f, mf, isQMLog)
err = f.Close()
if err != nil {
log.Errorf("Unable to close mirror file handle: %v", err)
}
// Re-open file
log.Debugf("Re-opening error log file %v", path)
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
log.Error(err)
errorChannel <- err
return
}
fi = newFI
// Don't seek this time, because we know it's a new file
mirrorAvailableMessages(f, mf, isQMLog)
}
select {
case <-ctx.Done():
log.Debugf("Context cancelled for mirroring %v", path)
if closing {
log.Debugf("Shutting down mirror for %v", path)
return
}
// Set a flag, to allow one more time through the loop
closing = true
default:
time.Sleep(500 * time.Millisecond)
}
}
}()
return errorChannel, nil
}

View File

@@ -0,0 +1,195 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"sync"
"testing"
"time"
)
func TestMirrorLogWithoutRotation(t *testing.T) {
// Repeat the test multiple times, to help identify timing problems
for i := 0; i < 10; i++ {
t.Run(t.Name()+strconv.Itoa(i), func(t *testing.T) {
// Use just the sub-test name in the file name
tmp, err := ioutil.TempFile("", strings.Split(t.Name(), "/")[1])
if err != nil {
t.Fatal(err)
}
t.Log(tmp.Name())
defer os.Remove(tmp.Name())
count := 0
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
_, err = mirrorLog(ctx, &wg, tmp.Name(), true, func(msg string, isQMLog bool) bool {
count++
return true
}, false)
if err != nil {
t.Fatal(err)
}
f, err := os.OpenFile(tmp.Name(), os.O_WRONLY, 0700)
if err != nil {
t.Fatal(err)
}
log.Println("Logging 3 JSON messages")
fmt.Fprintln(f, "{\"message\"=\"A\"}")
fmt.Fprintln(f, "{\"message\"=\"B\"}")
fmt.Fprintln(f, "{\"message\"=\"C\"}")
f.Close()
cancel()
wg.Wait()
if count != 3 {
t.Fatalf("Expected 3 log entries; got %v", count)
}
})
}
}
func TestMirrorLogWithRotation(t *testing.T) {
// Repeat the test multiple times, to help identify timing problems
for i := 0; i < 5; i++ {
t.Run(t.Name()+strconv.Itoa(i), func(t *testing.T) {
// Use just the sub-test name in the file name
tmp, err := ioutil.TempFile("", strings.Split(t.Name(), "/")[1])
if err != nil {
t.Fatal(err)
}
t.Log(tmp.Name())
defer func() {
t.Log("Removing file")
os.Remove(tmp.Name())
}()
count := 0
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
_, err = mirrorLog(ctx, &wg, tmp.Name(), true, func(msg string, isQMLog bool) bool {
count++
return true
}, false)
if err != nil {
t.Fatal(err)
}
f, err := os.OpenFile(tmp.Name(), os.O_WRONLY, 0700)
if err != nil {
t.Fatal(err)
}
t.Log("Logging 3 JSON messages")
fmt.Fprintln(f, "{\"message\"=\"A\"}")
fmt.Fprintln(f, "{\"message\"=\"B\"}")
fmt.Fprintln(f, "{\"message\"=\"C\"}")
f.Close()
// Rotate the file, by renaming it
rotated := tmp.Name() + ".1"
os.Rename(tmp.Name(), rotated)
defer os.Remove(rotated)
// Open a new file, with the same name as before
f, err = os.OpenFile(tmp.Name(), os.O_WRONLY|os.O_CREATE, 0700)
if err != nil {
t.Fatal(err)
}
t.Log("Logging 2 more JSON messages")
fmt.Fprintln(f, "{\"message\"=\"D\"}")
fmt.Fprintln(f, "{\"message\"=\"E\"}")
f.Close()
// Shut the mirroring down
cancel()
wg.Wait()
if count != 5 {
t.Fatalf("Expected 5 log entries; got %v", count)
}
})
}
}
func testMirrorLogExistingFile(t *testing.T, newQM bool) int {
tmp, err := ioutil.TempFile("", t.Name())
if err != nil {
t.Fatal(err)
}
t.Log(tmp.Name())
log.Println("Logging 1 message before we start")
ioutil.WriteFile(tmp.Name(), []byte("{\"message\"=\"A\"}\n"), 0600)
defer os.Remove(tmp.Name())
count := 0
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
_, err = mirrorLog(ctx, &wg, tmp.Name(), newQM, func(msg string, isQMLog bool) bool {
count++
return true
}, false)
if err != nil {
t.Fatal(err)
}
f, err := os.OpenFile(tmp.Name(), os.O_APPEND|os.O_WRONLY, 0700)
if err != nil {
t.Fatal(err)
}
log.Println("Logging 2 new JSON messages")
fmt.Fprintln(f, "{\"message\"=\"B\"}")
fmt.Fprintln(f, "{\"message\"=\"C\"}")
f.Close()
cancel()
wg.Wait()
return count
}
// TestMirrorLogExistingFile tests that we only get new log messages, if the
// log file already exists
func TestMirrorLogExistingFile(t *testing.T) {
count := testMirrorLogExistingFile(t, false)
if count != 2 {
t.Fatalf("Expected 2 log entries; got %v", count)
}
}
// TestMirrorLogExistingFileButNewQueueManager tests that we only get all log
// messages, even if the file exists, if we tell it we want all messages
func TestMirrorLogExistingFileButNewQueueManager(t *testing.T) {
count := testMirrorLogExistingFile(t, true)
if count != 3 {
t.Fatalf("Expected 3 log entries; got %v", count)
}
}
func TestMirrorLogCancelWhileWaiting(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
defer func() {
cancel()
wg.Wait()
}()
_, err := mirrorLog(ctx, &wg, "fake.log", true, func(msg string, isQMLog bool) bool {
return true
}, false)
if err != nil {
t.Error(err)
}
time.Sleep(time.Second * 3)
cancel()
wg.Wait()
// No need to assert anything. If it didn't work, the code would have hung (TODO: not ideal)
}

View File

@@ -1,151 +0,0 @@
/*
© Copyright IBM Corporation 2017
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 (
"io/ioutil"
"log"
"os/user"
"runtime"
"strings"
"github.com/ibm-messaging/mq-container/pkg/linux/capabilities"
"golang.org/x/sys/unix"
)
// fsTypes contains file system identifier codes.
// This code will not compile on some operating systems - Linux only.
var fsTypes = map[int64]string{
0x61756673: "aufs",
0xef53: "ext",
0x6969: "nfs",
0x65735546: "fuse",
0x9123683e: "btrfs",
0x01021994: "tmpfs",
0x794c7630: "overlayfs",
}
func logBaseImage() error {
buf, err := ioutil.ReadFile("/etc/os-release")
if err != nil {
return err
}
lines := strings.Split(string(buf), "\n")
for _, l := range lines {
if strings.HasPrefix(l, "PRETTY_NAME=") {
words := strings.Split(l, "\"")
if len(words) >= 2 {
log.Printf("Base image detected: %v", words[1])
return nil
}
}
}
return nil
}
func logUser() {
u, err := user.Current()
if err == nil {
log.Printf("Running as user ID %v (%v) with primary group %v", u.Uid, u.Name, u.Gid)
}
}
func logCapabilities() {
status, err := readProc("/proc/1/status")
if err != nil {
// Ignore
return
}
caps, err := capabilities.DetectCapabilities(status)
if err == nil {
log.Printf("Detected capabilities: %v", strings.Join(caps, ","))
}
}
func readProc(filename string) (value string, err error) {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return strings.TrimSpace(string(buf)), nil
}
func readMounts() error {
all, err := readProc("/proc/mounts")
if err != nil {
log.Println("Error: Couldn't read /proc/mounts")
return err
}
lines := strings.Split(all, "\n")
detected := false
for i := range lines {
parts := strings.Split(lines[i], " ")
//dev := parts[0]
mountPoint := parts[1]
fsType := parts[2]
if strings.Contains(mountPoint, "/mnt") {
log.Printf("Detected '%v' volume mounted to %v", fsType, mountPoint)
detected = true
}
}
if !detected {
log.Println("No volume detected. Persistent messages may be lost")
} else {
checkFS("/mnt/mqm")
}
return nil
}
func checkFS(path string) {
statfs := &unix.Statfs_t{}
err := unix.Statfs(path, statfs)
if err != nil {
log.Println(err)
return
}
t := fsTypes[statfs.Type]
switch t {
case "aufs", "overlayfs", "tmpfs":
log.Fatalf("Error: %v uses unsupported filesystem type %v", path, t)
default:
log.Printf("Detected %v has filesystem type '%v'", path, t)
}
}
func logConfig() {
log.Printf("CPU architecture: %v", runtime.GOARCH)
if runtime.GOOS == "linux" {
var err error
osr, err := readProc("/proc/sys/kernel/osrelease")
if err != nil {
log.Println(err)
} else {
log.Printf("Linux kernel version: %v", osr)
}
logBaseImage()
fileMax, err := readProc("/proc/sys/fs/file-max")
if err != nil {
log.Println(err)
} else {
log.Printf("Maximum file handles: %v", fileMax)
}
logUser()
logCapabilities()
readMounts()
} else {
log.Fatalf("Unsupported platform: %v", runtime.GOOS)
}
}

View File

@@ -0,0 +1,48 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"os"
"github.com/ibm-messaging/mq-container/internal/tls"
)
// postInit is run after /var/mqm is set up
func postInit(name, keylabel string, p12Trust tls.KeyStoreData) error {
enableWebServer := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER")
if enableWebServer == "true" || enableWebServer == "1" {
// Configure the web server (if enabled)
keystore, err := configureWebServer(keylabel, p12Trust)
if err != nil {
return err
}
// If trust-store is empty, set reference to point to the key-store
p12TrustStoreRef := "MQWebTrustStore"
if len(p12Trust.TrustedCerts) == 0 {
p12TrustStoreRef = "MQWebKeyStore"
}
// Start the web server, in the background (if installed)
// WARNING: No error handling or health checking available for the web server
go func() {
err = startWebServer(keystore, p12Trust.Password, p12TrustStoreRef)
if err != nil {
log.Printf("Error starting web server: %v", err)
}
}()
}
return nil
}

View File

@@ -0,0 +1,64 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
// Verifies that we are the main or only instance of this program
func verifySingleProcess() error {
programName, err := determineExecutable()
if err != nil {
return fmt.Errorf("Failed to determine name of this program - %v", err)
}
// Verify that there is only one runmqserver
_, err = verifyOnlyOne(programName)
if err != nil {
return fmt.Errorf("You cannot run more than one instance of this program")
}
return nil
}
// Verifies that there is only one instance running of the given program name.
func verifyOnlyOne(programName string) (int, error) {
// #nosec G104
out, _, _ := command.Run("ps", "-e", "--format", "cmd")
//if this goes wrong then assume we are the only one
numOfProg := strings.Count(out, programName)
if numOfProg != 1 {
return numOfProg, fmt.Errorf("Expected there to be only 1 instance of %s but found %d", programName, numOfProg)
}
return numOfProg, nil
}
// Determines the name of the currently running executable.
func determineExecutable() (string, error) {
file, err := os.Executable()
if err != nil {
return "", err
}
_, exec := filepath.Split(file)
return exec, nil
}

249
cmd/runmqserver/qmgr.go Normal file
View File

@@ -0,0 +1,249 @@
/*
© Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
containerruntime "github.com/ibm-messaging/mq-container/internal/containerruntime"
"github.com/ibm-messaging/mq-container/internal/mqscredact"
"github.com/ibm-messaging/mq-container/internal/ready"
)
// createDirStructure creates the default MQ directory structure under /var/mqm
func createDirStructure() error {
out, _, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-a")
if err != nil {
log.Printf("Error creating directory structure: %v\n", string(out))
return err
}
log.Println("Created directory structure under /var/mqm")
return nil
}
// createQueueManager creates a queue manager, if it doesn't already exist.
// It returns true if one was created (or a standby was created), or false if one already existed
func createQueueManager(name string) (bool, error) {
log.Printf("Creating queue manager %v", name)
// Run 'dspmqinf' to check if 'mqs.ini' configuration file exists
// If command succeeds, the queue manager (or standby queue manager) has already been created
_, _, err := command.Run("dspmqinf", name)
if err == nil {
log.Printf("Detected existing queue manager %v", name)
return false, nil
}
mounts, err := containerruntime.GetMounts()
if err != nil {
log.Printf("Error getting mounts for queue manager")
return false, err
}
// Check if 'qm.ini' configuration file exists for the queue manager
// TODO : handle possible race condition - use a file lock?
dataDir := getQueueManagerDataDir(mounts, name)
_, err = os.Stat(filepath.Join(dataDir, "qm.ini"))
if err != nil {
// If 'qm.ini' is not found - run 'crtmqm' to create a new queue manager
args := getCreateQueueManagerArgs(mounts, name)
out, rc, err := command.Run("crtmqm", args...)
if err != nil {
log.Printf("Error %v creating queue manager: %v", rc, string(out))
return false, err
}
} else {
// If 'qm.ini' is found - run 'addmqinf' to create a standby queue manager with existing configuration
args := getCreateStandbyQueueManagerArgs(name)
out, rc, err := command.Run("addmqinf", args...)
if err != nil {
log.Printf("Error %v creating standby queue manager: %v", rc, string(out))
return false, err
}
log.Println("Created standby queue manager")
return true, nil
}
log.Println("Created queue manager")
return true, nil
}
func updateCommandLevel() error {
level, ok := os.LookupEnv("MQ_CMDLEVEL")
if ok && level != "" {
log.Printf("Setting CMDLEVEL to %v", level)
out, rc, err := command.Run("strmqm", "-e", "CMDLEVEL="+level)
if err != nil {
log.Printf("Error %v setting CMDLEVEL: %v", rc, string(out))
return err
}
}
return nil
}
func startQueueManager(name string) error {
log.Println("Starting queue manager")
out, rc, err := command.Run("strmqm", "-x", name)
if err != nil {
// 30=standby queue manager started, which is fine
if rc == 30 {
log.Printf("Started standby queue manager")
return nil
}
log.Printf("Error %v starting queue manager: %v", rc, string(out))
return err
}
log.Println("Started queue manager")
return nil
}
func configureQueueManager() error {
const configDir string = "/etc/mqm"
files, err := ioutil.ReadDir(configDir)
if err != nil {
log.Println(err)
return err
}
for _, file := range files {
if strings.HasSuffix(file.Name(), ".mqsc") {
abs := filepath.Join(configDir, file.Name())
// #nosec G204
verify := exec.Command("runmqsc", "-v", "-e")
// #nosec G204 - command is fixed, no injection vector
cmd := exec.Command("runmqsc")
// Read mqsc file into variable
// #nosec G304 - filename variable is derived from contents of 'configDir' which is a defined constant
mqsc, err := ioutil.ReadFile(abs)
if err != nil {
log.Printf("Error reading file %v: %v", abs, err)
continue
}
// Write mqsc to buffer
var buffer bytes.Buffer
_, err = buffer.Write(mqsc)
if err != nil {
log.Printf("Error writing MQSC file %v to buffer: %v", abs, err)
continue
}
verifyBuffer := buffer
// Buffer mqsc to stdin of runmqsc
cmd.Stdin = &buffer
verify.Stdin = &verifyBuffer
// Verify the MQSC commands
out, err := verify.CombinedOutput()
if err != nil {
log.Errorf("Error verifying MQSC file %v (%v):\n\t%v", file.Name(), err, formatMQSCOutput(string(out)))
return fmt.Errorf("Error verifying MQSC file %v (%v):\n\t%v", file.Name(), err, formatMQSCOutput(string(out)))
}
// Run runmqsc command
out, err = cmd.CombinedOutput()
if err != nil {
log.Errorf("Error running MQSC file %v (%v):\n\t%v", file.Name(), err, formatMQSCOutput(string(out)))
continue
} else {
// Print the runmqsc output, adding tab characters to make it more readable as part of the log
log.Printf("Output for \"runmqsc\" with %v:\n\t%v", abs, formatMQSCOutput(string(out)))
}
}
}
return nil
}
func stopQueueManager(name string) error {
log.Println("Stopping queue manager")
isStandby, err := ready.IsRunningAsStandbyQM(name)
if err != nil {
log.Printf("Error getting status for queue manager %v: %v", name, err.Error())
return err
}
args := []string{"-w", "-r", name}
if os.Getenv("MQ_MULTI_INSTANCE") == "true" {
if isStandby {
args = []string{"-x", name}
} else {
args = []string{"-s", "-w", "-r", name}
}
}
out, rc, err := command.Run("endmqm", args...)
if err != nil {
log.Printf("Error %v stopping queue manager: %v", rc, string(out))
return err
}
if isStandby {
log.Printf("Stopped standby queue manager")
} else {
log.Println("Stopped queue manager")
}
return nil
}
func formatMQSCOutput(out string) string {
// redact sensitive information
out, _ = mqscredact.Redact(out)
// add tab characters to make it more readable as part of the log
return strings.Replace(string(out), "\n", "\n\t", -1)
}
func isStandbyQueueManager(name string) (bool, error) {
out, rc, err := command.Run("dspmq", "-n", "-m", name)
if err != nil {
log.Printf("Error %v getting status for queue manager %v: %v", rc, name, string(out))
return false, err
}
if strings.Contains(string(out), "(RUNNING AS STANDBY)") {
return true, nil
}
return false, nil
}
func getQueueManagerDataDir(mounts map[string]string, name string) string {
dataDir := filepath.Join("/var/mqm/qmgrs", name)
if _, ok := mounts["/mnt/mqm-data"]; ok {
dataDir = filepath.Join("/mnt/mqm-data/qmgrs", name)
}
return dataDir
}
func getCreateQueueManagerArgs(mounts map[string]string, name string) []string {
args := []string{"-q", "-p", "1414"}
if _, ok := mounts["/mnt/mqm-log"]; ok {
args = append(args, "-ld", "/mnt/mqm-log/log")
}
if _, ok := mounts["/mnt/mqm-data"]; ok {
args = append(args, "-md", "/mnt/mqm-data/qmgrs")
}
args = append(args, name)
return args
}
func getCreateStandbyQueueManagerArgs(name string) []string {
args := []string{"-s", "QueueManager"}
args = append(args, "-v", fmt.Sprintf("Name=%v", name))
args = append(args, "-v", fmt.Sprintf("Directory=%v", name))
args = append(args, "-v", "Prefix=/var/mqm")
args = append(args, "-v", fmt.Sprintf("DataPath=/mnt/mqm-data/qmgrs/%v", name))
return args
}

View File

@@ -0,0 +1,84 @@
/*
© Copyright IBM Corporation 2017, 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"os"
"os/signal"
"syscall"
"github.com/ibm-messaging/mq-container/internal/metrics"
"golang.org/x/sys/unix"
)
const (
startReaping = iota
reapNow = iota
)
func signalHandler(qmgr string) chan int {
control := make(chan int)
// Use separate channels for the signals, to avoid SIGCHLD signals swamping
// the buffer, and preventing other signals.
stopSignals := make(chan os.Signal)
reapSignals := make(chan os.Signal)
signal.Notify(stopSignals, syscall.SIGTERM, syscall.SIGINT)
go func() {
for {
select {
case sig := <-stopSignals:
log.Printf("Signal received: %v", sig)
signal.Stop(reapSignals)
signal.Stop(stopSignals)
metrics.StopMetricsGathering(log)
// #nosec G104
stopQueueManager(qmgr)
// One final reap
reapZombies()
close(control)
// End the goroutine
return
case <-reapSignals:
log.Debug("Received SIGCHLD signal")
reapZombies()
case job := <-control:
switch {
case job == startReaping:
// Add SIGCHLD to the list of signals we're listening to
log.Debug("Listening for SIGCHLD signals")
signal.Notify(reapSignals, syscall.SIGCHLD)
case job == reapNow:
reapZombies()
}
}
}
}()
return control
}
// reapZombies reaps any zombie (terminated) processes now.
// This function should be called before exiting.
func reapZombies() {
for {
var ws unix.WaitStatus
pid, err := unix.Wait4(-1, &ws, unix.WNOHANG, nil)
// If err or pid indicate "no child processes"
if pid == 0 || err == unix.ECHILD {
return
}
log.Debugf("Reaped PID %v", pid)
}
}

163
cmd/runmqserver/tls.go Normal file
View File

@@ -0,0 +1,163 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/keystore"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
"github.com/ibm-messaging/mq-container/internal/tls"
)
// Location to store the keystores
const keyStoreDir = "/run/runmqserver/tls/"
// KeyDir is the location of the certificate keys to import
const keyDir = "/etc/mqm/pki/keys"
// TrustDir is the location of the Certifates to add
const trustDir = "/etc/mqm/pki/trust"
// configureWebTLS configures TLS for Web Console
func configureWebTLS(label string) error {
// Return immediately if we have no certificate to use as identity
if label == "" && os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME") == "" {
return nil
}
webConfigDir := "/etc/mqm/web/installations/Installation1/servers/mqweb"
tls := "tls.xml"
tlsConfig := filepath.Join(webConfigDir, tls)
newTLSConfig := filepath.Join(webConfigDir, tls+".tpl")
err := os.Remove(tlsConfig)
if err != nil {
return fmt.Errorf("Could not delete file %s: %v", tlsConfig, err)
}
// we symlink here to prevent issues on restart
err = os.Symlink(newTLSConfig, tlsConfig)
if err != nil {
return fmt.Errorf("Could not create symlink %s->%s: %v", newTLSConfig, tlsConfig, err)
}
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return fmt.Errorf("Could not find mqm user or group: %v", err)
}
err = os.Chown(tlsConfig, mqmUID, mqmGID)
if err != nil {
return fmt.Errorf("Could change ownership of %s to mqm: %v", tlsConfig, err)
}
return nil
}
// configureTLSDev configures TLS for developer defaults
func configureTLSDev() error {
const mqsc string = "/etc/mqm/20-dev-tls.mqsc"
const mqscTemplate string = mqsc + ".tpl"
if os.Getenv("MQ_DEV") == "true" {
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{}, log)
if err != nil {
return err
}
} else {
_, err := os.Stat(mqsc)
if !os.IsNotExist(err) {
err = os.Remove(mqsc)
if err != nil {
log.Errorf("Error removing file %s: %v", mqsc, err)
return err
}
}
}
return nil
}
// configureTLS configures TLS for queue manager
func configureTLS(certLabel string, cmsKeystore tls.KeyStoreData, devmode bool) error {
log.Debug("Configuring TLS")
const mqsc string = "/etc/mqm/15-tls.mqsc"
const mqscTemplate string = mqsc + ".tpl"
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
"SSLKeyR": strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb"),
"CertificateLabel": certLabel,
}, log)
if err != nil {
return err
}
if devmode && certLabel != "" {
err = configureTLSDev()
if err != nil {
return err
}
}
return nil
}
// configureWebKeyStore configures the key stores for the web console
func configureWebKeyStore(p12TrustStore tls.KeyStoreData) (string, error) {
// TODO find way to supply this
// Override the webstore variables to hard coded defaults
webKeyStoreName := tls.WebDefaultLabel + ".p12"
// Check keystore exists
ks := filepath.Join(keyStoreDir, webKeyStoreName)
_, err := os.Stat(ks)
// Now we know if the file exists let's check whether we should have it or not.
// Check if we're being told to generate the certificate
genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME")
if genHostName != "" {
// We've got to generate the certificate with the hostname given
if err == nil {
log.Printf("Replacing existing keystore %s - generating new certificate", ks)
}
// Keystore doesn't exist so create it and populate a certificate
newKS := keystore.NewPKCS12KeyStore(ks, p12TrustStore.Password)
err = newKS.Create()
if err != nil {
return "", fmt.Errorf("Failed to create keystore %s: %v", ks, err)
}
err = newKS.CreateSelfSignedCertificate("default", fmt.Sprintf("CN=%s", genHostName), genHostName)
if err != nil {
return "", fmt.Errorf("Failed to generate certificate in keystore %s with DN of 'CN=%s': %v", ks, genHostName, err)
}
} else {
// Keystore should already exist
if err != nil {
return "", fmt.Errorf("Failed to find existing keystore %s: %v", ks, err)
}
}
// Check truststore exists
_, err = os.Stat(p12TrustStore.Keystore.Filename)
if err != nil {
return "", fmt.Errorf("Failed to find existing truststore %s: %v", p12TrustStore.Keystore.Filename, err)
}
return webKeyStoreName, nil
}

View File

@@ -0,0 +1,78 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
var (
// ImageCreated is the date the image was built
ImageCreated = "Not specified"
// ImageRevision is the source control revision identifier
ImageRevision = "Not specified"
// ImageSource is the URL to get source code for building the image
ImageSource = "Not specified"
// ImageTag is the tag of the image
ImageTag = "Not specified"
)
func logDateStamp() {
log.Printf("Image created: %v", ImageCreated)
}
func logGitRepo() {
// log.Printf("Image revision: %v", ImageRevision)
}
func logGitCommit() {
// log.Printf("Image source: %v", ImageSource)
}
func logImageTag() {
log.Printf("Image tag: %v", ImageTag)
}
func logMQVersion() {
mqVersion, _, err := command.Run("dspmqver", "-b", "-f", "2")
if err != nil {
log.Printf("Error Getting MQ version: %v", strings.TrimSuffix(string(mqVersion), "\n"))
}
mqBuild, _, err := command.Run("dspmqver", "-b", "-f", "4")
if err != nil {
log.Printf("Error Getting MQ build: %v", strings.TrimSuffix(string(mqBuild), "\n"))
}
mqLicense, _, err := command.Run("dspmqver", "-b", "-f", "8192")
if err != nil {
log.Printf("Error Getting MQ license: %v", strings.TrimSuffix(string(mqLicense), "\n"))
}
log.Printf("MQ version: %v", strings.TrimSuffix(mqVersion, "\n"))
log.Printf("MQ level: %v", strings.TrimSuffix(mqBuild, "\n"))
log.Printf("MQ license: %v", strings.TrimSuffix(mqLicense, "\n"))
}
func logVersionInfo() {
logDateStamp()
logGitRepo()
logGitCommit()
logImageTag()
logMQVersion()
}

View File

@@ -0,0 +1,210 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/ibm-messaging/mq-container/internal/command"
"github.com/ibm-messaging/mq-container/internal/copy"
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
"github.com/ibm-messaging/mq-container/internal/tls"
)
func startWebServer(keystore, keystorepw, p12TrustStoreRef string) error {
_, err := os.Stat("/opt/mqm/bin/strmqweb")
if err != nil && os.IsNotExist(err) {
log.Debug("Skipping web server, because it's not installed")
return nil
}
log.Println("Starting web server")
// #nosec G204 - command is fixed, no injection vector
cmd := exec.Command("strmqweb")
// Set a default app password for the web server, if one isn't already set
_, set := os.LookupEnv("MQ_APP_PASSWORD")
if !set {
// Take all current environment variables, and add the app password
cmd.Env = append(os.Environ(), "MQ_APP_PASSWORD=passw0rd")
} else {
cmd.Env = os.Environ()
}
// TLS enabled
if keystore != "" {
cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTORE="+keystore)
cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTOREPW="+keystorepw)
cmd.Env = append(cmd.Env, "AMQ_WEBTRUSTSTOREREF="+p12TrustStoreRef)
}
uid, gid, err := command.LookupMQM()
if err != nil {
return err
}
u, err := user.Current()
if err != nil {
return err
}
currentUID, err := strconv.Atoi(u.Uid)
if err != nil {
return fmt.Errorf("Error converting UID to string: %v", err)
}
// Add credentials to run as 'mqm', only if we aren't already 'mqm'
if currentUID != uid {
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
}
out, err := cmd.CombinedOutput()
rc := cmd.ProcessState.ExitCode()
if err != nil {
log.Printf("Error %v starting web server: %v", rc, string(out))
return err
}
log.Println("Started web server")
return nil
}
func configureSSO(p12TrustStore tls.KeyStoreData) (string, error) {
// Ensure all required environment variables are set for SSO
requiredEnvVars := []string{
"MQ_WEB_ADMIN_USERS",
"MQ_OIDC_CLIENT_ID",
"MQ_OIDC_CLIENT_SECRET",
"MQ_OIDC_UNIQUE_USER_IDENTIFIER",
"MQ_OIDC_AUTHORIZATION_ENDPOINT",
"MQ_OIDC_TOKEN_ENDPOINT",
"MQ_OIDC_JWK_ENDPOINT",
"MQ_OIDC_ISSUER_IDENTIFIER",
}
for _, envVar := range requiredEnvVars {
if len(os.Getenv(envVar)) == 0 {
return "", fmt.Errorf("%v must be set when MQ_BETA_ENABLE_SSO=true", envVar)
}
}
// Check mqweb directory exists
const mqwebDir string = "/etc/mqm/web/installations/Installation1/servers/mqweb"
_, err := os.Stat(mqwebDir)
if err != nil {
if os.IsNotExist(err) {
return "", nil
}
return "", err
}
// Process SSO template for generating file mqwebuser.xml
adminUsers := strings.Split(os.Getenv("MQ_WEB_ADMIN_USERS"), "\n")
err = mqtemplate.ProcessTemplateFile(mqwebDir+"/mqwebuser.xml.tpl", mqwebDir+"/mqwebuser.xml", map[string][]string{"AdminUser": adminUsers}, log)
if err != nil {
return "", err
}
// Configure SSO TLS
return configureWebKeyStore(p12TrustStore)
}
func configureWebServer(keyLabel string, p12Trust tls.KeyStoreData) (string, error) {
var keystore string
// Configure TLS for Web Console first if we have a certificate to use
err := configureWebTLS(keyLabel)
if err != nil {
return keystore, err
}
if keyLabel != "" {
keystore = keyLabel + ".p12"
}
// Configure Single-Sign-On for the web server (if enabled)
enableSSO := os.Getenv("MQ_BETA_ENABLE_SSO")
if enableSSO == "true" || enableSSO == "1" {
keystore, err = configureSSO(p12Trust)
if err != nil {
return keystore, err
}
} else if keyLabel == "" && os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME") != "" {
keystore, err = configureWebKeyStore(p12Trust)
}
_, err = os.Stat("/opt/mqm/bin/strmqweb")
if err != nil {
if os.IsNotExist(err) {
return keystore, nil
}
return keystore, err
}
const webConfigDir string = "/etc/mqm/web"
_, err = os.Stat(webConfigDir)
if err != nil {
if os.IsNotExist(err) {
return keystore, nil
}
return keystore, err
}
uid, gid, err := command.LookupMQM()
if err != nil {
return keystore, err
}
const prefix string = "/etc/mqm/web"
err = filepath.Walk(prefix, func(from string, info os.FileInfo, err error) error {
if err != nil {
return err
}
to := fmt.Sprintf("/var/mqm/web%v", from[len(prefix):])
exists := true
_, err = os.Stat(to)
if err != nil {
if os.IsNotExist(err) {
exists = false
} else {
return err
}
}
if info.IsDir() {
if !exists {
// #nosec G301 - write group permissions are required
err := os.MkdirAll(to, 0770)
if err != nil {
return err
}
}
} else {
if exists {
err := os.Remove(to)
if err != nil {
return err
}
}
err := copy.CopyFile(from, to)
if err != nil {
log.Error(err)
return err
}
}
err = os.Chown(to, uid, gid)
if err != nil {
return err
}
return nil
})
return keystore, err
}

40
docs/building.md Normal file
View File

@@ -0,0 +1,40 @@
# Building a container image
## Prerequisites
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
* [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.
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
This procedure works for building the MQ Continuous Delivery release, on `amd64`, `ppc64le` and `s390x` architectures.
1. Create a `downloads` directory in the root of this repository
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/) or [IBM Fix Central](https://www.ibm.com/support/fixcentral), and place the downloaded file (for example, `IBM_MQ_9.1.4_LINUX_X86-64.tar.gz`) in the `downloads` directory
3. Login to the Red Hat Registry: `docker login registry.redhat.io` using your Customer Portal credentials.
4. Run `make build-advancedserver`
> **Warning**: Note that MQ offers two different sets of packaging on Linux: one is called "MQ for Linux" and contains RPM files for installing on Red Hat Enterprise Linux and SUSE Linux Enterprise Server; the other is for Ubuntu. The MQ container build uses a Red Hat Universal Base Image, so you need the "MQ for Linux" RPM files.
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
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
```
## 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.
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).
## Installed components
This image includes the core MQ server, Java, language packs, GSKit, and web server. This can be configured by setting the `MQ_PACKAGES` argument to `make`.

50
docs/developer-config.md Normal file
View File

@@ -0,0 +1,50 @@
# Default developer configuration
If you build this image with MQ Advanced for Developers, then an optional set of configuration can be applied automatically. This configures your Queue Manager with a set of default objects that you can use to quickly get started developing with IBM MQ. If you do not want the default objects to be created you can set the `MQ_DEV` environment variable to `false`.
## Environment variables
The MQ Developer Defaults supports some customization options, these are all controlled using environment variables:
* **MQ_DEV** - Set this to `false` to stop the default objects being created.
* **MQ_ADMIN_PASSWORD** - Changes the password of the `admin` user. Must be at least 8 characters long.
* **MQ_APP_PASSWORD** - Changes the password of the app user. If set, this will cause the `DEV.APP.SVRCONN` channel to become secured and only allow connections that supply a valid userid and password. Must be at least 8 characters long.
* **MQ_TLS_KEYSTORE** - **DEPRECATED**. See section `Supplying TLS certificates` in [usage document](usage.md). Allows you to supply the location of a PKCS#12 keystore containing a single certificate which you want to use in both the web console and the queue manager. Requires `MQ_TLS_PASSPHRASE`. When enabled the channels created will be secured using the `TLS_RSA_WITH_AES_128_CBC_SHA256` CipherSpec. *Note*: you will need to make the keystore available inside your container, this can be done by mounting a volume to your container.
* **MQ_TLS_PASSPHRASE** - **DEPRECATED**. See section `Supplying TLS certificates` in [usage document](usage.md). Passphrase for the keystore referenced in `MQ_TLS_KEYSTORE`.
## Details of the default configuration
The following users are created:
* User **admin** for administration (in the `mqm` group). Default password is **passw0rd**.
* User **app** for messaging (in a group called `mqclient`). No password by default.
Users in `mqclient` group have been given access connect to all queues and topics starting with `DEV.**` and have `put`, `get`, `pub`, `sub`, `browse` and `inq` permissions.
The following queues and topics are created:
* DEV.QUEUE.1
* DEV.QUEUE.2
* DEV.QUEUE.3
* DEV.DEAD.LETTER.QUEUE - configured as the Queue Manager's Dead Letter Queue.
* DEV.BASE.TOPIC - uses a topic string of `dev/`.
Two channels are created, one for administration, the other for normal messaging:
* DEV.ADMIN.SVRCONN - configured to only allow the `admin` user to connect into it. A user and password must be supplied.
* DEV.APP.SVRCONN - does not allow administrative users to connect. Password is optional unless you choose a password for app users.
## Web Console
By default the MQ Advanced for Developers image will start the IBM MQ Web Console that allows you to administer your Queue Manager running on your container. When the web console has been started, you can access it by opening a web browser and navigating to https://<Container IP>:9443/ibmmq/console. Where <Container IP> is replaced by the IP address of your running container.
When you navigate to this page you may be presented with a security exception warning. This happens because, by default, the web console creates a self-signed certificate to use for the HTTPS operations. This certificate is not trusted by your browser and has an incorrect distinguished name.
If you choose to accept the security warning, you will be presented with the login menu for the IBM MQ Web Console. The default login for the console is:
* **User:** admin
* **Password:** passw0rd
If you wish to change the password for the admin user, this can be done using the `MQ_ADMIN_PASSWORD` environment variable. If you supply a PKCS#12 keystore using the `MQ_TLS_KEYSTORE` environment variable, then the web console will be configured to use the certificate inside the keystore for HTTPS operations.
If you do not wish the web console to run, you can disable it by setting the environment variable `MQ_ENABLE_EMBEDDED_WEB_SERVER` to `false`.

View File

@@ -1,34 +0,0 @@
# Developing
## Prerequisites
You need to ensure you have the following tools installed:
* [Docker](https://www.docker.com/)
* [Go](https://golang.org/)
* [Glide](https://glide.sh/)
* [dep](https://github.com/golang/dep) (official Go dependency management tool)
* make
For running the Kubernetes tests, a Kubernetes environment is needed, for example [Minikube](https://github.com/kubernetes/minikube) or [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/).
## Running the tests
There are three main sets of tests:
1. Unit tests
2. Docker tests, which test a complete Docker image, using the Docker API
3. Kubernetes tests, which test the Helm charts (and the Docker image) via [Helm](https://helm.sh)
### Running the tests
The unit and Docker tests can be run locally. For example:
```bash
make test-devserver
```
### Running the Kubernetes tests
For the Kubernetes tests, you need to have built the Docker image, and pushed it to the registry used by your Kubernetes cluster. Most of the configuration used by the tests is picked up from your `kubectl` configuration, but you will typically need to specify the image details. For example:
```bash
DOCKER_REPO_DEVSERVER=mycluster.icp:8500/default/mq-devserver make test-kubernetes-devserver
```

51
docs/internals.md Normal file
View File

@@ -0,0 +1,51 @@
# Internals
This page documents internal code details and design decisions.
The resulting Docker image contains the following:
* Base linux distribution - this provides standard Linux libraries (such as "glibc") and utilities (such as "ls" and "grep") required by MQ
* MQ installation (under `/opt/mqm`)
* Three additional programs, to enable running in a containerized environment:
- `runmqserver` - The main process, which creates and runs a queue manager
- `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.
- `chkmqready` - Checks if the queue manager is ready for work. This can be used by (say) a Kubernetes readiness probe.
## runmqserver
The `runmqserver` command has the following responsibilities:
* Checks license acceptance
* Sets up `/var/mqm`
- MQ data directory needs to be set up at container creation time. This is done using the `crtmqdir` utility, which was introduced in MQ V9.0.3
- It assumes that a storage volume for data is mounted under `/mnt/mqm`. It creates a sub-directory for the MQ data, so `/var/mqm` is a symlink which resolves to `/mnt/mqm/data`. The reason for this is that it's not always possible to change the ownership of an NFS mount point directly (`/var/mqm` needs to be owned by "mqm"), but you can change the ownership of a sub-directory.
* Acts like a daemon
- Handles UNIX signals, like SIGTERM
- Works as PID 1, so is responsible for [reaping zombie processes](https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/)
* Creating and starting a queue manager
* Configuring the queue manager, by running any MQSC scripts found under `/etc/mqm`
* Starts the MQ web server (if enabled)
* Starting Prometheus metrics generation for the queue manager (if enabled)
* Indicates to the `chkmqready` command that configuration is complete, and that normal readiness checking can happen. This is done by writing a file into `/run/runmqserver`
In addition, for MQ Advanced for Developers only, the web server is started.
## runmqdevserver
The `runmqdevserver` command is added to the MQ Advanced for Developers image only. It does the following, before invoking `runmqserver`:
1. Sets passwords based on supplied environment variables
2. Generates MQSC files to put in `/etc/mqm`, based on a template, which is updated with values based on supplied environment variables.
3. If requested, it creates TLS key stores under `/run/runmqdevserver`, and configures MQ and the web server to use them
## Prometheus metrics
[Prometheus](https://prometheus.io) metrics are generated for the queue manager as follows:
1. A connection is established with the queue manager
2. Metrics are discovered by subscribing to topics that provide meta-data on metric classes, types and elements
3. Subscriptions are then created for each topic that provides this metric data
4. Metrics are initialised using Prometheus names mapped from their element descriptions
5. The metrics are then registered with the Prometheus registry as Prometheus Gauges
6. Publications are processed on a periodic basis to retrieve the metric data
7. An HTTP server is setup to listen for requests from Prometheus on `/metrics` port `9157`
8. Prometheus requests are handled by updating the Prometheus Gauges with the latest metric data
9. These updated Prometheus Gauges are then collected by the Prometheus registry

39
docs/security.md Normal file
View File

@@ -0,0 +1,39 @@
# Security
## Container runtime
### User
The MQ server image is run using the "mqm" user, with a fixed UID and GID of 888.
### Capabilities
The MQ Advanced image requires no Linux capabilities, so you can drop any capabilities which are added by default. For example, in Docker you could do the following:
```sh
docker run \
--cap-drop=ALL \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--detach \
mqadvanced-server:9.1.4.0-amd64
```
The MQ Advanced for Developers image does require the "chown", "setuid", "setgid" and "audit_write" capabilities (plus "dac_override" if you're using an image based on Red Hat Enterprise Linux). This is because it uses the "sudo" command to change passwords inside the container. For example, in Docker, you could do the following:
```sh
docker run \
--cap-drop=ALL \
--cap-add=CHOWN \
--cap-add=SETUID \
--cap-add=SETGID \
--cap-add=AUDIT_WRITE \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--detach \
mqadvanced-server-dev:9.1.4.0-amd64
```
### SELinux
The SELinux label "spc_t" (super-privileged container) is needed to run the MQ container on a host with SELinux enabled. This is due to a current limitation in how MQ data is stored on volumes, which violates the usual policy applied when using the standard "container_t" label.

59
docs/testing.md Normal file
View File

@@ -0,0 +1,59 @@
# Testing
## Prerequisites
You need to ensure you have the following tools installed:
* [Docker](https://www.docker.com/)
* [GNU make](https://www.gnu.org/software/make/)
* [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
There are two main sets of tests:
1. Unit tests, which are run during a build
2. Docker tests, which test a complete Docker image, using the Docker API
### Running the Docker tests
The Docker tests can be run locally on a machine with Docker. For example:
```
make test-devserver
make test-advancedserver
```
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
```
MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server:9.1.4.0-amd64 make test-advancedserver
```
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command::
```
TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver
```
You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `mqadvanced-server:9.1.4.0-amd64`:
```
MQ_VERSION=9.1.4.0 make test-advancedserver
```
### Running the Docker tests with code coverage
You can produce code coverage results from the Docker tests by running the following:
```
make build-advancedserver-cover
make test-advancedserver-cover
```
In order to generate code coverage metrics from the Docker tests, the build step creates a new Docker image with an instrumented version of the code. Each test is then run individually, producing a coverage report each under `test/docker/coverage/`. These individual reports are then combined. The combined report is written to the `coverage` directory.
### Running the Kubernetes tests
For the Kubernetes tests, you need to have built the Docker image, and pushed it to the registry used by your Kubernetes cluster. Most of the configuration used by the tests is picked up from your `kubectl` configuration, but you will typically need to specify the image details. For example:
```bash
MQ_IMAGE=mycluster.icp:8500/default/mq-devserver make test-kubernetes-devserver
```

17
docs/troubleshooting.md Normal file
View File

@@ -0,0 +1,17 @@
# Troubleshooting
## AMQ7017: Log not available
If you see this message in the container logs, it means that the directory being used for the container's volume doesn't use a filesystem supported by IBM MQ. To solve this, you need to make sure the container's `/mnt/mqm` volume is put on a supported filesystem. The best way to do this is to use [Docker volumes](https://docs.docker.com/storage/volumes/), instead of bind-mounted directories.
## Container command not found or does not exist
This message also appears as "System error: no such file or directory" in some versions of Docker. This can happen using a Docker client on Windows, and is related to line-ending characters. When you clone the Git repository on Windows, Git is often configured to convert any UNIX-style LF line-endings to Windows-style CRLF line-endings. Files with these line-endings end up in the built Docker image, and cause the container to fail at start-up. One solution to this problem is to stop Git from converting the line-ending characters, with the following command:
```
git config --global core.autocrlf input
```
## Old Linux kernel versions
MQ works best if you have a Linux kernel version of V3.16 or higher (run `uname -r` to check).
If you have an older version, you might need to add the [`--ipc host`](https://docs.docker.com/engine/reference/run/#ipc-settings-ipc) option when you run an MQ container. The reason for this is that IBM MQ uses shared memory, and on Linux kernels prior to V3.16, containers are usually limited to 32 MB of shared memory. In a [change](https://git.kernel.org/cgit/linux/kernel/git/mhocko/mm.git/commit/include/uapi/linux/shm.h?id=060028bac94bf60a65415d1d55a359c3a17d5c31
) to Linux kernel V3.16, the hard-coded limit is greatly increased. This kernel version is available in Ubuntu 14.04.2 onwards, Fedora V20 onwards, and boot2docker V1.2 onwards. Some Linux distributions, like Red Hat Enterprise Linux, patch older kernel versions, so you might find that the patch has been applied already, even if you see a lower kernel version number. If you are using a host with an older kernel version, then you can still run MQ, but you have to give it access to the host's IPC namespace using the [`--ipc host`](https://docs.docker.com/engine/reference/run/#ipc-settings-ipc) option on `docker run`. Note that this reduces the security isolation of your container.

119
docs/usage.md Normal file
View File

@@ -0,0 +1,119 @@
# Usage
In order to use the image, it is necessary to accept the terms of the IBM MQ license. This is achieved by specifying the environment variable `LICENSE` equal to `accept` when running the image. You can also view the license terms by setting this variable to `view`. Failure to set the variable will result in the termination of the container with a usage statement. You can view the license in a different language by also setting the `LANG` environment variable.
> **Note**: You can use `podman` instead of `docker` in any of the examples on this page.
## Running with the default configuration
You can run a queue manager with the default configuration and a listener on port 1414 using the following command. For example, the following command creates and starts a queue manager called `QM1`, and maps port 1414 on the host to the MQ listener on port 1414 inside the container, as well as port 9443 on the host to the web console on port 9443 inside the container:
```sh
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--publish 1414:1414 \
--publish 9443:9443 \
--detach \
ibmcom/mq
```
## Running with the default configuration and a volume
The above example will not persist any configuration data or messages across container runs. In order to do this, you need to use a [volume](https://docs.docker.com/storage/volumes/). For example, you can create a volume with the following command:
```sh
docker volume create qm1data
```
You can then run a queue manager using this volume as follows:
```sh
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--publish 1414:1414 \
--publish 9443:9443 \
--detach \
--volume qm1data:/mnt/mqm \
ibmcom/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.
## Running with the default configuration and Prometheus metrics enabled
You can run a queue manager with [Prometheus](https://prometheus.io) metrics enabled. The following command will generate Prometheus metrics for your queue manager on `/metrics` port `9157`:
```sh
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--env MQ_ENABLE_METRICS=true \
--publish 1414:1414 \
--publish 9443:9443 \
--publish 9157:9157 \
--detach \
ibmcom/mq
```
## Customizing the queue manager configuration
You can customize the configuration in several ways:
1. For getting started, you can use the [default developer configuration](developer-config.md), which is available out-of-the-box for the MQ Advanced for Developers image
2. By creating your own image and adding your own MQSC file into the `/etc/mqm` directory on the image. This file will be run when your queue manager is created.
3. By using [remote MQ administration](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.1.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file, and an administrative user `alice`. Note that it is not normally recommended to include passwords in this way:
```dockerfile
FROM ibmcom/mq
USER root
RUN useradd alice -G mqm && \
echo alice:passw0rd | chpasswd
USER mqm
COPY 20-config.mqsc /etc/mqm/
```
The `USER` instructions are necessary to ensure that the `useradd` and `chpasswd` commands are run as the root user.
Here is an example corresponding `20-config.mqsc` script, which creates two local queues:
```mqsc
DEFINE QLOCAL(MY.QUEUE.1) REPLACE
DEFINE QLOCAL(MY.QUEUE.2) REPLACE
```
The file `20-config.mqsc` should be saved into the same directory as the `Dockerfile`.
## Running MQ commands
It is recommended that you configure MQ in your own custom image. However, you may need to run MQ commands directly inside the process space of the container. To run a command against a running queue manager, you can use `docker exec`, for example:
```sh
docker exec \
--tty \
--interactive \
${CONTAINER_ID} \
dspmq
```
Using this technique, you can have full control over all aspects of the MQ installation. Note that if you use this technique to make changes to the filesystem, then those changes would be lost if you re-created your container unless you make those changes in volumes.
## Supplying TLS certificates
If you wish to supply TLS Certificates that the queue manager and MQ Console should use for TLS operations then you must supply a PKCS#1 or unencrypted PKCS#8 PEM files for both the certificates and private keys in the following directories:
* `/etc/mqm/pki/keys/<Label>` - for certificates with public and private keys
* `/etc/mqm/pki/trust/<index>` - for certificates with only the public key
For example, if you have an identity certificate you wish to add with the label `mykey` and 2 certificates you wish to add as trusted then you would need to add the files into the following locations where files ending in `.key` contain private keys and `.crt` contain certificates:
- `/etc/mqm/pki/keys/mykey/tls.key`
- `/etc/mqm/pki/keys/mykey/tls.crt`
- `/etc/mqm/pki/keys/mykey/ca.crt`
- `/etc/mqm/pki/trust/0/tls.crt`
- `/etc/mqm/pki/trust/1/tls.crt`
This can be achieved by either mounting the directories or files into the container when you run it or by baking the files into the correct location in the image.
If you supply multiple identity certificates then the first label alphabetically will be chosen as the certificate to be used by the MQ Console and the default certificate for the queue manager. If you wish to use a different certificate on the queue manager then you can change the certificate to use at runtime by executing the MQSC command `ALTER QMGR CERTLABL('<newlabel>')`

View File

@@ -1,4 +1,5 @@
* © Copyright IBM Corporation 2017 * © Copyright IBM Corporation 2019
*
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -12,4 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
REFRESH SECURITY TYPE(CONNAUTH) * Set the keystore location for the queue manager
ALTER QMGR SSLKEYR('{{ .SSLKeyR }}')
ALTER QMGR CERTLABL('{{ .CertificateLabel }}')
REFRESH SECURITY(*) TYPE(SSL)

19
glide.lock generated
View File

@@ -1,19 +0,0 @@
hash: 170f17bb34eaa2c23733b3919e76a268654e50a21e70b45e1b7b2dd2161efc67
updated: 2017-09-25T16:58:43.624633314+01:00
imports:
- name: github.com/hpcloud/tail
version: a30252cb686a21eb2d0b98132633053ec2f7f1e5
subpackages:
- ratelimiter
- util
- watch
- winfile
- name: golang.org/x/sys
version: 7a4fde3fda8ef580a89dbae8138c26041be14299
subpackages:
- unix
- name: gopkg.in/fsnotify.v1
version: 7be54206639f256967dd82fa767397ba5f8f48f5
- name: gopkg.in/tomb.v1
version: c131134a1947e9afd9cecfe11f4c6dff0732ae58
testImports: []

View File

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

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2017 # © Copyright IBM Corporation 2015, 2019
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -12,27 +12,33 @@
# 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.
FROM ubuntu:16.04 FROM registry.redhat.io/ubi8/ubi-minimal AS mq-explorer
# The URL to download the MQ installer from in tar.gz format # The URL to download the MQ installer from in tar.gz format
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev912_linux_x86-64.tar.gz"
# The MQ packages to install # The MQ packages to install
ARG MQ_PACKAGES="ibmmq-explorer" ENV MQ_PACKAGES="MQSeriesRuntime*.rpm MQSeriesJRE*.rpm MQSeriesExplorer*.rpm"
RUN export DEBIAN_FRONTEND=noninteractive \ ARG MQM_UID=888
&& apt-get update \
&& apt-get install -y \ RUN microdnf install -y gtk2 libXtst \
libgtk2.0-0 \ && microdnf clean all
libxtst6
ADD install-mq.sh /usr/local/bin/ ADD install-mq.sh /usr/local/bin/
# Install MQ Explorer. To avoid a "text file busy" error here, we sleep before installing.
# Need to re-instate the `/var/mqm` directory after installation, to avoid MQ
# errors with some commands (e.g. `dspmqver`)
RUN chmod u+x /usr/local/bin/install-mq.sh \ RUN chmod u+x /usr/local/bin/install-mq.sh \
&& install-mq.sh && sleep 1 \
&& install-mq.sh $MQM_UID \
&& rm -rf /var/mqm \
&& /opt/mqm/bin/crtmqdir -f -s
ENV LANG=en_US.UTF-8 ENV LANG=en_US.UTF-8
# Run as mqm (999) # Run as mqm
USER 999 USER $MQM_UID
ENTRYPOINT ["MQExplorer"] ENTRYPOINT ["MQExplorer"]

View File

@@ -1,14 +1,19 @@
Docker for Mac Docker for Mac
-------------- --------------
Steps to build a Docker image containing IBM MQ Explorer:
1. Download and extract the code from [GitHub](https://codeload.github.com/ibm-messaging/mq-container/zip/master), or run the following command: `git clone https://github.com/ibm-messaging/mq-container`
2. Open a Terminal window in the `mq-container` directory
3. Run `docker build -t mq-explorer -f ./incubating/mq-explorer/Dockerfile .`
1. Install XQuartz. Version 2.7.10 works, but V2.7.11 doesn't seem to. Steps to prepare your Mac with XQuartz:
1. Install XQuartz. Version 2.7.10 works, but V2.7.11 doesn't seem to (see [this thread](https://stackoverflow.com/questions/38686932/how-to-forward-docker-for-mac-to-x11))
2. Run XQuartz 2. Run XQuartz
3. Open the XQuartz "Preferences" menu, go to the "Security" tab and enable "Allow connections from network clients" 3. Open the XQuartz "Preferences" menu, go to the "Security" tab and enable "Allow connections from network clients"
4. Add your IP address to the list of allowed hosts: `xhost + $(ipconfig getifaddr en0)`
5. Run MQ Explorer: `docker run -e DISPLAY=$(ipconfig getifaddr en0):0 -v /tmp/.X11-unix:/tmp/.X11-unix -u 0 -ti mq-explorer`
https://stackoverflow.com/questions/38686932/how-to-forward-docker-for-mac-to-x11 Steps to run IBM MQ Explorer:
1. Add your IP address to the list of allowed hosts: `xhost + $(ipconfig getifaddr en0)`
2. Run MQ Explorer: `docker run -e DISPLAY=$(ipconfig getifaddr en0):0 -v /tmp/.X11-unix:/tmp/.X11-unix -u 0 -ti mq-explorer`
docker run -e DISPLAY=docker.for.mac.localhost:0 -v /tmp/.X11-unix:/tmp/.X11-unix -u 0 -ti mq-explorer
Use DISPLAY=docker.for.mac.localhost:0 ???

View File

@@ -0,0 +1,38 @@
# © Copyright IBM Corporation 2018, 2019
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
FROM registry.redhat.io/rhel8/llvm-toolset:8.0.1-10 AS mq-sdk
#FROM docker.io/centos/devtoolset-7-toolchain-centos7 AS mq-sdk
# The URL to download the MQ installer from in tar.gz format
# This assumes an archive containing the MQ Debian (.deb) install packages
ARG MQ_URL
# The packages to install in install-mq.sh
ENV MQ_PACKAGES="MQSeriesRuntime-*.rpm MQSeriesSDK-*.rpm MQSeriesSamples*.rpm"
ENV MQM_UID=888
USER 0
COPY install-mq.sh /usr/local/bin/
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
# Need to re-instate the `/var/mqm` directory after installation, to avoid MQ
# errors with some commands (e.g. `dspmqver`)
RUN chmod u+x /usr/local/bin/install-mq.sh \
&& sleep 1 \
&& install-mq.sh $MQM_UID \
&& rm -rf /var/mqm \
&& /opt/mqm/bin/crtmqdir -f -s
USER 1001

View File

@@ -0,0 +1,13 @@
# IBM MQ Software Developer Kit (SDK)
This image contains the MQ SDK and the `build-essential` package, which includes GNU C and C++ compilers plus other essential tools.
## Usage
For example, you could compile the `amqsput0.c` sample program by running the following command in an SDK container:
```sh
gcc -o /tmp/amqsput0 /opt/mqm/samp/amqsput0.c -I /opt/mqm/inc -L /opt/mqm/lib64 -lmqm
```
Compiler and linker output is placed on the container's filesystem, so using multi-stage Docker builds is useful to build a final container.

View File

@@ -0,0 +1,47 @@
* © Copyright IBM Corporation 2017, 2019
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Developer queues
DEFINE QLOCAL('DEV.QUEUE.1') REPLACE
DEFINE QLOCAL('DEV.QUEUE.2') REPLACE
DEFINE QLOCAL('DEV.QUEUE.3') REPLACE
DEFINE QLOCAL('DEV.DEAD.LETTER.QUEUE') REPLACE
* Use a different dead letter queue, for undeliverable messages
ALTER QMGR DEADQ('DEV.DEAD.LETTER.QUEUE')
* Developer topics
DEFINE TOPIC('DEV.BASE.TOPIC') TOPICSTR('dev/') REPLACE
* Developer connection authentication
DEFINE AUTHINFO('DEV.AUTHINFO') AUTHTYPE(IDPWOS) CHCKCLNT(REQDADM) CHCKLOCL(OPTIONAL) ADOPTCTX(YES) REPLACE
ALTER QMGR CONNAUTH('DEV.AUTHINFO')
REFRESH SECURITY(*) TYPE(CONNAUTH)
* Developer channels (Application + Admin)
* Developer channels (Application + Admin)
DEFINE CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) REPLACE
DEFINE CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) MCAUSER('app') REPLACE
* Developer channel authentication rules
SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('Back-stop rule - Blocks everyone') ACTION(REPLACE)
SET CHLAUTH('DEV.APP.SVRCONN') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT({{ .ChckClnt }}) DESCR('Allows connection via APP channel') ACTION(REPLACE)
SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allows admins on ADMIN channel') ACTION(REPLACE)
SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(USERMAP) CLNTUSER('admin') USERSRC(CHANNEL) DESCR('Allows admin user to connect via ADMIN channel') ACTION(REPLACE)
* Developer authority records
SET AUTHREC GROUP('mqclient') OBJTYPE(QMGR) AUTHADD(CONNECT,INQ)
SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(QUEUE) AUTHADD(BROWSE,GET,INQ,PUT)
SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(TOPIC) AUTHADD(PUB,SUB)

View File

@@ -1,4 +1,5 @@
* © Copyright IBM Corporation 2017 * © Copyright IBM Corporation 2018, 2019
*
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -12,8 +13,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.
DEFINE CHANNEL(PASSWORD.SVRCONN) CHLTYPE(SVRCONN) REPLACE * Set the cipherspec for dev channels
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allow privileged users on this channel') ALTER CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12) SSLCAUTH(OPTIONAL)
SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('BackStop rule') ALTER CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12) SSLCAUTH(OPTIONAL)
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT(REQUIRED)
ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) ADOPTCTX(YES)

View File

@@ -0,0 +1,78 @@
{
"version": 0.1,
"tabs": [
{
"title": "IBM MQ Container",
"numColumns": 2,
"model": {
"title": "",
"rows": [
{
"columns": [
{
"widgets": [
{
"type": "channel",
"config": {
"selectedQM": "{{ .QueueManagerName }}",
"showSysObjs": false,
"sizex": 1,
"sizey": 1,
"subType": "all"
},
"title": "Channels on {{ .QueueManagerName }}",
"titleTemplateUrl": "adf/templates/widget-title.html",
"gridsterrow": 0,
"gridstercol": 1
},
{
"type": "topic",
"config": {
"selectedQM": "{{ .QueueManagerName }}",
"showSysObjs": false,
"sizex": 1,
"sizey": 1
},
"title": "Topics on {{ .QueueManagerName }}",
"titleTemplateUrl": "adf/templates/widget-title.html",
"gridsterrow": 1,
"gridstercol": 1
},
{
"type": "queue",
"config": {
"selectedQM": "{{ .QueueManagerName }}",
"showSysObjs": false,
"sizex": 1,
"sizey": 1,
"subType": "all"
},
"title": "Queues on {{ .QueueManagerName }}",
"titleTemplateUrl": "adf/templates/widget-title.html",
"gridsterrow": 1,
"gridstercol": 0
},
{
"type": "queuemanager",
"gridstercol": 0,
"gridsterrow": 0,
"config": {
"type": "local",
"sizex": 1,
"sizey": 1,
"customTitle": "Queue Manager"
},
"title": "Queue Manager",
"titleTemplateUrl": "adf/templates/widget-title.html"
}
]
}
]
}
],
"titleTemplateUrl": "adf/templates/dashboard-title.html"
},
"isMobile": false
}
]
}

View File

@@ -0,0 +1,41 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2019
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Fail on any non-zero return code
set -ex
test -f /usr/bin/yum && YUM=true || YUM=false
test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
if ($UBUNTU); then
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends sudo
rm -rf /var/lib/apt/lists/*
fi
if ($YUM); then
yum -y install sudo
yum -y clean all
rm -rf /var/cache/yum/*
fi
if ($MICRODNF); then
microdnf install sudo
microdnf clean all
fi

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<server>
<featureManager>
<feature>appSecurity-2.0</feature>
<feature>basicAuthenticationMQ-1.0</feature>
</featureManager>
<enterpriseApplication id="com.ibm.mq.console">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebUI" realm="defaultRealm"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<enterpriseApplication id="com.ibm.mq.rest">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebUI" realm="defaultRealm"/>
</security-role>
<security-role name="MQWebUser">
<group name="MQWebMessaging" realm="defaultRealm"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<basicRegistry id="basic" realm="defaultRealm">
<user name="admin" password="${env.MQ_ADMIN_PASSWORD}"/>
<!-- The app user will always get a default password of "passw0rd",
even if you don't set the environment variable.
See `webserver.go` -->
<user name="app" password="${env.MQ_APP_PASSWORD}"/>
<group name="MQWebUI">
<member name="admin"/>
</group>
<group name="MQWebMessaging">
<member name="app"/>
</group>
</basicRegistry>
<variable name="httpHost" value="*"/>
<variable name="managementMode" value="externallyprovisioned"/>
<include location="tls.xml"/>
</server>

View File

@@ -1,4 +1,4 @@
# © Copyright IBM Corporation 2015, 2017 # © Copyright IBM Corporation 2018
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -12,7 +12,21 @@
# 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.
FROM mqadvanced FROM ibmcom/ibmjava:jre
RUN useradd alice -G mqm && \
echo alice:passw0rd | chpasswd ARG IPTFILE=ms81_2.1.0.4_amd64_linux_2.tar
COPY *.mqsc /etc/mqm/
COPY $IPTFILE /opt/
RUN rm -rf /var/lib/apt/lists/* \
&& cd /opt/ \
&& tar xvf ./$IPTFILE \
&& chmod -R a-w /opt/mqipt
ENV MQIPT_PATH=/opt/mqipt
COPY startMQIPT.sh /usr/local/bin
VOLUME /var/mqipt
ENTRYPOINT ["startMQIPT.sh"]

View File

@@ -0,0 +1,44 @@
# IBM MQ Internet Pass-Thru (SupportPac MS81) on Docker
IBM® MQ Internet Pass-Thru (MQIPT) is an extension to the base IBM MQ product. MQIPT runs as a stand-alone service that can receive and forward IBM MQ message flows, either between two IBM MQ queue managers or between an IBM MQ client and an IBM MQ queue manager.
MQIPT enables this connection when the client and server are not on the same physical network.
This repository contains all of the resources you will need to create a Docker image containing MQIPT for use in your infrastructure.
## How to build this image
1. First download MQIPT from the [IBM MQ SupportPacs website](http://www-01.ibm.com/support/docview.wss?rs=171&uid=swg27007198#3). MQIPT is a `Category 3 - Product Extensions SupportPacs` with the identifier `MS81`.
2. Ensure the MQIPT downloaded tar file is available in this directory.
3. If the tar file is not called `ms81_2.1.0.4_amd64_linux_2.tar` you will need to either:
* Rename the file.
* Supply the new name as a `--build-arg IPTFILE=<new name>` when executing the docker build command in the next step.
* Alter the Dockerfile `IPTFILE` ARG to specify the new file name.
4. Run the following command in this directory to build the Docker image. `docker build -t mqipt .`
Once the Docker build has completed you will have a new Docker image called `mqipt:latest` available which contains MQIPT.
## How to run this image
Before you run the MQIPT docker image you should understand how MQIPT operates, please ensure you have read the [MQIPT knowledgecenter](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.ipt.doc/ipt0000_.htm) and any documentation supplied with the MQIPT installation tar.
First you need to create your [MQIPT configuration file](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.ipt.doc/ipt2540_.htm) and place this file in a directory that can be [mounted to a docker container](https://docs.docker.com/storage/). This file **must** be called `mqipt.conf`; there is a sample file available in the MQIPT installation tar.
Run the following command to start a container with your built MQIPT image:
`docker run -d --volume <path to config>:/var/mqipt -p 1414:1414 mqipt`
If you want the container ports to be accessible outside of the host you must expose the required ports, this will map the container port to a port on the host, meaning you can connect to that port on the host and access MQIPT. You will need to provide multiple `-p` parameters to expose all of the ports required by your MQIPT configuration. **Note:** these must be available otherwise the docker container will fail to start.
See [Docker Run reference](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) for more information on how to expose container ports.
## Further information
For further information on MQIPT please view the [MQIPT knowledgecenter](https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.ipt.doc/ipt0000_.htm)
## License
The Dockerfiles and associated code and scripts are provided as-is and licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
## Copyright
© Copyright IBM Corporation 2018

View File

@@ -1,4 +1,6 @@
# © Copyright IBM Corporation 2017 #!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2018
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -12,9 +14,15 @@
# 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.
apiVersion: v1 stop()
description: IBM MQ queue manager {
name: ibm-mqadvanced-server-dev /opt/mqipt/bin/mqiptAdmin -stop
version: 1.0.2 }
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png
tillerVersion: ">=2.4.0" trap stop SIGTERM SIGINT
# Run MQIPT and then wait on the process to end.
/opt/mqipt/bin/mqipt /var/mqipt &
MQIPTPROCESS=$!
wait "$MQIPTPROCESS"

25
test/kubernetes/Gopkg.toml → install-build-deps.sh Normal file → Executable file
View File

@@ -1,4 +1,7 @@
# © Copyright IBM Corporation 2017 #!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2019
#
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -12,18 +15,12 @@
# 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]] # Install Docker and dep, required by build (assumes Ubuntu host, as used by Travis build)
branch = "master"
name = "golang.org/x/sys"
# The version of client-go corresponds to a specific Kubernetes version set -ex
# (e.g. client-go 4.0.0 is for kubernetes 1.7)
# If you change this version, you also need to update the corresponding
# branch for k8s.io/apimachinery (below)
[[constraint]]
name = "k8s.io/client-go"
version = "4.0.0"
[[constraint]] sudo curl -Lo /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.5.1/dep-linux-$ARCH
name = "k8s.io/apimachinery" sudo chmod +x /usr/local/bin/dep
branch = "release-1.7"
go get -u golang.org/x/lint/golint
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."

View File

@@ -0,0 +1,81 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2019
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Fail on any non-zero return code
set -ex
test -f /usr/bin/yum && YUM=true || YUM=false
test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false
test -f /usr/bin/rpm && RPM=true || RPM=false
test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
if ($UBUNTU); then
export DEBIAN_FRONTEND=noninteractive
# Use a reduced set of apt repositories.
# This ensures no unsupported code gets installed, and makes the build faster
source /etc/os-release
# Figure out the correct apt URL based on the CPU architecture
CPU_ARCH=$(uname -p)
if [ ${CPU_ARCH} == "x86_64" ]; then
APT_URL="http://archive.ubuntu.com/ubuntu/"
else
APT_URL="http://ports.ubuntu.com/ubuntu-ports/"
fi
# Use a reduced set of apt repositories.
# This ensures no unsupported code gets installed, and makes the build faster
echo "deb ${APT_URL} ${UBUNTU_CODENAME} main restricted" > /etc/apt/sources.list
echo "deb ${APT_URL} ${UBUNTU_CODENAME}-updates main restricted" >> /etc/apt/sources.list
echo "deb ${APT_URL} ${UBUNTU_CODENAME}-security main restricted" >> /etc/apt/sources.list
# Install additional packages required by MQ, this install process and the runtime scripts
apt-get update
apt-get install -y --no-install-recommends \
bash \
bc \
ca-certificates \
coreutils \
curl \
debianutils \
file \
findutils \
gawk \
grep \
libc-bin \
mount \
passwd \
procps \
sed \
tar \
util-linux
fi
if ($RPM); then
EXTRA_RPMS="bash bc ca-certificates file findutils gawk glibc-common grep passwd procps-ng sed shadow-utils tar util-linux which"
# Install additional packages required by MQ, this install process and the runtime scripts
$YUM && yum -y install --setopt install_weak_deps=false ${EXTRA_RPMS}
$MICRODNF && microdnf install ${EXTRA_RPMS}
fi
# Apply any bug fixes not included in base Ubuntu or MQ image.
# Don't upgrade everything based on Docker best practices https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#run
$UBUNTU && apt-get install -y libapparmor1 libsystemd0 systemd systemd-sysv libudev1 perl-base --only-upgrade
# End of bug fixes
# Clean up cached files
$UBUNTU && rm -rf /var/lib/apt/lists/*
$YUM && yum -y clean all
$YUM && rm -rf /var/cache/yum/*
$MICRODNF && microdnf clean all

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# -*- mode: sh -*- # -*- mode: sh -*-
# © Copyright IBM Corporation 2015, 2017 # © Copyright IBM Corporation 2015, 2019
# #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,64 +18,43 @@
# Fail on any non-zero return code # Fail on any non-zero return code
set -ex set -ex
export DEBIAN_FRONTEND=noninteractive mqm_uid=${1:-888}
# Install additional packages required by MQ, this install process and the runtime scripts test -f /usr/bin/yum && YUM=true || YUM=false
apt-get update test -f /usr/bin/microdnf && MICRODNF=true || MICRODNF=false
apt-get install -y --no-install-recommends \ test -f /usr/bin/rpm && RPM=true || RPM=false
bash \ test -f /usr/bin/apt-get && UBUNTU=true || UBUNTU=false
bc \
ca-certificates \
coreutils \
curl \
debianutils \
file \
findutils \
gawk \
grep \
libc-bin \
mount \
passwd \
procps \
sed \
tar \
util-linux
# Download and extract the MQ installation files # Download and extract the MQ installation files
DIR_EXTRACT=/tmp/mq DIR_EXTRACT=/tmp/mq
mkdir -p ${DIR_EXTRACT} mkdir -p ${DIR_EXTRACT}
cd ${DIR_EXTRACT} cd ${DIR_EXTRACT}
curl -LO $MQ_URL curl -LO $MQ_URL
tar -zxvf ./*.tar.gz tar -zxf ./*.tar.gz
# Remove packages only needed by this script
apt-get purge -y \
ca-certificates \
curl
# Remove any orphaned packages
apt-get autoremove -y
# Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images # Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images
groupadd --system --gid 999 mqm groupadd --system --gid ${mqm_uid} mqm
useradd --system --uid 999 --gid mqm mqm useradd --system --uid ${mqm_uid} --gid mqm --groups 0 mqm
usermod -G mqm root
# Find directory containing .deb files # Find directory containing .deb files
DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1) $UBUNTU && DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1)
$RPM && DIR_RPM=$(find ${DIR_EXTRACT} -name "*.rpm" -printf "%h\n" | sort -u | head -1)
# Find location of mqlicense.sh # Find location of mqlicense.sh
MQLICENSE=$(find ${DIR_EXTRACT} -name "mqlicense.sh") MQLICENSE=$(find ${DIR_EXTRACT} -name "mqlicense.sh")
# Accept the MQ license # Accept the MQ license
${MQLICENSE} -text_only -accept ${MQLICENSE} -text_only -accept
echo "deb [trusted=yes] file:${DIR_DEB} ./" > /etc/apt/sources.list.d/IBM_MQ.list $UBUNTU && echo "deb [trusted=yes] file:${DIR_DEB} ./" > /etc/apt/sources.list.d/IBM_MQ.list
# Install MQ using the DEB packages # Install MQ using the DEB packages
apt-get update $UBUNTU && apt-get update
apt-get install -y $MQ_PACKAGES $UBUNTU && apt-get install -y $MQ_PACKAGES
$RPM && cd $DIR_RPM && rpm -ivh $MQ_PACKAGES
# Remove 32-bit libraries from 64-bit container # Remove 32-bit libraries from 64-bit container
find /opt/mqm /var/mqm -type f -exec file {} \; | awk -F: '/ELF 32-bit/{print $1}' | xargs --no-run-if-empty rm -f # The "file" utility isn't installed by default in UBI, so only try this if it's installed
which file && find /opt/mqm /var/mqm -type f -exec file {} \; | awk -F: '/ELF 32-bit/{print $1}' | xargs --no-run-if-empty rm -f
# Remove tar.gz files unpacked by RPM postinst scripts # Remove tar.gz files unpacked by RPM postinst scripts
find /opt/mqm -name '*.tar.gz' -delete find /opt/mqm -name '*.tar.gz' -delete
@@ -84,35 +63,51 @@ find /opt/mqm -name '*.tar.gz' -delete
/opt/mqm/bin/setmqinst -p /opt/mqm -i /opt/mqm/bin/setmqinst -p /opt/mqm -i
# Clean up all the downloaded files # Clean up all the downloaded files
rm -f /etc/apt/sources.list.d/IBM_MQ.list $UBUNTU && rm -f /etc/apt/sources.list.d/IBM_MQ.list
rm -rf ${DIR_EXTRACT} rm -rf ${DIR_EXTRACT}
# Apply any bug fixes not included in base Ubuntu or MQ image.
# Don't upgrade everything based on Docker best practices https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#run
apt-get upgrade -y libkrb5-26-heimdal
apt-get upgrade -y libexpat1
# End of bug fixes
# Clean up cached apt files
rm -rf /var/lib/apt/lists/*
# Optional: Update the command prompt with the MQ version # Optional: Update the command prompt with the MQ version
echo "mq:$(dspmqver -b -f 2)" > /etc/debian_chroot $UBUNTU && echo "mq:$(dspmqver -b -f 2)" > /etc/debian_chroot
# Remove the directory structure under /var/mqm which was created by the installer # Remove the directory structure under /var/mqm which was created by the installer
rm -rf /var/mqm rm -rf /var/mqm
# Create the mount point for volumes # Create the mount point for volumes, ensuring MQ has permissions to all directories
mkdir -p /mnt/mqm install --directory --mode 0775 --owner mqm --group root /mnt
install --directory --mode 0775 --owner mqm --group root /mnt/mqm
install --directory --mode 0775 --owner mqm --group root /mnt/mqm/data
install --directory --mode 0775 --owner mqm --group root /mnt/mqm-log
install --directory --mode 0775 --owner mqm --group root /mnt/mqm-log/log
install --directory --mode 0775 --owner mqm --group root /mnt/mqm-data
install --directory --mode 0775 --owner mqm --group root /mnt/mqm-data/qmgrs
# Create the directory for MQ configuration files # Create the directory for MQ configuration files
mkdir -p /etc/mqm install --directory --mode 0775 --owner mqm --group root /etc/mqm
# Create the directory for MQ runtime files
install --directory --mode 0775 --owner mqm --group root /run/mqm
# Create a symlink for /var/mqm -> /mnt/mqm/data # Create a symlink for /var/mqm -> /mnt/mqm/data
ln -s /mnt/mqm/data /var/mqm ln -s /mnt/mqm/data /var/mqm
# Optional: Set these values for the Bluemix Vulnerability Report # Optional: Ensure any passwords expire in a timely manner
sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' /etc/login.defs sed -i 's/PASS_MAX_DAYS\t99999/PASS_MAX_DAYS\t90/' /etc/login.defs
sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' /etc/login.defs sed -i 's/PASS_MIN_DAYS\t0/PASS_MIN_DAYS\t1/' /etc/login.defs
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/' /etc/pam.d/common-password sed -i 's/PASS_MIN_LEN\t5/PASS_MIN_LEN\t8/' /etc/login.defs
$RPM && sed -i 's/# minlen/minlen/' /etc/security/pwquality.conf
$UBUNTU && PAM_FILE=/etc/pam.d/common-password
$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
# List all the installed packages, for the build log
$RPM && rpm -q --all || true
$UBUNTU && dpkg --list || true
#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
# Copy MQ Licenses into the correct location
mkdir -p /licenses
cp /opt/mqm/licenses/*.txt /licenses/

View File

@@ -0,0 +1,72 @@
/*
© Copyright IBM Corporation 2017, 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package command contains code to run external commands
package command
import (
"fmt"
"os/exec"
"os/user"
"strconv"
"syscall"
)
// Run runs an OS command. On Linux it waits for the command to
// complete and returns the exit status (return code).
// Do not use this function to run shell built-ins (like "cd"), because
// the error handling works differently
func Run(name string, arg ...string) (string, int, error) {
// Run the command and wait for completion
// #nosec G204
cmd := exec.Command(name, arg...)
out, err := cmd.CombinedOutput()
rc := cmd.ProcessState.ExitCode()
if err != nil {
return string(out), rc, fmt.Errorf("%v: %v", cmd.Path, err)
}
return string(out), rc, nil
}
// RunAsMQM runs the specified command as the mqm user
func RunAsMQM(name string, arg ...string) (string, int, error) {
// #nosec G204
cmd := exec.Command(name, arg...)
cmd.SysProcAttr = &syscall.SysProcAttr{}
uid, gid, err := LookupMQM()
if err != nil {
return "", 0, err
}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
return Run(name, arg...)
}
// LookupMQM looks up the UID & GID of the mqm user
func LookupMQM() (int, int, error) {
mqm, err := user.Lookup("mqm")
if err != nil {
return -1, -1, err
}
mqmUID, err := strconv.Atoi(mqm.Uid)
if err != nil {
return -1, -1, err
}
mqmGID, err := strconv.Atoi(mqm.Gid)
if err != nil {
return -1, -1, err
}
return mqmUID, mqmGID, nil
}

View File

@@ -0,0 +1,47 @@
/*
© Copyright IBM Corporation 2017
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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 command
import (
"runtime"
"testing"
)
var commandTests = []struct {
name string
arg []string
rc int
}{
{"ls", []string{}, 0},
{"ls", []string{"madeup"}, 2},
{"bash", []string{"-c", "exit 99"}, 99},
}
func TestRun(t *testing.T) {
if runtime.GOOS != "linux" {
t.Skip("Skipping tests for package which only works on Linux")
}
for _, table := range commandTests {
arg := table.arg
_, rc, err := Run(table.name, arg...)
if rc != table.rc {
t.Errorf("Run(%v,%v) - expected %v, got %v", table.name, table.arg, table.rc, rc)
}
if rc != 0 && err == nil {
t.Errorf("Run(%v,%v) - expected error for non-zero return code (rc=%v)", table.name, table.arg, rc)
}
}
}

View File

@@ -0,0 +1,128 @@
/*
© Copyright IBM Corporation 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package containerruntime
import (
"fmt"
"io/ioutil"
"strings"
"github.com/genuinetools/amicontained/container"
)
func GetContainerRuntime() (string, error) {
return container.DetectRuntime()
}
func GetBaseImage() (string, error) {
buf, err := ioutil.ReadFile("/etc/os-release")
if err != nil {
return "", fmt.Errorf("Failed to read /etc/os-release: %v", err)
}
lines := strings.Split(string(buf), "\n")
for _, l := range lines {
if strings.HasPrefix(l, "PRETTY_NAME=") {
words := strings.Split(l, "\"")
if len(words) >= 2 {
return words[1], nil
}
}
}
return "unknown", nil
}
// GetCapabilities gets the Linux capabilities (e.g. setuid, setgid). See https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
func GetCapabilities() (map[string][]string, error) {
return container.Capabilities()
}
// GetSeccomp gets the seccomp enforcing mode, which affects which kernel calls can be made
func GetSeccomp() (string, error) {
s, err := container.SeccompEnforcingMode()
if err != nil {
return "", fmt.Errorf("Failed to get container SeccompEnforcingMode: %v", err)
}
return s, nil
}
// GetSecurityAttributes gets the security attributes of the current process.
// The security attributes indicate whether AppArmor or SELinux are being used,
// and what the level of confinement is.
func GetSecurityAttributes() string {
a, err := readProc("/proc/self/attr/current")
// On some systems, if AppArmor or SELinux are not installed, you get an
// error when you try and read `/proc/self/attr/current`, even though the
// file exists.
if err != nil || a == "" {
a = "none"
}
return a
}
func readProc(filename string) (value string, err error) {
// #nosec G304
buf, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return strings.TrimSpace(string(buf)), nil
}
func GetMounts() (map[string]string, error) {
all, err := readProc("/proc/mounts")
if err != nil {
return nil, fmt.Errorf("Couldn't read /proc/mounts")
}
result := make(map[string]string)
lines := strings.Split(all, "\n")
for i := range lines {
parts := strings.Split(lines[i], " ")
//dev := parts[0]
mountPoint := parts[1]
fsType := parts[2]
if strings.Contains(mountPoint, "/mnt/mqm") {
result[mountPoint] = fsType
}
}
return result, nil
}
func GetKernelVersion() (string, error) {
return readProc("/proc/sys/kernel/osrelease")
}
func GetMaxFileHandles() (string, error) {
return readProc("/proc/sys/fs/file-max")
}
// SupportedFilesystem returns true if the supplied filesystem type is supported for MQ data
func SupportedFilesystem(fsType string) bool {
switch fsType {
case "aufs", "overlayfs", "tmpfs":
return false
default:
return true
}
}
// ValidMultiInstanceFilesystem returns true if the supplied filesystem type is valid for a multi-instance queue manager
func ValidMultiInstanceFilesystem(fsType string) bool {
if !SupportedFilesystem(fsType) {
return false
}
// TODO : check for non-shared filesystems & shared filesystems which are known not to work
return true
}

View File

@@ -0,0 +1,115 @@
// +build linux
/*
© Copyright IBM Corporation 2017, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package containerruntime
import (
"golang.org/x/sys/unix"
)
// fsTypes contains file system identifier codes.
// This code will not compile on some operating systems - Linux only.
var fsTypes = map[int64]string{
0x61756673: "aufs",
0xef53: "ext",
0x6969: "nfs",
0x65735546: "fuse",
0x9123683e: "btrfs",
0x01021994: "tmpfs",
0x794c7630: "overlayfs",
0x58465342: "xfs",
// less popular codes
0xadf5: "adfs",
0xadff: "affs",
0x5346414F: "afs",
0x0187: "autofs",
0x73757245: "coda",
0x28cd3d45: "cramfs",
0x453dcd28: "cramfs",
0x64626720: "debugfs",
0x73636673: "securityfs",
0xf97cff8c: "selinux",
0x43415d53: "smack",
0x858458f6: "ramfs",
0x958458f6: "hugetlbfs",
0x73717368: "squashfs",
0xf15f: "ecryptfs",
0x414A53: "efs",
0xabba1974: "xenfs",
0x3434: "nilfs",
0xF2F52010: "f2fs",
0xf995e849: "hpfs",
0x9660: "isofs",
0x72b6: "jffs2",
0x6165676C: "pstorefs",
0xde5e81e4: "efivarfs",
0x00c0ffee: "hostfs",
0x137F: "minix_14", // minix v1 fs, 14 char names
0x138F: "minix_30", // minix v1 fs, 30 char names
0x2468: "minix2_14", // minix v2 fs, 14 char names
0x2478: "minix2_30", // minix v2 fs, 30 char names
0x4d5a: "minix3_60", // minix v3 fs, 60 char names
0x4d44: "msdos",
0x564c: "ncp",
0x7461636f: "ocfs2",
0x9fa1: "openprom",
0x002f: "qnx4",
0x68191122: "qnx6",
0x6B414653: "afs_fs",
0x52654973: "reiserfs",
0x517B: "smb",
0x27e0eb: "cgroup",
0x63677270: "cgroup2",
0x7655821: "rdtgroup",
0x57AC6E9D: "stack_end",
0x74726163: "tracefs",
0x01021997: "v9fs",
0x62646576: "bdevfs",
0x64646178: "daxfs",
0x42494e4d: "binfmtfs",
0x1cd1: "devpts",
0xBAD1DEA: "futexfs",
0x50495045: "pipefs",
0x9fa0: "proc",
0x534F434B: "sockfs",
0x62656572: "sysfs",
0x9fa2: "usbdevice",
0x11307854: "mtd_inode",
0x09041934: "anon_inode",
0x73727279: "btrfs",
0x6e736673: "nsfs",
0xcafe4a11: "bpf",
0x5a3c69f0: "aafs",
0x15013346: "udf",
0x13661366: "balloon_kvm",
0x58295829: "zsmalloc",
}
// GetFilesystem returns the filesystem type for the specified path
func GetFilesystem(path string) (string, error) {
statfs := &unix.Statfs_t{}
err := unix.Statfs(path, statfs)
if err != nil {
return "", err
}
// Use a type conversion to make type an int64. On s390x it's a uint32.
t, ok := fsTypes[int64(statfs.Type)]
if !ok {
return "unknown", nil
}
return t, nil
}

View File

@@ -0,0 +1,24 @@
// +build !linux
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package containerruntime
// Dummy version of this function, only for non-Linux systems.
// Having this allows unit tests to be run on other platforms (e.g. macOS)
func checkFS(path string) error {
return nil
}

58
internal/copy/copy.go Normal file
View File

@@ -0,0 +1,58 @@
/*
© Copyright IBM Corporation 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package copy
import (
"fmt"
"io"
"os"
"github.com/ibm-messaging/mq-container/internal/filecheck"
)
func CopyFileMode(src, dest string, perm os.FileMode) error {
err := filecheck.CheckFileSource(src)
if err != nil {
return fmt.Errorf("failed to open %s for copy: %v", src, err)
}
// #nosec G304 - filename variable 'src' is checked above to ensure it is valid
in, err := os.Open(src)
if err != nil {
return fmt.Errorf("failed to open %s for copy: %v", src, err)
}
defer in.Close()
out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, perm)
if err != nil {
return fmt.Errorf("failed to open %s for copy: %v", dest, err)
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
err = out.Close()
return err
}
// CopyFile copies the specified file
func CopyFile(src, dest string) error {
return CopyFileMode(src, dest, 0770)
}

View File

@@ -0,0 +1,37 @@
/*
© Copyright IBM Corporation 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package filecheck
import (
"fmt"
"path/filepath"
"strings"
)
// CheckFileSource checks the filename is valid
func CheckFileSource(fileName string) error {
absFile, _ := filepath.Abs(fileName)
prefixes := []string{"bin", "boot", "dev", "lib", "lib64", "proc", "sbin", "sys"}
for _, prefix := range prefixes {
if strings.HasPrefix(absFile, filepath.Join("/", prefix)) {
return fmt.Errorf("Filename resolves to invalid path '%v'", absFile)
}
}
return nil
}

View File

@@ -0,0 +1,40 @@
/*
© Copyright IBM Corporation 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package filecheck
import (
"testing"
)
func TestCheckFileSource(t *testing.T) {
invalidFilenames := []string{"/bin", "/boot", "/dev", "/lib", "/lib64", "/proc", "/sbin", "/sys", "/bin/myfile", "/boot/mydir/myfile", "/var/../dev", "/var/../lib/myfile"}
for _, invalidFilename := range invalidFilenames {
err := CheckFileSource(invalidFilename)
if err == nil {
t.Errorf("Expected to receive an error for filename '%v'", invalidFilename)
}
}
validFilenames := []string{"/var", "/mydir/dev", "/mydir/dev/myfile"}
for _, validFilename := range validFilenames {
err := CheckFileSource(validFilename)
if err != nil {
t.Errorf("Unexpected error received: %v", err)
}
}
}

View File

@@ -0,0 +1,244 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package keystore contains code to create and update keystores
package keystore
import (
"bufio"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
// KeyStore describes information about a keystore file
type KeyStore struct {
Filename string
Password string
keyStoreType string
command string
}
// NewJKSKeyStore creates a new Java Key Store, managed by the runmqckm command
func NewJKSKeyStore(filename, password string) *KeyStore {
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "jks",
command: "/opt/mqm/bin/runmqckm",
}
}
// NewCMSKeyStore creates a new MQ CMS Key Store, managed by the runmqakm command
func NewCMSKeyStore(filename, password string) *KeyStore {
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "cms",
command: "/opt/mqm/bin/runmqakm",
}
}
// NewPKCS12KeyStore creates a new PKCS12 Key Store, managed by the runmqakm command
func NewPKCS12KeyStore(filename, password string) *KeyStore {
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "p12",
command: "/opt/mqm/bin/runmqakm",
}
}
// Create a key store, if it doesn't already exist
func (ks *KeyStore) Create() error {
_, err := os.Stat(ks.Filename)
if err == nil {
// Keystore already exists so we should refresh it by deleting it.
extension := filepath.Ext(ks.Filename)
if ks.keyStoreType == "cms" {
// Only delete these when we are refreshing the kdb keystore
stashFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".sth"
rdbFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".rdb"
crlFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".crl"
err = os.Remove(stashFile)
if err != nil {
return err
}
err = os.Remove(rdbFile)
if err != nil {
return err
}
err = os.Remove(crlFile)
if err != nil {
return err
}
}
err = os.Remove(ks.Filename)
if err != nil {
return err
}
} else if !os.IsNotExist(err) {
// If the keystore exists but cannot be accessed then return the error
return err
}
// Create the keystore now we're sure it doesn't exist
out, _, err := command.Run(ks.command, "-keydb", "-create", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password, "-stash")
if err != nil {
return fmt.Errorf("error running \"%v -keydb -create\": %v %s", ks.command, err, out)
}
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return err
}
err = os.Chown(ks.Filename, mqmUID, mqmGID)
if err != nil {
return err
}
return nil
}
// CreateStash creates a key stash, if it doesn't already exist
func (ks *KeyStore) CreateStash() error {
extension := filepath.Ext(ks.Filename)
stashFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".sth"
_, err := os.Stat(stashFile)
if err != nil {
if os.IsNotExist(err) {
out, _, err := command.Run(ks.command, "-keydb", "-stashpw", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return fmt.Errorf("error running \"%v -keydb -stashpw\": %v %s", ks.command, err, out)
}
}
return err
}
mqmUID, mqmGID, err := command.LookupMQM()
if err != nil {
return err
}
err = os.Chown(stashFile, mqmUID, mqmGID)
if err != nil {
return err
}
return nil
}
// Import imports a certificate file in the keystore
func (ks *KeyStore) Import(inputFile, password string) error {
out, _, err := command.Run(ks.command, "-cert", "-import", "-file", inputFile, "-pw", password, "-target", ks.Filename, "-target_pw", ks.Password, "-target_type", ks.keyStoreType)
if err != nil {
return fmt.Errorf("error running \"%v -cert -import\": %v %s", ks.command, err, out)
}
return nil
}
// CreateSelfSignedCertificate creates a self-signed certificate in the keystore
func (ks *KeyStore) CreateSelfSignedCertificate(label, dn, hostname string) error {
out, _, err := command.Run(ks.command, "-cert", "-create", "-db", ks.Filename, "-pw", ks.Password, "-label", label, "-dn", dn, "-san_dnsname", hostname, "-size 2048 -sig_alg sha256 -eku serverAuth")
if err != nil {
return fmt.Errorf("error running \"%v -cert -create\": %v %s", ks.command, err, out)
}
return nil
}
// Add adds a CA certificate to the keystore
func (ks *KeyStore) Add(inputFile, label string) error {
out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile, "-label", label)
if err != nil {
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
}
return nil
}
// Add adds a CA certificate to the keystore
func (ks *KeyStore) AddNoLabel(inputFile string) error {
out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile)
if err != nil {
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
}
return nil
}
// GetCertificateLabels returns the labels of all certificates in the key store
func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
}
scanner := bufio.NewScanner(strings.NewReader(out))
var labels []string
for scanner.Scan() {
s := scanner.Text()
if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") {
s := strings.TrimLeft(s, "-*")
labels = append(labels, strings.TrimSpace(s))
}
}
err = scanner.Err()
if err != nil {
return nil, err
}
return labels, nil
}
// RenameCertificate renames the specified certificate
func (ks *KeyStore) RenameCertificate(from, to string) error {
if ks.command == "/opt/mqm/bin/runmqakm" {
// runmqakm can't handle certs with ' in them so just use capicmd
// Overriding gosec here as this function is in an internal package and only callable by our internal functions.
// #nosec G204
cmd := exec.Command("/opt/mqm/gskit8/bin/gsk8capicmd_64", "-cert", "-rename", "-db", ks.Filename, "-pw", ks.Password, "-label", from, "-new_label", to)
cmd.Env = append(os.Environ(), "LD_LIBRARY_PATH=/opt/mqm/gskit8/lib64/:/opt/mqm/gskit8/lib")
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error running \"%v -cert -rename\": %v %s", "/opt/mqm/gskit8/bin/gsk8capicmd_64", err, out)
}
} else {
out, _, err := command.Run(ks.command, "-cert", "-rename", "-db", ks.Filename, "-pw", ks.Password, "-label", from, "-new_label", to)
if err != nil {
return fmt.Errorf("error running \"%v -cert -rename\": %v %s", ks.command, err, out)
}
}
return nil
}
// ListAllCertificates Lists all certificates in the keystore
func (ks *KeyStore) ListAllCertificates() ([]string, error) {
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
}
scanner := bufio.NewScanner(strings.NewReader(out))
var labels []string
for scanner.Scan() {
s := scanner.Text()
if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") || strings.HasPrefix(s, "!") {
s := strings.TrimLeft(s, "-*!")
labels = append(labels, strings.TrimSpace(s))
}
}
err = scanner.Err()
if err != nil {
return nil, err
}
return labels, nil
}

View File

@@ -0,0 +1,191 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package metrics contains code to provide metrics for the queue manager
package metrics
import (
"github.com/ibm-messaging/mq-container/pkg/logger"
"github.com/prometheus/client_golang/prometheus"
)
const (
namespace = "ibmmq"
qmgrPrefix = "qmgr"
qmgrLabel = "qmgr"
objectPrefix = "object"
objectLabel = "object"
)
type exporter struct {
qmName string
gaugeMap map[string]*prometheus.GaugeVec
counterMap map[string]*prometheus.CounterVec
firstCollect bool
log *logger.Logger
}
func newExporter(qmName string, log *logger.Logger) *exporter {
return &exporter{
qmName: qmName,
gaugeMap: make(map[string]*prometheus.GaugeVec),
counterMap: make(map[string]*prometheus.CounterVec),
firstCollect: true,
log: log,
}
}
// Describe provides details of all available metrics
func (e *exporter) Describe(ch chan<- *prometheus.Desc) {
requestChannel <- false
response := <-responseChannel
for key, metric := range response {
if metric.isDelta {
// For delta type metrics - allocate a Prometheus Counter
counterVec := createCounterVec(metric.name, metric.description, metric.objectType)
e.counterMap[key] = counterVec
// Describe metric
counterVec.Describe(ch)
} else {
// For non-delta type metrics - allocate a Prometheus Gauge
gaugeVec := createGaugeVec(metric.name, metric.description, metric.objectType)
e.gaugeMap[key] = gaugeVec
// Describe metric
gaugeVec.Describe(ch)
}
}
}
// Collect is called at regular intervals to provide the current metric data
func (e *exporter) Collect(ch chan<- prometheus.Metric) {
requestChannel <- true
response := <-responseChannel
for key, metric := range response {
if metric.isDelta {
// For delta type metrics - update their Prometheus Counter
counterVec := e.counterMap[key]
// Populate Prometheus Counter with metric values
// - Skip on first collect to avoid build-up of accumulated values
if !e.firstCollect {
for label, value := range metric.values {
var err error
var counter prometheus.Counter
if label == qmgrLabelValue {
counter, err = counterVec.GetMetricWithLabelValues(e.qmName)
} else {
counter, err = counterVec.GetMetricWithLabelValues(label, e.qmName)
}
if err == nil {
counter.Add(value)
} else {
e.log.Errorf("Metrics Error: %s", err.Error())
}
}
}
// Collect metric
counterVec.Collect(ch)
} else {
// For non-delta type metrics - reset their Prometheus Gauge
gaugeVec := e.gaugeMap[key]
gaugeVec.Reset()
// Populate Prometheus Gauge with metric values
// - Skip on first collect to avoid build-up of accumulated values
if !e.firstCollect {
for label, value := range metric.values {
var err error
var gauge prometheus.Gauge
if label == qmgrLabelValue {
gauge, err = gaugeVec.GetMetricWithLabelValues(e.qmName)
} else {
gauge, err = gaugeVec.GetMetricWithLabelValues(label, e.qmName)
}
if err == nil {
gauge.Set(value)
} else {
e.log.Errorf("Metrics Error: %s", err.Error())
}
}
}
// Collect metric
gaugeVec.Collect(ch)
}
}
if e.firstCollect {
e.firstCollect = false
}
}
// createCounterVec returns a Prometheus CounterVec populated with metric details
func createCounterVec(name, description string, objectType bool) *prometheus.CounterVec {
prefix, labels := getVecDetails(objectType)
counterVec := prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Name: prefix + "_" + name,
Help: description,
},
labels,
)
return counterVec
}
// createGaugeVec returns a Prometheus GaugeVec populated with metric details
func createGaugeVec(name, description string, objectType bool) *prometheus.GaugeVec {
prefix, labels := getVecDetails(objectType)
gaugeVec := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Name: prefix + "_" + name,
Help: description,
},
labels,
)
return gaugeVec
}
// getVecDetails returns the required prefix and labels for a metric
func getVecDetails(objectType bool) (prefix string, labels []string) {
prefix = qmgrPrefix
labels = []string{qmgrLabel}
if objectType {
prefix = objectPrefix
labels = []string{objectLabel, qmgrLabel}
}
return prefix, labels
}

View File

@@ -0,0 +1,204 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metrics
import (
"testing"
"time"
"github.com/ibm-messaging/mq-golang/ibmmq"
"github.com/ibm-messaging/mq-golang/mqmetric"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)
func TestDescribe_Counter(t *testing.T) {
testDescribe(t, true)
}
func TestDescribe_Gauge(t *testing.T) {
testDescribe(t, false)
}
func testDescribe(t *testing.T, isDelta bool) {
teardownTestCase := setupTestCase(false)
defer teardownTestCase()
log := getTestLogger()
ch := make(chan *prometheus.Desc)
go func() {
exporter := newExporter("qmName", log)
exporter.Describe(ch)
}()
collect := <-requestChannel
if collect {
t.Errorf("Received unexpected collect request")
}
if isDelta {
mqmetric.Metrics.Classes[0].Types[0].Elements[0].Datatype = ibmmq.MQIAMO_MONITOR_DELTA
}
metrics, _ := initialiseMetrics(log)
responseChannel <- metrics
select {
case prometheusDesc := <-ch:
expected := "Desc{fqName: \"ibmmq_qmgr_" + testElement1Name + "\", help: \"" + testElement1Description + "\", constLabels: {}, variableLabels: [qmgr]}"
actual := prometheusDesc.String()
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
case <-time.After(1 * time.Second):
t.Error("Did not receive channel response from describe")
}
}
func TestCollect_Counter(t *testing.T) {
testCollect(t, true)
}
func TestCollect_Gauge(t *testing.T) {
testCollect(t, false)
}
func testCollect(t *testing.T, isDelta bool) {
teardownTestCase := setupTestCase(false)
defer teardownTestCase()
log := getTestLogger()
exporter := newExporter("qmName", log)
if isDelta {
exporter.counterMap[testKey1] = createCounterVec(testElement1Name, testElement1Description, false)
} else {
exporter.gaugeMap[testKey1] = createGaugeVec(testElement1Name, testElement1Description, false)
}
for i := 1; i <= 3; i++ {
ch := make(chan prometheus.Metric)
go func() {
exporter.Collect(ch)
close(ch)
}()
collect := <-requestChannel
if !collect {
t.Errorf("Received unexpected describe request")
}
populateTestMetrics(i, false)
if isDelta {
mqmetric.Metrics.Classes[0].Types[0].Elements[0].Datatype = ibmmq.MQIAMO_MONITOR_DELTA
}
metrics, _ := initialiseMetrics(log)
updateMetrics(metrics)
responseChannel <- metrics
select {
case <-ch:
var actual float64
prometheusMetric := dto.Metric{}
if isDelta {
exporter.counterMap[testKey1].WithLabelValues("qmName").Write(&prometheusMetric)
actual = prometheusMetric.GetCounter().GetValue()
} else {
exporter.gaugeMap[testKey1].WithLabelValues("qmName").Write(&prometheusMetric)
actual = prometheusMetric.GetGauge().GetValue()
}
if i == 1 {
if actual != float64(0) {
t.Errorf("Expected values to be zero on first collect; actual %f", actual)
}
} else if isDelta && i != 2 {
if actual != float64(i+(i-1)) {
t.Errorf("Expected value=%f; actual %f", float64(i+(i-1)), actual)
}
} else if actual != float64(i) {
t.Errorf("Expected value=%f; actual %f", float64(i), actual)
}
case <-time.After(1 * time.Second):
t.Error("Did not receive channel response from collect")
}
}
}
func TestCreateCounterVec(t *testing.T) {
ch := make(chan *prometheus.Desc)
counterVec := createCounterVec("MetricName", "MetricDescription", false)
go func() {
counterVec.Describe(ch)
}()
description := <-ch
expected := "Desc{fqName: \"ibmmq_qmgr_MetricName\", help: \"MetricDescription\", constLabels: {}, variableLabels: [qmgr]}"
actual := description.String()
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}
func TestCreateCounterVec_ObjectLabel(t *testing.T) {
ch := make(chan *prometheus.Desc)
counterVec := createCounterVec("MetricName", "MetricDescription", true)
go func() {
counterVec.Describe(ch)
}()
description := <-ch
expected := "Desc{fqName: \"ibmmq_object_MetricName\", help: \"MetricDescription\", constLabels: {}, variableLabels: [object qmgr]}"
actual := description.String()
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}
func TestCreateGaugeVec(t *testing.T) {
ch := make(chan *prometheus.Desc)
gaugeVec := createGaugeVec("MetricName", "MetricDescription", false)
go func() {
gaugeVec.Describe(ch)
}()
description := <-ch
expected := "Desc{fqName: \"ibmmq_qmgr_MetricName\", help: \"MetricDescription\", constLabels: {}, variableLabels: [qmgr]}"
actual := description.String()
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}
func TestCreateGaugeVec_ObjectLabel(t *testing.T) {
ch := make(chan *prometheus.Desc)
gaugeVec := createGaugeVec("MetricName", "MetricDescription", true)
go func() {
gaugeVec.Describe(ch)
}()
description := <-ch
expected := "Desc{fqName: \"ibmmq_object_MetricName\", help: \"MetricDescription\", constLabels: {}, variableLabels: [object qmgr]}"
actual := description.String()
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}

124
internal/metrics/mapping.go Normal file
View File

@@ -0,0 +1,124 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package metrics contains code to provide metrics for the queue manager
package metrics
type metricLookup struct {
name string
enabled bool
}
// generateMetricNamesMap generates metric names mapped from their description
func generateMetricNamesMap() map[string]metricLookup {
metricNamesMap := map[string]metricLookup{
"CPU/SystemSummary/CPU load - one minute average": metricLookup{"cpu_load_one_minute_average_percentage", true},
"CPU/SystemSummary/CPU load - five minute average": metricLookup{"cpu_load_five_minute_average_percentage", true},
"CPU/SystemSummary/CPU load - fifteen minute average": metricLookup{"cpu_load_fifteen_minute_average_percentage", true},
"CPU/SystemSummary/System CPU time percentage": metricLookup{"system_cpu_time_percentage", true},
"CPU/SystemSummary/User CPU time percentage": metricLookup{"user_cpu_time_percentage", true},
"CPU/SystemSummary/RAM free percentage": metricLookup{"ram_free_percentage", true},
"CPU/SystemSummary/RAM total bytes": metricLookup{"system_ram_size_bytes", false},
"CPU/QMgrSummary/System CPU time - percentage estimate for queue manager": metricLookup{"system_cpu_time_estimate_for_queue_manager_percentage", true},
"CPU/QMgrSummary/User CPU time - percentage estimate for queue manager": metricLookup{"user_cpu_time_estimate_for_queue_manager_percentage", true},
"CPU/QMgrSummary/RAM total bytes - estimate for queue manager": metricLookup{"ram_usage_estimate_for_queue_manager_bytes", true},
"DISK/SystemSummary/MQ trace file system - free space": metricLookup{"trace_file_system_free_space_percentage", true},
"DISK/SystemSummary/MQ trace file system - bytes in use": metricLookup{"trace_file_system_in_use_bytes", true},
"DISK/SystemSummary/MQ errors file system - free space": metricLookup{"errors_file_system_free_space_percentage", true},
"DISK/SystemSummary/MQ errors file system - bytes in use": metricLookup{"errors_file_system_in_use_bytes", true},
"DISK/SystemSummary/MQ FDC file count": metricLookup{"fdc_files", true},
"DISK/QMgrSummary/Queue Manager file system - free space": metricLookup{"queue_manager_file_system_free_space_percentage", true},
"DISK/QMgrSummary/Queue Manager file system - bytes in use": metricLookup{"queue_manager_file_system_in_use_bytes", true},
"DISK/Log/Log - logical bytes written": metricLookup{"log_logical_written_bytes_total", true},
"DISK/Log/Log - physical bytes written": metricLookup{"log_physical_written_bytes_total", true},
"DISK/Log/Log - current primary space in use": metricLookup{"log_primary_space_in_use_percentage", true},
"DISK/Log/Log - workload primary space utilization": metricLookup{"log_workload_primary_space_utilization_percentage", true},
"DISK/Log/Log - write latency": metricLookup{"log_write_latency_seconds", true},
"DISK/Log/Log - bytes max": metricLookup{"log_max_bytes", true},
"DISK/Log/Log - write size": metricLookup{"log_write_size_bytes", true},
"DISK/Log/Log - bytes in use": metricLookup{"log_in_use_bytes", true},
"DISK/Log/Log file system - bytes max": metricLookup{"log_file_system_max_bytes", true},
"DISK/Log/Log file system - bytes in use": metricLookup{"log_file_system_in_use_bytes", true},
"DISK/Log/Log - bytes occupied by reusable extents": metricLookup{"log_occupied_by_reusable_extents_bytes", true},
"DISK/Log/Log - bytes occupied by extents waiting to be archived": metricLookup{"log_occupied_by_extents_waiting_to_be_archived_bytes", true},
"DISK/Log/Log - bytes required for media recovery": metricLookup{"log_required_for_media_recovery_bytes", true},
"STATMQI/SUBSCRIBE/Create durable subscription count": metricLookup{"durable_subscription_create_total", true},
"STATMQI/SUBSCRIBE/Alter durable subscription count": metricLookup{"durable_subscription_alter_total", true},
"STATMQI/SUBSCRIBE/Resume durable subscription count": metricLookup{"durable_subscription_resume_total", true},
"STATMQI/SUBSCRIBE/Delete durable subscription count": metricLookup{"durable_subscription_delete_total", true},
"STATMQI/SUBSCRIBE/Create non-durable subscription count": metricLookup{"non_durable_subscription_create_total", true},
"STATMQI/SUBSCRIBE/Delete non-durable subscription count": metricLookup{"non_durable_subscription_delete_total", true},
"STATMQI/SUBSCRIBE/Failed create/alter/resume subscription count": metricLookup{"failed_subscription_create_alter_resume_total", true},
"STATMQI/SUBSCRIBE/Subscription delete failure count": metricLookup{"failed_subscription_delete_total", true},
"STATMQI/SUBSCRIBE/MQSUBRQ count": metricLookup{"mqsubrq_total", true},
"STATMQI/SUBSCRIBE/Failed MQSUBRQ count": metricLookup{"failed_mqsubrq_total", true},
"STATMQI/SUBSCRIBE/Durable subscriber - high water mark": metricLookup{"durable_subscriber_high_water_mark", false},
"STATMQI/SUBSCRIBE/Durable subscriber - low water mark": metricLookup{"durable_subscriber_low_water_mark", false},
"STATMQI/SUBSCRIBE/Non-durable subscriber - high water mark": metricLookup{"non_durable_subscriber_high_water_mark", false},
"STATMQI/SUBSCRIBE/Non-durable subscriber - low water mark": metricLookup{"non_durable_subscriber_low_water_mark", false},
"STATMQI/PUBLISH/Topic MQPUT/MQPUT1 interval total": metricLookup{"topic_mqput_mqput1_total", true},
"STATMQI/PUBLISH/Interval total topic bytes put": metricLookup{"topic_put_bytes_total", true},
"STATMQI/PUBLISH/Failed topic MQPUT/MQPUT1 count": metricLookup{"failed_topic_mqput_mqput1_total", true},
"STATMQI/PUBLISH/Persistent - topic MQPUT/MQPUT1 count": metricLookup{"persistent_topic_mqput_mqput1_total", true},
"STATMQI/PUBLISH/Non-persistent - topic MQPUT/MQPUT1 count": metricLookup{"non_persistent_topic_mqput_mqput1_total", true},
"STATMQI/PUBLISH/Published to subscribers - message count": metricLookup{"published_to_subscribers_message_total", true},
"STATMQI/PUBLISH/Published to subscribers - byte count": metricLookup{"published_to_subscribers_bytes_total", true},
"STATMQI/CONNDISC/MQCONN/MQCONNX count": metricLookup{"mqconn_mqconnx_total", true},
"STATMQI/CONNDISC/Failed MQCONN/MQCONNX count": metricLookup{"failed_mqconn_mqconnx_total", true},
"STATMQI/CONNDISC/MQDISC count": metricLookup{"mqdisc_total", true},
"STATMQI/CONNDISC/Concurrent connections - high water mark": metricLookup{"concurrent_connections_high_water_mark", false},
"STATMQI/OPENCLOSE/MQOPEN count": metricLookup{"mqopen_total", true},
"STATMQI/OPENCLOSE/Failed MQOPEN count": metricLookup{"failed_mqopen_total", true},
"STATMQI/OPENCLOSE/MQCLOSE count": metricLookup{"mqclose_total", true},
"STATMQI/OPENCLOSE/Failed MQCLOSE count": metricLookup{"failed_mqclose_total", true},
"STATMQI/INQSET/MQINQ count": metricLookup{"mqinq_total", true},
"STATMQI/INQSET/Failed MQINQ count": metricLookup{"failed_mqinq_total", true},
"STATMQI/INQSET/MQSET count": metricLookup{"mqset_total", true},
"STATMQI/INQSET/Failed MQSET count": metricLookup{"failed_mqset_total", true},
"STATMQI/PUT/Persistent message MQPUT count": metricLookup{"persistent_message_mqput_total", true},
"STATMQI/PUT/Persistent message MQPUT1 count": metricLookup{"persistent_message_mqput1_total", true},
"STATMQI/PUT/Put persistent messages - byte count": metricLookup{"persistent_message_put_bytes_total", true},
"STATMQI/PUT/Non-persistent message MQPUT count": metricLookup{"non_persistent_message_mqput_total", true},
"STATMQI/PUT/Non-persistent message MQPUT1 count": metricLookup{"non_persistent_message_mqput1_total", true},
"STATMQI/PUT/Put non-persistent messages - byte count": metricLookup{"non_persistent_message_put_bytes_total", true},
"STATMQI/PUT/Interval total MQPUT/MQPUT1 count": metricLookup{"mqput_mqput1_total", true},
"STATMQI/PUT/Interval total MQPUT/MQPUT1 byte count": metricLookup{"mqput_mqput1_bytes_total", true},
"STATMQI/PUT/Failed MQPUT count": metricLookup{"failed_mqput_total", true},
"STATMQI/PUT/Failed MQPUT1 count": metricLookup{"failed_mqput1_total", true},
"STATMQI/PUT/MQSTAT count": metricLookup{"mqstat_total", true},
"STATMQI/GET/Persistent message destructive get - count": metricLookup{"persistent_message_destructive_get_total", true},
"STATMQI/GET/Persistent message browse - count": metricLookup{"persistent_message_browse_total", true},
"STATMQI/GET/Got persistent messages - byte count": metricLookup{"persistent_message_get_bytes_total", true},
"STATMQI/GET/Persistent message browse - byte count": metricLookup{"persistent_message_browse_bytes_total", true},
"STATMQI/GET/Non-persistent message destructive get - count": metricLookup{"non_persistent_message_destructive_get_total", true},
"STATMQI/GET/Non-persistent message browse - count": metricLookup{"non_persistent_message_browse_total", true},
"STATMQI/GET/Got non-persistent messages - byte count": metricLookup{"non_persistent_message_get_bytes_total", true},
"STATMQI/GET/Non-persistent message browse - byte count": metricLookup{"non_persistent_message_browse_bytes_total", true},
"STATMQI/GET/Interval total destructive get- count": metricLookup{"destructive_get_total", true},
"STATMQI/GET/Interval total destructive get - byte count": metricLookup{"destructive_get_bytes_total", true},
"STATMQI/GET/Failed MQGET - count": metricLookup{"failed_mqget_total", true},
"STATMQI/GET/Failed browse count": metricLookup{"failed_browse_total", true},
"STATMQI/GET/MQCTL count": metricLookup{"mqctl_total", true},
"STATMQI/GET/Expired message count": metricLookup{"expired_message_total", true},
"STATMQI/GET/Purged queue count": metricLookup{"purged_queue_total", true},
"STATMQI/GET/MQCB count": metricLookup{"mqcb_total", true},
"STATMQI/GET/Failed MQCB count": metricLookup{"failed_mqcb_total", true},
"STATMQI/SYNCPOINT/Commit count": metricLookup{"commit_total", true},
"STATMQI/SYNCPOINT/Rollback count": metricLookup{"rollback_total", true},
}
return metricNamesMap
}

View File

@@ -0,0 +1,37 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metrics
import "testing"
func TestGenerateMetricNamesMap(t *testing.T) {
metricNamesMap := generateMetricNamesMap()
if len(metricNamesMap) != 93 {
t.Errorf("Expected mapping-size=%d; actual %d", 93, len(metricNamesMap))
}
actual, ok := metricNamesMap[testKey1]
if !ok {
t.Errorf("No metric name mapping found for %s", testKey1)
} else {
if actual.name != testElement1Name {
t.Errorf("Expected metric name=%s; actual %s", testElement1Name, actual.name)
}
}
}

120
internal/metrics/metrics.go Normal file
View File

@@ -0,0 +1,120 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package metrics contains code to provide metrics for the queue manager
package metrics
import (
"context"
"fmt"
"net/http"
"time"
"github.com/ibm-messaging/mq-container/pkg/logger"
"github.com/ibm-messaging/mq-container/internal/ready"
"github.com/prometheus/client_golang/prometheus"
)
const (
defaultPort = "9157"
)
var (
metricsEnabled = false
metricsServer = &http.Server{Addr: ":" + defaultPort}
)
// GatherMetrics gathers metrics for the queue manager
func GatherMetrics(qmName string, log *logger.Logger) {
// If running in standby mode - wait until the queue manager becomes active
for {
active, _ := ready.IsRunningAsActiveQM(qmName)
if active {
break
}
time.Sleep(requestTimeout * time.Second)
}
metricsEnabled = true
err := startMetricsGathering(qmName, log)
if err != nil {
log.Errorf("Metrics Error: %s", err.Error())
StopMetricsGathering(log)
}
}
// startMetricsGathering starts gathering metrics for the queue manager
func startMetricsGathering(qmName string, log *logger.Logger) error {
defer func() {
if r := recover(); r != nil {
log.Errorf("Metrics Error: %v", r)
}
}()
log.Println("Starting metrics gathering")
// Start processing metrics
go processMetrics(log, qmName)
// Wait for metrics to be ready before starting the Prometheus handler
<-startChannel
// Register metrics
metricsExporter := newExporter(qmName, log)
err := prometheus.Register(metricsExporter)
if err != nil {
return fmt.Errorf("Failed to register metrics: %v", err)
}
// Setup HTTP server to handle requests from Prometheus
http.Handle("/metrics", prometheus.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
// #nosec G104
w.Write([]byte("Status: METRICS ACTIVE"))
})
go func() {
err = metricsServer.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
log.Errorf("Metrics Error: Failed to handle metrics request: %v", err)
StopMetricsGathering(log)
}
}()
return nil
}
// StopMetricsGathering stops gathering metrics for the queue manager
func StopMetricsGathering(log *logger.Logger) {
if metricsEnabled {
// Stop processing metrics
stopChannel <- true
// Shutdown HTTP server
timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := metricsServer.Shutdown(timeout)
if err != nil {
log.Errorf("Failed to shutdown metrics server: %v", err)
}
}
}

227
internal/metrics/update.go Normal file
View File

@@ -0,0 +1,227 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package metrics contains code to provide metrics for the queue manager
package metrics
import (
"fmt"
"strings"
"time"
"github.com/ibm-messaging/mq-container/pkg/logger"
"github.com/ibm-messaging/mq-golang/ibmmq"
"github.com/ibm-messaging/mq-golang/mqmetric"
)
const (
qmgrLabelValue = mqmetric.QMgrMapKey
requestTimeout = 10
)
var (
startChannel = make(chan bool)
stopChannel = make(chan bool, 2)
requestChannel = make(chan bool)
responseChannel = make(chan map[string]*metricData)
)
type metricData struct {
name string
description string
objectType bool
values map[string]float64
isDelta bool
}
// processMetrics processes publications of metric data and handles describe/collect/stop requests
func processMetrics(log *logger.Logger, qmName string) {
var err error
var firstConnect = true
var metrics map[string]*metricData
for {
// Connect to queue manager and discover available metrics
err = doConnect(qmName)
if err == nil {
if firstConnect {
firstConnect = false
startChannel <- true
}
// #nosec G104
metrics, _ = initialiseMetrics(log)
}
// Now loop until something goes wrong
for err == nil {
// Process publications of metric data
// TODO: If we have a large number of metrics to process, then we could be blocked from responding to stop requests
err = mqmetric.ProcessPublications()
// Handle describe/collect/stop requests
if err == nil {
select {
case collect := <-requestChannel:
if collect {
updateMetrics(metrics)
}
responseChannel <- metrics
case <-stopChannel:
log.Println("Stopping metrics gathering")
mqmetric.EndConnection()
return
case <-time.After(requestTimeout * time.Second):
log.Debugf("Metrics: No requests received within timeout period (%d seconds)", requestTimeout)
}
}
}
log.Errorf("Metrics Error: %s", err.Error())
// Close the connection
mqmetric.EndConnection()
// Handle stop requests
select {
case <-stopChannel:
log.Println("Stopping metrics gathering")
return
case <-time.After(requestTimeout * time.Second):
log.Println("Retrying metrics gathering")
}
}
}
// doConnect connects to the queue manager and discovers available metrics
func doConnect(qmName string) error {
// Set connection configuration
var connConfig mqmetric.ConnectionConfig
connConfig.ClientMode = false
connConfig.UserId = ""
connConfig.Password = ""
// Connect to the queue manager - open the command and dynamic reply queues
err := mqmetric.InitConnectionStats(qmName, "SYSTEM.DEFAULT.MODEL.QUEUE", "", &connConfig)
if err != nil {
return fmt.Errorf("Failed to connect to queue manager %s: %v", qmName, err)
}
// Discover available metrics for the queue manager and subscribe to them
err = mqmetric.DiscoverAndSubscribe("", true, "")
if err != nil {
return fmt.Errorf("Failed to discover and subscribe to metrics: %v", err)
}
return nil
}
// initialiseMetrics sets initial details for all available metrics
func initialiseMetrics(log *logger.Logger) (map[string]*metricData, error) {
metrics := make(map[string]*metricData)
validMetrics := true
metricNamesMap := generateMetricNamesMap()
for _, metricClass := range mqmetric.Metrics.Classes {
for _, metricType := range metricClass.Types {
if !strings.Contains(metricType.ObjectTopic, "%s") {
for _, metricElement := range metricType.Elements {
// Get unique metric key
key := makeKey(metricElement)
// Get metric name from mapping
if metricLookup, found := metricNamesMap[key]; found {
// Check if metric is enabled
if metricLookup.enabled {
// Check if metric is a delta type
isDelta := false
if metricElement.Datatype == ibmmq.MQIAMO_MONITOR_DELTA {
isDelta = true
}
// Set metric details
metric := metricData{
name: metricLookup.name,
description: metricElement.Description,
isDelta: isDelta,
}
// Add metric
if _, exists := metrics[key]; !exists {
metrics[key] = &metric
} else {
log.Errorf("Metrics Error: Found duplicate metric key [%s]", key)
validMetrics = false
}
} else {
log.Debugf("Metrics: Skipping metric, metric is not enabled for key [%s]", key)
}
} else {
log.Errorf("Metrics Error: Skipping metric, unexpected key [%s]", key)
validMetrics = false
}
}
}
}
}
if !validMetrics {
return metrics, fmt.Errorf("Invalid metrics data")
}
return metrics, nil
}
// updateMetrics updates values for all available metrics
func updateMetrics(metrics map[string]*metricData) {
for _, metricClass := range mqmetric.Metrics.Classes {
for _, metricType := range metricClass.Types {
if !strings.Contains(metricType.ObjectTopic, "%s") {
for _, metricElement := range metricType.Elements {
// Unexpected metric elements (with no defined mapping) are handled in 'initialiseMetrics'
// - if any exist, they are logged as errors and skipped (they are not added to the metrics map)
// Therefore we can ignore handling any unexpected metric elements found here
// - this avoids us logging excessive errors, as this function is called frequently
metric, ok := metrics[makeKey(metricElement)]
if ok {
// Clear existing metric values
metric.values = make(map[string]float64)
// Update metric with cached values of publication data
for label, value := range metricElement.Values {
normalisedValue := mqmetric.Normalise(metricElement, label, value)
metric.values[label] = normalisedValue
}
}
// Reset cached values of publication data for this metric
metricElement.Values = make(map[string]int64)
}
}
}
}
}
// makeKey builds a unique key for each metric
func makeKey(metricElement *mqmetric.MonElement) string {
return metricElement.Parent.Parent.Name + "/" + metricElement.Parent.Name + "/" + metricElement.Description
}

View File

@@ -0,0 +1,197 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metrics
import (
"os"
"testing"
"github.com/ibm-messaging/mq-container/pkg/logger"
"github.com/ibm-messaging/mq-golang/mqmetric"
)
const (
testClassName = "CPU"
testTypeName = "SystemSummary"
testElement1Name = "cpu_load_five_minute_average_percentage"
testElement2Name = "cpu_load_fifteen_minute_average_percentage"
testElement1Description = "CPU load - five minute average"
testElement2Description = "CPU load - fifteen minute average"
testKey1 = testClassName + "/" + testTypeName + "/" + testElement1Description
testKey2 = testClassName + "/" + testTypeName + "/" + testElement2Description
)
func TestInitialiseMetrics(t *testing.T) {
teardownTestCase := setupTestCase(false)
defer teardownTestCase()
metrics, err := initialiseMetrics(getTestLogger())
metric, ok := metrics[testKey1]
if err != nil {
t.Errorf("Unexpected error %s", err.Error())
}
if !ok {
t.Error("Expected metric not found in map")
} else {
if metric.name != testElement1Name {
t.Errorf("Expected name=%s; actual %s", testElement1Name, metric.name)
}
if metric.description != testElement1Description {
t.Errorf("Expected description=%s; actual %s", testElement1Description, metric.description)
}
if metric.objectType != false {
t.Errorf("Expected objectType=%v; actual %v", false, metric.objectType)
}
if len(metric.values) != 0 {
t.Errorf("Expected values-size=%d; actual %d", 0, len(metric.values))
}
}
_, ok = metrics[testKey2]
if ok {
t.Errorf("Unexpected metric found in map, %%s object topics should be ignored")
}
if len(metrics) != 1 {
t.Errorf("Map contains unexpected metrics, map size=%d", len(metrics))
}
}
func TestInitialiseMetrics_UnexpectedKey(t *testing.T) {
teardownTestCase := setupTestCase(false)
defer teardownTestCase()
mqmetric.Metrics.Classes[0].Types[0].Elements[0].Description = "New Metric"
_, err := initialiseMetrics(getTestLogger())
if err == nil {
t.Error("Expected skipping metric error")
}
}
func TestInitialiseMetrics_DuplicateKeys(t *testing.T) {
teardownTestCase := setupTestCase(true)
defer teardownTestCase()
_, err := initialiseMetrics(getTestLogger())
if err == nil {
t.Error("Expected duplicate keys error")
}
}
func TestUpdateMetrics(t *testing.T) {
teardownTestCase := setupTestCase(false)
defer teardownTestCase()
metrics, _ := initialiseMetrics(getTestLogger())
updateMetrics(metrics)
metric, _ := metrics[testKey1]
actual, ok := metric.values[qmgrLabelValue]
if !ok {
t.Error("No metric values found for queue manager label")
} else {
if actual != float64(1) {
t.Errorf("Expected metric value=%f; actual %f", float64(1), actual)
}
if len(metric.values) != 1 {
t.Errorf("Expected values-size=%d; actual %d", 1, len(metric.values))
}
}
if len(mqmetric.Metrics.Classes[0].Types[0].Elements[0].Values) != 0 {
t.Error("Unexpected cached value; publication data should have been reset")
}
updateMetrics(metrics)
if len(metric.values) != 0 {
t.Errorf("Unexpected metric value; data should have been cleared")
}
}
func TestMakeKey(t *testing.T) {
teardownTestCase := setupTestCase(false)
defer teardownTestCase()
expected := testKey1
actual := makeKey(mqmetric.Metrics.Classes[0].Types[0].Elements[0])
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}
func setupTestCase(duplicateKey bool) func() {
populateTestMetrics(1, duplicateKey)
return func() {
cleanTestMetrics()
}
}
func populateTestMetrics(testValue int, duplicateKey bool) {
metricClass := new(mqmetric.MonClass)
metricType1 := new(mqmetric.MonType)
metricType2 := new(mqmetric.MonType)
metricElement1 := new(mqmetric.MonElement)
metricElement2 := new(mqmetric.MonElement)
metricClass.Name = testClassName
metricType1.Name = testTypeName
metricType2.Name = testTypeName
metricElement1.MetricName = "Element1Name"
metricElement1.Description = testElement1Description
metricElement1.Values = make(map[string]int64)
metricElement1.Values[qmgrLabelValue] = int64(testValue)
metricElement2.MetricName = "Element2Name"
metricElement2.Description = testElement2Description
metricElement2.Values = make(map[string]int64)
metricType1.ObjectTopic = "ObjectTopic"
metricType2.ObjectTopic = "%s"
metricElement1.Parent = metricType1
metricElement2.Parent = metricType2
metricType1.Parent = metricClass
metricType2.Parent = metricClass
metricType1.Elements = make(map[int]*mqmetric.MonElement)
metricType2.Elements = make(map[int]*mqmetric.MonElement)
metricType1.Elements[0] = metricElement1
if duplicateKey {
metricType1.Elements[1] = metricElement1
}
metricType2.Elements[0] = metricElement2
metricClass.Types = make(map[int]*mqmetric.MonType)
metricClass.Types[0] = metricType1
metricClass.Types[1] = metricType2
mqmetric.Metrics.Classes = make(map[int]*mqmetric.MonClass)
mqmetric.Metrics.Classes[0] = metricClass
}
func cleanTestMetrics() {
mqmetric.Metrics.Classes = make(map[int]*mqmetric.MonClass)
}
func getTestLogger() *logger.Logger {
log, _ := logger.NewLogger(os.Stdout, false, false, "test")
return log
}

View File

@@ -0,0 +1,20 @@
#*******************************************************************#
#* Module Name: mqat.ini *#
#* Type : IBM MQ queue manager configuration file *#
# Function : Define the configuration of application activity *#
#* trace for a single queue manager. *#
#*******************************************************************#
# Global settings stanza, default values
AllActivityTrace:
ActivityInterval=1
ActivityCount=100
TraceLevel=MEDIUM
TraceMessageData=0
StopOnGetTraceMsg=ON
SubscriptionDelivery=BATCHED
# Prevent the sample activity trace program from generating data
ApplicationTrace:
ApplName=amqsact*
Trace=OFF

View File

@@ -0,0 +1,352 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package mqinimerge merges user-supplied INI files into qm.ini and mqat.ini
package mqinimerge
import (
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/pkg/mqini"
)
var qmgrDir string
var stanzasQMINI []string
var stanzasMQATINI []string
// AddStanzas reads supplied MQ INI configuration files and updates the stanzas
// in the queue manager's INI configuration files.
func AddStanzas(qmname string) error {
// Find the qmgr directory.
qm, err := mqini.GetQueueManager(qmname)
if err != nil {
return err
}
qmgrDir = mqini.GetDataDirectory(qm)
// Find the users ini configuration file
files, err := getIniFileList()
if err != nil {
return err
}
if len(files) > 1 {
msg := fmt.Sprintf("[ %v ]", files)
return errors.New("Only a single INI file can be provided. Following INI files were found:" + msg)
}
if len(files) == 0 {
// No INI file update required.
return nil
}
//read user supplied config file.
iniFileBytes, err := ioutil.ReadFile(files[0])
if err != nil {
return err
}
userconfig := string(iniFileBytes)
if len(userconfig) == 0 {
return nil
}
// Prepare a list of all supported stanzas
PopulateAllAvailableStanzas()
// Update the qmgr ini file with user config.
qminiConfiglist, qmatConfiglist, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
return err
}
err = writeConfigStanzas(qminiConfiglist, qmatConfiglist)
if err != nil {
return err
}
return nil
}
// PopulateAllAvailableStanzas initializes the INI stanzas prescribed by MQ specification.
func PopulateAllAvailableStanzas() {
stanzasQMINI = []string{"ExitPath",
"Log",
"Service",
"ServiceComponent",
"Channels",
"TCP",
"ApiExitLocal",
"AccessMode",
"RestrictedMode",
"XAResourceManager",
"DefaultBindType",
"SSL",
"DiagnosticMessages",
"Filesystem",
"Security",
"TuningParameters",
"ExitPropertiesLocal",
"LU62",
"NETBIOS"}
stanzasMQATINI = []string{"AllActivityTrace", "ApplicationTrace"}
}
// getIniFileList checks for the user supplied INI file in `/etc/mqm` directory.
func getIniFileList() ([]string, error) {
fileList := []string{}
err := filepath.Walk("/etc/mqm", func(path string, f os.FileInfo, err error) error {
if strings.HasSuffix(path, ".ini") {
fileList = append(fileList, path)
}
return nil
})
if err != nil {
return nil, err
}
return fileList, nil
}
// PrepareConfigStanzasToWrite Reads through the user supplied INI config file and prepares list of
// updates to be written into corresponding mq ini files (qm.ini and/or mqat.ini files)
func PrepareConfigStanzasToWrite(userconfig string) ([]string, []string, error) {
var qminiConfigStr string
var mqatiniConfigStr string
//read the initial version.
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
iniFileBytes, err := ioutil.ReadFile(filepath.Join(qmgrDir, "qm.ini"))
if err != nil {
return nil, nil, err
}
qminiConfigStr = string(iniFileBytes)
qminiConfiglist := strings.Split(qminiConfigStr, "\n")
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
iniFileBytes, err = ioutil.ReadFile(filepath.Join(qmgrDir, "mqat.ini"))
if err != nil {
return nil, nil, err
}
mqatiniConfigStr = string(iniFileBytes)
qmatConfiglist := strings.Split(mqatiniConfigStr, "\n")
stanzaListMerge := make(map[string]strings.Builder)
stanzaListAppend := make(map[string]strings.Builder)
var sbAppend strings.Builder
var sbMerger strings.Builder
scanner := bufio.NewScanner(strings.NewReader(userconfig))
scanner.Split(bufio.ScanLines)
consumetoAppend := false
consumeToMerge := false
var stanza string
// Read through the user file and prepare what we want.
for scanner.Scan() {
//if this is comment or an empty line, ignore it.
if strings.HasPrefix(scanner.Text(), "#") || len(strings.TrimSpace(scanner.Text())) == 0 {
continue
}
//thumb rule - all stanzas have ":".
if strings.Contains(scanner.Text(), ":") {
stanza = strings.TrimSpace(scanner.Text())
consumetoAppend = false
consumeToMerge = false
// Check if this stanza exists in the qm.ini/mqat.ini files
if strings.Contains(qminiConfigStr, stanza) ||
(strings.Contains(mqatiniConfigStr, stanza) && !(strings.Contains(stanza, "ApplicationTrace"))) {
consumeToMerge = true
sbMerger = strings.Builder{}
stanzaListMerge[stanza] = sbMerger
} else {
consumetoAppend = true
sbAppend = strings.Builder{}
stanzaListAppend[stanza] = sbAppend
}
} else {
if consumetoAppend {
sb := stanzaListAppend[stanza]
_, err := sb.WriteString(scanner.Text() + "\n")
if err != nil {
return nil, nil, err
}
stanzaListAppend[stanza] = sb
}
if consumeToMerge {
sb := stanzaListMerge[stanza]
_, err := sb.WriteString(scanner.Text() + "\n")
if err != nil {
return nil, nil, err
}
stanzaListMerge[stanza] = sb
}
}
}
// do merge.
if len(stanzaListMerge) > 0 {
for key := range stanzaListMerge {
toWrite, filename := ValidateStanzaToWrite(key)
if toWrite {
attrList := stanzaListMerge[key]
switch filename {
case "qm.ini":
qminiConfiglist, err = prepareStanzasToMerge(key, attrList, qminiConfiglist)
if err != nil {
return nil, nil, err
}
case "mqat.ini":
qmatConfiglist, err = prepareStanzasToMerge(key, attrList, qmatConfiglist)
if err != nil {
return nil, nil, err
}
default:
}
}
}
}
// do append.
if len(stanzaListAppend) > 0 {
for key := range stanzaListAppend {
attrList := stanzaListAppend[key]
if strings.Contains(strings.Join(stanzasMQATINI, ", "), strings.TrimSuffix(strings.TrimSpace(key), ":")) {
qmatConfiglist = prepareStanzasToAppend(key, attrList, qmatConfiglist)
} else {
qminiConfiglist = prepareStanzasToAppend(key, attrList, qminiConfiglist)
}
}
}
return qminiConfiglist, qmatConfiglist, nil
}
// ValidateStanzaToWrite validates stanza to be written and the file it belongs to.
func ValidateStanzaToWrite(stanza string) (bool, string) {
stanza = strings.TrimSuffix(strings.TrimSpace(stanza), ":")
if strings.Contains(strings.Join(stanzasQMINI, ", "), stanza) {
return true, "qm.ini"
} else if strings.Contains(strings.Join(stanzasMQATINI, ", "), stanza) {
return true, "mqat.ini"
} else {
return false, ""
}
}
// prepareStanzasToAppend Prepares list of stanzas that are to be appended into qm ini files(qm.ini/mqat.ini)
func prepareStanzasToAppend(key string, attrList strings.Builder, iniConfigList []string) []string {
newVal := key + "\n" + attrList.String()
list := strings.Split(newVal, "\n")
iniConfigList = append(iniConfigList, list...)
return iniConfigList
}
// prepareStanzasToMerge Prepares list of stanzas that are to be updated into qm ini files(qm.ini/mqat.ini)
// These stanzas are already present in mq ini files and their values have to be updated with user supplied ini.
func prepareStanzasToMerge(key string, attrList strings.Builder, iniConfigList []string) ([]string, error) {
pos := -1
//find the index of current stanza in qm's ini file.
for i := 0; i < len(iniConfigList); i++ {
if strings.Contains(iniConfigList[i], key) {
pos = i
break
}
}
var appList strings.Builder
lineScanner := bufio.NewScanner(strings.NewReader(attrList.String()))
lineScanner.Split(bufio.ScanLines)
//Now go through the array and merge the values.
for lineScanner.Scan() {
attrLine := lineScanner.Text()
keyvalue := strings.Split(attrLine, "=")
merged := false
for i := pos + 1; i < len(iniConfigList); i++ {
if strings.HasPrefix(iniConfigList[i], "#") {
continue
}
if strings.Contains(iniConfigList[i], ":") {
break
}
if strings.Contains(iniConfigList[i], keyvalue[0]) {
iniConfigList[i] = attrLine
merged = true
break
}
}
//If this is not merged, then its a new parameter in existing stanza.
if !merged && len(strings.TrimSpace(attrLine)) > 0 {
_, err := appList.WriteString(attrLine)
if err != nil {
return nil, err
}
merged = false
}
if len(appList.String()) > 0 {
temp := make([]string, pos+1)
for i := 0; i < pos+1; i++ {
temp[i] = iniConfigList[i]
}
list := strings.Split(appList.String(), "\n")
temp = append(temp, list...)
temp1 := iniConfigList[pos+1:]
iniConfigList = append(temp, temp1...)
}
}
return iniConfigList, nil
}
// writeFileIfChanged writes the specified data to the specified file path
// (just like ioutil.WriteFile), but first checks if this is needed
func writeFileIfChanged(path string, data []byte, perm os.FileMode) error {
// #nosec G304 - internal utility using file name derived from dspmqinf
current, err := ioutil.ReadFile(path)
if err != nil {
return err
}
// Only write the new file if the it's different from the current file
if !bytes.Equal(current, data) {
err = ioutil.WriteFile(path, data, perm)
if err != nil {
return err
}
}
return nil
}
// writeConfigStanzas writes the INI file updates into corresponding MQ INI files.
func writeConfigStanzas(qmConfig []string, atConfig []string) error {
err := writeFileIfChanged(filepath.Join(qmgrDir, "qm.ini"), []byte(strings.Join(qmConfig, "\n")), 0644)
if err != nil {
return err
}
err = writeFileIfChanged(filepath.Join(qmgrDir, "mqat.ini"), []byte(strings.Join(atConfig, "\n")), 0644)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,256 @@
/*
© Copyright IBM Corporation 2018, 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mqinimerge
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestIniFileStanzas(t *testing.T) {
PopulateAllAvailableStanzas()
checkReturns("ApiExitLocal", true, true, t)
checkReturns("Channels", true, true, t)
checkReturns("TCP", true, true, t)
checkReturns("ServiceComponent", true, true, t)
checkReturns("Service", true, true, t)
checkReturns("AccessMode", true, true, t)
checkReturns("RestrictedMode", true, true, t)
checkReturns("XAResourceManager", true, true, t)
checkReturns("SSL", true, true, t)
checkReturns("Security", true, true, t)
checkReturns("TuningParameters", true, true, t)
checkReturns("ABC", false, false, t)
checkReturns("#1234ABD", true, false, t)
checkReturns("AllActivityTrace", false, true, t)
checkReturns("ApplicationTrace", false, true, t)
checkReturns("xyz123abvc", false, false, t)
}
func TestIniFile1Update(t *testing.T) {
iniFileBytes, err := ioutil.ReadFile("test1qm.ini")
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
userconfig := string(iniFileBytes)
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(atConfig) == 0 {
t.Errorf("Unexpected stanza file update: mqat.ini[%s]\n", atConfig)
}
if len(qmConfig) == 0 {
t.Errorf("Expected stanza file not found: qm.ini\n")
}
count := 0
//we want this line to be present exactly one.
for _, item := range qmConfig {
item = strings.TrimSpace(item)
if strings.Contains(item, "mylib") {
count++
}
}
if count != 1 {
t.Errorf("Expected stanza line not found or appeared more than once in updated string. line=mylib\n config=%s\n count=%d\n", strings.Join(qmConfig, "\n"), count)
}
}
func TestIniFile2Update(t *testing.T) {
iniFileBytes, err := ioutil.ReadFile("test2qm.ini")
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
userconfig := string(iniFileBytes)
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(atConfig) == 0 {
t.Errorf("Expected stanza file not found: mqat.ini\n")
}
if len(qmConfig) == 0 {
t.Errorf("Expected stanza file not found: qm.ini\n")
}
count := 0
//we want this line to be present exactly one.
for _, item := range atConfig {
item = strings.TrimSpace(item)
if strings.Contains(item, "amqsget") {
count++
}
}
if count != 1 {
t.Errorf("Expected stanza line not found or appeared more than once in updated string. line=amqsget, Config:%s\n", strings.Join(atConfig, "\n"))
}
}
func TestIniFile3Update(t *testing.T) {
i := 0
iniFileBytes, err := ioutil.ReadFile("test3qm.ini")
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
userconfig := string(iniFileBytes)
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(qmConfig) == 0 {
t.Errorf("Unexpected stanza file update: qm.ini[%s]\n", atConfig)
}
if len(atConfig) == 0 {
t.Errorf("Expected stanza file not found: mqat.ini\n")
}
qmConfigStr := strings.Join(qmConfig, "\n")
atConfigStr := strings.Join(atConfig, "\n")
scanner := bufio.NewScanner(strings.NewReader(userconfig))
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
i++
//first 20 lines of test3qm.ini shall go into qm.ini file and rest into mqat.ini file.
if i < 20 {
if !strings.Contains(qmConfigStr, strings.TrimSpace(line)) {
t.Errorf("Expected stanza line not found in updated string. line=%s\n, Stanza:%s\n", line, qmConfigStr)
}
} else if i > 20 {
if !strings.Contains(atConfigStr, line) {
t.Errorf("Expected stanza line not found in updated string. line=%s\n, Stanza:%s\n", line, atConfigStr)
}
}
}
}
func TestIniFile4Update(t *testing.T) {
iniFileBytes, err := ioutil.ReadFile("test1qm.ini")
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
//First merge
userconfig := string(iniFileBytes)
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(atConfig) == 0 {
t.Errorf("Expected stanza file not found: mqat.ini\n")
}
if len(qmConfig) == 0 {
t.Errorf("Expected stanza file not found: qm.ini\n")
}
//second merge.
qmConfig, atConfig, err = PrepareConfigStanzasToWrite(userconfig)
if err != nil {
t.Errorf("Unexpected error: [%s]\n", err.Error())
}
if len(atConfig) == 0 {
t.Errorf("Expected stanza file not found: mqat.ini\n")
}
if len(qmConfig) == 0 {
t.Errorf("Expected stanza file not found: qm.ini\n")
}
count := 0
//we just did a double merge, however we want this line to be present exactly one.
for _, item := range qmConfig {
item = strings.TrimSpace(item)
if strings.Contains(item, "mylib") {
count++
}
}
if count != 1 {
t.Errorf("Expected stanza line not found or appeared more than once in updated string. line=mylib\n config=%s\n count=%d\n", strings.Join(qmConfig, "\n"), count)
}
}
func checkReturns(stanza string, isqmini bool, shouldexist bool, t *testing.T) {
exists, filename := ValidateStanzaToWrite(stanza)
if exists != shouldexist {
t.Errorf("Stanza should exist %t but found was %t", shouldexist, exists)
}
if shouldexist {
if isqmini {
if filename != "qm.ini" {
t.Errorf("Expected filename:qm.ini for stanza:%s. But got %s", stanza, filename)
}
} else {
if filename != "mqat.ini" {
t.Errorf("Expected filename:mqat.ini for stanza:%s. But got %s", stanza, filename)
}
}
}
}
var writeFileIfChangedTests = []struct {
before []byte
after []byte
same bool
}{
{[]byte("ABC€"), []byte("ABC€"), true},
{[]byte("ABC€"), []byte("ABC$"), false},
{[]byte("ABC€"), []byte("BBC€"), false},
}
func TestWriteFileIfChanged(t *testing.T) {
tmpFile := filepath.Join(os.TempDir(), t.Name())
t.Logf("Using temp file %v", tmpFile)
for i, table := range writeFileIfChangedTests {
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
err := ioutil.WriteFile(tmpFile, table.before, 0600)
time.Sleep(time.Second * 1)
defer os.Remove(tmpFile)
fi, err := os.Stat(tmpFile)
if err != nil {
t.Fatal(err)
}
beforeMod := fi.ModTime()
err = writeFileIfChanged(tmpFile, table.after, 0600)
if err != nil {
t.Error(err)
}
fi, err = os.Stat(tmpFile)
if err != nil {
t.Error(err)
}
afterMod := fi.ModTime()
if table.same {
if beforeMod != afterMod {
t.Errorf("Expected file timestamps to be the same (%v); got %v", beforeMod, afterMod)
}
} else {
if beforeMod == afterMod {
t.Errorf("Expected file timestamp to be different got %v and %v", beforeMod, afterMod)
}
}
})
}
}

View File

@@ -0,0 +1,45 @@
#*******************************************************************#
#* Module Name: qm.ini *#
#* Type : IBM MQ queue manager configuration file *#
# Function : Define the configuration of a single queue manager *#
#* *#
#*******************************************************************#
#* Notes : *#
#* 1) This file defines the configuration of the queue manager *#
#* *#
#*******************************************************************#
ExitPath:
ExitsDefaultPath=C:\ProgramData\IBM\MQ\exits
ExitsDefaultPath64=C:\ProgramData\IBM\MQ\exits64
InstanceData:
InstanceID=1562831591
Startup=ServiceManual
#* *#
#* *#
Log:
LogPrimaryFiles=3
LogSecondaryFiles=2
LogFilePages=4096
LogType=CIRCULAR
LogBufferPages=0
LogPath=C:\ProgramData\IBM\MQ\log\INI1\
LogWriteIntegrity=TripleWrite
Service:
Name=AuthorizationService
EntryPoints=14
ServiceComponent:
Service=AuthorizationService
Name=MQSeries.WindowsNT.auth.service
Module=amqzfu.dll
ComponentDataSize=0
Channels:
ChlauthEarlyAdopt=Y
TCP:
SndBuffSize=0
RcvBuffSize=0
RcvSndBuffSize=0
RcvRcvBuffSize=0
ClntSndBuffSize=0
ClntRcvBuffSize=0
SvrSndBuffSize=0
SvrRcvBuffSize=0

View File

@@ -0,0 +1,5 @@
ApiExitLocal:   
Sequence=1
Function=EntryPoint
Module=/opt/mqm/exitlib.so
Name=mylib

View File

@@ -0,0 +1,7 @@
AllActivityTrace:
ActivityInterval=11
ActivityCount=1
TraceLevel=INFO
ApplicationTrace:
ApplName=amqsget
Trace=ON

View File

@@ -0,0 +1,23 @@
ApiExitLocal:   
Sequence=1
Function=EntryPoint
Module=/opt/foo/foo.so
Name=FooExit
Channels:
MQIBindType=FASTPATH
Log:
LogPrimaryFiles=30
LogType=CIRCULAR
LogPath=/ProgramfILES/IBM/MQ/log/INI1/
TCP:
SndBuffSize=4095
RcvBuffSize=4095
RcvSndBuffSize=4095
RcvRcvBuffSize=4095
ClntSndBuffSize=2049
ClntRcvBuffSize=2049
SvrSndBuffSize=2049
SvrRcvBuffSize=2049
ApplicationTrace:
ApplName=amqsput
Trace=ON

View File

@@ -0,0 +1,264 @@
/*
© Copyright IBM Corporation 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mqscredact
import (
"bufio"
"io"
"regexp"
"strings"
)
/* List of sensitive MQ Parameters */
var sensitiveParameters = []string{"LDAPPWD", "PASSWORD", "SSLCRYP"}
// redactionString is what sensitive paramters will be replaced with
const redactionString = "(*********)"
func findEndOfParamterString(stringDenoter rune, r *bufio.Reader) string {
parameter := ""
for {
char, _, err := r.ReadRune()
if err != nil {
return parameter
}
parameter = parameter + string(char)
if char == stringDenoter {
break
} else if char == '\n' {
// Check if we're on a comment line
NewLineLoop:
for {
// Look at next character without moving buffer forwards
chars, err := r.Peek(1)
if err != nil {
return parameter
}
// Check if we're at the beginning of some data.
startOutput, _ := regexp.MatchString(`[^:0-9\s]`, string(chars[0]))
if startOutput {
// We are at the start, check if we're on a comment line
if chars[0] == '*' {
// found a comment line. go to the next newline chraracter
CommentLoop:
for {
char, _, err = r.ReadRune()
if err != nil {
return parameter
}
parameter = parameter + string(char)
if char == '\n' {
break CommentLoop
}
}
// Go round again as we're now on a new line
continue NewLineLoop
}
// We've checked for comment and it isn't a comment line so break without moving buffer forwards
break NewLineLoop
}
// Move the buffer forward and try again
char, _, _ = r.ReadRune()
parameter = parameter + string(char)
}
}
}
return parameter
}
// getParameterString reads from r in order to find the end of the MQSC Parameter value. This is enclosed in ( ).
// This function will return what it finds and will increment the reader pointer along as it goes.
func getParameterString(r *bufio.Reader) string {
// Add the ( in as it will have been dropped before.
parameter := "("
Loop:
for {
char, _, err := r.ReadRune()
if err != nil {
return parameter
}
parameter = parameter + string(char)
switch char {
case ')':
break Loop
// TODO: Duplicate code..
case '\'', '"':
parameter = parameter + findEndOfParamterString(char, r)
}
}
return parameter
}
func resetAllParameters(currentVerb, originalString *string, lineContinuation, foundGap, parameterNext, redacting, checkComment *bool) {
*currentVerb = ""
*originalString = ""
*lineContinuation = false
*foundGap = false
*parameterNext = false
*redacting = false
*checkComment = true
}
// Redact is the main function for redacting sensitive parameters in MQSC strings
// It accepts a string and redacts sensitive paramters such as LDAPPWD or PASSWORD
func Redact(out string) (string, error) {
out = strings.TrimSpace(out)
var returnStr, currentVerb, originalString string
var lineContinuation, foundGap, parameterNext, redacting, checkComment bool
newline := true
resetAllParameters(&currentVerb, &originalString, &lineContinuation, &foundGap, &parameterNext, &redacting, &checkComment)
r := bufio.NewReader(strings.NewReader(out))
MainLoop:
for {
// We have found a opening ( so use special parameter parsing
if parameterNext {
parameterStr := getParameterString(r)
if !redacting {
returnStr = returnStr + parameterStr
} else {
returnStr = returnStr + redactionString
}
resetAllParameters(&currentVerb, &originalString, &lineContinuation, &foundGap, &parameterNext, &redacting, &checkComment)
}
// Loop round getting hte next parameter
char, _, err := r.ReadRune()
if err == io.EOF {
if originalString != "" {
returnStr = returnStr + originalString
}
break
} else if err != nil {
return returnStr, err
}
/* We need to push forward until we find a non-whitespace, digit or colon character */
if newline {
startOutput, _ := regexp.MatchString(`[^:0-9\s]`, string(char))
if !startOutput {
originalString = originalString + string(char)
continue MainLoop
}
newline = false
}
switch char {
// Found a line continuation character
case '+', '-':
lineContinuation = true
foundGap = false
originalString = originalString + string(char)
continue MainLoop
// Found whitespace/new line
case '\n':
checkComment = true
newline = true
fallthrough
case '\t', '\r', ' ':
if !lineContinuation {
foundGap = true
}
originalString = originalString + string(char)
continue MainLoop
// Found a paramter value
case '(':
parameterNext = true
/* Do not continue as we need to do some checks */
// Found a comment, parse in a special manner
case '*':
if checkComment {
originalString = originalString + string(char)
// Loop round until we find the new line character that marks the end of the comment
CommentLoop:
for {
char, _, err := r.ReadRune()
if err == io.EOF {
if originalString != "" {
returnStr = returnStr + originalString
}
break MainLoop
} else if err != nil {
return returnStr, err
}
originalString = originalString + string(char)
if char == '\n' {
break CommentLoop
}
}
//Comment has been read and added to original string, go back to start
checkComment = true
newline = true
continue MainLoop
}
/* Do not continue as we need to do some checks */
} //end of switch
checkComment = false
if lineContinuation {
lineContinuation = false
}
if foundGap || parameterNext {
// we've completed an parameter so check whether it is sensitive
currentVerb = strings.ToUpper(currentVerb)
if isSensitiveCommand(currentVerb) {
redacting = true
}
// Add the unedited string to the return string
returnStr = returnStr + originalString
//reset some of the parameters
originalString = ""
currentVerb = ""
foundGap = false
lineContinuation = false
}
originalString = originalString + string(char)
currentVerb = currentVerb + string(char)
}
return returnStr, nil
}
// isSensitiveCommand checks whether the given string contains a sensitive parameter.
// We use contains here because we can't determine whether a line continuation seperates
// parts of a parameter or two different parameters.
func isSensitiveCommand(command string) bool {
for _, v := range sensitiveParameters {
if strings.Contains(command, v) {
return true
}
}
return false
}

View File

@@ -0,0 +1,171 @@
/*
© Copyright IBM Corporation 2019
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mqscredact
import (
"strings"
"testing"
)
const passwordString = passwordHalf1 + passwordHalf2
const passwordHalf1 = "hippo"
const passwordHalf2 = "123456"
var testStrings = [...]string{
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD('" + passwordString + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordString + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD ('" + passwordString + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD\t\t('" + passwordString + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) ldappwd('" + passwordString + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LdApPwD('" + passwordString + "')",
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD('" + passwordString + "')",
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD(\"" + passwordString + "\")",
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD ('" + passwordString + "')",
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD\t\t('" + passwordString + "')",
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) password('" + passwordString + "')",
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) pAsSwOrD('" + passwordString + "')",
"ALTER QMGR SSLCRYP('" + passwordString + "')",
"ALTER QMGR SSLCRYP(\"" + passwordString + "\")",
"ALTER QMGR SSLCRYP ('" + passwordString + "')",
"ALTER QMGR SSLCRYP\t\t('" + passwordString + "')",
"ALTER QMGR sslcryp('" + passwordString + "')",
"ALTER QMGR sslCRYP('" + passwordString + "')",
// Line continuation ones
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "+\n " + passwordHalf2 + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "+\n\t" + passwordHalf2 + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "+\n\t " + passwordHalf2 + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD('" + passwordHalf1 + "+\n " + passwordHalf2 + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD('" + passwordHalf1 + "+\n\t" + passwordHalf2 + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD('" + passwordHalf1 + "+\n\t " + passwordHalf2 + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "-\n" + passwordHalf2 + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD('" + passwordHalf1 + "-\n" + passwordHalf2 + "')",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "+ \n " + passwordHalf2 + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "+\t\n " + passwordHalf2 + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "- \n" + passwordHalf2 + "\")",
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD(\"" + passwordHalf1 + "-\t\n" + passwordHalf2 + "\")",
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD(\"" + passwordHalf1 + "+\n " + passwordHalf2 + "\")",
"ALTER QMGR SSLCRYP(\"" + passwordHalf1 + "+\n " + passwordHalf2 + "\")",
//edge cases
"ALTER QMGR SSLCRYP(\"" + passwordHalf1 + "+\n 123+\n 456\")",
"ALTER QMGR SSLCRYP(\"" + passwordHalf1 + "-\n123-\n456\")",
"ALTER QMGR SSLCRYP(\"" + passwordHalf1 + "+\n 1+\n 2+\n 3+\n 4+\n 5+\n 6\")",
"ALTER QMGR SSLCRYP(\"" + passwordHalf1 + "-\n1-\n2-\n3-\n4-\n5-\n6\")",
"ALTER QMGR SSLCRYP + \n (\"" + passwordHalf1 + "+\n 1+\n 2+\n 3+\n 4+\n 5+\n 6\")",
"ALTER QMGR SSLCRYP - \n(\"" + passwordHalf1 + "-\n1-\n2-\n3-\n4-\n5-\n6\")",
"ALTER QMGR SSL + \n CRYP(\"" + passwordHalf1 + "+\n 1+\n 2+\n 3+\n 4+\n 5+\n 6\")",
"ALTER QMGR SSL - \nCRYP(\"" + passwordHalf1 + "-\n1-\n2-\n3-\n4-\n5-\n6\")",
"ALTER QMGR + \n SSL +\n CRYP(\"" + passwordHalf1 + "+\n 1+\n 2+\n 3+\n 4+\n 5+\n 6\") +\n TEST(1234)",
"ALTER QMGR -\nSSL -\nCRYP(\"" + passwordHalf1 + "-\n1-\n2-\n3-\n4-\n5-\n6\") -\nTEST(1234)",
"ALTER QMGR +\n * COMMENT\n SSL +\n * COMMENT IN MIDDLE\n CRYP('" + passwordString + "')",
" 1: ALTER CHANNEL(TEST2) CHLTYPE(SDR) PASS+\n : *test comment\n : WORD('" + passwordString + "')",
" 2: ALTER CHANNEL(TEST3) CHLTYPE(SDR) PASSWORD('" + passwordHalf1 + "-\n*commentinmiddle with ' \n" + passwordHalf2 + "')",
" 3: ALTER CHANNEL(TEST3) CHLTYPE(SDR) PASSWORD('" + passwordHalf1 + "-\n*commentinmiddle with ') \n" + passwordHalf2 + "')",
}
var expected = [...]string{
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD " + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD\t\t" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) ldappwd" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LdApPwD" + redactionString,
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD" + redactionString,
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD" + redactionString,
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD " + redactionString,
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD\t\t" + redactionString,
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) password" + redactionString,
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) pAsSwOrD" + redactionString,
"ALTER QMGR SSLCRYP" + redactionString,
"ALTER QMGR SSLCRYP" + redactionString,
"ALTER QMGR SSLCRYP " + redactionString,
"ALTER QMGR SSLCRYP\t\t" + redactionString,
"ALTER QMGR sslcryp" + redactionString,
"ALTER QMGR sslCRYP" + redactionString,
// Line continuation ones
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE AUTHINFO(TEST) AUTHTYPE(IDPWLDAP) LDAPPWD" + redactionString,
"DEFINE CHANNEL(CHL) CHLTYPE(SOMETHING) PASSWORD" + redactionString,
"ALTER QMGR SSLCRYP" + redactionString,
//edge cases
"ALTER QMGR SSLCRYP" + redactionString,
"ALTER QMGR SSLCRYP" + redactionString,
"ALTER QMGR SSLCRYP" + redactionString,
"ALTER QMGR SSLCRYP" + redactionString,
"ALTER QMGR SSLCRYP + \n \t " + redactionString,
"ALTER QMGR SSLCRYP - \n " + redactionString,
"ALTER QMGR SSL + \n CRYP" + redactionString,
"ALTER QMGR SSL - \nCRYP" + redactionString,
"ALTER QMGR + \n SSL +\n CRYP" + redactionString + " +\n TEST(1234)",
"ALTER QMGR -\nSSL -\nCRYP" + redactionString + " -\nTEST(1234)",
"ALTER QMGR +\n * COMMENT\n SSL +\n * COMMENT IN MIDDLE\n CRYP" + redactionString,
"1: ALTER CHANNEL(TEST2) CHLTYPE(SDR) PASS+\n : *test comment\n : WORD" + redactionString,
"2: ALTER CHANNEL(TEST3) CHLTYPE(SDR) PASSWORD" + redactionString,
"3: ALTER CHANNEL(TEST3) CHLTYPE(SDR) PASSWORD" + redactionString,
}
// Returns true if the 2 strings are equal ignoring whitespace characters
func compareIgnoreWhiteSpace(str1, str2 string) bool {
whiteSpaces := [...]string{" ", "\t", "\n", "\r"}
for _, w := range whiteSpaces {
str1 = strings.Replace(str1, w, "", -1)
str2 = strings.Replace(str2, w, "", -1)
}
return str1 == str2
}
func TestAll(t *testing.T) {
for i, v := range testStrings {
back, _ := Redact(v)
if strings.Contains(back, passwordHalf1) || strings.Contains(back, passwordHalf2) || strings.Contains(back, passwordString) {
t.Errorf("MAJOR FAIL[%d]: Found an instance of the password. ", i)
}
if !compareIgnoreWhiteSpace(back, expected[i]) {
t.Errorf("FAIL[%d]:\nGave :%s\nexpected:%s\ngot :%s", i, v, expected[i], back)
}
}
}

Some files were not shown because too many files have changed in this diff Show More