Compare commits
847 Commits
v9.0.3
...
9.3.3.0-r1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3599852fc1 | ||
|
|
05fe51d96d | ||
|
|
1f7334e3d1 | ||
|
|
dfa8e1ba41 | ||
|
|
9a8582a7a9 | ||
|
|
57ffe4011d | ||
|
|
1d60dd7ce5 | ||
|
|
dc71321648 | ||
|
|
bc4f246a75 | ||
|
|
cc619bdd86 | ||
|
|
784f03875e | ||
|
|
1b7dd14555 | ||
|
|
91603a08b0 | ||
|
|
1766663a78 | ||
|
|
8ca5f31853 | ||
|
|
447e1c57ce | ||
|
|
0e95c1ca9e | ||
|
|
7d093b4340 | ||
|
|
33566bed16 | ||
|
|
e14ffb261a | ||
|
|
1d239647f4 | ||
|
|
f10e2facf8 | ||
|
|
bad1cfaa96 | ||
|
|
bddb9bfd3a | ||
|
|
53790e17c1 | ||
|
|
319c120625 | ||
|
|
8d7adc8581 | ||
|
|
60f7225442 | ||
|
|
38c55eae86 | ||
|
|
6084af2386 | ||
|
|
d2f7d3764e | ||
|
|
b47ad7fde2 | ||
|
|
167ec03f04 | ||
|
|
98129eb660 | ||
|
|
9c7f49d8d3 | ||
|
|
572e883841 | ||
|
|
26195d1bd9 | ||
|
|
c8d13e36e6 | ||
|
|
ca719539a7 | ||
|
|
b281d59577 | ||
|
|
5f0142acdc | ||
|
|
4588cd44f9 | ||
|
|
5c4422badf | ||
|
|
f2842d7eee | ||
|
|
4e9877722a | ||
|
|
8efaa55c4f | ||
|
|
537320a32d | ||
|
|
ed618dc6f6 | ||
|
|
862427306b | ||
|
|
e08a8121f1 | ||
|
|
7c4598bd87 | ||
|
|
d3a197e0f2 | ||
|
|
9518a6d3ed | ||
|
|
53af11ff0d | ||
|
|
88f72409e4 | ||
|
|
ecb71fcca7 | ||
|
|
794d1ed2b2 | ||
|
|
1ead807326 | ||
|
|
046517af63 | ||
|
|
13b4e0772d | ||
|
|
4af8458ba5 | ||
|
|
7ecb80540e | ||
|
|
00648afa87 | ||
|
|
98a1939577 | ||
|
|
0ddccb971d | ||
|
|
50260e1f57 | ||
|
|
a824b75bfa | ||
|
|
336d542ff1 | ||
|
|
4a9fd2965c | ||
|
|
ffd72e8b31 | ||
|
|
8182fc43ab | ||
|
|
63a05ad8e4 | ||
|
|
f6b1ff2afd | ||
|
|
8d996081cc | ||
|
|
15d21c594f | ||
|
|
bfd37e39c5 | ||
|
|
3adb91d9bb | ||
|
|
391f4b66d7 | ||
|
|
a8a281db5a | ||
|
|
05d63e3cbf | ||
|
|
467324dd26 | ||
|
|
8abe55b86c | ||
|
|
8db26ebbb0 | ||
|
|
34831f08a0 | ||
|
|
e9a3b79a90 | ||
|
|
c0a4fb9318 | ||
|
|
fb53af6e7b | ||
|
|
65a36fd896 | ||
|
|
b04ef21071 | ||
|
|
6acc28125f | ||
|
|
08c533ed99 | ||
|
|
45384755bb | ||
|
|
67b2a690c5 | ||
|
|
cdc2d0b16b | ||
|
|
4a66728b79 | ||
|
|
64e4976a43 | ||
|
|
1a45834865 | ||
|
|
2ff55a381b | ||
|
|
7c05f4cbcb | ||
|
|
6e10f3ba76 | ||
|
|
e7b641cb1b | ||
|
|
37187e5199 | ||
|
|
f86dcb1c36 | ||
|
|
ae82196402 | ||
|
|
bebb8e1559 | ||
|
|
a1eda64df3 | ||
|
|
813e1ac2dc | ||
|
|
3111d48330 | ||
|
|
b8dcbde7b7 | ||
|
|
c74cc13a3b | ||
|
|
35cc716fcb | ||
|
|
163873d7a8 | ||
|
|
0e18f17dc9 | ||
|
|
d6ea28ee6b | ||
|
|
093c6be85a | ||
|
|
28faa252a2 | ||
|
|
334df22cfd | ||
|
|
b32963854b | ||
|
|
ad153a3fc2 | ||
|
|
caa0fd6904 | ||
|
|
bd7e1193bf | ||
|
|
7c4d95aa2d | ||
|
|
7f8ffbf914 | ||
|
|
d3c543a42e | ||
|
|
4931e43b67 | ||
|
|
4e26150542 | ||
|
|
bf3d8dd26d | ||
|
|
7c58e2bea2 | ||
|
|
ae5b736f40 | ||
|
|
c1b092e0b1 | ||
|
|
adf7582e8b | ||
|
|
544c2d1e41 | ||
|
|
c3f60c5e24 | ||
|
|
b16246455e | ||
|
|
fdc447761c | ||
|
|
7f5563fa97 | ||
|
|
767381b2a0 | ||
|
|
3ad3e7ea16 | ||
|
|
f6fbc71092 | ||
|
|
0943d420bc | ||
|
|
48cac4fb6c | ||
|
|
c56ec8cd79 | ||
|
|
748d2fd11f | ||
|
|
24eb903b56 | ||
|
|
ebbe30ccf9 | ||
|
|
65e5d60984 | ||
|
|
2279f0b33c | ||
|
|
8fa8d8cb2a | ||
|
|
40d3a9e9ce | ||
|
|
6a8dcfae79 | ||
|
|
85976e1c08 | ||
|
|
4bf3c81e4e | ||
|
|
61e94ed50c | ||
|
|
5c964ef5f7 | ||
|
|
8db0023815 | ||
|
|
060a2e9655 | ||
|
|
d7595f46ff | ||
|
|
d2c11089c8 | ||
|
|
d7fd217770 | ||
|
|
00ada50f06 | ||
|
|
5d88af462f | ||
|
|
eff6ded259 | ||
|
|
2f103128f3 | ||
|
|
a48ac18522 | ||
|
|
1f6d37afed | ||
|
|
5f706e0282 | ||
|
|
1a8855547b | ||
|
|
d0062e71e8 | ||
|
|
353a671c27 | ||
|
|
a46177893c | ||
|
|
65c0ddb289 | ||
|
|
78203aaead | ||
|
|
7cba9ee95f | ||
|
|
7e6b01825b | ||
|
|
79d79ca3d6 | ||
|
|
1e415a30aa | ||
|
|
8461c8822a | ||
|
|
eac4363913 | ||
|
|
a3bf84bcea | ||
|
|
8284ac3169 | ||
|
|
68ef36fafb | ||
|
|
1af99634b4 | ||
|
|
53353c6bac | ||
|
|
a73303d6e6 | ||
|
|
18b0458fa5 | ||
|
|
44eeda157a | ||
|
|
062b29960f | ||
|
|
d4e38c6d85 | ||
|
|
25ba610c6a | ||
|
|
6d2ff0933a | ||
|
|
7a6afb4654 | ||
|
|
f5fdd1008f | ||
|
|
0857c654d2 | ||
|
|
480c3ee027 | ||
|
|
54076af43d | ||
|
|
608f255ab0 | ||
|
|
a927b6e01e | ||
|
|
987a7657ce | ||
|
|
94a78b3122 | ||
|
|
fcc458bf31 | ||
|
|
14987c1170 | ||
|
|
46b0ceede3 | ||
|
|
4bbb447e74 | ||
|
|
ebbbbb04ab | ||
|
|
54bad805c1 | ||
|
|
cecade9845 | ||
|
|
f61a08fe50 | ||
|
|
573fbb8fb1 | ||
|
|
e99c07192d | ||
|
|
9252465cab | ||
|
|
a778eb1cc9 | ||
|
|
2bf2052248 | ||
|
|
d903336fe0 | ||
|
|
b7dcff0bbc | ||
|
|
3e6ceb4bb9 | ||
|
|
b2767947a0 | ||
|
|
a24258834e | ||
|
|
76070234d4 | ||
|
|
d2ea17ec30 | ||
|
|
c0e05be791 | ||
|
|
12a2dee175 | ||
|
|
ac3dcdd0d0 | ||
|
|
4257f6a199 | ||
|
|
5fd9fc5e26 | ||
|
|
adbc95c5d5 | ||
|
|
99a1e4aa74 | ||
|
|
2ae82d71d6 | ||
|
|
8a2faf2955 | ||
|
|
1d41f4b138 | ||
|
|
e1c96655b1 | ||
|
|
68fe4a1dc1 | ||
|
|
adf15b7bd3 | ||
|
|
e77ac9617d | ||
|
|
54824879c5 | ||
|
|
bf8580248b | ||
|
|
e1978541db | ||
|
|
aa7580aa5a | ||
|
|
4366cd8c81 | ||
|
|
2a5242a4d9 | ||
|
|
a4dc545a4f | ||
|
|
f16ce5e4a4 | ||
|
|
03cdf67439 | ||
|
|
e8e86dcc92 | ||
|
|
abf969a64d | ||
|
|
34a55135fb | ||
|
|
dd1d534045 | ||
|
|
c39a532da9 | ||
|
|
efb35ff1b0 | ||
|
|
c2b8753c76 | ||
|
|
f8ae8b0be1 | ||
|
|
e8d26aa79e | ||
|
|
a3e3b0d8c6 | ||
|
|
23f31b1639 | ||
|
|
8d164340c6 | ||
|
|
94ad66661e | ||
|
|
f39f90728f | ||
|
|
a7125b7700 | ||
|
|
9f50b0efaa | ||
|
|
0d5ed76979 | ||
|
|
c37f8f1c4c | ||
|
|
f74777e498 | ||
|
|
55c094a58a | ||
|
|
3d6199e0d8 | ||
|
|
8111761c4f | ||
|
|
4fcdb50928 | ||
|
|
23eba2524e | ||
|
|
678a62f152 | ||
|
|
a2940a4ba8 | ||
|
|
70def702b8 | ||
|
|
f72dc51475 | ||
|
|
afe8aba912 | ||
|
|
444cadf864 | ||
|
|
c2d46d1dff | ||
|
|
6808af107b | ||
|
|
720ecae5bb | ||
|
|
490055e74c | ||
|
|
461529dd98 | ||
|
|
8d7085c18f | ||
|
|
b84581c7ee | ||
|
|
b9dd2f5e79 | ||
|
|
12bcf8b2da | ||
|
|
64a66f6590 | ||
|
|
cd69f6287f | ||
|
|
7dee4c82aa | ||
|
|
dc4675b99a | ||
|
|
ba493cbeb3 | ||
|
|
872050a2cd | ||
|
|
4737a8b660 | ||
|
|
9b81aedd9a | ||
|
|
c64c6fe95d | ||
|
|
a53fb7f49a | ||
|
|
d95e44f57c | ||
|
|
4b19af1dfe | ||
|
|
b4949aaf4f | ||
|
|
b9d48aa980 | ||
|
|
59baa97e91 | ||
|
|
394cb56ba0 | ||
|
|
62a2d6ef96 | ||
|
|
dcfebc38bd | ||
|
|
1ffc598064 | ||
|
|
fee0eac14c | ||
|
|
c56e305aec | ||
|
|
1bb39bc9fd | ||
|
|
c8de2df2cf | ||
|
|
7f14cc2751 | ||
|
|
35293e1b46 | ||
|
|
d2bc7b2adc | ||
|
|
f3777a499b | ||
|
|
f491d23d3b | ||
|
|
d4c3fad8c5 | ||
|
|
d9c8fc5c78 | ||
|
|
c1cbb62ee1 | ||
|
|
2fae0e2258 | ||
|
|
c9bac5b544 | ||
|
|
1a7a9236b7 | ||
|
|
6d69355ab9 | ||
|
|
49b4660360 | ||
|
|
ea38c9cd5c | ||
|
|
3ebd64f4da | ||
|
|
5e23d979d2 | ||
|
|
b64f8e8c21 | ||
|
|
2cbad648b9 | ||
|
|
88bcaaecc3 | ||
|
|
176a023a99 | ||
|
|
7f7883a312 | ||
|
|
84ea13eef2 | ||
|
|
4cab3e8d3b | ||
|
|
98ddca52ca | ||
|
|
3ba37b2b2b | ||
|
|
b4a3d7d732 | ||
|
|
3d5317f3da | ||
|
|
5891f170c8 | ||
|
|
f94d1b8af5 | ||
|
|
956b4a8e49 | ||
|
|
ce184408df | ||
|
|
140db42675 | ||
|
|
28b723d6cf | ||
|
|
61c909f551 | ||
|
|
ffda647cdf | ||
|
|
5897d6a644 | ||
|
|
34f7a57c5d | ||
|
|
5b5951ec3c | ||
|
|
b20761cea0 | ||
|
|
5449622d2a | ||
|
|
dd31fb37c3 | ||
|
|
2e453f2257 | ||
|
|
1f4528d597 | ||
|
|
c83aeb17c0 | ||
|
|
5a18280057 | ||
|
|
8e380b94f4 | ||
|
|
ebe8b7a6f0 | ||
|
|
ed4466d934 | ||
|
|
37601187b2 | ||
|
|
366d406f57 | ||
|
|
68ad98fc49 | ||
|
|
65edac267e | ||
|
|
ad0046ab01 | ||
|
|
c3fbc5816e | ||
|
|
11890d887b | ||
|
|
ac50d46c78 | ||
|
|
de298a4aad | ||
|
|
4de32ab8d2 | ||
|
|
8505579b37 | ||
|
|
7c59d647f5 | ||
|
|
8d8e4e4403 | ||
|
|
52b4eeea32 | ||
|
|
28291306cb | ||
|
|
4da7c60aee | ||
|
|
1ae24263ad | ||
|
|
d6248424a1 | ||
|
|
455c67ad3d | ||
|
|
f6ea588349 | ||
|
|
60fe631616 | ||
|
|
221796f746 | ||
|
|
97941bc87c | ||
|
|
b8a7167c4e | ||
|
|
dc00231ec1 | ||
|
|
8a8ea6c6a9 | ||
|
|
9714d0d513 | ||
|
|
6691438fa1 | ||
|
|
426c6c3b9a | ||
|
|
8088cb2902 | ||
|
|
a2ce23aa96 | ||
|
|
95ba16cdb2 | ||
|
|
83fe77b222 | ||
|
|
7ab30723cd | ||
|
|
3f9fc0eaa5 | ||
|
|
ee4351e55d | ||
|
|
ebf55608d7 | ||
|
|
b3fd5f7562 | ||
|
|
3c9ec5f14c | ||
|
|
81c0b70a6f | ||
|
|
a6f307c6b5 | ||
|
|
6f677e2a59 | ||
|
|
612fe3a9ec | ||
|
|
0a9c745d96 | ||
|
|
b64c060ef4 | ||
|
|
8e22763f16 | ||
|
|
40b64e620e | ||
|
|
700cc53c07 | ||
|
|
44d75b169c | ||
|
|
c0bf371b9e | ||
|
|
e362644a55 | ||
|
|
c079c1b60d | ||
|
|
4a3bdf3b53 | ||
|
|
5ff269d2e3 | ||
|
|
3fb2d3fe61 | ||
|
|
6c72c894f7 | ||
|
|
63af43f19d | ||
|
|
64bb5aed8a | ||
|
|
f05a7d3eaf | ||
|
|
723fe2b998 | ||
|
|
44d0e0a432 | ||
|
|
33defc0fc9 | ||
|
|
d69befed71 | ||
|
|
0934289b61 | ||
|
|
f6231cd51c | ||
|
|
d5f04bc470 | ||
|
|
d8cbf4566e | ||
|
|
493bc7bfd4 | ||
|
|
1fa4f6f148 | ||
|
|
ce664dd654 | ||
|
|
f8e057a1d6 | ||
|
|
efd550822d | ||
|
|
d4df05fd2a | ||
|
|
194b04ac13 | ||
|
|
6848038165 | ||
|
|
0d3e177147 | ||
|
|
13f620f21a | ||
|
|
d4a81741cc | ||
|
|
0047301335 | ||
|
|
5ef532d2c1 | ||
|
|
281cdc4578 | ||
|
|
d68c051104 | ||
|
|
c5a52e616c | ||
|
|
c441de7d26 | ||
|
|
a194545f08 | ||
|
|
4f57d1bae2 | ||
|
|
cc0f072908 | ||
|
|
d834ac7c9c | ||
|
|
2dbee560fe | ||
|
|
17d3238161 | ||
|
|
c08ca2e79f | ||
|
|
84df0e8362 | ||
|
|
cc213f429f | ||
|
|
c29159dd38 | ||
|
|
f345ccf920 | ||
|
|
d1b1cfc5d8 | ||
|
|
a19c455ea4 | ||
|
|
694b31d6e8 | ||
|
|
33f82d76ff | ||
|
|
77319629fe | ||
|
|
d9c70c48c5 | ||
|
|
599f5f4b53 | ||
|
|
6840a575f9 | ||
|
|
1b8c816f57 | ||
|
|
9a8ff9b524 | ||
|
|
f3c858184f | ||
|
|
43676049b7 | ||
|
|
df6ce917c2 | ||
|
|
d3eb6e0d3d | ||
|
|
2bfdd51a01 | ||
|
|
be11b3cda1 | ||
|
|
525ff82fe7 | ||
|
|
3e07814bf6 | ||
|
|
b1daacf377 | ||
|
|
9c8b3825be | ||
|
|
4145f077b6 | ||
|
|
c063ddd67d | ||
|
|
5f000ff891 | ||
|
|
e33710eb00 | ||
|
|
2fdd2c51ff | ||
|
|
b73ad12011 | ||
|
|
b276e0b4ef | ||
|
|
a3c0af9648 | ||
|
|
1208a5d08b | ||
|
|
fe8a87b39f | ||
|
|
9a34e9b15c | ||
|
|
78ce84b3a1 | ||
|
|
6d11b0d8ae | ||
|
|
d0fce28ef3 | ||
|
|
31f604cc47 | ||
|
|
c6a921efee | ||
|
|
822a073c4e | ||
|
|
a854c4c627 | ||
|
|
3989661778 | ||
|
|
9a7d44fef6 | ||
|
|
f73347a9cf | ||
|
|
ad1b2db1fd | ||
|
|
11b94de1c0 | ||
|
|
1906896038 | ||
|
|
d5ec1fa505 | ||
|
|
e03ceff7c9 | ||
|
|
64f5ce3624 | ||
|
|
b921bb82d3 | ||
|
|
92e57f2cb1 | ||
|
|
0281e52b47 | ||
|
|
8bdba41f75 | ||
|
|
aa04229d85 | ||
|
|
9e04bfc68a | ||
|
|
8fcdfeb1c4 | ||
|
|
a2d3abfb86 | ||
|
|
e66bcfd77f | ||
|
|
d2ea8d4f06 | ||
|
|
fc19776c04 | ||
|
|
3f07b1e77f | ||
|
|
00568adc6d | ||
|
|
ba1b4f8ef9 | ||
|
|
9b98555886 | ||
|
|
dbfc47591e | ||
|
|
b087f37505 | ||
|
|
08299dd0d1 | ||
|
|
b8f96d0148 | ||
|
|
6bb669d6ac | ||
|
|
80384a65a2 | ||
|
|
c11c0a2bf4 | ||
|
|
29dfe38d32 | ||
|
|
89eae35724 | ||
|
|
b751640b79 | ||
|
|
0bef0e224e | ||
|
|
7166727528 | ||
|
|
cafa841f63 | ||
|
|
f2a9bb4e9d | ||
|
|
e4f02d55cf | ||
|
|
59eaa9c7d2 | ||
|
|
79bfd99911 | ||
|
|
5583cc6fac | ||
|
|
75efeae51b | ||
|
|
7822c2c3bc | ||
|
|
f0e681e23f | ||
|
|
4b1b417b8b | ||
|
|
be0ce898d7 | ||
|
|
1800482934 | ||
|
|
65449ffea8 | ||
|
|
3a2efabdb7 | ||
|
|
bf330ee926 | ||
|
|
fcbb241f07 | ||
|
|
1e2ced3594 | ||
|
|
626fc05d78 | ||
|
|
ea7105c82c | ||
|
|
5c176cce15 | ||
|
|
854a0119de | ||
|
|
4d4051312e | ||
|
|
4ad8f269ee | ||
|
|
9624d7eeb0 | ||
|
|
7f51184821 | ||
|
|
62c7516465 | ||
|
|
ecace2b033 | ||
|
|
5a63591b18 | ||
|
|
29dcccad32 | ||
|
|
0769ebd309 | ||
|
|
1358b32f66 | ||
|
|
4ec2887047 | ||
|
|
74659dbf59 | ||
|
|
0b9a9186cf | ||
|
|
cd46078d2a | ||
|
|
0f9cd3f204 | ||
|
|
bff2f6bfae | ||
|
|
a1ae6b3a97 | ||
|
|
2e0aad0318 | ||
|
|
d6f689d515 | ||
|
|
4984beb139 | ||
|
|
6ded21daac | ||
|
|
32a3fdf2fd | ||
|
|
616cb179d6 | ||
|
|
d4d5e09a02 | ||
|
|
16e244427b | ||
|
|
f0faac6af7 | ||
|
|
aaa86d65e5 | ||
|
|
b887c1a277 | ||
|
|
4660c0622c | ||
|
|
b570a9f019 | ||
|
|
9805c1eaf8 | ||
|
|
63ce0b3377 | ||
|
|
2e3dee931c | ||
|
|
dae2a65e8b | ||
|
|
19f22cd994 | ||
|
|
172a4b0420 | ||
|
|
53fdfe55de | ||
|
|
16abf50f9a | ||
|
|
c409179f4a | ||
|
|
7551ce3812 | ||
|
|
4dfe8ed855 | ||
|
|
2939a9fd1a | ||
|
|
5d0a87ae0a | ||
|
|
2af6953b2b | ||
|
|
0f4e79c0a6 | ||
|
|
f8b500e0a1 | ||
|
|
bcfef94b08 | ||
|
|
ab01d124a9 | ||
|
|
be9c759a1c | ||
|
|
70f45d58bf | ||
|
|
143649deb6 | ||
|
|
0b36edae58 | ||
|
|
45e970e18a | ||
|
|
9f3032f014 | ||
|
|
54f0ae65a6 | ||
|
|
6996f2b9b3 | ||
|
|
987b629a27 | ||
|
|
00a0b1574b | ||
|
|
531f2710c7 | ||
|
|
1ce796a9e2 | ||
|
|
91e20f0f98 | ||
|
|
6f079ca0bb | ||
|
|
7f78ba89bf | ||
|
|
4bbdb36da0 | ||
|
|
a4b9a9abaf | ||
|
|
e251839639 | ||
|
|
9b595a0e01 | ||
|
|
6493e82fa6 | ||
|
|
3127abd5ad | ||
|
|
adad573f99 | ||
|
|
5d3519d9bb | ||
|
|
36a24d8864 | ||
|
|
e18dcbd8e8 | ||
|
|
5da57489e2 | ||
|
|
c389886d3c | ||
|
|
6775264bcc | ||
|
|
77c0cfa221 | ||
|
|
04bb404eee | ||
|
|
d8b6b78d66 | ||
|
|
8eb937b8e0 | ||
|
|
f051325deb | ||
|
|
3aa46e0793 | ||
|
|
bf36f8bb2c | ||
|
|
2be0501904 | ||
|
|
6895097d36 | ||
|
|
d7633d8313 | ||
|
|
818cbaca8d | ||
|
|
60d098d86d | ||
|
|
0075b5b727 | ||
|
|
13981cef86 | ||
|
|
363c8487df | ||
|
|
9d46e6e25a | ||
|
|
4826e83c9e | ||
|
|
1cba663922 | ||
|
|
c9e7ae194e | ||
|
|
d61cc9c686 | ||
|
|
20a2b3f593 | ||
|
|
a382984ab9 | ||
|
|
477d39da9f | ||
|
|
a6f4bdb598 | ||
|
|
e478f8cc67 | ||
|
|
2a858abff8 | ||
|
|
57b4eab2b6 | ||
|
|
55cfb59c75 | ||
|
|
88ca989b41 | ||
|
|
3be0d0d1dd | ||
|
|
a69c06dbf3 | ||
|
|
49e90d2e54 | ||
|
|
1affe991cc | ||
|
|
cde2a5186e | ||
|
|
c55d8f3956 | ||
|
|
460aec3863 | ||
|
|
3d569b3e8c | ||
|
|
831f0695a9 | ||
|
|
81e921162b | ||
|
|
f96304ae8f | ||
|
|
1752e45934 | ||
|
|
9851743ae2 | ||
|
|
ff016cf2be | ||
|
|
d56fce65c2 | ||
|
|
faea308506 | ||
|
|
6773496d99 | ||
|
|
3fcc7b4c6e | ||
|
|
516c8ecc41 | ||
|
|
eea80d139a | ||
|
|
2397966a86 | ||
|
|
3449dc31ad | ||
|
|
9a02ddfa48 | ||
|
|
7009f3a392 | ||
|
|
7c36a9ceea | ||
|
|
bec2e4457d | ||
|
|
9c71fa1c6c | ||
|
|
b41a58645b | ||
|
|
6f3672df4f | ||
|
|
28f2076882 | ||
|
|
fd0f0e0b3a | ||
|
|
ef04949036 | ||
|
|
f9ef635f37 | ||
|
|
6287a25156 | ||
|
|
ab5d7ca1d1 | ||
|
|
b02d8d27b2 | ||
|
|
13e41aeb37 | ||
|
|
f5beed0bef | ||
|
|
778cd07400 | ||
|
|
96311df366 | ||
|
|
89ee583336 | ||
|
|
4968ba2516 | ||
|
|
7e8c8b1f0f | ||
|
|
2910ae363c | ||
|
|
a525c8c380 | ||
|
|
9fb0170f1f | ||
|
|
189637e518 | ||
|
|
b40db6b816 | ||
|
|
3479455449 | ||
|
|
fa8867b9bd | ||
|
|
fcb7377575 | ||
|
|
0e71468826 | ||
|
|
749a459f33 | ||
|
|
2d59a94168 | ||
|
|
54885597fa | ||
|
|
94a4eac2ca | ||
|
|
357cfcba66 | ||
|
|
ab3b44e84b | ||
|
|
913465620b | ||
|
|
6ef3bfa28d | ||
|
|
401306b3ab | ||
|
|
e809d0959b | ||
|
|
ef4232dee5 | ||
|
|
37b650c367 | ||
|
|
4fc5460ac8 | ||
|
|
01331b0203 | ||
|
|
b240a84ce0 | ||
|
|
c75aed0851 | ||
|
|
d495b3640e | ||
|
|
98c594c91e | ||
|
|
6b4720a07c | ||
|
|
10e448056b | ||
|
|
1b350549cc | ||
|
|
104098c7b4 | ||
|
|
a14da7aaa8 | ||
|
|
ab60a8975f | ||
|
|
9c072060df | ||
|
|
6f8b47a670 | ||
|
|
8710721fe3 | ||
|
|
37e07fc0b0 | ||
|
|
97f5f44b92 | ||
|
|
e07110108f | ||
|
|
1e0ba3d897 | ||
|
|
782fe367a5 | ||
|
|
e1829f3f47 | ||
|
|
91bf65ab57 | ||
|
|
b497a04dcb | ||
|
|
c9cc1741c7 | ||
|
|
d70bbe4dfa | ||
|
|
cb475e8dde | ||
|
|
c30a8e4223 | ||
|
|
02cce7ab96 | ||
|
|
8c92e02a23 | ||
|
|
0845025cf8 | ||
|
|
3600841e2b | ||
|
|
05d1c6f0de | ||
|
|
ace6e6364c | ||
|
|
b23ec084fa | ||
|
|
e65d679a21 | ||
|
|
b62a883d4c | ||
|
|
9b8e32cbf0 | ||
|
|
4cdf03a77c | ||
|
|
2312842a9f | ||
|
|
911f9db2fd | ||
|
|
54a5052631 | ||
|
|
1d223f3157 | ||
|
|
cf687196b7 | ||
|
|
47c865d497 | ||
|
|
40c7ab927e | ||
|
|
3f4dd2dd3a | ||
|
|
b24e375912 | ||
|
|
48185668af | ||
|
|
cbfa24a267 | ||
|
|
0459880a65 | ||
|
|
741aa18da9 | ||
|
|
eab783f3c5 | ||
|
|
a03bad9ee7 | ||
|
|
81bba0db32 | ||
|
|
753612530f | ||
|
|
f565e9fe66 | ||
|
|
ce40e207a4 | ||
|
|
ed1154c881 | ||
|
|
d1852d9af4 | ||
|
|
0eacad5848 | ||
|
|
bf4cdfc906 | ||
|
|
238529918c | ||
|
|
20b54f35ce | ||
|
|
bf31513b99 | ||
|
|
451ea00aed | ||
|
|
095009dba0 | ||
|
|
fe23ec9aaa | ||
|
|
45f53082aa | ||
|
|
f6c583df0b | ||
|
|
ee94b1702a | ||
|
|
64867944a3 | ||
|
|
b938a5eb95 | ||
|
|
b6b72952e4 | ||
|
|
aeefd0a9fc | ||
|
|
a2326dc0f6 | ||
|
|
93389309f4 | ||
|
|
d6182bf2fc | ||
|
|
499c6d4b18 | ||
|
|
18635b704c | ||
|
|
878442905d | ||
|
|
b66a799d7f | ||
|
|
584a4f2eb4 | ||
|
|
c297e1bf5d | ||
|
|
abbc8ce852 | ||
|
|
176543e100 | ||
|
|
f5515d72a3 | ||
|
|
70f1a43fd8 | ||
|
|
81b5db4969 | ||
|
|
2f3ca70d7b | ||
|
|
a80b839c14 | ||
|
|
5b0259ec6e | ||
|
|
0ad595dc99 | ||
|
|
0823fd1cea | ||
|
|
f3a1f94445 | ||
|
|
5780ec2a26 | ||
|
|
7ea6b4c610 | ||
|
|
4aa8918745 | ||
|
|
4200d9df1b | ||
|
|
f492171276 | ||
|
|
d674334574 | ||
|
|
fef9ab4f06 | ||
|
|
46110436b8 | ||
|
|
5e787ba4cf | ||
|
|
099397442b | ||
|
|
3848c39147 | ||
|
|
3bbdeec3f0 | ||
|
|
faf6c4bc08 | ||
|
|
15acd8ccdc | ||
|
|
fceac2d4b8 | ||
|
|
3da06b27a5 | ||
|
|
f65b06be3c | ||
|
|
35043ee488 | ||
|
|
4874483f9c | ||
|
|
3721dbdb31 | ||
|
|
0fdda62e34 | ||
|
|
781ce07e9c | ||
|
|
d4fae78a66 | ||
|
|
7c91187ce3 | ||
|
|
3cc1a09d48 | ||
|
|
f720eb2338 | ||
|
|
de28a7030a | ||
|
|
8c4daa9554 | ||
|
|
9c9a2e1e91 | ||
|
|
e6c4a21726 | ||
|
|
0ffa87be31 | ||
|
|
7efcef67e0 | ||
|
|
c7c1db9b1a | ||
|
|
6195ff892e | ||
|
|
a8bb8084b3 | ||
|
|
721c2e616e | ||
|
|
9a05a1d5d1 | ||
|
|
ab12ded727 | ||
|
|
68f679d0be | ||
|
|
774cf26ac6 | ||
|
|
72228f3119 | ||
|
|
ef92f58805 |
@@ -1,6 +0,0 @@
|
||||
charts
|
||||
cmd
|
||||
downloads
|
||||
pkg
|
||||
test
|
||||
vendor
|
||||
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Fore LF line endings to prevent errors in Bash on Windows
|
||||
* text=auto
|
||||
*.sh text eol=lf
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -1,7 +1,23 @@
|
||||
.dockerignore
|
||||
.DS_Store
|
||||
.vscode
|
||||
test/docker/coverage
|
||||
test/docker/vendor
|
||||
test/kubernetes/vendor
|
||||
build
|
||||
coverage
|
||||
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
|
||||
internal/qmgrauth/qmgroam/patch
|
||||
.tagcache
|
||||
|
||||
# Nix
|
||||
*.nix
|
||||
.envrc
|
||||
.direnv
|
||||
result
|
||||
|
||||
100
.travis.yml
100
.travis.yml
@@ -1,25 +1,101 @@
|
||||
# © Copyright IBM Corporation 2018, 2023
|
||||
#
|
||||
# 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: bionic
|
||||
group: beta
|
||||
sudo: required
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.9
|
||||
- "1.19.9"
|
||||
|
||||
services:
|
||||
- docker
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAIN_BRANCH=private-master
|
||||
- TAGCACHE_FILE=tagcache
|
||||
- RELEASE=r1
|
||||
|
||||
go_import_path: "github.com/ibm-messaging/mq-container"
|
||||
|
||||
# cache:
|
||||
# directories:
|
||||
# - downloads
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: basic-build
|
||||
if: branch != private-master AND tag IS blank
|
||||
name: "Basic AMD64 build"
|
||||
os: linux
|
||||
env:
|
||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||
script: bash -e travis-build-scripts/run.sh
|
||||
|
||||
# CD Build
|
||||
|
||||
- stage: global-tag
|
||||
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
|
||||
name: "Generate Global Tag"
|
||||
os: linux
|
||||
script: bash -e travis-build-scripts/global-tag.sh
|
||||
- stage: build
|
||||
if: branch = private-master OR tag =~ ^release-candidate*
|
||||
name: "Multi-Arch AMD64 build"
|
||||
os: linux
|
||||
env:
|
||||
- BUILD_ALL=true
|
||||
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_AMD64
|
||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_AMD64
|
||||
script: bash -e travis-build-scripts/run.sh
|
||||
- stage: build
|
||||
if: branch = private-master OR tag =~ ^release-candidate*
|
||||
name: "Multi-Arch S390X build"
|
||||
os: linux-s390
|
||||
env:
|
||||
- BUILD_ALL=true
|
||||
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_S390X
|
||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_S390X
|
||||
script: bash -e travis-build-scripts/run.sh
|
||||
- stage: build
|
||||
if: branch = private-master OR tag =~ ^release-candidate*
|
||||
name: "Multi-Arch PPC64LE build"
|
||||
os: linux-ppc64le
|
||||
env:
|
||||
- BUILD_ALL=true
|
||||
- TEST_OPTS_DOCKER="-run TestGoldenPathWithMetrics"
|
||||
- MQ_ARCHIVE_REPOSITORY=$MQ_933_ARCHIVE_REPOSITORY_PPC64LE
|
||||
- MQ_ARCHIVE_REPOSITORY_DEV=$MQ_933_ARCHIVE_REPOSITORY_DEV_PPC64LE
|
||||
script: bash -e travis-build-scripts/run.sh
|
||||
- stage: push-manifest
|
||||
if: branch = private-master AND type != pull_request OR tag =~ ^release-candidate*
|
||||
name: "Push Manifest-list to registry"
|
||||
env:
|
||||
- PUSH_MANIFEST_ONLY=true
|
||||
script: bash -e travis-build-scripts/run.sh
|
||||
|
||||
before_install:
|
||||
- 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
|
||||
- make install-build-deps
|
||||
- make install-credential-helper
|
||||
|
||||
install:
|
||||
- echo nothing
|
||||
|
||||
before_script:
|
||||
- make deps
|
||||
before_script: echo nothing
|
||||
|
||||
script:
|
||||
- make build-devserver
|
||||
- make test-devserver
|
||||
after_success:
|
||||
- make lint
|
||||
|
||||
10
.whitesource
Normal file
10
.whitesource
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"settingsInheritedFrom": "whitesource-config/whitesource-config@master",
|
||||
"scanSettings": {
|
||||
"configMode": "LOCAL",
|
||||
"baseBranches": ["private-master", "v9.2.0.x-eus", "v9.3.0.x"]
|
||||
},
|
||||
"issueSettings": {
|
||||
"issueRepoName": "whitesource-scan-issues"
|
||||
}
|
||||
}
|
||||
161
CHANGELOG.md
Normal file
161
CHANGELOG.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Change log
|
||||
|
||||
## 9.3.3.0 (2023-06)
|
||||
|
||||
* Updated to MQ version 9.3.3.0
|
||||
|
||||
## 9.3.2.0 (2023-02)
|
||||
|
||||
* Updated to MQ version 9.3.2.0
|
||||
* Queue manager certificates with the same Subject Distinguished Name (DN) as the issuer (CA) certificate are not supported. A certificate must have a unique Subject Distinguished Name.
|
||||
* New logging environment variables: MQ_LOGGING_CONSOLE_SOURCE, MQ_LOGGING_CONSOLE_FORMAT, MQ_LOGGING_CONSOLE_EXCLUDE_ID. The LOG_FORMAT variable is deprecated.
|
||||
* New environment variable: MQ_QMGR_LOG_FILE_PAGES
|
||||
|
||||
## 9.3.1.0-r2 (2022-11)
|
||||
|
||||
* Queue manager attribute SSLKEYR is now set to blank instead of '/run/runmqserver/tls/key' if key and certificate are not supplied.
|
||||
|
||||
## 9.3.1.0 (2022-10)
|
||||
|
||||
* Updated to MQ version 9.3.1.0
|
||||
|
||||
## 9.3.0.0 (2022-06)
|
||||
|
||||
* Updated to MQ version 9.3.0.0
|
||||
* Use `registry.access.redhat.com` instead of `registry.redhat.io`, so that you don't need to login with a Red Hat account.
|
||||
* Updated default developer config to use TLS cipher `ANY_TLS12_OR_HIGHER` instead of `ANY_TLS12`
|
||||
* Added default `jvm.options` file fix issue with missing preferences file causing an error in the web server log.
|
||||
* Updated to allow building image from Podman on macOS (requires Podman 4.1)
|
||||
* Container builds are now faster
|
||||
* Updated signal handling to use a buffer, as recommended by the Go 1.17 vetting tool
|
||||
|
||||
## 9.2.5.0 (2022-03)
|
||||
|
||||
* Updated to MQ version 9.2.5.0
|
||||
|
||||
## 9.2.4.0 (2021-11)
|
||||
|
||||
* Updated to MQ version 9.2.4.0
|
||||
|
||||
## 9.2.3.0 (2021-07-22)
|
||||
|
||||
* Updated to MQ version 9.2.3.0
|
||||
|
||||
## 9.2.2.0 (2021-03-26)
|
||||
|
||||
* Updated to MQ version 9.2.2.0
|
||||
|
||||
## 9.2.1.0 (2020-02-18)
|
||||
|
||||
* Updated to MQ version 9.2.1.0
|
||||
|
||||
|
||||
## 9.2.0.1-LTS (2020-12-04)
|
||||
|
||||
* Added support for MQ Long Term Support (production licensed only) in the mq-container
|
||||
|
||||
## 9.2.0.0 (2020-07-23)
|
||||
|
||||
* Updated to [MQ version 9.2.0.0](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.2.0/com.ibm.mq.pro.doc/q113110_.htm)
|
||||
* Use `-ic` arguments with `crtmqm` to process MQSC files in `/etc/mqm`. Replaces previous use of "runmqsc" commands
|
||||
|
||||
## 9.1.5.0 (2020-04-02)
|
||||
|
||||
* Updated to MQ version 9.1.5.0
|
||||
* Can now run as a random user, instead of the "mqm" user, which has now been removed. This adds compatability for the [Red Hat OpenShift restricted SCC](https://docs.openshift.com/container-platform/4.3/authentication/managing-security-context-constraints.html#security-context-constraints-about_configuring-internal-oauth). The default image UID is `1001`.
|
||||
|
||||
## 9.1.4.0 (2019-12-06)
|
||||
|
||||
* Updated to MQ version 9.1.4.0
|
||||
* 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)
|
||||
|
||||
* Updated to MQ version 9.0.4.0
|
||||
* Updated to Go version 9
|
||||
* Removed packages `curl`, `ca-certificates`, and their dependencies, which were only used at build time
|
||||
* Improved logging
|
||||
* Helm charts now work on Kubernetes V1.6
|
||||
* Production Helm chart now includes a default image repository and tag
|
||||
* Updated to use multi-stage Docker build, so that Go code is built inside a container
|
||||
|
||||
## 9.0.3 (2017-10-17)
|
||||
|
||||
* Initial version
|
||||
@@ -1,50 +0,0 @@
|
||||
# © Copyright IBM Corporation 2015, 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.
|
||||
|
||||
FROM ubuntu:16.04
|
||||
|
||||
LABEL "ProductID"="4486e8c4cc9146fd9b3ce1f14a2dfc5b" \
|
||||
"ProductName"="IBM MQ Advanced for Developers" \
|
||||
"ProductVersion"="9.0.3"
|
||||
|
||||
# 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=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||
|
||||
# The MQ packages to install
|
||||
ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams"
|
||||
|
||||
COPY install-mq.sh /usr/local/bin/
|
||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
||||
# To avoid a "text file busy" error here we sleep before installing.
|
||||
&& sleep 1 && install-mq.sh
|
||||
|
||||
COPY build/runmqserver /usr/local/bin/
|
||||
COPY build/chkmq* /usr/local/bin/
|
||||
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
||||
|
||||
# MQ default developer config
|
||||
COPY dev/mq-dev-config /etc/mqm/mq-dev-config
|
||||
COPY dev/mq-dev-config.sh /usr/local/bin/
|
||||
COPY dev/admin.json /etc/mqm/
|
||||
|
||||
RUN chmod +x /usr/local/bin/runmqserver \
|
||||
&& chmod +x /usr/local/bin/chk*
|
||||
|
||||
# Always use port 1414
|
||||
EXPOSE 1414
|
||||
|
||||
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1
|
||||
|
||||
ENTRYPOINT ["runmqserver"]
|
||||
@@ -1,4 +1,4 @@
|
||||
# © Copyright IBM Corporation 2015, 2017
|
||||
# © Copyright IBM Corporation 2015, 2023
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -12,38 +12,192 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM ubuntu:16.04
|
||||
ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal
|
||||
ARG BASE_TAG=8.8-860
|
||||
ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset
|
||||
ARG BUILDER_TAG=1.19.9-2
|
||||
ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container
|
||||
ARG MQ_ARCHIVE="downloads/9.3.3.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"
|
||||
|
||||
ARG IBM_PRODUCT_ID
|
||||
ARG IBM_PRODUCT_NAME
|
||||
ARG IBM_PRODUCT_VERSION
|
||||
###############################################################################
|
||||
# Build stage to build Go code
|
||||
###############################################################################
|
||||
FROM $BUILDER_IMAGE:$BUILDER_TAG as builder
|
||||
ARG IMAGE_REVISION="Not specified"
|
||||
ARG IMAGE_SOURCE="Not specified"
|
||||
ARG IMAGE_TAG="Not specified"
|
||||
ARG GO_WORKDIR
|
||||
ARG MQ_ARCHIVE
|
||||
USER 0
|
||||
WORKDIR $GO_WORKDIR/
|
||||
ADD $MQ_ARCHIVE /opt/mqm
|
||||
ENV CGO_CFLAGS="-I/opt/mqm/inc/" \
|
||||
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
|
||||
PATH="${PATH}:/opt/mqm/bin"
|
||||
COPY go.mod go.sum ./
|
||||
COPY cmd/ ./cmd
|
||||
COPY internal/ ./internal
|
||||
COPY pkg/ ./pkg
|
||||
COPY vendor/ ./vendor
|
||||
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/ \
|
||||
&& go build ./cmd/chkmqready/ \
|
||||
&& go build ./cmd/chkmqhealthy/ \
|
||||
&& go build ./cmd/chkmqstarted/ \
|
||||
&& go build ./cmd/runmqdevserver/ \
|
||||
&& go test -v ./cmd/runmqdevserver/... \
|
||||
&& go test -v ./cmd/runmqserver/ \
|
||||
&& go test -v ./cmd/chkmqready/ \
|
||||
&& go test -v ./cmd/chkmqhealthy/ \
|
||||
&& go test -v ./cmd/chkmqstarted/ \
|
||||
&& go test -v ./pkg/... \
|
||||
&& go test -v ./internal/... \
|
||||
&& go vet ./cmd/... ./internal/...
|
||||
|
||||
# The URL to download the MQ installer from in tar.gz format
|
||||
# This assumes an archive containing the MQ Debian (.deb) install packages
|
||||
###############################################################################
|
||||
# Build stage to reduce MQ packages included using genmqpkg
|
||||
###############################################################################
|
||||
FROM $BASE_IMAGE:$BASE_TAG AS mq-redux
|
||||
ARG BASE_IMAGE
|
||||
ARG BASE_TAG
|
||||
ARG MQ_ARCHIVE
|
||||
WORKDIR /tmp/mq
|
||||
ENV genmqpkg_inc32=0 \
|
||||
genmqpkg_incadm=1 \
|
||||
genmqpkg_incamqp=0 \
|
||||
genmqpkg_incams=1 \
|
||||
genmqpkg_inccbl=0 \
|
||||
genmqpkg_inccics=0 \
|
||||
genmqpkg_inccpp=0 \
|
||||
genmqpkg_incdnet=0 \
|
||||
genmqpkg_incjava=1 \
|
||||
genmqpkg_incjre=1 \
|
||||
genmqpkg_incman=0 \
|
||||
genmqpkg_incmqbc=0 \
|
||||
genmqpkg_incmqft=0 \
|
||||
genmqpkg_incmqsf=0 \
|
||||
genmqpkg_incmqxr=0 \
|
||||
genmqpkg_incnls=1 \
|
||||
genmqpkg_incras=1 \
|
||||
genmqpkg_incsamp=1 \
|
||||
genmqpkg_incsdk=0 \
|
||||
genmqpkg_inctls=1 \
|
||||
genmqpkg_incunthrd=0 \
|
||||
genmqpkg_incweb=1
|
||||
ADD $MQ_ARCHIVE /opt/mqm-noinstall
|
||||
# Run genmqpkg to reduce the MQ packages included
|
||||
RUN /opt/mqm-noinstall/bin/genmqpkg.sh -b /opt/mqm-redux
|
||||
|
||||
###############################################################################
|
||||
# Main build stage, to build MQ image
|
||||
###############################################################################
|
||||
FROM $BASE_IMAGE:$BASE_TAG AS mq-server
|
||||
ARG MQ_URL
|
||||
|
||||
# The MQ packages to install
|
||||
ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams"
|
||||
|
||||
LABEL "ProductID"=$IBM_PRODUCT_ID \
|
||||
"ProductName"=$IBM_PRODUCT_NAME \
|
||||
"ProductVersion"=$IBM_PRODUCT_VERSION
|
||||
|
||||
COPY install-mq.sh /usr/local/bin/
|
||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
||||
# To avoid a "text file busy" error here we sleep before installing.
|
||||
&& sleep 1 && install-mq.sh
|
||||
|
||||
COPY build/runmqserver /usr/local/bin/
|
||||
COPY build/chkmq* /usr/local/bin/
|
||||
ARG BASE_IMAGE
|
||||
ARG BASE_TAG
|
||||
ARG GO_WORKDIR
|
||||
LABEL summary="IBM MQ Advanced Server" \
|
||||
description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises" \
|
||||
vendor="IBM" \
|
||||
maintainer="IBM" \
|
||||
distribution-scope="private" \
|
||||
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
|
||||
url="https://www.ibm.com/products/mq/advanced" \
|
||||
io.openshift.tags="mq messaging" \
|
||||
io.k8s.display-name="IBM MQ Advanced Server" \
|
||||
io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises" \
|
||||
base-image=$BASE_IMAGE \
|
||||
base-image-release=$BASE_TAG
|
||||
COPY --from=mq-redux /opt/mqm-redux/ /opt/mqm/
|
||||
COPY setup-image.sh /usr/local/bin/
|
||||
COPY install-mq-server-prereqs.sh /usr/local/bin/
|
||||
RUN env \
|
||||
&& chmod u+x /usr/local/bin/install-*.sh \
|
||||
&& chmod u+x /usr/local/bin/setup-image.sh \
|
||||
&& install-mq-server-prereqs.sh \
|
||||
&& setup-image.sh \
|
||||
&& /opt/mqm/bin/security/amqpamcf \
|
||||
&& chown -R 1001:root /opt/mqm/*
|
||||
COPY --from=builder $GO_WORKDIR/runmqserver /usr/local/bin/
|
||||
COPY --from=builder $GO_WORKDIR/chkmq* /usr/local/bin/
|
||||
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
||||
|
||||
RUN chmod +x /usr/local/bin/runmqserver \
|
||||
&& chmod +x /usr/local/bin/chkmq*
|
||||
|
||||
# Always use port 1414
|
||||
EXPOSE 1414
|
||||
|
||||
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1
|
||||
|
||||
COPY ha/native-ha.ini.tpl /etc/mqm/native-ha.ini.tpl
|
||||
# Copy web XML files
|
||||
COPY web /etc/mqm/web
|
||||
COPY etc/mqm/*.tpl /etc/mqm/
|
||||
RUN chmod ug+x /usr/local/bin/runmqserver \
|
||||
&& chown 1001:root /usr/local/bin/*mq* \
|
||||
&& chmod ug+x /usr/local/bin/chkmq* \
|
||||
&& chown -R 1001:root /etc/mqm/* \
|
||||
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqserver \
|
||||
&& touch /run/termination-log \
|
||||
&& chown 1001:root /run/termination-log \
|
||||
&& chmod 0660 /run/termination-log \
|
||||
&& chmod -R g+w /etc/mqm/web
|
||||
# Always use port 1414 for MQ & 9157 for the metrics
|
||||
EXPOSE 1414 9157 9443
|
||||
ENV MQ_OVERRIDE_DATA_PATH=/mnt/mqm/data MQ_OVERRIDE_INSTALLATION_NAME=Installation1 MQ_USER_NAME="mqm" PATH="${PATH}:/opt/mqm/bin"
|
||||
ENV MQ_GRACE_PERIOD=30
|
||||
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1 AMQ_ADDITIONAL_JSON_LOG=1
|
||||
ENV MQ_LOGGING_CONSOLE_EXCLUDE_ID=AMQ5041I,AMQ5052I,AMQ5051I,AMQ5037I,AMQ5975I
|
||||
ENV WLP_LOGGING_MESSAGE_FORMAT=json
|
||||
# We can run as any UID
|
||||
USER 1001
|
||||
ENV MQ_CONNAUTH_USE_HTP=false
|
||||
ENTRYPOINT ["runmqserver"]
|
||||
|
||||
###############################################################################
|
||||
# Build stage to build C code for custom authorization service (developer-only)
|
||||
###############################################################################
|
||||
# Use the Go toolset image, which already includes gcc and the MQ SDK
|
||||
FROM builder as cbuilder
|
||||
USER 0
|
||||
# Install the Apache Portable Runtime code (used for htpasswd hash checking)
|
||||
RUN yum --assumeyes --disableplugin=subscription-manager install apr-devel apr-util-openssl apr-util-devel
|
||||
COPY authservice/ /opt/app-root/src/authservice/
|
||||
WORKDIR /opt/app-root/src/authservice/mqhtpass
|
||||
RUN make all
|
||||
|
||||
###############################################################################
|
||||
# Add default developer config
|
||||
###############################################################################
|
||||
FROM mq-server AS mq-dev-server
|
||||
ARG BASE_IMAGE
|
||||
ARG BASE_TAG
|
||||
ARG GO_WORKDIR
|
||||
LABEL summary="IBM MQ Advanced for Developers Server" \
|
||||
description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises" \
|
||||
vendor="IBM" \
|
||||
distribution-scope="private" \
|
||||
authoritative-source-url="https://www.ibm.com/software/passportadvantage/" \
|
||||
url="https://www.ibm.com/products/mq/advanced" \
|
||||
io.openshift.tags="mq messaging" \
|
||||
io.k8s.display-name="IBM MQ Advanced for Developers Server" \
|
||||
io.k8s.description="Simplify, accelerate and facilitate the reliable exchange of data with a security-rich messaging solution — trusted by the world’s most successful enterprises" \
|
||||
base-image=$BASE_IMAGE \
|
||||
base-image-release=$BASE_TAG
|
||||
USER 0
|
||||
COPY --from=cbuilder /opt/app-root/src/authservice/mqhtpass/build/mqhtpass.so /opt/mqm/lib64/
|
||||
COPY etc/mqm/*.ini /etc/mqm/
|
||||
COPY etc/mqm/mq.htpasswd /etc/mqm/
|
||||
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
|
||||
COPY --from=builder $GO_WORKDIR/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 1001:root /etc/mqm/* \
|
||||
&& chmod -R g+w /etc/mqm/web \
|
||||
&& chmod +x /usr/local/bin/runmq* \
|
||||
&& chmod 0660 /etc/mqm/mq.htpasswd \
|
||||
&& install --directory --mode 2775 --owner 1001 --group root /run/runmqdevserver
|
||||
ENV MQ_DEV=true \
|
||||
MQ_ENABLE_EMBEDDED_WEB_SERVER=1 \
|
||||
MQ_GENERATE_CERTIFICATE_HOSTNAME=localhost \
|
||||
LD_LIBRARY_PATH=/opt/mqm/lib64 \
|
||||
MQ_CONNAUTH_USE_HTP=true \
|
||||
MQS_PERMIT_UNKNOWN_ID=true
|
||||
USER 1001
|
||||
ENTRYPOINT ["runmqdevserver"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# © Copyright IBM Corporation 2017
|
||||
# © 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.
|
||||
@@ -12,11 +12,21 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# 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 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 \
|
||||
&& mkdir -p /var/coverage/
|
||||
|
||||
ENTRYPOINT ["runmqserver.test", "-test", "-test.coverprofile", "/var/coverage/coverage.cov"]
|
||||
ENTRYPOINT ["runmqserver.test", "-test", "-test.coverprofile", "/var/coverage/container.cov"]
|
||||
|
||||
15
LICENSE
15
LICENSE
@@ -176,18 +176,7 @@
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
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]
|
||||
© 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.
|
||||
@@ -199,4 +188,4 @@
|
||||
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.
|
||||
limitations under the License.
|
||||
|
||||
648
Makefile
648
Makefile
@@ -1,4 +1,4 @@
|
||||
# © Copyright IBM Corporation 2017
|
||||
# © Copyright IBM Corporation 2017, 2023
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -12,153 +12,561 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
BUILD_SERVER_CONTAINER=build-server
|
||||
export GOARCH ?= amd64
|
||||
# Don't set GOOS globally, so that tests can be run locally
|
||||
DOCKER_TAG_ARCH ?= x86_64
|
||||
DOCKER_TAG ?= latest-$(DOCKER_TAG_ARCH)
|
||||
DOCKER_REPO_DEVSERVER ?= mq-devserver
|
||||
DOCKER_REPO_ADVANCEDSERVER ?= mq-advancedserver
|
||||
DOCKER_FULL_DEVSERVER = $(DOCKER_REPO_DEVSERVER):$(DOCKER_TAG)
|
||||
DOCKER_FULL_ADVANCEDSERVER = $(DOCKER_REPO_ADVANCEDSERVER):$(DOCKER_TAG)
|
||||
# Options to `go test` for the Docker tests
|
||||
TEST_OPTS_DOCKER ?=
|
||||
# Options to `go test` for the Kubernetes tests
|
||||
TEST_OPTS_KUBERNETES ?=
|
||||
###############################################################################
|
||||
# Conditional variables - you can override the values of these variables from
|
||||
# the command line
|
||||
###############################################################################
|
||||
|
||||
include config.env
|
||||
include source-branch.env
|
||||
|
||||
# arch_uname is the platform architecture according to the uname program. Can be differ by OS, e.g. `arm64` on macOS, but `aarch64` on Linux.
|
||||
arch_uname := $(shell uname -m)
|
||||
# arch_go is the platform architecture in Go-style (e.g. amd64, ppc64le, s390x or arm64).
|
||||
arch_go := $(if $(findstring x86_64,$(arch_uname)),amd64,$(if $(findstring aarch64,$(arch_uname)),arm64,$(arch_uname)))
|
||||
# ARCH is the platform architecture in Go-style (e.g. amd64, ppc64le, s390x or arm64).
|
||||
# Override this to build an image for a different architecture. Note that RUN instructions will not be able to succeed without the help of emulation provided by packages like qemu-user-static.
|
||||
ARCH ?= $(arch_go)
|
||||
# RELEASE shows what release of the container code has been built
|
||||
RELEASE ?=
|
||||
# MQ_ARCHIVE_REPOSITORY is a remote repository from which to pull the MQ_ARCHIVE (if required)
|
||||
MQ_ARCHIVE_REPOSITORY ?=
|
||||
# MQ_ARCHIVE_REPOSITORY_DEV is a remote repository from which to pull the MQ_ARCHIVE_DEV (if required)
|
||||
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. Does not apply to MQ Advanced for Developers
|
||||
MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION_VRM)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH)_NOINST.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_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-$(MQ_ARCHIVE_DEV_TYPE)$(MQ_ARCHIVE_DEV_ARCH).tar.gz
|
||||
# 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 Container tests
|
||||
TEST_OPTS_CONTAINER ?=
|
||||
# Timeout for the tests
|
||||
TEST_TIMEOUT_CONTAINER ?= 45m
|
||||
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
||||
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
||||
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
||||
MQ_IMAGE_DEVSERVER ?=ibm-mqadvanced-server-dev
|
||||
# MQ_MANIFEST_TAG is the tag to use for fat-manifest
|
||||
MQ_MANIFEST_TAG ?= $(MQ_VERSION)$(RELEASE_TAG)$(LTS_TAG)$(MQ_MANIFEST_TAG_SUFFIX)
|
||||
# MQ_TAG is the tag of the built MQ Advanced image & MQ Advanced for Developers image
|
||||
MQ_TAG ?= $(MQ_MANIFEST_TAG)-$(ARCH)
|
||||
# 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 ?=
|
||||
# LTS is a boolean value to enable/disable LTS container build
|
||||
LTS ?= false
|
||||
# VOLUME_MOUNT_OPTIONS is used when bind-mounting files from the "downloads" directory into the container. By default, SELinux labels are automatically re-written, but this doesn't work on some filesystems with extended attributes (xattrs). You can turn off the label re-writing by setting this variable to be blank.
|
||||
VOLUME_MOUNT_OPTIONS ?= :Z
|
||||
|
||||
###############################################################################
|
||||
# Other variables
|
||||
###############################################################################
|
||||
# Lock Docker API version for compatibility with Podman and with the Docker version in Travis' Ubuntu Bionic
|
||||
DOCKER_API_VERSION=1.40
|
||||
GO_PKG_DIRS = ./cmd ./internal ./test
|
||||
MQ_ARCHIVE_TYPE=LINUX
|
||||
MQ_ARCHIVE_DEV_TYPE=Linux
|
||||
# BUILD_SERVER_CONTAINER is the name of the web server container used at build time
|
||||
BUILD_SERVER_CONTAINER=build-server
|
||||
# BUILD_SERVER_NETWORK is the name of the network to use for the web server container used at build time
|
||||
BUILD_SERVER_NETWORK=build
|
||||
# NUM_CPU is the number of CPUs available to Docker. Used to control how many
|
||||
# test run in parallel
|
||||
NUM_CPU ?= $(or $(shell $(COMMAND) info --format "{{ .NCPU }}"),2)
|
||||
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
|
||||
BASE_IMAGE_TAG=$(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.2.0 instead of 9.2.0.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_ARCHIVE_DEV_ARCH:=X64
|
||||
else ifeq "$(ARCH)" "ppc64le"
|
||||
MQ_ARCHIVE_ARCH:=PPC64LE
|
||||
MQ_ARCHIVE_DEV_ARCH:=PPC64LE
|
||||
else ifeq "$(ARCH)" "s390x"
|
||||
MQ_ARCHIVE_ARCH:=S390X
|
||||
MQ_ARCHIVE_DEV_ARCH:=S390X
|
||||
else ifeq "$(ARCH)" "arm64"
|
||||
MQ_ARCHIVE_ARCH:=ARM64
|
||||
MQ_ARCHIVE_DEV_ARCH:=ARM64
|
||||
endif
|
||||
|
||||
# If this is a fake master build, push images to alternative location (pipeline wont consider these images GA candidates)
|
||||
ifeq ($(shell [ "$(TRAVIS)" = "true" ] && [ -n "$(MAIN_BRANCH)" ] && [ -n "$(SOURCE_BRANCH)" ] && [ "$(MAIN_BRANCH)" != "$(SOURCE_BRANCH)" ] && echo "true"), true)
|
||||
MQ_DELIVERY_REGISTRY_NAMESPACE="master-fake"
|
||||
endif
|
||||
|
||||
# LTS_TAG is the tag modifier for an LTS container build
|
||||
LTS_TAG=
|
||||
ifeq "$(LTS)" "true"
|
||||
ifneq "$(LTS_TAG_OVERRIDE)" "$(EMPTY)"
|
||||
LTS_TAG=$(LTS_TAG_OVERRIDE)
|
||||
else
|
||||
LTS_TAG=-lts
|
||||
endif
|
||||
MQ_ARCHIVE:=$(MQ_VERSION)-IBM-MQ-Advanced-Non-Install-Linux$(MQ_ARCHIVE_ARCH).tar.gz
|
||||
MQ_DELIVERY_REGISTRY_NAMESPACE:=$(MQ_DELIVERY_REGISTRY_NAMESPACE)$(LTS_TAG)
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring release-candidate,$(TRAVIS_TAG)))
|
||||
MQ_DELIVERY_REGISTRY_NAMESPACE=release-candidates
|
||||
endif
|
||||
|
||||
ifneq "$(MQ_DELIVERY_REGISTRY_NAMESPACE)" "$(EMPTY)"
|
||||
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)/$(MQ_DELIVERY_REGISTRY_NAMESPACE)
|
||||
else
|
||||
MQ_DELIVERY_REGISTRY_FULL_PATH=$(MQ_DELIVERY_REGISTRY_HOSTNAME)
|
||||
endif
|
||||
|
||||
# image tagging
|
||||
|
||||
ifneq "$(RELEASE)" "$(EMPTY)"
|
||||
EXTRA_LABELS_RELEASE=--label "release=$(RELEASE)"
|
||||
RELEASE_TAG="-$(RELEASE)"
|
||||
endif
|
||||
|
||||
ifneq "$(MQ_ARCHIVE_LEVEL)" "$(EMPTY)"
|
||||
EXTRA_LABELS_LEVEL=--label "mq-build=$(MQ_ARCHIVE_LEVEL)"
|
||||
endif
|
||||
|
||||
EXTRA_LABELS=$(EXTRA_LABELS_RELEASE) $(EXTRA_LABELS_LEVEL)
|
||||
|
||||
ifeq "$(TIMESTAMPFLAT)" "$(EMPTY)"
|
||||
TIMESTAMPFLAT=$(shell date "+%Y%m%d%H%M%S")
|
||||
endif
|
||||
|
||||
ifeq "$(GIT_COMMIT)" "$(EMPTY)"
|
||||
GIT_COMMIT=$(shell git rev-parse --short HEAD)
|
||||
endif
|
||||
|
||||
ifeq ($(shell [ ! -z $(TRAVIS) ] && [ "$(TRAVIS_PULL_REQUEST)" = "false" ] && [ "$(TRAVIS_BRANCH)" = "$(MAIN_BRANCH)" ] && echo true), true)
|
||||
MQ_MANIFEST_TAG_SUFFIX=.$(TIMESTAMPFLAT).$(GIT_COMMIT)
|
||||
endif
|
||||
|
||||
# Make sure we don't use VOLUME_MOUNT_OPTIONS for Podman on macOS
|
||||
ifeq "$(COMMAND)" "podman"
|
||||
ifeq "$(shell uname -s)" "Darwin"
|
||||
VOLUME_MOUNT_OPTIONS:=
|
||||
endif
|
||||
endif
|
||||
|
||||
PATH_TO_MQ_TAG_CACHE=$(TRAVIS_BUILD_DIR)/.tagcache
|
||||
ifneq "$(TRAVIS)" "$(EMPTY)"
|
||||
ifneq ("$(wildcard $(PATH_TO_MQ_TAG_CACHE))","")
|
||||
include $(PATH_TO_MQ_TAG_CACHE)
|
||||
endif
|
||||
endif
|
||||
|
||||
MQ_AMD64_TAG=$(MQ_MANIFEST_TAG)-amd64
|
||||
MQ_S390X_TAG?=$(MQ_MANIFEST_TAG)-s390x
|
||||
MQ_PPC64LE_TAG?=$(MQ_MANIFEST_TAG)-ppc64le
|
||||
|
||||
# end image tagging
|
||||
|
||||
MQ_IMAGE_FULL_RELEASE_NAME=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
||||
MQ_IMAGE_DEV_FULL_RELEASE_NAME=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
||||
|
||||
#setup variables for fat-manifests
|
||||
MQ_IMAGE_DEVSERVER_MANIFEST=$(MQ_IMAGE_DEVSERVER):$(MQ_MANIFEST_TAG)
|
||||
MQ_IMAGE_ADVANCEDSERVER_MANIFEST=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_MANIFEST_TAG)
|
||||
MQ_IMAGE_DEVSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_AMD64_TAG)
|
||||
MQ_IMAGE_DEVSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_S390X_TAG)
|
||||
MQ_IMAGE_DEVSERVER_PPC64LE=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_DEVSERVER):$(MQ_PPC64LE_TAG)
|
||||
MQ_IMAGE_ADVANCEDSERVER_AMD64=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_AMD64_TAG)
|
||||
MQ_IMAGE_ADVANCEDSERVER_S390X=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_S390X_TAG)
|
||||
MQ_IMAGE_ADVANCEDSERVER_PPC64LE=$(MQ_DELIVERY_REGISTRY_FULL_PATH)/$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_PPC64LE_TAG)
|
||||
|
||||
###############################################################################
|
||||
# Build targets
|
||||
###############################################################################
|
||||
.PHONY: default
|
||||
default: build-devserver test
|
||||
default: build-devserver
|
||||
|
||||
# Build all components (except incubating ones)
|
||||
.PHONY: all
|
||||
all: build-devserver build-advancedserver
|
||||
|
||||
.PHONY: test-all
|
||||
test-all: build-devjmstest test-devserver test-advancedserver
|
||||
|
||||
.PHONY: devserver
|
||||
devserver: build-devserver test-devserver
|
||||
devserver: build-devserver build-devjmstest test-devserver
|
||||
|
||||
.PHONY: advancedserver
|
||||
advancedserver: build-advancedserver test-advancedserver
|
||||
|
||||
# Build incubating components
|
||||
.PHONY: incubating
|
||||
incubating: build-explorer
|
||||
|
||||
downloads/$(MQ_ARCHIVE_DEV):
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers "$(MQ_VERSION)$(END)))
|
||||
mkdir -p downloads
|
||||
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)"
|
||||
# Use key which is not stored in the repository to fetch the files from the fileserver
|
||||
curl --fail --location $(BUILD_RSYNC_ENCRYPTED_KEY_URL) --output ./host.key.gpg
|
||||
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --batch --passphrase-fd 0 ./host.key.gpg
|
||||
chmod 600 ./host.key
|
||||
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE_DEV)
|
||||
-@rm host.key.gpg host.key
|
||||
else
|
||||
ifneq "$(MQ_ARCHIVE_REPOSITORY_DEV)" "$(EMPTY)"
|
||||
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" --output downloads/$(MQ_ARCHIVE_DEV)
|
||||
else
|
||||
curl --fail --location https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV) --output downloads/$(MQ_ARCHIVE_DEV)
|
||||
endif
|
||||
endif
|
||||
|
||||
downloads/$(MQ_ARCHIVE):
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced "$(MQ_VERSION)$(END)))
|
||||
mkdir -p downloads
|
||||
ifneq "$(BUILD_RSYNC_SERVER)" "$(EMPTY)"
|
||||
# Use key which is not stored in the repository to fetch the files from the fileserver
|
||||
-@rm host.key.gpg host.key
|
||||
curl --fail --location $(BUILD_RSYNC_ENCRYPTED_KEY_URL) --output ./host.key.gpg
|
||||
@echo $(BUILD_RSYNC_ENCRYPTION_PASSWORD)|gpg --batch --passphrase-fd 0 ./host.key.gpg
|
||||
chmod 600 ./host.key
|
||||
rsync -rv -e "ssh -o BatchMode=yes -q -o StrictHostKeyChecking=no -i ./host.key" --include="*/" --include="*.tar.gz" --exclude="*" $(BUILD_RSYNC_USER)@$(BUILD_RSYNC_SERVER):"$(BUILD_RSYNC_PATH)" downloads/$(MQ_ARCHIVE)
|
||||
-@rm host.key.gpg host.key
|
||||
else
|
||||
ifneq "$(MQ_ARCHIVE_REPOSITORY)" "$(EMPTY)"
|
||||
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY)" --output downloads/$(MQ_ARCHIVE)
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: downloads
|
||||
downloads: downloads/$(MQ_ARCHIVE_DEV) downloads/$(MQ_SDK_ARCHIVE)
|
||||
|
||||
.PHONY: cache-mq-tag
|
||||
cache-mq-tag:
|
||||
@printf "MQ_MANIFEST_TAG=$(MQ_MANIFEST_TAG)\n" | tee $(PATH_TO_MQ_TAG_CACHE)
|
||||
|
||||
###############################################################################
|
||||
# Test targets
|
||||
###############################################################################
|
||||
|
||||
# Vendor Go dependencies for the Container tests
|
||||
test/container/vendor:
|
||||
cd test/container && go mod vendor
|
||||
|
||||
# Shortcut to just run the unit tests
|
||||
.PHONY: test-unit
|
||||
test-unit:
|
||||
$(COMMAND) build --target builder --file Dockerfile-server .
|
||||
|
||||
.PHONY: test-advancedserver
|
||||
test-advancedserver: test/container/vendor
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||
$(COMMAND) inspect $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)
|
||||
cd test/container && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) EXPECTED_LICENSE=Production DOCKER_API_VERSION=$(DOCKER_API_VERSION) COMMAND=$(COMMAND) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_CONTAINER) $(TEST_OPTS_CONTAINER)
|
||||
|
||||
.PHONY: build-devjmstest
|
||||
build-devjmstest:
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
|
||||
cd test/messaging && $(COMMAND) build --tag $(DEV_JMS_IMAGE) .
|
||||
|
||||
.PHONY: test-devserver
|
||||
test-devserver: test/container/vendor
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END)))
|
||||
$(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG)
|
||||
cd test/container && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=false DOCKER_API_VERSION=$(DOCKER_API_VERSION) COMMAND=$(COMMAND) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_CONTAINER) -tags mqdev $(TEST_OPTS_CONTAINER)
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
mkdir coverage
|
||||
|
||||
.PHONY: test-advancedserver-cover
|
||||
test-advancedserver-cover: test/container/vendor coverage
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG) with code coverage on $(shell $(COMMAND) --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/container/coverage/*.cov
|
||||
rm -f ./coverage/container.*
|
||||
mkdir -p ./test/container/coverage/
|
||||
cd test/container && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER):$(MQ_TAG)-cover TEST_COVER=true DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test $(TEST_OPTS_CONTAINER)
|
||||
echo 'mode: count' > ./coverage/container.cov
|
||||
tail -q -n +2 ./test/container/coverage/*.cov >> ./coverage/container.cov
|
||||
go tool cover -html=./coverage/container.cov -o ./coverage/container.html
|
||||
|
||||
echo 'mode: count' > ./coverage/combined.cov
|
||||
tail -q -n +2 ./coverage/unit.cov ./coverage/container.cov >> ./coverage/combined.cov
|
||||
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
||||
|
||||
###############################################################################
|
||||
# Build functions
|
||||
###############################################################################
|
||||
|
||||
# Command to build the image
|
||||
# Args: imageName, imageTag, dockerfile, extraArgs, dockerfileTarget
|
||||
# If the ARCH variable has been changed from the default value (arch_go variable), then the `--platform` parameter is added
|
||||
# Args: imageName, imageTag, dockerfile, mqArchive, dockerfileTarget
|
||||
define build-mq
|
||||
rm -f .dockerignore && echo ".git\ndownloads\n!downloads/$4" > .dockerignore
|
||||
$(COMMAND) build \
|
||||
--tag $1:$2 \
|
||||
--file $3 \
|
||||
--build-arg IMAGE_REVISION="$(IMAGE_REVISION)" \
|
||||
--build-arg IMAGE_SOURCE="$(IMAGE_SOURCE)" \
|
||||
--build-arg IMAGE_TAG="$1:$2" \
|
||||
--build-arg MQ_ARCHIVE="downloads/$4" \
|
||||
--label version=$(MQ_VERSION) \
|
||||
--label name=$1 \
|
||||
--label build-date=$(shell date +%Y-%m-%dT%H:%M:%S%z) \
|
||||
--label architecture="$(ARCH)" \
|
||||
--label run="podman run -d -e LICENSE=accept $1:$2" \
|
||||
--label vcs-ref=$(IMAGE_REVISION) \
|
||||
--label vcs-type=git \
|
||||
--label vcs-url=$(IMAGE_SOURCE) \
|
||||
$(if $(findstring $(arch_go),$(ARCH)),,--platform=linux/$(ARCH)) \
|
||||
$(EXTRA_LABELS) \
|
||||
--target $5 \
|
||||
.
|
||||
endef
|
||||
|
||||
###############################################################################
|
||||
# Build targets
|
||||
###############################################################################
|
||||
.PHONY: build-advancedserver-host
|
||||
build-advancedserver-host: build-advancedserver
|
||||
|
||||
.PHONY: build-advancedserver
|
||||
build-advancedserver: 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: 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: 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: 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: 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)
|
||||
|
||||
###############################################################################
|
||||
# Logging targets
|
||||
###############################################################################
|
||||
.PHONY: log-build-env
|
||||
log-build-vars:
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Build environment"$(END)))
|
||||
@echo arch_uname=$(arch_uname)
|
||||
@echo arch_go=$(arch_go)
|
||||
@echo "ARCH=$(ARCH) (origin:$(origin ARCH))"
|
||||
@echo MQ_VERSION="$(MQ_VERSION) (origin:$(origin MQ_VERSION))"
|
||||
@echo MQ_ARCHIVE="$(MQ_ARCHIVE) (origin:$(origin MQ_ARCHIVE))"
|
||||
@echo MQ_ARCHIVE_DEV_ARCH=$(MQ_ARCHIVE_DEV_ARCH)
|
||||
@echo MQ_ARCHIVE_DEV=$(MQ_ARCHIVE_DEV)
|
||||
@echo MQ_IMAGE_DEVSERVER=$(MQ_IMAGE_DEVSERVER)
|
||||
@echo MQ_IMAGE_ADVANCEDSERVER=$(MQ_IMAGE_ADVANCEDSERVER)
|
||||
@echo COMMAND=$(COMMAND)
|
||||
|
||||
.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
|
||||
|
||||
###############################################################################
|
||||
# Push/pull targets
|
||||
###############################################################################
|
||||
.PHONY: pull-mq-archive
|
||||
pull-mq-archive:
|
||||
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY)" --output downloads/$(MQ_ARCHIVE)
|
||||
|
||||
.PHONY: pull-mq-archive-dev
|
||||
pull-mq-archive-dev:
|
||||
curl --fail --user $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) --request GET "$(MQ_ARCHIVE_REPOSITORY_DEV)" --output downloads/$(MQ_ARCHIVE_DEV)
|
||||
|
||||
.PHONY: push-advancedserver
|
||||
push-advancedserver:
|
||||
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
|
||||
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
|
||||
fi
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Push production image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
|
||||
$(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:
|
||||
@if [ $(MQ_DELIVERY_REGISTRY_NAMESPACE) = "master-fake" ]; then\
|
||||
echo "Detected fake master build. Note that the push destination is set to the fake master namespace: $(MQ_DELIVERY_REGISTRY_FULL_PATH)";\
|
||||
fi
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Push developer image to $(MQ_DELIVERY_REGISTRY_FULL_PATH)"$(END)))
|
||||
$(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: 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: push-manifest
|
||||
push-manifest: build-skopeo-container
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"** Determining the image digests **"$(END)))
|
||||
ifneq "$(LTS)" "true"
|
||||
$(eval MQ_IMAGE_DEVSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_AMD64) | jq -r .Digest))
|
||||
$(eval MQ_IMAGE_DEVSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_S390X) | jq -r .Digest))
|
||||
$(eval MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_DEVSERVER_PPC64LE) | jq -r .Digest))
|
||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_AMD64) has a digest of $(MQ_IMAGE_DEVSERVER_AMD64_DIGEST)**"$(END)))
|
||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_S390X) has a digest of $(MQ_IMAGE_DEVSERVER_S390X_DIGEST)**"$(END)))
|
||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_DEVSERVER_PPC64LE) has a digest of $(MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST)**"$(END)))
|
||||
endif
|
||||
$(eval MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_AMD64) | jq -r .Digest))
|
||||
$(eval MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_S390X) | jq -r .Digest))
|
||||
$(eval MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST=$(shell $(COMMAND) run skopeo:latest --override-os linux inspect --creds $(MQ_ARCHIVE_REPOSITORY_USER):$(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) docker://$(MQ_IMAGE_ADVANCEDSERVER_PPC64LE) | jq -r .Digest))
|
||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_AMD64) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST)**"$(END)))
|
||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_S390X) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST)**"$(END)))
|
||||
$(info $(shell printf "** Determined the built $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE) has a digest of $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST)**"$(END)))
|
||||
ifneq "$(LTS)" "true"
|
||||
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_DEVSERVER_MANIFEST)**"$(END)))
|
||||
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_DEVSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_DEVSERVER_AMD64_DIGEST) $(MQ_IMAGE_DEVSERVER_S390X_DIGEST) $(MQ_IMAGE_DEVSERVER_PPC64LE_DIGEST)" $(END))
|
||||
endif
|
||||
$(info $(shell printf "** Calling script to create fat-manifest for $(MQ_IMAGE_ADVANCEDSERVER_MANIFEST)**"$(END)))
|
||||
echo $(shell ./travis-build-scripts/create-manifest-list.sh -r $(MQ_DELIVERY_REGISTRY_HOSTNAME) -n $(MQ_DELIVERY_REGISTRY_NAMESPACE) -i $(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_MANIFEST_TAG) -u $(MQ_ARCHIVE_REPOSITORY_USER) -p $(MQ_ARCHIVE_REPOSITORY_CREDENTIAL) -d "$(MQ_IMAGE_ADVANCEDSERVER_AMD64_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_S390X_DIGEST) $(MQ_IMAGE_ADVANCEDSERVER_PPC64LE_DIGEST)" $(END))
|
||||
|
||||
.PHONY: build-skopeo-container
|
||||
build-skopeo-container:
|
||||
$(COMMAND) images | grep -q "skopeo"; if [ $$? != 0 ]; then $(COMMAND) build -t skopeo:latest ./docker-builds/skopeo/; fi
|
||||
|
||||
###############################################################################
|
||||
# Other targets
|
||||
###############################################################################
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf ./coverage
|
||||
rm -rf ./build
|
||||
rm -rf ./deps
|
||||
|
||||
downloads/mqadv_dev903_ubuntu_x86-64.tar.gz:
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers"$(END)))
|
||||
mkdir -p downloads
|
||||
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||
.PHONY: install-build-deps
|
||||
install-build-deps:
|
||||
ARCH=$(ARCH) ./install-build-deps.sh
|
||||
|
||||
.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
|
||||
|
||||
build/runmqserver:
|
||||
mkdir -p build
|
||||
cd build; GOOS=linux go build ../cmd/runmqserver/
|
||||
|
||||
build/chkmqready:
|
||||
mkdir -p build
|
||||
cd build; GOOS=linux go build ../cmd/chkmqready/
|
||||
|
||||
build/chkmqhealthy:
|
||||
mkdir -p build
|
||||
cd build; GOOS=linux go build ../cmd/chkmqhealthy/
|
||||
|
||||
.PHONY: build
|
||||
build: build/runmqserver build/chkmqready build/chkmqhealthy
|
||||
.PHONY: install-credential-helper
|
||||
install-credential-helper:
|
||||
ifeq ($(ARCH),amd64)
|
||||
ARCH=$(ARCH) ./travis-build-scripts/install-credential-helper.sh
|
||||
endif
|
||||
|
||||
.PHONY: build-cov
|
||||
build-cov:
|
||||
mkdir -p build
|
||||
cd build; go test -c -covermode=count ../cmd/runmqserver
|
||||
|
||||
.PHONY: test-advancedserver
|
||||
test-advancedserver: build
|
||||
cd pkg/name && go test
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_ADVANCEDSERVER) go test $(TEST_OPTS_DOCKER)
|
||||
.PHONY: precommit
|
||||
precommit: fmt lint
|
||||
|
||||
.PHONY: test-devserver
|
||||
test-devserver: build
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_DEVSERVER)"$(END)))
|
||||
cd pkg/name && go test
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_DEVSERVER) go test
|
||||
.PHONY: fmt
|
||||
fmt: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
||||
go fmt $(addsuffix /..., $(GO_PKG_DIRS))
|
||||
|
||||
.PHONY: test-kubernetes-devserver
|
||||
test-kubernetes-devserver: build
|
||||
$(call test-kubernetes,$(DOCKER_REPO_DEVSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-dev")
|
||||
.PHONY: lint
|
||||
lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
|
||||
@# 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
|
||||
test-kubernetes-advancedserver: build
|
||||
$(call test-kubernetes,$(DOCKER_REPO_ADVANCEDSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-prod")
|
||||
.PHONY: gosec
|
||||
gosec:
|
||||
$(info $(SPACER)$(shell printf "Running gosec test"$(END)))
|
||||
@gosecrc=0; gosec -fmt=json -out=gosec_results.json cmd/... internal/... 2> /dev/null || gosecrc=$$?; \
|
||||
cat gosec_results.json | jq '{"GolangErrors": (.["Golang errors"]|length>0),"Issues":(.Issues|length>0)}' | grep 'true' >/dev/null ;\
|
||||
if [ $$? -eq 0 ] || [ $$gosecrc -ne 0 ]; then \
|
||||
printf "FAILURE: Issues found running gosec - see gosec_results.json\n" ;\
|
||||
cat "gosec_results.json" ;\
|
||||
exit 1 ;\
|
||||
else \
|
||||
printf "gosec found no issues\n" ;\
|
||||
cat "gosec_results.json" ;\
|
||||
fi
|
||||
|
||||
define test-kubernetes
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $1:$2 on Kubernetes"$(END)))
|
||||
cd test/kubernetes && TEST_REPO=$1 TEST_TAG=$2 TEST_CHART=$3 go test $(TEST_OPTS_KUBERNETES)
|
||||
endef
|
||||
.PHONY: update-release-information
|
||||
update-release-information:
|
||||
sed -i.bak 's/ARG MQ_ARCHIVE=.*-LinuxX64.tar.gz"/ARG MQ_ARCHIVE="downloads\/$(MQ_VERSION)-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz"/g' Dockerfile-server && rm Dockerfile-server.bak
|
||||
$(eval MQ_VERSION_1=$(shell echo '${MQ_VERSION}' | rev | cut -c 3- | rev))
|
||||
sed -i.bak 's/IBM_MQ_.*_LINUX_X86-64_NOINST.tar.gz/IBM_MQ_${MQ_VERSION_1}_LINUX_X86-64_NOINST.tar.gz/g' docs/building.md && rm docs/building.md.bak
|
||||
sed -i.bak 's/ibm-mqadvanced-server:.*-amd64/ibm-mqadvanced-server:$(MQ_VERSION)-amd64/g' docs/security.md
|
||||
sed -i.bak 's/ibm-mqadvanced-server-dev.*-amd64/ibm-mqadvanced-server-dev:$(MQ_VERSION)-amd64/g' docs/security.md && rm docs/security.md.bak
|
||||
sed -i.bak 's/MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:.*-amd64/MQ_IMAGE_ADVANCEDSERVER=ibm-mqadvanced-server:$(MQ_VERSION)-amd64/g' docs/testing.md && rm docs/testing.md.bak
|
||||
$(eval MQ_VERSION_2=$(shell echo '${MQ_VERSION_1}' | rev | cut -c 3- | rev))
|
||||
sed -i.bak 's/knowledgecenter\/SSFKSJ_.*\/com/knowledgecenter\/SSFKSJ_${MQ_VERSION_2}.0\/com/g' docs/usage.md && rm docs/usage.md.bak
|
||||
$(eval MQ_VERSION_3=$(shell echo '${MQ_VERSION_1}' | sed "s/\.//g"))
|
||||
sed -i.bak 's/MQ_..._ARCHIVE_REPOSITORY/MQ_${MQ_VERSION_3}_ARCHIVE_REPOSITORY/g' .travis.yml && rm .travis.yml.bak
|
||||
|
||||
define docker-build-mq
|
||||
# Create a temporary network to use for the build
|
||||
docker network create build
|
||||
# Start a web server to host the MQ downloadable (tar.gz) file
|
||||
docker run \
|
||||
--rm \
|
||||
--name $(BUILD_SERVER_CONTAINER) \
|
||||
--network build \
|
||||
--network-alias build \
|
||||
--volume "$(realpath ./downloads/)":/usr/share/nginx/html:ro \
|
||||
--detach \
|
||||
nginx:alpine
|
||||
# Build the new image
|
||||
docker build \
|
||||
--tag $1 \
|
||||
--file $2 \
|
||||
--network build \
|
||||
--build-arg MQ_URL=http://build:80/$3 \
|
||||
--build-arg IBM_PRODUCT_ID=$4 \
|
||||
--build-arg IBM_PRODUCT_NAME=$5 \
|
||||
--build-arg 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
|
||||
build-advancedserver: 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-devserver
|
||||
build-devserver: build 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: build 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
|
||||
COMMAND_SERVER_VERSION=$(shell $(COMMAND) version --format "{{ .Server.Version }}")
|
||||
COMMAND_CLIENT_VERSION=$(shell $(COMMAND) version --format "{{ .Client.Version }}")
|
||||
PODMAN_VERSION=$(shell podman version --format "{{ .Version }}")
|
||||
.PHONY: command-version
|
||||
command-version:
|
||||
# If we're using Docker, then check it's recent enough to support multi-stage builds
|
||||
ifneq (,$(findstring docker,$(COMMAND)))
|
||||
@test "$(word 1,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker client 17.05 or greater is required" && exit 1)
|
||||
@test "$(word 1,$(subst ., ,$(COMMAND_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(COMMAND_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(COMMAND_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)
|
||||
endif
|
||||
ifneq (,$(findstring podman,$(COMMAND)))
|
||||
@test "$(word 1,$(subst ., ,$(PODMAN_VERSION)))" -ge "1" || (echo "Error: Podman version 1.0 or greater is required" && exit 1)
|
||||
endif
|
||||
12788
NOTICES.txt
12788
NOTICES.txt
File diff suppressed because it is too large
Load Diff
78
README.md
78
README.md
@@ -1,51 +1,59 @@
|
||||

|
||||
|
||||
# Overview
|
||||
|
||||
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).
|
||||
|
||||
# Current status
|
||||
MQ Advanced for Developers image - [](https://travis-ci.org/ibm-messaging/mq-container)
|
||||
|
||||
# Build
|
||||
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 for MQ Advanced, follow these steps:
|
||||
|
||||
1. Clone this repository into the correct location in your [`GOPATH`](https://github.com/golang/go/wiki/GOPATH)
|
||||
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
|
||||
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.
|
||||
# IBM MQ container
|
||||
|
||||
|
||||
## List of all Environment variables supported by this image
|
||||
[](https://travis-ci.org/ibm-messaging/mq-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`.
|
||||
* **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.
|
||||
* **MQ_QMGR_CMDLEVEL** - Set this to the `CMDLEVEL` you wish your Queue Manager to be started with.
|
||||
**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.
|
||||
|
||||
## Overview
|
||||
|
||||
# Issues and contributions
|
||||
Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container.
|
||||
|
||||
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).
|
||||
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.
|
||||
|
||||
## Build
|
||||
|
||||
# License
|
||||
After extracting the code from this repository, you can follow the [build documentation](docs/building.md) to build an image.
|
||||
|
||||
## Usage
|
||||
|
||||
See the [usage documentation](docs/usage.md) for details on how to run a container.
|
||||
|
||||
Note that in order to use the image, it is necessary to accept the terms of the [IBM MQ license](#license).
|
||||
|
||||
### Environment variables supported by this image
|
||||
|
||||
- **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
|
||||
- **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.
|
||||
- **MQ_QMGR_LOG_FILE_PAGES** - Set this to control the value for LogFilePages passed to the "crtmqm" command. Cannot be changed after queue manager creation.
|
||||
- **MQ_LOGGING_CONSOLE_SOURCE** - Specifies a comma-separated list of sources for logs which are mirrored to the container's stdout. The valid values are "qmgr" and "web". Defaults to "qmgr".
|
||||
- **MQ_LOGGING_CONSOLE_FORMAT** - Changes 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_LOGGING_CONSOLE_EXCLUDE_ID** - Excludes log messages with the specified ID. The log messages still appear in the log file on disk, but are excluded from the container's stdout. Defaults to "AMQ5041I,AMQ5052I,AMQ5051I,AMQ5037I,AMQ5975I".
|
||||
- **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 on [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM MQ Sample Helm Chart](https://github.com/ibm-messaging/mq-helm). This can be used to run the container on a Kubernetes cluster, such as the [IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/container-service).
|
||||
|
||||
## Issues and contributions
|
||||
|
||||
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). Pull requests are not currently accepted.
|
||||
|
||||
## 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).
|
||||
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](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.
|
||||
- License information for Ubuntu packages may be found in `/usr/share/doc/${package}/copyright`
|
||||
- [IBM MQ Advanced for Developers](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=Z125-3301-14&li_formnum=L-AXAF-JLZ53A) (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-AMRD-XH6P3Q) (International Program License Agreement). This license may be viewed from an image using the `LICENSE=view` environment variable as described above or by following the link above.
|
||||
|
||||
Note: The IBM MQ Advanced for Developers license does not permit further distribution and the terms restrict usage to a developer machine.
|
||||
|
||||
# Copyright
|
||||
|
||||
© Copyright IBM Corporation 2015, 2017
|
||||
## Copyright
|
||||
|
||||
© Copyright IBM Corporation 2015, 2023
|
||||
|
||||
62
authservice/mqhtpass/Makefile
Normal file
62
authservice/mqhtpass/Makefile
Normal file
@@ -0,0 +1,62 @@
|
||||
# © Copyright IBM Corporation 2017, 2022
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This Makefile expects the following to be installed:
|
||||
# - gcc
|
||||
# - ldd
|
||||
# - MQ SDK (mqm_r library, plus header files)
|
||||
# - Apache Portable Runtime (apr-1 and aprutil-1 libraries, plus header files)
|
||||
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = ./build
|
||||
ARCH ?= $(if $(findstring x86_64,$(shell uname -m)),amd64,$(if $(findstring aarch64,$(shell uname -m)),aarch64,$(shell uname -m)))
|
||||
|
||||
# Flags passed to the C compiler. Need to use gnu11 to get POSIX functions needed for file locking.
|
||||
CFLAGS.amd64 := -m64
|
||||
CFLAGS.ppc64le := -m64
|
||||
CFLAGS.s390x := -m64
|
||||
# -m64 is not a valid compiler option on aarch64/arm64 (ARM)
|
||||
CFLAGS.arm64 :=
|
||||
CFLAGS += -std=gnu11 -fPIC -Wall ${CFLAGS.${ARCH}}
|
||||
|
||||
LIB_APR = -L/usr/lib64 -lapr-1 -laprutil-1
|
||||
LIB_MQ = -L/opt/mqm/lib64 -lmqm_r
|
||||
|
||||
all: $(BUILD_DIR)/mqhtpass.so $(BUILD_DIR)/htpass_test $(BUILD_DIR)/log_test
|
||||
|
||||
$(BUILD_DIR)/log.o : $(SRC_DIR)/log.c $(SRC_DIR)/log.h
|
||||
mkdir -p ${dir $@}
|
||||
gcc $(CFLAGS) -c $(SRC_DIR)/log.c -o $@
|
||||
|
||||
$(BUILD_DIR)/log_test : $(BUILD_DIR)/log.o
|
||||
mkdir -p ${dir $@}
|
||||
gcc $(CFLAGS) $(SRC_DIR)/log_test.c $^ -o $@
|
||||
# Run Logging tests, and print log if they fail
|
||||
$@ || (cat log_test*.log && exit 1)
|
||||
|
||||
$(BUILD_DIR)/htpass.o : $(SRC_DIR)/htpass.c $(SRC_DIR)/htpass.h
|
||||
mkdir -p ${dir $@}
|
||||
gcc $(CFLAGS) -c $(SRC_DIR)/htpass.c -I /usr/include/apr-1 -o $@
|
||||
|
||||
$(BUILD_DIR)/htpass_test : $(BUILD_DIR)/htpass.o $(BUILD_DIR)/log.o
|
||||
mkdir -p ${dir $@}
|
||||
gcc $(CFLAGS) $(LIB_APR) -lpthread $(SRC_DIR)/htpass_test.c $^ -o $@
|
||||
# Run HTPasswd tests, and print log if they fail
|
||||
$@ || (cat htpass_test*.log && exit 1)
|
||||
|
||||
$(BUILD_DIR)/mqhtpass.so : $(BUILD_DIR)/log.o $(BUILD_DIR)/htpass.o
|
||||
mkdir -p ${dir $@}
|
||||
# NOTE: rpath for libapr will be different on Ubuntu
|
||||
gcc $(CFLAGS) -I/opt/mqm/inc -D_REENTRANT $(LIB_APR) $(LIB_MQ) -Wl,-rpath,/opt/mqm/lib64 -Wl,-rpath,/usr/lib64 -shared $(SRC_DIR)/mqhtpass.c $^ -o $@
|
||||
ldd $@
|
||||
145
authservice/mqhtpass/src/htpass.c
Normal file
145
authservice/mqhtpass/src/htpass.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2021
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "log.h"
|
||||
#include "htpass.h"
|
||||
#include <linux/limits.h>
|
||||
#include <apr_general.h>
|
||||
#include <apr_errno.h>
|
||||
#include <apr_md5.h>
|
||||
|
||||
bool htpass_valid_file(char *filename)
|
||||
{
|
||||
bool valid = true;
|
||||
FILE *fp;
|
||||
char *huser;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
log_errorf("Error %d opening htpasswd file '%s'", errno, filename);
|
||||
}
|
||||
if (fp)
|
||||
{
|
||||
const size_t line_size = 1024;
|
||||
char *line = malloc(line_size);
|
||||
while (fgets(line, line_size, fp) != NULL)
|
||||
{
|
||||
char *saveptr;
|
||||
// Need to use strtok_r to be safe for multiple threads
|
||||
huser = strtok_r(line, ":", &saveptr);
|
||||
if (strlen(huser) >= 12)
|
||||
{
|
||||
log_errorf("Invalid htpasswd file for use with IBM MQ. User '%s' is longer than twelve characters", huser);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
if (line)
|
||||
{
|
||||
free(line);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
char *find_hash(char *filename, char *user)
|
||||
{
|
||||
bool found = false;
|
||||
FILE *fp;
|
||||
char *huser;
|
||||
char *hash;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
log_errorf("Error %d opening htpasswd file '%s'", errno, filename);
|
||||
}
|
||||
if (fp)
|
||||
{
|
||||
const size_t line_size = 1024;
|
||||
char *line = malloc(line_size);
|
||||
while (fgets(line, line_size, fp) != NULL)
|
||||
{
|
||||
char *saveptr;
|
||||
// Need to use strtok_r to be safe for multiple threads
|
||||
huser = strtok_r(line, ":", &saveptr);
|
||||
if (huser && (strcmp(user, huser) == 0))
|
||||
{
|
||||
// Make a duplicate of the string, because we'll be keeping it
|
||||
hash = strdup(strtok_r(NULL, " \r\n\t", &saveptr));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
if (line)
|
||||
{
|
||||
free(line);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
hash = NULL;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
int htpass_authenticate_user(char *filename, char *user, char *password)
|
||||
{
|
||||
char *hash = find_hash(filename, user);
|
||||
int result = -1;
|
||||
if (hash == NULL)
|
||||
{
|
||||
result = HTPASS_INVALID_USER;
|
||||
log_debugf("User does not exist. user=%s", user);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the Apache Portable Runtime utilities to validate the password against the hash.
|
||||
// Supports multiple hashing algorithms, but we should only be using bcrypt
|
||||
apr_status_t status = apr_password_validate(password, hash);
|
||||
// status is usually either APR_SUCCESS or APR_EMISMATCH
|
||||
if (status == APR_SUCCESS)
|
||||
{
|
||||
result = HTPASS_VALID;
|
||||
log_debugf("Correct password supplied. user=%s", user);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = HTPASS_INVALID_PASSWORD;
|
||||
log_debugf("Incorrect password supplied. user=%s", user);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool htpass_valid_user(char *filename, char *user)
|
||||
{
|
||||
char *hash = find_hash(filename, user);
|
||||
bool valid = false;
|
||||
if (hash != NULL)
|
||||
{
|
||||
valid = true;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
49
authservice/mqhtpass/src/htpass.h
Normal file
49
authservice/mqhtpass/src/htpass.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2021
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _HTPASS_H
|
||||
#define _HTPASS_H
|
||||
|
||||
#define HTPASS_VALID 0
|
||||
#define HTPASS_INVALID_USER 1
|
||||
#define HTPASS_INVALID_PASSWORD 2
|
||||
|
||||
/**
|
||||
* Validate an HTPasswd file for use with IBM MQ.
|
||||
*
|
||||
* @param filename the HTPasswd file
|
||||
*/
|
||||
_Bool htpass_valid_file(char *filename);
|
||||
|
||||
/**
|
||||
* Authenticate a user, based on the supplied file name.
|
||||
*
|
||||
* @param filename the HTPasswd file
|
||||
* @param user the user name to authenticate
|
||||
* @param password the password of the user
|
||||
* @return HTPASS_VALID, HTPASS_INVALID_USER or HTPASS_INVALID_PASSWORD
|
||||
*/
|
||||
int htpass_authenticate_user(char *filename, char *user, char *password);
|
||||
|
||||
/**
|
||||
* Validate that a user exists in the password file.
|
||||
*
|
||||
* @param filename the HTPasswd file
|
||||
* @param user the user name to validate
|
||||
*/
|
||||
_Bool htpass_valid_user(char *filename, char *user);
|
||||
|
||||
#endif
|
||||
223
authservice/mqhtpass/src/htpass_test.c
Normal file
223
authservice/mqhtpass/src/htpass_test.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2021
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
#include "htpass.h"
|
||||
|
||||
// Headers for multi-threaded tests
|
||||
#include <pthread.h>
|
||||
|
||||
// Start a test and log the function name
|
||||
#define test_start() printf("=== RUN: %s\n", __func__)
|
||||
|
||||
// Indicate test has passed
|
||||
#define test_pass() printf("--- PASS: %s\n", __func__)
|
||||
|
||||
// Indicate test has failed
|
||||
void test_fail(const char *test_name)
|
||||
{
|
||||
printf("--- FAIL: %s\n", test_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Simple tests for file validation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void test_htpass_valid_file_ok()
|
||||
{
|
||||
test_start();
|
||||
int ok = htpass_valid_file("./src/htpass_test.htpasswd");
|
||||
if (!ok)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
void test_htpass_valid_file_too_long()
|
||||
{
|
||||
test_start();
|
||||
int ok = htpass_valid_file("./src/htpass_test_invalid.htpasswd");
|
||||
if (ok)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Simple tests for authentication
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void test_htpass_authenticate_user_fred_valid()
|
||||
{
|
||||
test_start();
|
||||
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
|
||||
printf("%s: fred - %d\n", __func__, rc);
|
||||
if (rc != HTPASS_VALID)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
void test_htpass_authenticate_user_fred_invalid1()
|
||||
{
|
||||
test_start();
|
||||
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd ");
|
||||
printf("%s: fred - %d\n", __func__, rc);
|
||||
if (rc != HTPASS_INVALID_PASSWORD)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
void test_htpass_authenticate_user_fred_invalid2()
|
||||
{
|
||||
test_start();
|
||||
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "");
|
||||
printf("%s: fred - %d\n", __func__, rc);
|
||||
if (rc != HTPASS_INVALID_PASSWORD)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
void test_htpass_authenticate_user_fred_invalid3()
|
||||
{
|
||||
test_start();
|
||||
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "clearlywrong");
|
||||
printf("%s: fred - %d\n", __func__, rc);
|
||||
if (rc != HTPASS_INVALID_PASSWORD)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
void test_htpass_authenticate_user_barney_valid()
|
||||
{
|
||||
test_start();
|
||||
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
|
||||
printf("%s: barney - %d\n", __func__, rc);
|
||||
if (rc != HTPASS_VALID)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
void test_htpass_authenticate_user_unknown()
|
||||
{
|
||||
test_start();
|
||||
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "george", "s3cret");
|
||||
printf("%s: barney - %d\n", __func__, rc);
|
||||
if (rc != HTPASS_INVALID_USER)
|
||||
test_fail(__func__);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Multi-threaded test
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define NUM_THREADS 5
|
||||
// Number of tests to perform per thread. Higher numbers are more likely to trigger timing issue.
|
||||
#define NUM_TESTS_PER_THREAD 1000
|
||||
// Maximum number of JSON errors to report (log can get flooded)
|
||||
#define MAX_JSON_ERRORS 10
|
||||
|
||||
// Authenticate multiple users, multiple times
|
||||
void *authenticate_many_times(void *p)
|
||||
{
|
||||
for (int i = 0; i < NUM_TESTS_PER_THREAD; i++)
|
||||
{
|
||||
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
|
||||
if (rc != HTPASS_VALID)
|
||||
test_fail(__func__);
|
||||
rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
|
||||
if (rc != HTPASS_VALID)
|
||||
test_fail(__func__);
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void check_log_file_valid(char *filename)
|
||||
{
|
||||
int errors = 0;
|
||||
printf("--- Checking log file is valid\n");
|
||||
// Check that the JSON log file isn't corrupted
|
||||
FILE *log = fopen(filename, "r");
|
||||
if (log == NULL)
|
||||
{
|
||||
test_fail(__func__);
|
||||
}
|
||||
const size_t line_size = 1024;
|
||||
char *line = malloc(line_size);
|
||||
while (fgets(line, line_size, log) != NULL)
|
||||
{
|
||||
if ((line[0] != '{') && (errors < MAX_JSON_ERRORS))
|
||||
{
|
||||
printf("*** Invalid JSON detected: %s\n", line);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (line)
|
||||
{
|
||||
free(line);
|
||||
}
|
||||
fclose(log);
|
||||
}
|
||||
|
||||
// Test authenticate_user with multiple threads, each doing many authentications
|
||||
void test_htpass_authenticate_user_multithreaded(char *logfile)
|
||||
{
|
||||
pthread_t threads[NUM_THREADS];
|
||||
int rc;
|
||||
test_start();
|
||||
// Re-initialize the log to use a file for the multi-threaded test
|
||||
log_init(logfile);
|
||||
for (int i = 0; i < NUM_THREADS; i++)
|
||||
{
|
||||
printf("Creating thread %d\n", i);
|
||||
rc = pthread_create(&threads[i], NULL, authenticate_many_times, NULL);
|
||||
if (rc)
|
||||
{
|
||||
printf("Error: Unable to create thread, %d\n", rc);
|
||||
test_fail(__func__);
|
||||
}
|
||||
}
|
||||
// Wait for all the threads to complete
|
||||
for (int i = 0; i < NUM_THREADS; i++)
|
||||
{
|
||||
pthread_join(threads[i], NULL);
|
||||
}
|
||||
check_log_file_valid(logfile);
|
||||
test_pass();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int main()
|
||||
{
|
||||
// Turn on debugging for the tests
|
||||
setenv("DEBUG", "true", true);
|
||||
log_init("htpass_test.log");
|
||||
test_htpass_valid_file_ok();
|
||||
test_htpass_valid_file_too_long();
|
||||
test_htpass_authenticate_user_fred_valid();
|
||||
test_htpass_authenticate_user_fred_invalid1();
|
||||
test_htpass_authenticate_user_fred_invalid2();
|
||||
test_htpass_authenticate_user_fred_invalid3();
|
||||
test_htpass_authenticate_user_barney_valid();
|
||||
test_htpass_authenticate_user_unknown();
|
||||
log_close();
|
||||
|
||||
// Call multi-threaded test last, because it re-initializes the log to use a file
|
||||
test_htpass_authenticate_user_multithreaded("htpass_test_multithreaded.log");
|
||||
}
|
||||
2
authservice/mqhtpass/src/htpass_test.htpasswd
Normal file
2
authservice/mqhtpass/src/htpass_test.htpasswd
Normal file
@@ -0,0 +1,2 @@
|
||||
fred:$2y$05$3Fp9epsqEwWOHdyj9Ngf9.qfX34kzc9zNrdQ7kac0GmcCvQjIkAwy
|
||||
barney:$2y$05$l8EoyCQ9y2PyfUzIDDfTyu7SSaJEYB1TuHy07xZvN7xt/pR3SIw0a
|
||||
3
authservice/mqhtpass/src/htpass_test_invalid.htpasswd
Normal file
3
authservice/mqhtpass/src/htpass_test_invalid.htpasswd
Normal file
@@ -0,0 +1,3 @@
|
||||
fred:$2y$05$3Fp9epsqEwWOHdyj9Ngf9.qfX34kzc9zNrdQ7kac0GmcCvQjIkAwy
|
||||
barney:$2y$05$l8EoyCQ9y2PyfUzIDDfTyu7SSaJEYB1TuHy07xZvN7xt/pR3SIw0a
|
||||
namewhichisfartoolongformq:$2y$05$l8EoyCQ9y2PyfUzIDDfTyu7SSaJEYB1TuHy07xZvN7xt/pR3SIw0a
|
||||
162
authservice/mqhtpass/src/log.c
Normal file
162
authservice/mqhtpass/src/log.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2021, 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
FILE *fp = NULL;
|
||||
int pid;
|
||||
char hostname[255];
|
||||
bool debug = false;
|
||||
|
||||
/**
|
||||
* Determine whether debugging is enabled or not, using an environment variable.
|
||||
*/
|
||||
void init_debug(){
|
||||
char *debug_env = getenv("DEBUG");
|
||||
if (debug_env != NULL)
|
||||
{
|
||||
// Enable debug logging if the DEBUG environment variable is set
|
||||
if (strncmp(debug_env, "true", 4) || strncmp(debug_env, "1", 1))
|
||||
{
|
||||
debug = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to initialize the log with the given file mode.
|
||||
*/
|
||||
int log_init_internal(char *filename, const char *mode)
|
||||
{
|
||||
int result = 0;
|
||||
pid = getpid();
|
||||
hostname[254] = '\0';
|
||||
gethostname(hostname, 254);
|
||||
if (!fp)
|
||||
{
|
||||
fp = fopen(filename, "a");
|
||||
if (fp)
|
||||
{
|
||||
// Disable buffering for this file
|
||||
setbuf(fp, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
init_debug();
|
||||
return result;
|
||||
}
|
||||
|
||||
int log_init_reset(char *filename)
|
||||
{
|
||||
// Open the log file for writing (overwrite if it already exists)
|
||||
return log_init_internal(filename, "w");
|
||||
}
|
||||
|
||||
int log_init(char *filename)
|
||||
{
|
||||
// Open the log file file for appending
|
||||
return log_init_internal(filename, "a");
|
||||
}
|
||||
|
||||
void log_init_file(FILE *f)
|
||||
{
|
||||
fp = f;
|
||||
init_debug();
|
||||
}
|
||||
|
||||
void log_close()
|
||||
{
|
||||
if (fp)
|
||||
{
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void log_printf(const char *source_file, int source_line, const char *level, const char *format, ...)
|
||||
{
|
||||
if (fp)
|
||||
{
|
||||
// If this is a DEBUG message, and debugging is off
|
||||
if ((strncmp(level, "DEBUG", 5) == 0) && !debug)
|
||||
{
|
||||
return;
|
||||
}
|
||||
char buf[1024] = "";
|
||||
char *cur = buf;
|
||||
char* const end = buf + sizeof buf;
|
||||
char date_buf[70];
|
||||
struct tm *utc;
|
||||
time_t t;
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
t = now.tv_sec;
|
||||
t = time(NULL);
|
||||
utc = gmtime(&t);
|
||||
|
||||
cur += snprintf(cur, end-cur, "{");
|
||||
cur += snprintf(cur, end-cur, "\"loglevel\":\"%s\"", level);
|
||||
// Print ISO-8601 time and date
|
||||
if (strftime(date_buf, sizeof date_buf, "%FT%T", utc))
|
||||
{
|
||||
// Round microseconds down to milliseconds, for consistency
|
||||
cur += snprintf(cur, end-cur, ", \"ibm_datetime\":\"%s.%03ldZ\"", date_buf, now.tv_usec / (long)1000);
|
||||
}
|
||||
cur += snprintf(cur, end-cur, ", \"ibm_processId\":\"%d\"", pid);
|
||||
cur += snprintf(cur, end-cur, ", \"host\":\"%s\"", hostname);
|
||||
cur += snprintf(cur, end-cur, ", \"module\":\"%s:%d\"", source_file, source_line);
|
||||
cur += snprintf(cur, end-cur, ", \"message\":\"");
|
||||
|
||||
if (strncmp(level, "DEBUG", 5) == 0)
|
||||
{
|
||||
// Add a prefix on any debug messages
|
||||
cur += snprintf(cur, end-cur, "mqhtpass: ");
|
||||
}
|
||||
|
||||
// Print log message, using varargs
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
cur += vsnprintf(cur, end-cur, format, args);
|
||||
va_end(args);
|
||||
cur += snprintf(cur, end-cur, "\"}\n");
|
||||
|
||||
// Important: Just do one file write, to prevent problems with multi-threading.
|
||||
// This only works if the log message is not too long for the buffer.
|
||||
fprintf(fp, "%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
int trimmed_len(char *s, int max_len)
|
||||
{
|
||||
int i;
|
||||
for (i = max_len - 1; i >= 0; i--)
|
||||
{
|
||||
if (s[i] != ' ')
|
||||
break;
|
||||
}
|
||||
return i+1;
|
||||
}
|
||||
70
authservice/mqhtpass/src/log.h
Normal file
70
authservice/mqhtpass/src/log.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2021, 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
/**
|
||||
* Initialize the log to use the given file name, wiping any existing contents.
|
||||
*/
|
||||
int log_init_reset(char *filename);
|
||||
|
||||
/**
|
||||
* Initialize the log to use the given file name.
|
||||
*/
|
||||
int log_init(char *filename);
|
||||
|
||||
/**
|
||||
* Initialize the log with an existing file handle.
|
||||
*/
|
||||
void log_init_file(FILE *f);
|
||||
|
||||
/**
|
||||
* Write a message to the log file, based on a printf format string.
|
||||
*
|
||||
* @param source_file the name of the source code file submitting this log message
|
||||
* @param source_line the line of code in the source file
|
||||
* @param level the log level, one of "DEBUG", "INFO" or "ERROR"
|
||||
* @param format the printf format string for the message
|
||||
*/
|
||||
void log_printf(const char *source_file, int source_line, const char *level, const char *format, ...);
|
||||
|
||||
void log_close();
|
||||
|
||||
/**
|
||||
* Variadic macro to write an informational message to the log file, based on a printf format string.
|
||||
*/
|
||||
#define log_infof(format,...) log_printf(__FILE__, __LINE__, "INFO", format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Variadic macro to write an error message to the log file, based on a printf format string.
|
||||
*/
|
||||
#define log_errorf(format,...) log_printf(__FILE__, __LINE__, "ERROR", format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Variadic macro to write a debug message to the log file, based on a printf format string.
|
||||
*/
|
||||
#define log_debugf(format,...) log_printf(__FILE__, __LINE__, "DEBUG", format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Return the length of the string when trimmed of trailing spaces.
|
||||
* IBM MQ uses fixed length strings, so this function can be used to print
|
||||
* a trimmed version of a string using the "%.*s" printf format string.
|
||||
* For example, `log_printf("%.*s", trimmed_len(fw_str, 48), fw_str)`
|
||||
*/
|
||||
int trimmed_len(char *s, int);
|
||||
|
||||
#endif
|
||||
120
authservice/mqhtpass/src/log_test.c
Normal file
120
authservice/mqhtpass/src/log_test.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "log.h"
|
||||
|
||||
// Headers for multi-threaded tests
|
||||
#include <pthread.h>
|
||||
|
||||
// Start a test and log the function name
|
||||
#define test_start() printf("=== RUN: %s\n", __func__)
|
||||
|
||||
// Indicate test has passed
|
||||
#define test_pass() printf("--- PASS: %s\n", __func__)
|
||||
|
||||
// The length of strings used in the tests
|
||||
#define STR_LEN 5
|
||||
|
||||
// Indicate test has failed
|
||||
void test_fail(const char *test_name)
|
||||
{
|
||||
printf("--- FAIL: %s\n", test_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Print a fixed-width string in hexadecimal
|
||||
void print_hex(char fw_string[STR_LEN])
|
||||
{
|
||||
printf("[");
|
||||
for (int i=0; i<STR_LEN; i++)
|
||||
{
|
||||
printf("%02x", fw_string[i]);
|
||||
if (i < STR_LEN-1)
|
||||
printf(",");
|
||||
}
|
||||
printf("]");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Tests for string manipulation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void test_trimmed_len(const char *test_name, char fw_string[STR_LEN], int expected_len)
|
||||
{
|
||||
printf("=== RUN: %s\n", test_name);
|
||||
int len;
|
||||
// Create a copy of the fixed-width string
|
||||
char fw_string2[STR_LEN];
|
||||
memcpy(fw_string2, fw_string, STR_LEN * sizeof(char));
|
||||
// Call the function under test
|
||||
len = trimmed_len(fw_string, STR_LEN);
|
||||
// Check the result is correct
|
||||
if (len != expected_len)
|
||||
{
|
||||
printf("%s: Expected result to be %d; got %d\n", __func__, expected_len, len);
|
||||
test_fail(test_name);
|
||||
}
|
||||
// Check that the original string has not been changed
|
||||
for (int i=0; i<STR_LEN; i++)
|
||||
{
|
||||
if (fw_string[i] != fw_string2[i])
|
||||
{
|
||||
printf("%c-%c\n", fw_string[i], fw_string2[i]);
|
||||
printf("%s: Expected string to be identical to input hex ", __func__);
|
||||
print_hex(fw_string2);
|
||||
printf("; got hex ");
|
||||
print_hex(fw_string);
|
||||
printf("\n");
|
||||
test_fail(test_name);
|
||||
}
|
||||
}
|
||||
printf("--- PASS: %s\n", test_name);
|
||||
}
|
||||
|
||||
void test_trimmed_len_normal()
|
||||
{
|
||||
char fw_string[STR_LEN] = {'a','b','c',' ',' '};
|
||||
test_trimmed_len(__func__, fw_string, 3);
|
||||
}
|
||||
|
||||
void test_trimmed_len_full()
|
||||
{
|
||||
char fw_string[STR_LEN] = {'a','b','c','d','e'};
|
||||
test_trimmed_len(__func__, fw_string, 5);
|
||||
}
|
||||
|
||||
void test_trimmed_len_empty()
|
||||
{
|
||||
char fw_string[STR_LEN] = {' ',' ',' ',' ',' '};
|
||||
test_trimmed_len(__func__, fw_string, 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int main()
|
||||
{
|
||||
// Turn on debugging for the tests
|
||||
setenv("DEBUG", "true", true);
|
||||
log_init("log_test.log");
|
||||
test_trimmed_len_normal();
|
||||
test_trimmed_len_full();
|
||||
test_trimmed_len_empty();
|
||||
log_close();
|
||||
}
|
||||
342
authservice/mqhtpass/src/mqhtpass.c
Normal file
342
authservice/mqhtpass/src/mqhtpass.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2021, 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This is a developer only configuration and not recommended for production usage.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cmqec.h>
|
||||
#include "log.h"
|
||||
#include "htpass.h"
|
||||
|
||||
// Declare the internal functions that implement the interface
|
||||
MQZ_INIT_AUTHORITY MQStart;
|
||||
static MQZ_AUTHENTICATE_USER mqhtpass_authenticate_user;
|
||||
static MQZ_FREE_USER mqhtpass_free_user;
|
||||
static MQZ_TERM_AUTHORITY mqhtpass_terminate;
|
||||
|
||||
#define LOG_FILE "/var/mqm/errors/mqhtpass.json"
|
||||
#define HTPASSWD_FILE "/etc/mqm/mq.htpasswd"
|
||||
#define NAME "MQ Advanced for Developers custom authentication service"
|
||||
|
||||
/**
|
||||
* Initialization and entrypoint for the dynamically loaded
|
||||
* authorization installable service. It registers the addresses of the
|
||||
* other functions which are to be called by the queue manager.
|
||||
*
|
||||
* This function is called whenever the module is loaded. The Options
|
||||
* field will show whether it's a PRIMARY (i.e. during qmgr startup) or
|
||||
* SECONDARY.
|
||||
*/
|
||||
void MQENTRY MQStart(
|
||||
MQHCONFIG hc,
|
||||
MQLONG Options,
|
||||
MQCHAR48 QMgrName,
|
||||
MQLONG ComponentDataLength,
|
||||
PMQBYTE ComponentData,
|
||||
PMQLONG Version,
|
||||
PMQLONG pCompCode,
|
||||
PMQLONG pReason)
|
||||
{
|
||||
MQLONG CC = MQCC_OK;
|
||||
MQLONG Reason = MQRC_NONE;
|
||||
int log_rc = 0;
|
||||
|
||||
if (Options == MQZIO_PRIMARY)
|
||||
{
|
||||
// Reset the log file. The file could still get large if debug is turned on,
|
||||
// but this is a simpler solution for now.
|
||||
log_rc = log_init_reset(LOG_FILE);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_rc = log_init(LOG_FILE);
|
||||
}
|
||||
|
||||
if (log_rc != 0)
|
||||
{
|
||||
CC = MQCC_FAILED;
|
||||
Reason = MQRC_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
if (Options == MQZIO_PRIMARY)
|
||||
{
|
||||
log_infof("Initializing %s", NAME);
|
||||
}
|
||||
log_debugf("MQStart options=%s qmgr=%.*s", ((Options == MQZIO_SECONDARY) ? "Secondary" : "Primary"), trimmed_len(QMgrName, MQ_Q_MGR_NAME_LENGTH), QMgrName);
|
||||
|
||||
if (!htpass_valid_file(HTPASSWD_FILE))
|
||||
{
|
||||
CC = MQCC_FAILED;
|
||||
Reason = MQRC_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
// Initialize the functions to use for each entry point
|
||||
if (CC == MQCC_OK)
|
||||
{
|
||||
hc->MQZEP_Call(hc, MQZID_INIT_AUTHORITY, (PMQFUNC)MQStart, &CC, &Reason);
|
||||
}
|
||||
if (CC == MQCC_OK)
|
||||
{
|
||||
hc->MQZEP_Call(hc, MQZID_TERM_AUTHORITY, (PMQFUNC)mqhtpass_terminate, &CC, &Reason);
|
||||
}
|
||||
if (CC == MQCC_OK)
|
||||
{
|
||||
hc->MQZEP_Call(hc, MQZID_AUTHENTICATE_USER, (PMQFUNC)mqhtpass_authenticate_user, &CC, &Reason);
|
||||
}
|
||||
if (CC == MQCC_OK)
|
||||
{
|
||||
hc->MQZEP_Call(hc, MQZID_FREE_USER, (PMQFUNC)mqhtpass_free_user, &CC, &Reason);
|
||||
}
|
||||
*Version = MQZAS_VERSION_5;
|
||||
*pCompCode = CC;
|
||||
*pReason = Reason;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during the connection of any application which supplies an MQCSP (Connection Security Parameters).
|
||||
* This is the usual case.
|
||||
* See https://www.ibm.com/support/knowledgecenter/SSFKSJ_latest/com.ibm.mq.ref.dev.doc/q095610_.html
|
||||
*/
|
||||
static void MQENTRY mqhtpass_authenticate_user_csp(
|
||||
PMQCHAR pQMgrName,
|
||||
PMQCSP pSecurityParms,
|
||||
PMQZAC pApplicationContext,
|
||||
PMQZIC pIdentityContext,
|
||||
PMQPTR pCorrelationPtr,
|
||||
PMQBYTE pComponentData,
|
||||
PMQLONG pContinuation,
|
||||
PMQLONG pCompCode,
|
||||
PMQLONG pReason)
|
||||
{
|
||||
char *csp_user = NULL;
|
||||
char *csp_pass = NULL;
|
||||
|
||||
// Firstly, create null-terminated strings from the user credentials in the MQ CSP object
|
||||
csp_user = malloc(pSecurityParms->CSPUserIdLength + 1);
|
||||
if (!csp_user)
|
||||
{
|
||||
log_errorf("%s is unable to allocate memory for a user", NAME);
|
||||
*pCompCode = MQCC_FAILED;
|
||||
*pReason = MQRC_SERVICE_ERROR;
|
||||
return;
|
||||
}
|
||||
strncpy(csp_user, pSecurityParms->CSPUserIdPtr, pSecurityParms->CSPUserIdLength);
|
||||
csp_user[pSecurityParms->CSPUserIdLength] = 0;
|
||||
csp_pass = malloc((pSecurityParms->CSPPasswordLength + 1));
|
||||
if (!csp_pass)
|
||||
{
|
||||
log_errorf("%s is unable to allocate memory for a password", NAME);
|
||||
*pCompCode = MQCC_FAILED;
|
||||
*pReason = MQRC_SERVICE_ERROR;
|
||||
if (csp_user)
|
||||
{
|
||||
free(csp_user);
|
||||
}
|
||||
return;
|
||||
}
|
||||
strncpy(csp_pass, pSecurityParms->CSPPasswordPtr, pSecurityParms->CSPPasswordLength);
|
||||
csp_pass[pSecurityParms->CSPPasswordLength] = 0;
|
||||
log_debugf("%s with CSP user set. user=%s", __func__, csp_user);
|
||||
int auth_result = htpass_authenticate_user(HTPASSWD_FILE, csp_user, csp_pass);
|
||||
|
||||
if (auth_result == HTPASS_VALID)
|
||||
{
|
||||
// An OK completion code means MQ will accept this user is authenticated
|
||||
*pCompCode = MQCC_OK;
|
||||
*pReason = MQRC_NONE;
|
||||
// Tell the queue manager to stop trying other authorization services.
|
||||
*pContinuation = MQZCI_STOP;
|
||||
memcpy(pIdentityContext->UserIdentifier, csp_user, sizeof(pIdentityContext->UserIdentifier));
|
||||
log_debugf("Authenticated user=%s", pIdentityContext->UserIdentifier);
|
||||
}
|
||||
// If the htpasswd file does not have an entry for this user
|
||||
else if (auth_result == HTPASS_INVALID_USER)
|
||||
{
|
||||
*pCompCode = MQCC_WARNING;
|
||||
*pReason = MQRC_NONE;
|
||||
// Tell the queue manager to continue trying other authorization services, as they might have the user.
|
||||
*pContinuation = MQZCI_CONTINUE;
|
||||
log_debugf(
|
||||
"User authentication failed due to invalid user. user=%.*s effuser=%.*s applname=%.*s csp_user=%s cc=%d reason=%d",
|
||||
trimmed_len(pIdentityContext->UserIdentifier, MQ_USER_ID_LENGTH),
|
||||
pIdentityContext->UserIdentifier,
|
||||
trimmed_len(pApplicationContext->EffectiveUserID, MQ_USER_ID_LENGTH),
|
||||
pApplicationContext->EffectiveUserID,
|
||||
trimmed_len(pApplicationContext->ApplName, MQ_APPL_NAME_LENGTH),
|
||||
pApplicationContext->ApplName,
|
||||
csp_user,
|
||||
*pCompCode,
|
||||
*pReason);
|
||||
}
|
||||
// If the htpasswd file has an entry for this user, but the password supplied is incorrect
|
||||
else if (auth_result == HTPASS_INVALID_PASSWORD)
|
||||
{
|
||||
*pCompCode = MQCC_WARNING;
|
||||
*pReason = MQRC_NOT_AUTHORIZED;
|
||||
// Tell the queue manager to stop trying other authorization services.
|
||||
*pContinuation = MQZCI_STOP;
|
||||
log_debugf(
|
||||
"User authentication failed due to invalid password. user=%.*s effuser=%.*s applname=%.*s csp_user=%s cc=%d reason=%d",
|
||||
trimmed_len(pIdentityContext->UserIdentifier, MQ_USER_ID_LENGTH),
|
||||
pIdentityContext->UserIdentifier,
|
||||
trimmed_len(pApplicationContext->EffectiveUserID, MQ_USER_ID_LENGTH),
|
||||
pApplicationContext->EffectiveUserID,
|
||||
trimmed_len(pApplicationContext->ApplName, MQ_APPL_NAME_LENGTH),
|
||||
pApplicationContext->ApplName,
|
||||
csp_user,
|
||||
*pCompCode,
|
||||
*pReason);
|
||||
}
|
||||
if (csp_user)
|
||||
{
|
||||
free(csp_user);
|
||||
}
|
||||
if (csp_pass)
|
||||
{
|
||||
free(csp_pass);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during the connection of any application.
|
||||
* For more information on the parameters, see https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_latest/com.ibm.mq.ref.dev.doc/q110090_.html
|
||||
*/
|
||||
static void MQENTRY mqhtpass_authenticate_user(
|
||||
PMQCHAR pQMgrName,
|
||||
PMQCSP pSecurityParms,
|
||||
PMQZAC pApplicationContext,
|
||||
PMQZIC pIdentityContext,
|
||||
PMQPTR pCorrelationPtr,
|
||||
PMQBYTE pComponentData,
|
||||
PMQLONG pContinuation,
|
||||
PMQLONG pCompCode,
|
||||
PMQLONG pReason)
|
||||
{
|
||||
char *spuser = NULL;
|
||||
// By default, return a warning, which indicates to MQ that this
|
||||
// authorization service hasn't authenticated the user.
|
||||
*pCompCode = MQCC_WARNING;
|
||||
*pReason = MQRC_NONE;
|
||||
// By default, tell the queue manager to continue trying other
|
||||
// authorization services.
|
||||
*pContinuation = MQZCI_CONTINUE;
|
||||
|
||||
if ((pSecurityParms->AuthenticationType) == MQCSP_AUTH_USER_ID_AND_PWD)
|
||||
{
|
||||
mqhtpass_authenticate_user_csp(pQMgrName, pSecurityParms, pApplicationContext, pIdentityContext, pCorrelationPtr, pComponentData, pContinuation, pCompCode, pReason);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Password not supplied, so just check that the user ID is valid
|
||||
spuser = malloc(sizeof(PMQCHAR12) + 1);
|
||||
if (!spuser)
|
||||
{
|
||||
log_errorf("%s is unable to allocate memory to check a user", NAME);
|
||||
*pCompCode = MQCC_FAILED;
|
||||
*pReason = MQRC_SERVICE_ERROR;
|
||||
return;
|
||||
}
|
||||
strncpy(spuser, pApplicationContext->EffectiveUserID, strlen(pApplicationContext->EffectiveUserID));
|
||||
spuser[sizeof(PMQCHAR12)] = 0;
|
||||
log_debugf("%s without CSP user set. effectiveuid=%s env=%d, callertype=%d, type=%d, accttoken=%d applidentitydata=%d", __func__, spuser, pApplicationContext->Environment, pApplicationContext->CallerType, pApplicationContext->AuthenticationType, pIdentityContext->AccountingToken, pIdentityContext->ApplIdentityData);
|
||||
if (strncmp(spuser, "mqm", 3) == 0)
|
||||
{
|
||||
// Special case: pass the "mqm" user on for validation up the chain
|
||||
// A warning in the completion code means MQ will pass this to other authorization services
|
||||
*pCompCode = MQCC_WARNING;
|
||||
*pReason = MQRC_NONE;
|
||||
*pContinuation = MQZCI_CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool valid_user = htpass_valid_user(HTPASSWD_FILE, spuser);
|
||||
if (valid_user)
|
||||
{
|
||||
// An OK completion code means MQ will accept this user is authenticated
|
||||
*pCompCode = MQCC_OK;
|
||||
*pReason = MQRC_NONE;
|
||||
*pContinuation = MQZCI_STOP;
|
||||
memcpy(pIdentityContext->UserIdentifier, spuser, sizeof(pIdentityContext->UserIdentifier));
|
||||
}
|
||||
else
|
||||
{
|
||||
log_debugf(
|
||||
"User authentication failed user=%.*s effuser=%.*s applname=%.*s cspuser=%s cc=%d reason=%d",
|
||||
trimmed_len(pIdentityContext->UserIdentifier, MQ_USER_ID_LENGTH),
|
||||
pIdentityContext->UserIdentifier,
|
||||
trimmed_len(pApplicationContext->EffectiveUserID, MQ_USER_ID_LENGTH),
|
||||
pApplicationContext->EffectiveUserID,
|
||||
trimmed_len(pApplicationContext->ApplName, MQ_APPL_NAME_LENGTH),
|
||||
pApplicationContext->ApplName,
|
||||
spuser,
|
||||
*pCompCode,
|
||||
*pReason);
|
||||
}
|
||||
if (spuser)
|
||||
{
|
||||
free(spuser);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during MQDISC, as the inverse of the call to authenticate.
|
||||
*/
|
||||
static void MQENTRY mqhtpass_free_user(
|
||||
PMQCHAR pQMgrName,
|
||||
PMQZFP pFreeParms,
|
||||
PMQBYTE pComponentData,
|
||||
PMQLONG pContinuation,
|
||||
|
||||
PMQLONG pCompCode,
|
||||
PMQLONG pReason)
|
||||
{
|
||||
log_debugf("mqhtpass_freeuser()");
|
||||
*pCompCode = MQCC_WARNING;
|
||||
*pReason = MQRC_NONE;
|
||||
*pContinuation = MQZCI_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the authorization service is terminated.
|
||||
*/
|
||||
static void MQENTRY mqhtpass_terminate(
|
||||
MQHCONFIG hc,
|
||||
MQLONG Options,
|
||||
PMQCHAR pQMgrName,
|
||||
PMQBYTE pComponentData,
|
||||
PMQLONG pCompCode,
|
||||
PMQLONG pReason)
|
||||
{
|
||||
if (Options == MQZTO_PRIMARY)
|
||||
{
|
||||
log_infof("Terminating %s", NAME);
|
||||
log_close();
|
||||
}
|
||||
else {
|
||||
log_debugf("Terminating secondary");
|
||||
}
|
||||
*pCompCode = MQCC_OK;
|
||||
*pReason = MQRC_NONE;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
License information for Ubuntu packages may be found inside the image: /usr/share/doc/${package}/copyright
|
||||
@@ -1,89 +0,0 @@
|
||||

|
||||
|
||||
# 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.7 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
|
||||
@@ -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)
|
||||
@@ -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 -}}
|
||||
@@ -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 }}
|
||||
@@ -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" . }}
|
||||
@@ -1,102 +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
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
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 }}
|
||||
@@ -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
|
||||
@@ -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
@@ -1 +0,0 @@
|
||||
License information for Ubuntu packages may be found inside the image: /usr/share/doc/${package}/copyright
|
||||
@@ -1,198 +0,0 @@
|
||||

|
||||
|
||||
# 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.7 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
|
||||
@@ -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
|
||||
|
||||
@@ -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 -}}
|
||||
@@ -1,30 +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
|
||||
selector:
|
||||
app: {{ template "fullname" . }}
|
||||
@@ -1,105 +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
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
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 }}
|
||||
@@ -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
|
||||
@@ -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:
|
||||
# tag is the tag to use for the container repository
|
||||
tag:
|
||||
# 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
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
© Copyright IBM Corporation 2017, 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,38 +18,51 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strings"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/pkg/name"
|
||||
)
|
||||
|
||||
func queueManagerHealthy() (bool, error) {
|
||||
func queueManagerHealthy(ctx context.Context) (bool, error) {
|
||||
name, err := name.GetQueueManagerName()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Specify the queue manager name, just in case someone's created a second queue manager
|
||||
cmd := exec.Command("dspmq", "-n", "-m", name)
|
||||
// #nosec G204
|
||||
cmd := exec.CommandContext(ctx, "dspmq", "-n", "-m", name)
|
||||
// Run the command and wait for completion
|
||||
out, err := cmd.CombinedOutput()
|
||||
fmt.Printf("%s", out)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false, err
|
||||
}
|
||||
if !strings.Contains(string(out), "(RUNNING)") {
|
||||
if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") && !strings.Contains(string(out), "(REPLICA)") {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
healthy, err := queueManagerHealthy()
|
||||
func doMain() int {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
||||
defer cancel()
|
||||
|
||||
healthy, err := queueManagerHealthy(ctx)
|
||||
if err != nil {
|
||||
os.Exit(2)
|
||||
return 2
|
||||
}
|
||||
if !healthy {
|
||||
os.Exit(1)
|
||||
return 1
|
||||
}
|
||||
os.Exit(0)
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
os.Exit(doMain())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
© Copyright IBM Corporation 2017, 2023
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,14 +18,59 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/internal/ready"
|
||||
"github.com/ibm-messaging/mq-container/pkg/name"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:1414")
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
func doMain() int {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
||||
defer cancel()
|
||||
|
||||
// Check if runmqserver has indicated that it's finished configuration
|
||||
r, err := ready.Check()
|
||||
if !r || err != nil {
|
||||
return 1
|
||||
}
|
||||
name, err := name.GetQueueManagerName()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 1
|
||||
}
|
||||
|
||||
// Check if the queue manager has a running listener
|
||||
status, err := ready.Status(ctx, name)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
switch status {
|
||||
case ready.StatusActiveQM:
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:1414")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 1
|
||||
}
|
||||
err = conn.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return 0
|
||||
case ready.StatusStandbyQM:
|
||||
fmt.Printf("Detected queue manager running in standby mode")
|
||||
return 10
|
||||
case ready.StatusReplicaQM:
|
||||
fmt.Printf("Detected queue manager running in replica mode")
|
||||
return 20
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
func main() {
|
||||
os.Exit(doMain())
|
||||
}
|
||||
|
||||
67
cmd/chkmqstarted/main.go
Normal file
67
cmd/chkmqstarted/main.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2021, 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// chkmqstarted checks that MQ has successfully started, by checking the output of the "dspmq" command
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strings"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/pkg/name"
|
||||
)
|
||||
|
||||
func queueManagerStarted(ctx context.Context) (bool, error) {
|
||||
name, err := name.GetQueueManagerName()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Specify the queue manager name, just in case someone's created a second queue manager
|
||||
// #nosec G204
|
||||
cmd := exec.CommandContext(ctx, "dspmq", "-n", "-m", name)
|
||||
// Run the command and wait for completion
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false, err
|
||||
}
|
||||
if !strings.Contains(string(out), "(RUNNING)") && !strings.Contains(string(out), "(RUNNING AS STANDBY)") && !strings.Contains(string(out), "(STARTING)") && !strings.Contains(string(out), "(REPLICA)") {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func doMain() int {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
||||
defer cancel()
|
||||
|
||||
started, err := queueManagerStarted(ctx)
|
||||
if err != nil {
|
||||
return 2
|
||||
}
|
||||
if !started {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
os.Exit(doMain())
|
||||
}
|
||||
162
cmd/runmqdevserver/main.go
Normal file
162
cmd/runmqdevserver/main.go
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2018, 2023
|
||||
|
||||
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"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/internal/htpasswd"
|
||||
"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 getLogFormat() string {
|
||||
logFormat := strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_FORMAT")))
|
||||
//old-style env var is used.
|
||||
if logFormat == "" {
|
||||
logFormat = strings.ToLower(strings.TrimSpace(os.Getenv("LOG_FORMAT")))
|
||||
}
|
||||
|
||||
if logFormat != "" && (logFormat == "basic" || logFormat == "json") {
|
||||
return logFormat
|
||||
} else {
|
||||
//this is the case where value is either empty string or set to something other than "basic"/"json"
|
||||
logFormat = "basic"
|
||||
}
|
||||
|
||||
return logFormat
|
||||
}
|
||||
|
||||
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 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)
|
||||
// #nosec G306 - its a read by owner/s group, and pose no harm.
|
||||
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 {
|
||||
adminPassword = "passw0rd"
|
||||
err = os.Setenv("MQ_ADMIN_PASSWORD", adminPassword)
|
||||
if err != nil {
|
||||
logTerminationf("Error setting admin password variable: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = htpasswd.SetPassword("admin", adminPassword, false)
|
||||
if err != nil {
|
||||
logTerminationf("Error setting admin password: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
appPassword, set := os.LookupEnv("MQ_APP_PASSWORD")
|
||||
if set {
|
||||
err = htpasswd.SetPassword("app", appPassword, false)
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
50
cmd/runmqdevserver/mqsc.go
Normal file
50
cmd/runmqdevserver/mqsc.go
Normal 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
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
© Copyright IBM Corporation 2017, 2020
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,33 +16,14 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
//const mainDir string := "/mnt/mqm"
|
||||
const mqmUID uint32 = 999
|
||||
const mqmGID uint32 = 999
|
||||
|
||||
func createVolume(path string) error {
|
||||
// fi, err := os.Stat(path)
|
||||
// if err != nil {
|
||||
// if os.IsNotExist(err) {
|
||||
// // TODO: Should this be fatal?
|
||||
// //log.Warnf("No volume found under %v", path)
|
||||
// return nil
|
||||
// } else {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
//log.Printf("%v details: %v", path, fi.Sys())
|
||||
dataPath := filepath.Join(path, "data")
|
||||
fi, err := os.Stat(dataPath)
|
||||
func createVolume(dataPath string) error {
|
||||
_, err := os.Stat(dataPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// #nosec G301
|
||||
err = os.MkdirAll(dataPath, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -51,37 +32,5 @@ func createVolume(path string) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fi, err = os.Stat(dataPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sys := fi.Sys()
|
||||
if sys != nil && runtime.GOOS == "linux" {
|
||||
// log.Printf("Checking UID/GID for %v", dataPath)
|
||||
//log.Debugf("Checking UID/GID for %v", dataPath)
|
||||
stat := sys.(*syscall.Stat_t)
|
||||
if stat.Uid != mqmUID || stat.Gid != mqmGID {
|
||||
err = os.Chown(dataPath, int(mqmUID), int(mqmGID))
|
||||
if err != nil {
|
||||
log.Printf("Error: Unable to change ownership of %v", dataPath)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If /mnt/mqm exists
|
||||
// If /mnt/mqm contains a "data" directory AND data is owned by mqm:mqm AND data is writeable by mqm:mqm then
|
||||
// Create Symlink from /var/mqm to /mnt/mqm/data
|
||||
// Else
|
||||
// // Try to sort it out
|
||||
// Create directory /mnt/mqm/data
|
||||
// If directory not already owned by mqm:mqm
|
||||
// chown mqm:mqm
|
||||
// if error
|
||||
// delete directory again if empty
|
||||
// if directory not already 0755
|
||||
// chmod 0755
|
||||
// if error
|
||||
// delete directory again if empty
|
||||
|
||||
93
cmd/runmqserver/license.go
Normal file
93
cmd/runmqserver/license.go
Normal 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")
|
||||
}
|
||||
282
cmd/runmqserver/license_test.go
Normal file
282
cmd/runmqserver/license_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
432
cmd/runmqserver/logging.go
Normal file
432
cmd/runmqserver/logging.go
Normal file
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017, 2023
|
||||
|
||||
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"
|
||||
"sort"
|
||||
"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)
|
||||
// #nosec G306 - its a read by owner/s group, and pose no harm.
|
||||
err := ioutil.WriteFile("/run/termination-log", []byte(msg), 0660)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
log.Error(msg)
|
||||
|
||||
if collectDiagOnFail {
|
||||
logDiagnostics()
|
||||
}
|
||||
}
|
||||
|
||||
func getLogFormat() string {
|
||||
logFormat := strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_FORMAT")))
|
||||
//old-style env var is used.
|
||||
if logFormat == "" {
|
||||
logFormat = strings.ToLower(strings.TrimSpace(os.Getenv("LOG_FORMAT")))
|
||||
}
|
||||
|
||||
if logFormat != "" && (logFormat == "basic" || logFormat == "json") {
|
||||
return logFormat
|
||||
} else {
|
||||
//this is the case where value is either empty string or set to something other than "basic"/"json"
|
||||
logFormat = "basic"
|
||||
}
|
||||
|
||||
return logFormat
|
||||
}
|
||||
|
||||
// formatBasic formats a log message parsed from JSON, as "basic" text
|
||||
func formatBasic(obj map[string]interface{}) string {
|
||||
// Emulate the MQ "MessageDetail=Extended" option, by appending inserts to the message
|
||||
// This is important for certain messages, where key details are only available in the extended message content
|
||||
inserts := make([]string, 0)
|
||||
for k, v := range obj {
|
||||
if strings.HasPrefix(k, "ibm_commentInsert") {
|
||||
inserts = append(inserts, fmt.Sprintf("%s(%v)", strings.Replace(k, "ibm_comment", "Comment", 1), obj[k]))
|
||||
} else if strings.HasPrefix(k, "ibm_arithInsert") {
|
||||
if v.(float64) != 0 {
|
||||
inserts = append(inserts, fmt.Sprintf("%s(%v)", strings.Replace(k, "ibm_arith", "Arith", 1), obj[k]))
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Strings(inserts)
|
||||
if len(inserts) > 0 {
|
||||
return fmt.Sprintf("%s %s [%v]\n", obj["ibm_datetime"], obj["message"], strings.Join(inserts, ", "))
|
||||
}
|
||||
// Convert time zone information from some logs (e.g. Liberty) for consistency
|
||||
obj["ibm_datetime"] = strings.Replace(obj["ibm_datetime"].(string), "+0000", "Z", 1)
|
||||
// Escape any new-line characters, so that we don't get multi-line messages messing up the output
|
||||
obj["message"] = strings.ReplaceAll(obj["message"].(string), "\n", "\\n")
|
||||
|
||||
if obj["type"] != nil && (obj["type"] == "liberty_trace") {
|
||||
timeStamp := obj["ibm_datetime"]
|
||||
threadID := ""
|
||||
srtModuleName := ""
|
||||
logLevel := ""
|
||||
ibmClassName := ""
|
||||
srtIbmClassName := ""
|
||||
ibmMethodName := ""
|
||||
message := ""
|
||||
|
||||
if obj["loglevel"] != nil {
|
||||
//threadID is captured below
|
||||
if obj["ibm_threadId"] != nil {
|
||||
threadID = obj["ibm_threadId"].(string)
|
||||
}
|
||||
|
||||
//logLevel character to be mirrored in console web server logging is decided below
|
||||
logLevelTmp := obj["loglevel"].(string)
|
||||
switch logLevelTmp {
|
||||
case "AUDIT":
|
||||
logLevel = "A"
|
||||
case "INFO":
|
||||
logLevel = "I"
|
||||
case "EVENT":
|
||||
logLevel = "1"
|
||||
case "ENTRY":
|
||||
logLevel = ">"
|
||||
case "EXIT":
|
||||
logLevel = "<"
|
||||
case "FINE":
|
||||
logLevel = "1"
|
||||
case "FINER":
|
||||
logLevel = "2"
|
||||
case "FINEST":
|
||||
logLevel = "3"
|
||||
default:
|
||||
logLevel = string(logLevelTmp[0])
|
||||
}
|
||||
|
||||
//This is a 13 characters string present in extracted out of module node
|
||||
if obj["module"] != nil {
|
||||
srtModuleNameArr := strings.Split(obj["module"].(string), ".")
|
||||
arrLen := len(srtModuleNameArr)
|
||||
srtModuleName = srtModuleNameArr[arrLen-1]
|
||||
if len(srtModuleName) > 13 {
|
||||
srtModuleName = srtModuleName[0:13]
|
||||
}
|
||||
}
|
||||
if obj["ibm_className"] != nil {
|
||||
ibmClassName = obj["ibm_className"].(string)
|
||||
|
||||
//A 13 character string is extracted from class name. This is required for FINE, FINER & FINEST log lines
|
||||
ibmClassNameArr := strings.Split(ibmClassName, ".")
|
||||
arrLen := len(ibmClassNameArr)
|
||||
srtIbmClassName = ibmClassNameArr[arrLen-1]
|
||||
if len(srtModuleName) > 13 {
|
||||
srtIbmClassName = srtIbmClassName[0:13]
|
||||
}
|
||||
}
|
||||
if obj["ibm_methodName"] != nil {
|
||||
ibmMethodName = obj["ibm_methodName"].(string)
|
||||
}
|
||||
if obj["message"] != nil {
|
||||
message = obj["message"].(string)
|
||||
}
|
||||
|
||||
//For AUDIT & INFO logging
|
||||
if logLevel == "A" || logLevel == "I" {
|
||||
return fmt.Sprintf("%s %s %-13s %s %s %s %s\n", timeStamp, threadID, srtModuleName, logLevel, ibmClassName, ibmMethodName, message)
|
||||
}
|
||||
//For EVENT logLevel
|
||||
if logLevelTmp == "EVENT" {
|
||||
return fmt.Sprintf("%s %s %-13s %s %s\n", timeStamp, threadID, srtModuleName, logLevel, message)
|
||||
}
|
||||
//For ENTRY & EXIT
|
||||
if logLevel == ">" || logLevel == "<" {
|
||||
return fmt.Sprintf("%s %s %-13s %s %s %s\n", timeStamp, threadID, srtModuleName, logLevel, ibmMethodName, message)
|
||||
}
|
||||
//For deeper log levels
|
||||
if logLevelTmp == "FINE" || logLevel == "2" || logLevel == "3" {
|
||||
return fmt.Sprintf("%s %s %-13s %s %s %s %s\n", timeStamp, threadID, srtIbmClassName, logLevel, ibmClassName, ibmMethodName, message)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s %s\n", obj["ibm_datetime"], obj["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)
|
||||
}
|
||||
|
||||
// mirrorHTPasswdLogs starts a goroutine to mirror the contents of the MQ HTPasswd authorization service's log
|
||||
func mirrorHTPasswdLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
||||
return mirrorLog(ctx, wg, "/var/mqm/errors/mqhtpass.json", false, mf, true)
|
||||
}
|
||||
|
||||
// mirrorWebServerLogs starts a goroutine to mirror the contents of the Liberty web server messages.log
|
||||
func mirrorWebServerLogs(ctx context.Context, wg *sync.WaitGroup, name string, fromStart bool, mf mirrorFunc) (chan error, error) {
|
||||
return mirrorLog(ctx, wg, "/var/mqm/web/installations/Installation1/servers/mqweb/logs/messages.log", 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 {
|
||||
arrLoggingConsoleExcludeIds := strings.Split(strings.ToUpper(os.Getenv("MQ_LOGGING_CONSOLE_EXCLUDE_ID")), ",")
|
||||
if isExcludedMsgIdPresent(msg, arrLoggingConsoleExcludeIds) {
|
||||
//If excluded id is present do not mirror it, return back
|
||||
return false
|
||||
}
|
||||
// Check if the message is JSON
|
||||
if len(msg) > 0 && msg[0] == '{' {
|
||||
obj, err := processLogMessage(msg)
|
||||
if err == nil && isQMLog && filterQMLogMessage(obj) {
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("Failed to unmarshall JSON in log message - %v", msg)
|
||||
} else {
|
||||
fmt.Println(msg)
|
||||
}
|
||||
} else {
|
||||
// The log being mirrored isn't JSON, so wrap it in a simple JSON message
|
||||
// MQ error logs are usually JSON, but this is useful for Liberty logs - usually expect WLP_LOGGING_MESSAGE_FORMAT=JSON to be set when mirroring Liberty logs.
|
||||
fmt.Printf("{\"message\":\"%s\"}\n", msg)
|
||||
}
|
||||
return true
|
||||
}, 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 {
|
||||
arrLoggingConsoleExcludeIds := strings.Split(strings.ToUpper(os.Getenv("MQ_LOGGING_CONSOLE_EXCLUDE_ID")), ",")
|
||||
if isExcludedMsgIdPresent(msg, arrLoggingConsoleExcludeIds) {
|
||||
//If excluded id is present do not mirror it, return back
|
||||
return false
|
||||
}
|
||||
// Check if the message is JSON
|
||||
if len(msg) > 0 && msg[0] == '{' {
|
||||
// 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 in log message - %v", err)
|
||||
} else {
|
||||
fmt.Print(formatBasic(obj))
|
||||
}
|
||||
} else {
|
||||
// The log being mirrored isn't JSON, so just print it.
|
||||
// MQ error logs are usually JSON, but this is useful for Liberty logs - usually expect WLP_LOGGING_MESSAGE_FORMAT=JSON to be set when mirroring Liberty logs.
|
||||
fmt.Println(msg)
|
||||
}
|
||||
return true
|
||||
}, 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
|
||||
}
|
||||
|
||||
// Function to check if ids provided in MQ_LOGGING_CONSOLE_EXCLUDE_ID are present in given log line or not
|
||||
func isExcludedMsgIdPresent(msg string, envExcludeIds []string) bool {
|
||||
for _, id := range envExcludeIds {
|
||||
if id != "" && strings.Contains(msg, strings.TrimSpace(id)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func logDiagnostics() {
|
||||
if getDebug() {
|
||||
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 ---")
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the value of MQ_LOGGING_CONSOLE_SOURCE environment variable
|
||||
func getMQLogConsoleSource() string {
|
||||
return strings.ToLower(strings.TrimSpace(os.Getenv("MQ_LOGGING_CONSOLE_SOURCE")))
|
||||
|
||||
}
|
||||
|
||||
// Function to check if valid values are provided for environment variable MQ_LOGGING_CONSOLE_SOURCE. If not valid, main program throws a warning to console
|
||||
func isLogConsoleSourceValid() bool {
|
||||
mqLogSource := getMQLogConsoleSource()
|
||||
retValue := false
|
||||
//If nothing is set, we will mirror qmgr, so valid
|
||||
if mqLogSource == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
logConsoleSource := strings.Split(mqLogSource, ",")
|
||||
//This will find out if the environment variable contains permitted values and is comma separated
|
||||
for _, src := range logConsoleSource {
|
||||
switch strings.TrimSpace(src) {
|
||||
//If it is a permitted value, it is valid. Keep it as true, but dont return it. We may encounter something junk soon
|
||||
case "qmgr", "web", "":
|
||||
retValue = true
|
||||
//If invalid entry arrives in-between/anywhere, just return false, there is no turning back
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return retValue
|
||||
}
|
||||
|
||||
// To check which all logs have to be mirrored
|
||||
func checkLogSourceForMirroring(source string) bool {
|
||||
logsrcs := getMQLogConsoleSource()
|
||||
|
||||
//Nothing set, this is when we mirror qmgr
|
||||
if logsrcs == "" {
|
||||
if source == "qmgr" {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Split the csv environment value so that we get an accurate comparison instead of a contains() check
|
||||
logSrcArr := strings.Split(logsrcs, ",")
|
||||
|
||||
//Iterate through the array to decide on mirroring
|
||||
for _, arr := range logSrcArr {
|
||||
switch strings.TrimSpace(arr) {
|
||||
case "qmgr":
|
||||
//If value of source is qmgr and it exists in environment variable, mirror qmgr logs
|
||||
if source == "qmgr" {
|
||||
return true
|
||||
}
|
||||
case "web":
|
||||
//If value of source is web and it exists in environment variable, and mirror web logs
|
||||
if source == "web" {
|
||||
//If older environment variable is set make sure to print appropriate message
|
||||
if os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG") != "" {
|
||||
log.Println("Environment variable MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG has now been replaced. Use MQ_LOGGING_CONSOLE_SOURCE instead.")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
139
cmd/runmqserver/logging_test.go
Normal file
139
cmd/runmqserver/logging_test.go
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2020, 2023
|
||||
|
||||
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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var formatBasicTests = []struct {
|
||||
in []byte
|
||||
outContains string
|
||||
}{
|
||||
{
|
||||
[]byte("{\"ibm_datetime\":\"2020/06/24 00:00:00\",\"message\":\"Hello world\"}"),
|
||||
"Hello",
|
||||
},
|
||||
{
|
||||
[]byte("{\"ibm_datetime\":\"2020/06/24 00:00:00\",\"message\":\"Hello world\", \"ibm_commentInsert1\":\"foo\"}"),
|
||||
"CommentInsert1(foo)",
|
||||
},
|
||||
{
|
||||
[]byte("{\"ibm_datetime\":\"2020/06/24 00:00:00\",\"message\":\"Hello world\", \"ibm_arithInsert1\":1}"),
|
||||
"ArithInsert1(1)",
|
||||
},
|
||||
}
|
||||
|
||||
func TestFormatBasic(t *testing.T) {
|
||||
for i, table := range formatBasicTests {
|
||||
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
|
||||
var inObj map[string]interface{}
|
||||
json.Unmarshal(table.in, &inObj)
|
||||
t.Logf("Unmarshalled: %+v", inObj)
|
||||
out := formatBasic(inObj)
|
||||
if !strings.Contains(out, table.outContains) {
|
||||
t.Errorf("formatBasic() with input=%v - expected output to contain %v, got %v", string(table.in), table.outContains, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// This test covers for functions isLogConsoleSourceValid() & checkLogSourceForMirroring()
|
||||
var mqLogSourcesTests = []struct {
|
||||
testNum int
|
||||
logsrc string
|
||||
exptValid bool
|
||||
exptQmgrSrc bool
|
||||
exptWebSrc bool
|
||||
}{
|
||||
{1, "qmgr,web", true, true, true},
|
||||
{2, "qmgr", true, true, false},
|
||||
{3, "web,qmgr", true, true, true},
|
||||
{4, "web", true, false, true},
|
||||
{5, " ", true, true, false},
|
||||
{6, "QMGR,WEB", true, true, true},
|
||||
{7, "qmgr, ", true, true, false},
|
||||
{8, "qmgr , web", true, true, true},
|
||||
{9, "qmgr,dummy", false, true, false},
|
||||
{10, "fake,dummy", false, false, false},
|
||||
{11, "qmgr,fake,dummy", false, true, false},
|
||||
{12, "fake,dummy,web", false, false, true},
|
||||
{13, "true", false, false, false},
|
||||
{14, "false", false, false, false},
|
||||
{15, "", true, true, false},
|
||||
}
|
||||
|
||||
func TestLoggingConsoleSourceInputs(t *testing.T) {
|
||||
for _, mqlogsrctest := range mqLogSourcesTests {
|
||||
err := os.Setenv("MQ_LOGGING_CONSOLE_SOURCE", mqlogsrctest.logsrc)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
isValid := isLogConsoleSourceValid()
|
||||
if isValid != mqlogsrctest.exptValid {
|
||||
t.Errorf("Expected return value from isLogConsoleSourceValid() is %v for MQ_LOGGING_CONSOLE_SOURCE='%v', got %v\n", mqlogsrctest.exptValid, mqlogsrctest.logsrc, isValid)
|
||||
}
|
||||
isLogSrcQmgr := checkLogSourceForMirroring("qmgr")
|
||||
if isLogSrcQmgr != mqlogsrctest.exptQmgrSrc {
|
||||
t.Errorf("Expected return value from checkLogSourceForMirroring() is %v for MQ_LOGGING_CONSOLE_SOURCE='%v', got %v\n", mqlogsrctest.exptQmgrSrc, mqlogsrctest.logsrc, isLogSrcQmgr)
|
||||
}
|
||||
isLogSrcWeb := checkLogSourceForMirroring("web")
|
||||
if isLogSrcWeb != mqlogsrctest.exptWebSrc {
|
||||
t.Errorf("Expected return value from checkLogSourceForMirroring() is %v for MQ_LOGGING_CONSOLE_SOURCE='%v', got %v\n", mqlogsrctest.exptWebSrc, mqlogsrctest.logsrc, isLogSrcWeb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test covers for function isExcludedMsgIdPresent()
|
||||
var mqExcludeIDTests = []struct {
|
||||
testNum int
|
||||
exculdeIDsArr []string
|
||||
expectedRetVal bool
|
||||
logEntry string
|
||||
}{
|
||||
{
|
||||
1,
|
||||
[]string{"AMQ5051I", "AMQ5037I", "AMQ5975I"},
|
||||
true,
|
||||
"{\"ibm_messageId\":\"AMQ5051I\",\"ibm_arithInsert1\":0,\"ibm_arithInsert2\":1,\"message\":\"AMQ5051I: The queue manager task 'AUTOCONFIG' has started.\"}",
|
||||
},
|
||||
{
|
||||
2,
|
||||
[]string{"AMQ5975I", "AMQ5037I"},
|
||||
false,
|
||||
"{\"ibm_messageId\":\"AMQ5051I\",\"ibm_arithInsert1\":0,\"ibm_arithInsert2\":1,\"message\":\"AMQ5051I: The queue manager task 'AUTOCONFIG' has started.\"}",
|
||||
},
|
||||
{
|
||||
3,
|
||||
[]string{""},
|
||||
false,
|
||||
"{\"ibm_messageId\":\"AMQ5051I\",\"ibm_arithInsert1\":0,\"ibm_arithInsert2\":1,\"message\":\"AMQ5051I: The queue manager task 'AUTOCONFIG' has started.\"}",
|
||||
},
|
||||
}
|
||||
|
||||
func TestIsExcludedMsgIDPresent(t *testing.T) {
|
||||
for _, excludeIDTest := range mqExcludeIDTests {
|
||||
retVal := isExcludedMsgIdPresent(excludeIDTest.logEntry, excludeIDTest.exculdeIDsArr)
|
||||
if retVal != excludeIDTest.expectedRetVal {
|
||||
t.Errorf("%v. Expected return value from isExcludedMsgIdPresent() is %v for MQ_LOGGING_CONSOLE_EXCLUDE_ID='%v', got %v\n",
|
||||
excludeIDTest.testNum, excludeIDTest.expectedRetVal, excludeIDTest.exculdeIDsArr, retVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
© Copyright IBM Corporation 2017, 2023
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,314 +18,307 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"github.com/ibm-messaging/mq-container/internal/fips"
|
||||
"github.com/ibm-messaging/mq-container/internal/ha"
|
||||
"github.com/ibm-messaging/mq-container/internal/metrics"
|
||||
"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
|
||||
// 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"
|
||||
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 doMain() error {
|
||||
var initFlag = flag.Bool("i", false, "initialize volume only, then exit")
|
||||
var infoFlag = flag.Bool("info", false, "Display debug info, then exit")
|
||||
var noLogRuntimeFlag = flag.Bool("nologruntime", false, "used when running this program from another program, to control log output")
|
||||
var devFlag = flag.Bool("dev", false, "used when running this program from runmqdevserver to control how TLS is configured")
|
||||
flag.Parse()
|
||||
|
||||
func checkLicense() {
|
||||
lic, ok := os.LookupEnv("LICENSE")
|
||||
switch {
|
||||
case ok && lic == "accept":
|
||||
return
|
||||
case ok && lic == "view":
|
||||
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
|
||||
buf, err := ioutil.ReadFile(file)
|
||||
name, nameErr := name.GetQueueManagerName()
|
||||
mf, err := configureLogger(name)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Check whether they only want debug info
|
||||
if *infoFlag {
|
||||
logVersionInfo()
|
||||
err = containerruntimelogger.LogContainerDetails(log)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
log.Printf("Error displaying container details: %v", err)
|
||||
}
|
||||
fmt.Println(string(buf))
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
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
|
||||
func sanitizeQueueManagerName(name string) string {
|
||||
var re = regexp.MustCompile("[^a-zA-Z0-9._%/]")
|
||||
return re.ReplaceAllString(name, "")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return "", err
|
||||
}
|
||||
name = sanitizeQueueManagerName(name)
|
||||
}
|
||||
// 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
|
||||
// complete and returns the exit status (return code).
|
||||
func runCommand(name string, arg ...string) (string, int, error) {
|
||||
// log.Debugf("Running command %v %v", name, arg)
|
||||
cmd := exec.Command(name, arg...)
|
||||
// Run the command and wait for completion
|
||||
out, err := cmd.CombinedOutput()
|
||||
err = verifySingleProcess()
|
||||
if err != nil {
|
||||
var rc int
|
||||
// Only works on Linux
|
||||
if runtime.GOOS == "linux" {
|
||||
// func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error)
|
||||
var ws unix.WaitStatus
|
||||
//var rusage syscall.Rusage
|
||||
unix.Wait4(cmd.Process.Pid, &ws, 0, nil)
|
||||
//ee := err.(*os.SyscallError)
|
||||
//ws := ee.Sys().(syscall.WaitStatus)
|
||||
rc = ws.ExitStatus()
|
||||
} else {
|
||||
rc = -1
|
||||
}
|
||||
if rc == 0 {
|
||||
return string(out), rc, nil
|
||||
}
|
||||
return string(out), rc, err
|
||||
// We don't do the normal termination here as it would create a termination file.
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
return string(out), 0, nil
|
||||
}
|
||||
|
||||
// createDirStructure creates the default MQ directory structure under /var/mqm
|
||||
func createDirStructure() {
|
||||
out, _, err := runCommand("/opt/mqm/bin/crtmqdir", "-f", "-s")
|
||||
if nameErr != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
err = ready.Clear()
|
||||
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")
|
||||
}
|
||||
|
||||
func createQueueManager(name string) {
|
||||
log.Printf("Creating queue manager %v", name)
|
||||
out, rc, err := runCommand("crtmqm", "-q", "-p", "1414", name)
|
||||
accepted, err := checkLicense()
|
||||
if err != nil {
|
||||
// 8=Queue manager exists, which is fine
|
||||
if rc != 8 {
|
||||
log.Printf("crtmqm returned %v", rc)
|
||||
log.Fatalln(string(out))
|
||||
} else {
|
||||
log.Printf("Detected existing queue manager %v", name)
|
||||
return
|
||||
}
|
||||
logTerminationf("Error checking license acceptance: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func updateCommandLevel() {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// mirrorLog tails the specified file, and logs each line.
|
||||
// This is useful for usability, as the container console log can show
|
||||
// messages from the MQ log.
|
||||
// func mirrorLog(path string) error {
|
||||
// tail, err := tail.TailFile(path, tail.Config{
|
||||
// ReOpen: true,
|
||||
// Follow: true,
|
||||
// Poll: true,
|
||||
// Location: &tail.SeekInfo{
|
||||
// Offset: 0,
|
||||
// // End of file
|
||||
// Whence: 2,
|
||||
// },
|
||||
// Logger: tail.DiscardingLogger,
|
||||
// })
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// go func() {
|
||||
// for line := range tail.Lines {
|
||||
// // TODO: Unless we parse the message, the timestamp will be (slightly) wrong
|
||||
// if strings.HasPrefix(line.Text, "AMQ") {
|
||||
// // TODO: Extended characters don't print correctly
|
||||
// log.Println(line.Text)
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func main() {
|
||||
createReaper()
|
||||
checkLicense()
|
||||
|
||||
// Start SIGTERM handler channel
|
||||
done := createTerminateChannel()
|
||||
|
||||
name, err := getQueueManagerName()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
if !accepted {
|
||||
err = errors.New("License not accepted")
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
log.Printf("Using queue manager name: %v", name)
|
||||
logConfig()
|
||||
err = createVolume("/mnt/mqm")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
// Start signal handler
|
||||
signalControl := signalHandler(name)
|
||||
// Enable diagnostic collecting on failure
|
||||
collectDiagOnFail = true
|
||||
|
||||
if *noLogRuntimeFlag == false {
|
||||
err = containerruntimelogger.LogContainerDetails(log)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
enableTraceCrtmqdir := os.Getenv("MQ_ENABLE_TRACE_CRTMQDIR")
|
||||
if enableTraceCrtmqdir == "true" || enableTraceCrtmqdir == "1" {
|
||||
err = startMQTrace()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = createDirStructure()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if enableTraceCrtmqdir == "true" || enableTraceCrtmqdir == "1" {
|
||||
err = endMQTrace()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If init flag is set, exit now
|
||||
if *initFlag {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Print out versioning information
|
||||
logVersionInfo()
|
||||
|
||||
// Determine FIPS compliance level
|
||||
fips.ProcessFIPSType(log)
|
||||
|
||||
keyLabel, defaultCmsKeystore, defaultP12Truststore, err := tls.ConfigureDefaultTLSKeystores()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = tls.ConfigureTLS(keyLabel, defaultCmsKeystore, *devFlag, log)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
//Validate MQ_LOG_CONSOLE_SOURCE variable
|
||||
if !isLogConsoleSourceValid() {
|
||||
log.Println("One or more invalid value is provided for MQ_LOGGING_CONSOLE_SOURCE. Allowed values are 'qmgr' & 'web' in csv format")
|
||||
}
|
||||
|
||||
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()
|
||||
}()
|
||||
|
||||
//For mirroring web server logs if source variable is set
|
||||
if checkLogSourceForMirroring("web") {
|
||||
// Always log from the end of the web server messages.log, because the log rotation should happen as soon as the web server starts
|
||||
_, err = mirrorWebServerLogs(ctx, &wg, name, false, mf)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = postInit(name, keyLabel, defaultP12Truststore)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if os.Getenv("MQ_NATIVE_HA") == "true" {
|
||||
err = ha.ConfigureNativeHA(log)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Post FIPS initialization processing
|
||||
fips.PostInit(log)
|
||||
|
||||
enableTraceCrtmqm := os.Getenv("MQ_ENABLE_TRACE_CRTMQM")
|
||||
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
||||
err = startMQTrace()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
newQM, err := createQueueManager(name, *devFlag)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
||||
err = endMQTrace()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//For mirroring mq system logs and qm logs, if environment variable is set
|
||||
if checkLogSourceForMirroring("qmgr") {
|
||||
//Mirror MQ system logs
|
||||
_, err = mirrorSystemErrorLogs(ctx, &wg, mf)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
//Mirror queue manager logs
|
||||
_, err = mirrorQueueManagerErrorLogs(ctx, &wg, name, newQM, mf)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if *devFlag {
|
||||
_, err = mirrorHTPasswdLogs(ctx, &wg, name, newQM, mf)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = updateCommandLevel()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
enableTraceStrmqm := os.Getenv("MQ_ENABLE_TRACE_STRMQM")
|
||||
if enableTraceStrmqm == "true" || enableTraceStrmqm == "1" {
|
||||
err = startMQTrace()
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// This is a developer image only change
|
||||
// This workaround should be removed and handled via <crtmqm -ii>, when inimerge is ready to handle stanza ordering
|
||||
if *devFlag {
|
||||
err = updateQMini(name)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = startQueueManager(name)
|
||||
if err != nil {
|
||||
logTermination(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if enableTraceStrmqm == "true" || enableTraceStrmqm == "1" {
|
||||
err = endMQTrace()
|
||||
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()
|
||||
//mirrorLog("/var/mqm/qmgrs/" + name + "/errors/AMQERR01.LOG")
|
||||
createQueueManager(name)
|
||||
updateCommandLevel()
|
||||
startQueueManager()
|
||||
configureQueueManager()
|
||||
// Wait for terminate signal
|
||||
<-done
|
||||
<-signalControl
|
||||
return nil
|
||||
}
|
||||
|
||||
var osExit = os.Exit
|
||||
|
||||
func main() {
|
||||
err := doMain()
|
||||
if err != nil {
|
||||
osExit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
© 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.
|
||||
@@ -17,18 +17,45 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/pkg/logger"
|
||||
)
|
||||
|
||||
var test *bool
|
||||
|
||||
func init() {
|
||||
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.
|
||||
func TestSystem(t *testing.T) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
200
cmd/runmqserver/mirror.go
Normal file
200
cmd/runmqserver/mirror.go
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
© 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.
|
||||
// #nosec G304 - no harm, we open readonly and check error.
|
||||
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())
|
||||
// #nosec G304 - no harm, we open readonly and check error.
|
||||
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)
|
||||
// #nosec G304 - no harm, we open readonly and check error.
|
||||
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
|
||||
}
|
||||
195
cmd/runmqserver/mirror_test.go
Normal file
195
cmd/runmqserver/mirror_test.go
Normal 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)
|
||||
}
|
||||
@@ -1,135 +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"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"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 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)
|
||||
// TODO: You can't use os.user if you're cross-compiling
|
||||
// u, err := user.Current()
|
||||
// if err != nil {
|
||||
// log.Println(err)
|
||||
// } else {
|
||||
// log.Printf("Running as user ID %v (%v) with primary group %v", u.Uid, u.Name, u.Gid)
|
||||
// }
|
||||
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)
|
||||
}
|
||||
readMounts()
|
||||
} else {
|
||||
log.Fatalf("Unsupported platform: %v", runtime.GOOS)
|
||||
}
|
||||
}
|
||||
59
cmd/runmqserver/post_init.go
Normal file
59
cmd/runmqserver/post_init.go
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2018, 2023
|
||||
|
||||
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/fips"
|
||||
"github.com/ibm-messaging/mq-container/internal/tls"
|
||||
)
|
||||
|
||||
// postInit is run after /var/mqm is set up
|
||||
func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error {
|
||||
enableWebServer := os.Getenv("MQ_ENABLE_EMBEDDED_WEB_SERVER")
|
||||
if enableWebServer == "true" || enableWebServer == "1" {
|
||||
|
||||
// Enable FIPS for MQ Web Server if asked for.
|
||||
if fips.IsFIPSEnabled() {
|
||||
err := configureFIPSWebServer(p12Truststore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the web server (if enabled)
|
||||
webKeystore, err := configureWebServer(keyLabel, p12Truststore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If trust-store is empty, set reference to point to the keystore
|
||||
webTruststoreRef := "MQWebTrustStore"
|
||||
if len(p12Truststore.TrustedCerts) == 0 {
|
||||
webTruststoreRef = "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(webKeystore, p12Truststore.Password, webTruststoreRef)
|
||||
if err != nil {
|
||||
log.Printf("Error starting web server: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
64
cmd/runmqserver/process.go
Normal file
64
cmd/runmqserver/process.go
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2018
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/internal/command"
|
||||
)
|
||||
|
||||
// Verifies that we are the main or only instance of this program
|
||||
func verifySingleProcess() error {
|
||||
programName, err := determineExecutable()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to determine name of this program - %v", err)
|
||||
}
|
||||
|
||||
// Verify that there is only one runmqserver
|
||||
_, err = verifyOnlyOne(programName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("You cannot run more than one instance of this program")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verifies that there is only one instance running of the given program name.
|
||||
func verifyOnlyOne(programName string) (int, error) {
|
||||
// #nosec G104
|
||||
out, _, _ := command.Run("ps", "-e", "--format", "cmd")
|
||||
//if this goes wrong then assume we are the only one
|
||||
numOfProg := strings.Count(out, programName)
|
||||
if numOfProg != 1 {
|
||||
return numOfProg, fmt.Errorf("Expected there to be only 1 instance of %s but found %d", programName, numOfProg)
|
||||
}
|
||||
return numOfProg, nil
|
||||
}
|
||||
|
||||
// Determines the name of the currently running executable.
|
||||
func determineExecutable() (string, error) {
|
||||
file, err := os.Executable()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, exec := filepath.Split(file)
|
||||
return exec, nil
|
||||
}
|
||||
339
cmd/runmqserver/qmgr.go
Normal file
339
cmd/runmqserver/qmgr.go
Normal file
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017, 2023
|
||||
|
||||
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"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"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/mqversion"
|
||||
"github.com/ibm-messaging/mq-container/internal/ready"
|
||||
)
|
||||
|
||||
// createDirStructure creates the default MQ directory structure under /var/mqm
|
||||
func createDirStructure() error {
|
||||
// log file diagnostics before and after crtmqdir if DEBUG=true
|
||||
logDiagnostics()
|
||||
out, rc, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-a")
|
||||
if err != nil {
|
||||
if rc == 10 {
|
||||
log.Printf("Warning creating directory structure: %v\n", string(out))
|
||||
} else {
|
||||
log.Printf("Error creating directory structure: %v\n", string(out))
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Println("Created directory structure under /var/mqm")
|
||||
logDiagnostics()
|
||||
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, devMode bool) (bool, error) {
|
||||
log.Printf("Creating queue manager %v", name)
|
||||
|
||||
mounts, err := containerruntime.GetMounts()
|
||||
if err != nil {
|
||||
log.Printf("Error getting mounts for queue manager")
|
||||
return false, err
|
||||
}
|
||||
|
||||
dataDir := getQueueManagerDataDir(mounts, 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)
|
||||
// Check if MQ_QMGR_LOG_FILE_PAGES matches the value set in qm.ini
|
||||
lfp := os.Getenv("MQ_QMGR_LOG_FILE_PAGES")
|
||||
if lfp != "" {
|
||||
qmIniBytes, err := readQMIni(dataDir)
|
||||
if err != nil {
|
||||
log.Printf("Error reading qm.ini : %v", err)
|
||||
return false, err
|
||||
}
|
||||
if !validateLogFilePageSetting(qmIniBytes, lfp) {
|
||||
log.Println("Warning: the value of MQ_QMGR_LOG_FILE_PAGES does not match the value of 'LogFilePages' in the qm.ini. This setting cannot be altered after Queue Manager creation.")
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Check if 'qm.ini' configuration file exists for the queue manager
|
||||
// TODO : handle possible race condition - use a file lock?
|
||||
_, 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, devMode)
|
||||
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
|
||||
}
|
||||
|
||||
//readQMIni reads the qm.ini file and returns it as a byte array
|
||||
//This function is specific to comply with the nosec.
|
||||
func readQMIni(dataDir string) ([]byte, error) {
|
||||
qmgrDir := filepath.Join(dataDir, "qm.ini")
|
||||
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
|
||||
iniFileBytes, err := ioutil.ReadFile(qmgrDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iniFileBytes, err
|
||||
}
|
||||
|
||||
//validateLogFilePageSetting validates if the specified logFilePage number is equal to the existing value in the qm.ini
|
||||
func validateLogFilePageSetting(iniFileBytes []byte, logFilePages string) bool {
|
||||
lfpString := "LogFilePages=" + logFilePages
|
||||
qminiConfigStr := string(iniFileBytes)
|
||||
return strings.Contains(qminiConfigStr, lfpString)
|
||||
}
|
||||
|
||||
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
|
||||
// 94=native HA replica started, which is fine
|
||||
if rc == 30 {
|
||||
log.Printf("Started standby queue manager")
|
||||
return nil
|
||||
} else if rc == 94 {
|
||||
log.Printf("Started replica queue manager")
|
||||
return nil
|
||||
}
|
||||
log.Printf("Error %v starting queue manager: %v", rc, string(out))
|
||||
return err
|
||||
}
|
||||
log.Println("Started queue manager")
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopQueueManager(name string) error {
|
||||
log.Println("Stopping queue manager")
|
||||
qmGracePeriod := os.Getenv("MQ_GRACE_PERIOD")
|
||||
status, err := ready.Status(context.Background(), name)
|
||||
if err != nil {
|
||||
log.Printf("Error getting status for queue manager %v: %v", name, err.Error())
|
||||
return err
|
||||
}
|
||||
isStandby := status.StandbyQM()
|
||||
args := []string{"-w", "-r", "-tp", qmGracePeriod, name}
|
||||
if os.Getenv("MQ_MULTI_INSTANCE") == "true" {
|
||||
if isStandby {
|
||||
args = []string{"-x", name}
|
||||
} else {
|
||||
args = []string{"-s", "-w", "-tp", qmGracePeriod, 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 startMQTrace() error {
|
||||
log.Println("Starting MQ trace")
|
||||
out, rc, err := command.Run("strmqtrc")
|
||||
if err != nil {
|
||||
log.Printf("Error %v starting trace: %v", rc, string(out))
|
||||
return err
|
||||
}
|
||||
log.Println("Started MQ trace")
|
||||
return nil
|
||||
}
|
||||
|
||||
func endMQTrace() error {
|
||||
log.Println("Ending MQ Trace")
|
||||
out, rc, err := command.Run("endmqtrc")
|
||||
if err != nil {
|
||||
log.Printf("Error %v ending trace: %v", rc, string(out))
|
||||
return err
|
||||
}
|
||||
log.Println("Ended MQ trace")
|
||||
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, devMode bool) []string {
|
||||
|
||||
mqversionBase := "9.2.1.0"
|
||||
|
||||
// use "UserExternal" only if we are 9.2.1.0 or above.
|
||||
oaVal := "user"
|
||||
mqVersionCheck, err := mqversion.Compare(mqversionBase)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error comparing MQ versions for oa,rc: %v", mqVersionCheck)
|
||||
}
|
||||
if mqVersionCheck >= 0 {
|
||||
oaVal = "UserExternal"
|
||||
}
|
||||
|
||||
//build args
|
||||
args := []string{"-ii", "/etc/mqm/", "-ic", "/etc/mqm/", "-q", "-p", "1414"}
|
||||
|
||||
if os.Getenv("MQ_NATIVE_HA") == "true" {
|
||||
args = append(args, "-lr", os.Getenv("HOSTNAME"))
|
||||
}
|
||||
if devMode {
|
||||
args = append(args, "-oa", oaVal)
|
||||
}
|
||||
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")
|
||||
}
|
||||
if os.Getenv("MQ_QMGR_LOG_FILE_PAGES") != "" {
|
||||
_, err = strconv.Atoi(os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
|
||||
if err != nil {
|
||||
log.Printf("Error processing MQ_QMGR_LOG_FILE_PAGES, the default value for LogFilePages will be used. Err: %v", err)
|
||||
} else {
|
||||
args = append(args, "-lf", os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// updateQMini removes the original ServicecCmponent stanza so we can add a new one
|
||||
func updateQMini(qmname string) error {
|
||||
|
||||
val, set := os.LookupEnv("MQ_CONNAUTH_USE_HTP")
|
||||
if !set {
|
||||
//htpasswd mode not enabled.
|
||||
return nil
|
||||
}
|
||||
bval, err := strconv.ParseBool(strings.ToLower(val))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bval == false {
|
||||
//htpasswd mode not enabled.
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("Removing existing ServiceComponent configuration")
|
||||
|
||||
mounts, err := containerruntime.GetMounts()
|
||||
if err != nil {
|
||||
log.Printf("Error getting mounts for queue manager")
|
||||
return err
|
||||
}
|
||||
dataDir := getQueueManagerDataDir(mounts, qmname)
|
||||
qmgrDir := filepath.Join(dataDir, "qm.ini")
|
||||
//read the initial version.
|
||||
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
|
||||
iniFileBytes, err := ioutil.ReadFile(qmgrDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
qminiConfigStr := string(iniFileBytes)
|
||||
if strings.Contains(qminiConfigStr, "ServiceComponent:") {
|
||||
var re = regexp.MustCompile(`(?m)^.*ServiceComponent.*$\s^.*Service.*$\s^.*Name.*$\s^.*Module.*$\s^.*ComponentDataSize.*$`)
|
||||
curFile := re.ReplaceAllString(qminiConfigStr, "")
|
||||
// #nosec G304 G306 - qmgrDir filepath is derived from dspmqinf and
|
||||
// its a read by owner/s group, and pose no harm.
|
||||
err := ioutil.WriteFile(qmgrDir, []byte(curFile), 0660)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
86
cmd/runmqserver/qmgr_test.go
Normal file
86
cmd/runmqserver/qmgr_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2023
|
||||
|
||||
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"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_validateLogFilePageSetting(t *testing.T) {
|
||||
type args struct {
|
||||
iniFilePath string
|
||||
isValid bool
|
||||
logFilePagesValue string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
{
|
||||
name: "TestLogFilePages1",
|
||||
args: args{
|
||||
iniFilePath: "./test-files/testvalidateLogFilePages_1.ini",
|
||||
isValid: true,
|
||||
logFilePagesValue: "1235",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TestLogFilePages2",
|
||||
args: args{
|
||||
iniFilePath: "./test-files/testvalidateLogFilePages_2.ini",
|
||||
isValid: true,
|
||||
logFilePagesValue: "2224",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TestLogFilePages3",
|
||||
args: args{
|
||||
iniFilePath: "./test-files/testvalidateLogFilePages_3.ini",
|
||||
isValid: false,
|
||||
logFilePagesValue: "1235",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TestLogFilePages4",
|
||||
args: args{
|
||||
iniFilePath: "./test-files/testvalidateLogFilePages_4.ini",
|
||||
isValid: false,
|
||||
logFilePagesValue: "1235",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TestLogFilePages5",
|
||||
args: args{
|
||||
iniFilePath: "./test-files/testvalidateLogFilePages_5.ini",
|
||||
isValid: false,
|
||||
logFilePagesValue: "1235",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
iniFileBytes, err := ioutil.ReadFile(tt.args.iniFilePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
validate := validateLogFilePageSetting(iniFileBytes, tt.args.logFilePagesValue)
|
||||
if validate != tt.args.isValid {
|
||||
t.Fatalf("Expected ini file validation output to be %v got %v", tt.args.isValid, validate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
84
cmd/runmqserver/signals.go
Normal file
84
cmd/runmqserver/signals.go
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017, 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"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, 1)
|
||||
reapSignals := make(chan os.Signal, 1)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
ExitPath:
|
||||
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||
Log:
|
||||
LogPrimaryFiles=3
|
||||
LogSecondaryFiles=2
|
||||
LogFilePages=1235
|
||||
LogBufferPages=0
|
||||
LogWriteIntegrity=TripleWrite
|
||||
@@ -0,0 +1,9 @@
|
||||
ExitPath:
|
||||
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||
Log:
|
||||
LogPrimaryFiles=3
|
||||
LogSecondaryFiles=2
|
||||
LogFilePages=2224
|
||||
LogBufferPages=0
|
||||
LogWriteIntegrity=TripleWrite
|
||||
@@ -0,0 +1,9 @@
|
||||
ExitPath:
|
||||
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||
Log:
|
||||
LogPrimaryFiles=3
|
||||
LogSecondaryFiles=2
|
||||
LogFilePages=6002
|
||||
LogBufferPages=0
|
||||
LogWriteIntegrity=TripleWrite
|
||||
@@ -0,0 +1,8 @@
|
||||
ExitPath:
|
||||
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||
Log:
|
||||
LogPrimaryFiles=3
|
||||
LogSecondaryFiles=2
|
||||
LogBufferPages=0
|
||||
LogWriteIntegrity=TripleWrite
|
||||
@@ -0,0 +1,8 @@
|
||||
ExitPath:
|
||||
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||
Log:
|
||||
LogPrimaryFiles=3
|
||||
LogSecondaryFiles=2
|
||||
LogBufferPages=1235
|
||||
LogWriteIntegrity=TripleWrite
|
||||
79
cmd/runmqserver/version.go
Normal file
79
cmd/runmqserver/version.go
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
© 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"
|
||||
"github.com/ibm-messaging/mq-container/internal/mqversion"
|
||||
)
|
||||
|
||||
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 := mqversion.Get()
|
||||
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()
|
||||
}
|
||||
221
cmd/runmqserver/webserver.go
Normal file
221
cmd/runmqserver/webserver.go
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2018, 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"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(webKeystore, webkeystorePW, webTruststoreRef 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 webKeystore != "" {
|
||||
cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTORE="+webKeystore)
|
||||
cmd.Env = append(cmd.Env, "AMQ_WEBKEYSTOREPW="+webkeystorePW)
|
||||
cmd.Env = append(cmd.Env, "AMQ_WEBTRUSTSTOREREF="+webTruststoreRef)
|
||||
}
|
||||
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, webKeystore string) (string, error) {
|
||||
requiredEnvVars := []string{}
|
||||
_, set := os.LookupEnv("MQ_ZEN_INTERNAL_ENDPOINT")
|
||||
if !set {
|
||||
// Ensure all required environment variables are set for SSO
|
||||
requiredEnvVars = []string{
|
||||
"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",
|
||||
}
|
||||
} else {
|
||||
// Ensure all required environment variables are set for Zen SSO
|
||||
requiredEnvVars = []string{
|
||||
"MQ_ZEN_UNIQUE_USER_IDENTIFIER",
|
||||
"MQ_ZEN_INTERNAL_ENDPOINT",
|
||||
"MQ_ZEN_ISSUER_IDENTIFIER",
|
||||
"MQ_ZEN_AUDIENCES",
|
||||
"MQ_ZEN_CONTEXT_NAME",
|
||||
"MQ_ZEN_BASE_URI",
|
||||
"MQ_ZEN_CONTEXT_NAMESPACE",
|
||||
"IAM_URL",
|
||||
}
|
||||
}
|
||||
for _, envVar := range requiredEnvVars {
|
||||
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 tls.ConfigureWebKeystore(p12TrustStore, webKeystore)
|
||||
}
|
||||
|
||||
func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string, error) {
|
||||
var webKeystore string
|
||||
|
||||
// Configure TLS for Web Console first if we have a certificate to use
|
||||
err := tls.ConfigureWebTLS(keyLabel)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if keyLabel != "" {
|
||||
webKeystore = keyLabel + ".p12"
|
||||
}
|
||||
|
||||
// Configure Single-Sign-On for the web server (if enabled)
|
||||
enableSSO := os.Getenv("MQ_BETA_ENABLE_SSO")
|
||||
if enableSSO == "true" || enableSSO == "1" {
|
||||
webKeystore, err = configureSSO(p12Truststore, webKeystore)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if keyLabel == "" && os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME") != "" {
|
||||
webKeystore, err = tls.ConfigureWebKeystore(p12Truststore, webKeystore)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = os.Stat("/opt/mqm/bin/strmqweb")
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
const webConfigDir string = "/etc/mqm/web"
|
||||
_, err = os.Stat(webConfigDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
const prefix string = "/etc/mqm/web"
|
||||
err = filepath.Walk(prefix, func(from string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return webKeystore, err
|
||||
}
|
||||
|
||||
// Configure FIPS mode for MQ Web Server
|
||||
func configureFIPSWebServer(p12TrustStore tls.KeyStoreData) error {
|
||||
var errOut error
|
||||
// Need to update jvm.options file of MQ Web Server. We don't update the jvm.options file
|
||||
// in /etc/mqm/web/installations/Installation1/servers/mqweb directory. Instead we update
|
||||
// the one in /etc/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults.
|
||||
// During runtime MQ Web Server merges the data from two files.
|
||||
mqwebJvmOptsDir := "/etc/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults"
|
||||
_, errOut = os.Stat(mqwebJvmOptsDir)
|
||||
if errOut == nil {
|
||||
// Update the jvm.options file using the data from template file. Tell the MQ Web Server
|
||||
// use a FIPS provider by setting "-Dcom.ibm.jsse2.usefipsprovider=true" and then tell it
|
||||
// use a specific FIPS provider by setting "Dcom.ibm.jsse2.usefipsProviderName=IBMJCEPlusFIPS".
|
||||
errOut = mqtemplate.ProcessTemplateFile(mqwebJvmOptsDir+"/jvm.options.tpl",
|
||||
mqwebJvmOptsDir+"/jvm.options", map[string]string{
|
||||
"FipsProvider": "true",
|
||||
"FipsProviderName": "IBMJCEPlusFIPS",
|
||||
}, log)
|
||||
}
|
||||
return errOut
|
||||
}
|
||||
6
config.env
Normal file
6
config.env
Normal file
@@ -0,0 +1,6 @@
|
||||
###########################################################################################################################################################
|
||||
|
||||
# MQ_VERSION is the fully qualified MQ version number to build
|
||||
MQ_VERSION ?= 9.3.3.0
|
||||
|
||||
###########################################################################################################################################################
|
||||
@@ -1,4 +1,4 @@
|
||||
# © Copyright IBM Corporation 2015, 2017
|
||||
# © Copyright IBM Corporation 2020
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -12,7 +12,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM mqadvanced
|
||||
RUN useradd alice -G mqm && \
|
||||
echo alice:passw0rd | chpasswd
|
||||
COPY *.mqsc /etc/mqm/
|
||||
FROM fedora:32
|
||||
RUN yum install skopeo -y -qq
|
||||
ENTRYPOINT [ "skopeo" ]
|
||||
47
docs/building.md
Executable file
47
docs/building.md
Executable file
@@ -0,0 +1,47 @@
|
||||
# Building a container image
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You need to have the following tools installed:
|
||||
|
||||
* [Docker](https://www.docker.com/) 17.06.1 or later, or [Podman](https://podman.io) 1.0 or later (Podman 4.1 on macOS).
|
||||
* [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.
|
||||
|
||||
## Building a production image
|
||||
|
||||
From MQ 9.2.X, the MQ container adds support for MQ Long Term Support (LTS) **production licensed** releases.
|
||||
|
||||
### Building MQ 9.3 Long Term Support (LTS) and Continuous Delivery (CD)
|
||||
|
||||
**Note**: MQ 9.3 is the latest MQ version with MQ Long Term Support (LTS), as well as being the latest Continuous Delivery (CD) version.
|
||||
|
||||
The procedure below is for building the 9.3 release, on `amd64`, `ppc64le` and `s390x` architectures.
|
||||
|
||||
1. Create a `downloads` directory in the root of this repository
|
||||
2. Download MQ from [IBM Passport Advantage](https://www.ibm.com/software/passportadvantage/). Identify the correct 'Long Term Support Release for Containers' eImage part number for your architecture from the 9.3.0 LTS tab at https://www.ibm.com/support/pages/downloading-ibm-mq-930
|
||||
3. Ensure the `tar.gz` file is in the `downloads` directory
|
||||
4. Run `make build-advancedserver`
|
||||
|
||||
If you have an MQ archive file with a different file name, you can specify a particular file (which must be in the `downloads` directory). You should also specify the MQ version, so that the resulting image is tagged correctly, for example:
|
||||
|
||||
```bash
|
||||
MQ_ARCHIVE=mq-1.2.3.4.tar.gz MQ_VERSION=1.2.3.4 make build-advancedserver
|
||||
```
|
||||
|
||||
### Building previous MQ Long Term Support (LTS)
|
||||
|
||||
**Note**: MQ 9.3 is the latest MQ version with MQ Long Term Support (LTS), as well as being the latest Continuous Delivery (CD) version. Therefore, to build build 9.3.0.X, follow the [instructions above for MQ 9.3](#building-mq-93-long-term-support-lts-and-continuous-delivery-cd).
|
||||
|
||||
However, if you wish to build the previous MQ LTS, use the [instructions](https://github.ibm.com/mq-cloudpak/mq-container/blob/v9.2.0.x-eus/docs/building.md#mq-long-term-support-lts) in the `v9.2.0.x-eus` branch.
|
||||
|
||||
## Building a developer image
|
||||
|
||||
Run `make build-devserver`, which will download the latest version of MQ Advanced for Developers from IBM developerWorks. This is currently only available on the `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 is configured in the `mq-redux` build stage in `Dockerfile-server`.
|
||||
48
docs/developer-config.md
Normal file
48
docs/developer-config.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 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.
|
||||
|
||||
## Details of the default configuration
|
||||
|
||||
The following users are created:
|
||||
|
||||
* User **admin** for administration. 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 do not wish the web console to run, you can disable it by setting the environment variable `MQ_ENABLE_EMBEDDED_WEB_SERVER` to `false`.
|
||||
@@ -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
|
||||
```
|
||||
52
docs/internals.md
Normal file
52
docs/internals.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# 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.
|
||||
- `chkmqstarted` - Checks if the queue manager has successfully started. This can be used by (say) a Kubernetes startup 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
|
||||
29
docs/pluggable-connauth.md
Normal file
29
docs/pluggable-connauth.md
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
### Queue Manager Connection Authentication using a htpasswd file
|
||||
|
||||
This pluggable authentication mode is to allow developers using the mq-container developer image to define users and their credentials into a .htpasswd file. This is in addition to the existing methods of MQ Connection Authentication (`CONNAUTH`) using Operating System or LDAP users.
|
||||
|
||||
**Please note:**
|
||||
1. This new feature is enabled only when environment variable `--env MQ_CONNAUTH_USE_HTP=true` is set while creating a container.
|
||||
2. When enabled, the `AuthType` value of the ConnectionAuthentication (`CONNAUTH`) is ignored and htpasswd mode is used. However, the MQ authority records created using (`SETMQAUT` or `AUTHREC`) will be in effect while using the htpasswd mode.
|
||||
3. Channel Authentication records (`CHLAUTH`) will be in effect while using the htpasswd mode.
|
||||
4. Passwords should be encrypted using bcrypt (golang.org/x/crypto/bcrypt).
|
||||
5. This is developer only feature and not recommended for use in Production.
|
||||
|
||||
### Preparing htpasswd file
|
||||
|
||||
1. A default `mq.htpasswd` file is provided and placed under /etc/mqm/ directory inside the container.
|
||||
2. You can set the password for user `admin` by setting the environment variable `MQ_ADMIN_PASSWORD`.
|
||||
3. You can add user `app` into mq.htpasswd file by setting the environment variable `MQ_APP_PASSWORD`. This user `app` can be used to access `DEV.*` objects of the queue manager.
|
||||
|
||||
#### Next Steps:
|
||||
|
||||
Use an administrative tool or your application to connect to queue manager using the credentials defined in the mq.htpasswd file.
|
||||
|
||||
**Please note**: When an authentication request is made with a userid that is not defined in the `mq.htpasswd` file, then the authentication process is delegated to queue manager to handle. This will then use `IDPWOS` or `LDAP` modes for further processing.
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
A log file named `mqhtpass.log` is generated under `/var/mqm/errors` directory path of the container. This file will contain all the failed connection authentication requests. Additional information is logged to this file if the environment variable `DEBUG` is set to `true`.
|
||||
|
||||
**Please note**: This log file will be wiped when the queue manager is next started.
|
||||
20
docs/security.md
Normal file
20
docs/security.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Security
|
||||
|
||||
## Container runtime
|
||||
|
||||
### User
|
||||
|
||||
The MQ server image is run using with UID 1001, though this can be any UID, with a fixed GID of 0 (root).
|
||||
|
||||
### 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 \
|
||||
ibm-mqadvanced-server:9.3.3.0-amd64
|
||||
```
|
||||
50
docs/testing.md
Normal file
50
docs/testing.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Testing
|
||||
|
||||
## Prerequisites
|
||||
You need to ensure you have the following tools installed:
|
||||
* [Docker](https://www.docker.com/) 19.03 or higher (API version 1.40)
|
||||
* [GNU make](https://www.gnu.org/software/make/)
|
||||
* [Go](https://golang.org/) - only needed 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=ibm-mqadvanced-server:9.3.3.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 `ibm-mqadvanced-server:9.2.0.0-amd64`:
|
||||
|
||||
```
|
||||
MQ_VERSION=9.2.0.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.
|
||||
17
docs/troubleshooting.md
Normal file
17
docs/troubleshooting.md
Normal 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.
|
||||
116
docs/usage.md
Normal file
116
docs/usage.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# 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 \
|
||||
icr.io/ibm-messaging/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 \
|
||||
icr.io/ibm-messaging/mq
|
||||
```
|
||||
|
||||
The Docker image always uses `/mnt/mqm` for MQ data, which is correctly linked for you under `/var/mqm` at runtime. This is to handle problems with file permissions on some platforms.
|
||||
|
||||
## 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 \
|
||||
icr.io/ibm-messaging/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.3.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
|
||||
|
||||
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
|
||||
|
||||
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom MQ configuration file:
|
||||
|
||||
```dockerfile
|
||||
FROM icr.io/ibm-messaging/mq
|
||||
USER 1001
|
||||
COPY 20-config.mqsc /etc/mqm/
|
||||
```
|
||||
|
||||
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>')`
|
||||
|
||||
It must be noted that queue manager certificate with a Subject Distinguished Name (DN) same as it's Issuer certificate (CA) is not supported. Certificates must have a unique Subject Distinguished Name.
|
||||
@@ -1,4 +1,5 @@
|
||||
* © Copyright IBM Corporation 2017
|
||||
* © Copyright IBM Corporation 2019, 2022
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -12,4 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
|
||||
REFRESH SECURITY TYPE(CONNAUTH)
|
||||
* Set the keystore location for the queue manager
|
||||
ALTER QMGR SSLKEYR('{{ .SSLKeyR }}')
|
||||
ALTER QMGR CERTLABL('{{ .CertificateLabel }}')
|
||||
ALTER QMGR SSLFIPS({{ .SSLFips }})
|
||||
REFRESH SECURITY(*) TYPE(SSL)
|
||||
2
etc/mqm/mq.htpasswd
Normal file
2
etc/mqm/mq.htpasswd
Normal file
@@ -0,0 +1,2 @@
|
||||
admin:$2y$05$M/C1U62RZ6q1kv4E7.S7ueNESJmFe85RsZcoMUReRXUDB8QcP3yqS
|
||||
app:$2y$05$BnbPtcjXTjk5JRJ8gzHqIuHgoQbLF3qtbPV3Q3tLyr0XJNg.7dkxW
|
||||
11
etc/mqm/qm-service-component.ini
Normal file
11
etc/mqm/qm-service-component.ini
Normal file
@@ -0,0 +1,11 @@
|
||||
ServiceComponent:
|
||||
Service=AuthorizationService
|
||||
Name=Dev.HtpAuth.Service
|
||||
Module=/opt/mqm/lib64/mqhtpass.so
|
||||
ComponentDataSize=0
|
||||
ServiceComponent:
|
||||
Service=AuthorizationService
|
||||
Name=MQSeries.UNIX.auth.service
|
||||
Module=amqzfu
|
||||
ComponentDataSize=0
|
||||
|
||||
19
glide.lock
generated
19
glide.lock
generated
@@ -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: []
|
||||
24
go.mod
Normal file
24
go.mod
Normal file
@@ -0,0 +1,24 @@
|
||||
module github.com/ibm-messaging/mq-container
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/genuinetools/amicontained v0.4.3
|
||||
github.com/ibm-messaging/mq-golang v2.0.0+incompatible
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1
|
||||
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/golang/protobuf v1.4.3 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||
google.golang.org/protobuf v1.26.0-rc.1 // indirect
|
||||
)
|
||||
149
go.sum
Normal file
149
go.sum
Normal file
@@ -0,0 +1,149 @@
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/genuinetools/amicontained v0.4.3 h1:cqq9XiAHfWWY3dk8VU8bSJFu9yh8Il5coEdeTAPq72o=
|
||||
github.com/genuinetools/amicontained v0.4.3/go.mod h1:PAMZkg9CcUTa6gNyULQ6tOMTMEb2HTKJufvKeFqDw+o=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/ibm-messaging/mq-golang v2.0.0+incompatible h1:xAufRPYSzoRGaME2+x7LcW5+uvy/G3xL/3Sn3u+G/lY=
|
||||
github.com/ibm-messaging/mq-golang v2.0.0+incompatible/go.mod h1:qjsZDb7m1oKnbPeDma2JVJTKgyCA91I4bcJ1qHY+gcA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001 h1:AVd6O+azYjVQYW1l55IqkbL8/JxjrLtO6q4FCmV8N5c=
|
||||
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
|
||||
21
ha/native-ha.ini.tpl
Normal file
21
ha/native-ha.ini.tpl
Normal file
@@ -0,0 +1,21 @@
|
||||
NativeHALocalInstance:
|
||||
Name={{ .Name }}
|
||||
{{ if .CertificateLabel }}
|
||||
CertificateLabel={{ .CertificateLabel }}
|
||||
KeyRepository={{ .KeyRepository }}
|
||||
{{ if .CipherSpec }}
|
||||
CipherSpec={{ .CipherSpec }}
|
||||
{{- end }}
|
||||
{{ if .SSLFipsRequired }}
|
||||
SSLFipsRequired={{ .SSLFipsRequired }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
NativeHAInstance:
|
||||
Name={{ .NativeHAInstance0_Name }}
|
||||
ReplicationAddress={{ .NativeHAInstance0_ReplicationAddress }}
|
||||
NativeHAInstance:
|
||||
Name={{ .NativeHAInstance1_Name }}
|
||||
ReplicationAddress={{ .NativeHAInstance1_ReplicationAddress }}
|
||||
NativeHAInstance:
|
||||
Name={{ .NativeHAInstance2_Name }}
|
||||
ReplicationAddress={{ .NativeHAInstance2_ReplicationAddress }}
|
||||
@@ -1,4 +1,4 @@
|
||||
# © Copyright IBM Corporation 2015, 2017
|
||||
# © 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.
|
||||
@@ -15,14 +15,16 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
# 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
|
||||
ARG MQ_PACKAGES="ibmmq-sfbridge"
|
||||
|
||||
ARG MQM_UID=999
|
||||
|
||||
ADD install-mq.sh /usr/local/bin/
|
||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
||||
&& install-mq.sh
|
||||
&& install-mq.sh $MQM_UID
|
||||
|
||||
ENV LANG=en_US.UTF-8
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# © Copyright IBM Corporation 2015, 2017
|
||||
# © Copyright IBM Corporation 2015, 2019
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# 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
|
||||
# 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
|
||||
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
|
||||
ARG MQ_PACKAGES="ibmmq-explorer"
|
||||
ENV MQ_PACKAGES="MQSeriesRuntime*.rpm MQSeriesJRE*.rpm MQSeriesExplorer*.rpm"
|
||||
|
||||
RUN export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y \
|
||||
libgtk2.0-0 \
|
||||
libxtst6
|
||||
ARG MQM_UID=888
|
||||
|
||||
RUN microdnf install -y gtk2 libXtst \
|
||||
&& microdnf clean all
|
||||
|
||||
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 \
|
||||
&& 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
|
||||
|
||||
# Run as mqm (999)
|
||||
USER 999
|
||||
# Run as mqm
|
||||
USER $MQM_UID
|
||||
|
||||
ENTRYPOINT ["MQExplorer"]
|
||||
@@ -1,14 +1,19 @@
|
||||
|
||||
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
|
||||
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 ???
|
||||
|
||||
38
incubating/mq-sdk/Dockerfile
Normal file
38
incubating/mq-sdk/Dockerfile
Normal 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
|
||||
13
incubating/mq-sdk/README.md
Normal file
13
incubating/mq-sdk/README.md
Normal 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.
|
||||
48
incubating/mqadvanced-server-dev/10-dev.mqsc.tpl
Normal file
48
incubating/mqadvanced-server-dev/10-dev.mqsc.tpl
Normal file
@@ -0,0 +1,48 @@
|
||||
* © 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)
|
||||
SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(USERMAP) CLNTUSER('admin') USERSRC(MAP) MCAUSER ('mqm') DESCR ('Allow admin as MQ-admin') ACTION(REPLACE)
|
||||
|
||||
* Developer authority records
|
||||
SET AUTHREC PRINCIPAL('app') OBJTYPE(QMGR) AUTHADD(CONNECT,INQ)
|
||||
SET AUTHREC PROFILE('DEV.**') PRINCIPAL('app') OBJTYPE(QUEUE) AUTHADD(BROWSE,GET,INQ,PUT)
|
||||
SET AUTHREC PROFILE('DEV.**') PRINCIPAL('app') OBJTYPE(TOPIC) AUTHADD(PUB,SUB)
|
||||
@@ -1,4 +1,5 @@
|
||||
* © Copyright IBM Corporation 2017
|
||||
* © Copyright IBM Corporation 2018, 2022
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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
|
||||
* limitations under the License.
|
||||
|
||||
DEFINE CHANNEL(PASSWORD.SVRCONN) CHLTYPE(SVRCONN) REPLACE
|
||||
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allow privileged users on this channel')
|
||||
SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('BackStop rule')
|
||||
SET CHLAUTH(PASSWORD.SVRCONN) TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT(REQUIRED)
|
||||
ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) ADOPTCTX(YES)
|
||||
* Set the cipherspec for dev channels
|
||||
ALTER CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12_OR_HIGHER) SSLCAUTH(OPTIONAL)
|
||||
ALTER CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(ANY_TLS12_OR_HIGHER) SSLCAUTH(OPTIONAL)
|
||||
78
incubating/mqadvanced-server-dev/admin.json.tpl
Normal file
78
incubating/mqadvanced-server-dev/admin.json.tpl
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
||||
41
incubating/mqadvanced-server-dev/install-extra-packages.sh
Normal file
41
incubating/mqadvanced-server-dev/install-extra-packages.sh
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
# -*- mode: sh -*-
|
||||
# © Copyright IBM Corporation 2019, 2021
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# 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 libaprutil1
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
fi
|
||||
|
||||
if ($YUM); then
|
||||
yum -y install apr-util-openssl
|
||||
yum -y clean all
|
||||
rm -rf /var/cache/yum/*
|
||||
fi
|
||||
|
||||
if ($MICRODNF); then
|
||||
microdnf --disableplugin=subscription-manager install apr-util-openssl
|
||||
microdnf --disableplugin=subscription-manager clean all
|
||||
fi
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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"/>
|
||||
<variable name="mqConsoleRemoteSupportEnabled" value="false"/>
|
||||
<variable name="mqConsoleEnableUnsafeInline" value="true"/>
|
||||
<jndiEntry jndiName="mqConsoleDefaultCCDTHostname" value="${env.MQ_CONSOLE_DEFAULT_CCDT_HOSTNAME}"/>
|
||||
<jndiEntry jndiName="mqConsoleDefaultCCDTPort" value="${env.MQ_CONSOLE_DEFAULT_CCDT_PORT}"/>
|
||||
<include location="tls.xml"/>
|
||||
</server>
|
||||
32
incubating/mqipt/Dockerfile
Normal file
32
incubating/mqipt/Dockerfile
Normal file
@@ -0,0 +1,32 @@
|
||||
# © 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.
|
||||
|
||||
FROM ibmcom/ibmjava:jre
|
||||
|
||||
ARG IPTFILE=ms81_2.1.0.4_amd64_linux_2.tar
|
||||
|
||||
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"]
|
||||
44
incubating/mqipt/README.md
Normal file
44
incubating/mqipt/README.md
Normal 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
|
||||
22
charts/ibm-mqadvanced-server-dev/Chart.yaml → incubating/mqipt/startMQIPT.sh
Normal file → Executable file
22
charts/ibm-mqadvanced-server-dev/Chart.yaml → incubating/mqipt/startMQIPT.sh
Normal file → Executable 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");
|
||||
# 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
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: v1
|
||||
description: IBM MQ queue manager
|
||||
name: ibm-mqadvanced-server-dev
|
||||
version: 1.0.1
|
||||
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png
|
||||
tillerVersion: ">=2.4.0"
|
||||
stop()
|
||||
{
|
||||
/opt/mqipt/bin/mqiptAdmin -stop
|
||||
}
|
||||
|
||||
trap stop SIGTERM SIGINT
|
||||
|
||||
# Run MQIPT and then wait on the process to end.
|
||||
/opt/mqipt/bin/mqipt /var/mqipt &
|
||||
MQIPTPROCESS=$!
|
||||
|
||||
wait "$MQIPTPROCESS"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user