Merge pull request #28 from arthurbarr/master

Default developer configuration
This commit is contained in:
Arthur Barr
2018-03-26 12:13:20 +01:00
committed by GitHub
63 changed files with 1273 additions and 5325 deletions

View File

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

View File

@@ -19,7 +19,7 @@
# BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel" # BASE_IMAGE is the base image to use for MQ, for example "ubuntu" or "rhel"
BASE_IMAGE ?= ubuntu:16.04 BASE_IMAGE ?= ubuntu:16.04
# MQ_VERSION is the fully qualified MQ version number to build # MQ_VERSION is the fully qualified MQ version number to build
MQ_VERSION ?= 9.0.4.0 MQ_VERSION ?= 9.0.5.0
# MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can # MQ_ARCHIVE is the name of the file, under the downloads directory, from which MQ Advanced can
# be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture # be installed. The default value is derived from MQ_VERSION, BASE_IMAGE and architecture
# Does not apply to MQ Advanced for Developers. # Does not apply to MQ Advanced for Developers.
@@ -29,8 +29,6 @@ MQ_ARCHIVE ?= IBM_MQ_$(MQ_VERSION)_$(MQ_ARCHIVE_TYPE)_$(MQ_ARCHIVE_ARCH).tar.gz
MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION)) MQ_ARCHIVE_DEV ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
# Options to `go test` for the Docker tests # Options to `go test` for the Docker tests
TEST_OPTS_DOCKER ?= TEST_OPTS_DOCKER ?=
# Options to `go test` for the Kubernetes tests
TEST_OPTS_KUBERNETES ?=
# MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image # MQ_IMAGE_ADVANCEDSERVER is the name and tag of the built MQ Advanced image
MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG) MQ_IMAGE_ADVANCEDSERVER ?=mqadvanced-server:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image # MQ_IMAGE_DEVSERVER is the name and tag of the built MQ Advanced for Developers image
@@ -53,6 +51,8 @@ NUM_CPU=$(shell docker info --format "{{ .NCPU }}")
# BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag # BASE_IMAGE_TAG is a normalized version of BASE_IMAGE, suitable for use in a Docker tag
BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE))) BASE_IMAGE_TAG=$(subst /,-,$(subst :,-,$(BASE_IMAGE)))
MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG) MQ_IMAGE_DEVSERVER_BASE=mqadvanced-server-dev-base:$(MQ_VERSION)-$(ARCH)-$(BASE_IMAGE_TAG)
# Docker image name to use for JMS tests
DEV_JMS_IMAGE=mq-dev-jms-test
# Try to figure out which archive to use from the BASE_IMAGE # Try to figure out which archive to use from the BASE_IMAGE
ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu" ifeq "$(findstring ubuntu,$(BASE_IMAGE))" "ubuntu"
@@ -69,8 +69,8 @@ else ifeq "$(ARCH)" "s390x"
MQ_ARCHIVE_ARCH=SYSTEM_Z MQ_ARCHIVE_ARCH=SYSTEM_Z
endif endif
# Archive names for IBM MQ Advanced for Developers for Ubuntu # Archive names for IBM MQ Advanced for Developers for Ubuntu
MQ_ARCHIVE_DEV_9.0.3.0=mqadv_dev903_ubuntu_x86-64.tar.gz
MQ_ARCHIVE_DEV_9.0.4.0=mqadv_dev904_ubuntu_x86-64.tar.gz MQ_ARCHIVE_DEV_9.0.4.0=mqadv_dev904_ubuntu_x86-64.tar.gz
MQ_ARCHIVE_DEV_9.0.5.0=mqadv_dev905_ubuntu_x86-64.tar.gz
############################################################################### ###############################################################################
# Build targets # Build targets
@@ -89,6 +89,12 @@ default: build-devserver test
.PHONY: all .PHONY: all
all: build-devserver build-advancedserver all: build-devserver build-advancedserver
.PHONY: test-all
test-all: test-devserver test-advancedserver
.PHONY: precommit
precommit: all test-all
.PHONY: devserver .PHONY: devserver
devserver: build-devserver test-devserver devserver: build-devserver test-devserver
@@ -118,10 +124,6 @@ deps:
test/docker/vendor: test/docker/vendor:
cd test/docker && dep ensure -vendor-only cd test/docker && dep ensure -vendor-only
# Vendor Go dependencies for the Kubernetes tests
test/kubernetes/vendor:
cd test/docker && dep ensure -vendor-only
.PHONY: build-cov .PHONY: build-cov
build-cov: build-cov:
mkdir -p build mkdir -p build
@@ -137,10 +139,15 @@ test-advancedserver: test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on Docker"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_ADVANCEDSERVER) on Docker"$(END)))
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER) cd test/docker && TEST_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) go test -parallel $(NUM_CPU) $(TEST_OPTS_DOCKER)
.PHONY: build-devjmstest
build-devjmstest:
$(info $(SPACER)$(shell printf $(TITLE)"Build JMS tests for developer config"$(END)))
cd test/messaging && docker build --tag $(DEV_JMS_IMAGE) .
.PHONY: test-devserver .PHONY: test-devserver
test-devserver: test/docker/vendor test-devserver: test/docker/vendor build-devjmstest
$(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on Docker"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER) on Docker"$(END)))
cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER) cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER) DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) go test -parallel $(NUM_CPU) -tags mqdev $(TEST_OPTS_DOCKER)
.PHONY: test-advancedserver-cover .PHONY: test-advancedserver-cover
test-advancedserver-cover: test/docker/vendor test-advancedserver-cover: test/docker/vendor
@@ -165,19 +172,6 @@ test-advancedserver-cover: test/docker/vendor
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
.PHONY: test-kubernetes-devserver
test-kubernetes-devserver: test/kubernetes/vendor
$(call test-kubernetes,$(MQ_IMAGE_DEVSERVER),"../../charts/ibm-mqadvanced-server-dev")
.PHONY: test-kubernetes-advancedserver
test-kubernetes-advancedserver: test/kubernetes/vendor
$(call test-kubernetes,$(MQ_IMAGE_ADVANCEDSERVER),"../../charts/ibm-mqadvanced-server-prod")
define test-kubernetes
$(info $(SPACER)$(shell printf $(TITLE)"Test $1 on Kubernetes"$(END)))
cd test/kubernetes && TEST_IMAGE=$1 TEST_CHART=$2 go test $(TEST_OPTS_KUBERNETES)
endef
define docker-build-mq define docker-build-mq
# Create a temporary network to use for the build # Create a temporary network to use for the build
$(DOCKER) network create build $(DOCKER) network create build

View File

@@ -2,7 +2,7 @@
# Overview # Overview
Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container. The supplied [Helm](https://helm.sh/) charts 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 Cloud Container Service](https://www.ibm.com/cloud/container-service). Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container.
# Current status # Current status
MQ Advanced for Developers image - [![Build Status](https://travis-ci.org/ibm-messaging/mq-container.svg?branch=master)](https://travis-ci.org/ibm-messaging/mq-container) MQ Advanced for Developers image - [![Build Status](https://travis-ci.org/ibm-messaging/mq-container.svg?branch=master)](https://travis-ci.org/ibm-messaging/mq-container)
@@ -11,7 +11,7 @@ MQ Advanced for Developers image - [![Build Status](https://travis-ci.org/ibm-me
After extracting the code from this repository, you can build an image by following the instructions [here](docs/building.md) After extracting the code from this repository, you can build an image by following the instructions [here](docs/building.md)
# Usage # 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. In order to use the image, it is necessary to accept the terms of the [IBM MQ license](#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.
## List of all Environment variables supported by this image ## List of all Environment variables supported by this image
@@ -21,6 +21,8 @@ In order to use the image, it is necessary to accept the terms of the IBM MQ lic
* **MQ_QMGR_NAME** - Set this to the name you want your Queue Manager to be created with. * **MQ_QMGR_NAME** - Set this to the name you want your Queue Manager to be created with.
* **LOG_FORMAT** - Set this to change the format of the logs which are printed on the container's stdout. Set to "json" to use JSON format (JSON object per line); set to "basic" to use a simple human-readable format. Defaults to "basic". * **LOG_FORMAT** - Set this to change the format of the logs which are printed on the container's stdout. Set to "json" to use JSON format (JSON object per line); set to "basic" to use a simple human-readable format. Defaults to "basic".
## Kubernetes
If you want to use IBM MQ in [Kubernetes](https://kubernetes.io), you can find an example [Helm](https://helm.sh/) chart here: [IBM charts](https://github.com/IBM/charts). This can be used to run the container on a cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Cloud Container Service](https://www.ibm.com/cloud/container-service).
# Issues and contributions # Issues and contributions

View File

@@ -1,20 +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
description: IBM MQ queue manager
name: ibm-mqadvanced-server-dev
version: 1.1.0
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/12/ibm_mq_200.png
tillerVersion: ">=2.4.0"

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
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]
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.

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,29 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,34 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Secret
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
{{ if .Values.queueManager.dev.adminPassword }}
adminPassword: {{ .Values.queueManager.dev.adminPassword | b64enc | quote }}
{{ else }}
adminPassword: {{ randAlphaNum 10 | b64enc | quote }}
{{ end }}
{{ if .Values.queueManager.dev.appPassword }}
appPassword: {{ .Values.queueManager.dev.appPassword | b64enc | quote }}
{{ end }}

View File

@@ -1,32 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
type: {{ .Values.service.type }}
ports:
- port: 1414
name: {{ .Values.service.name }}-server
- port: 9443
name: {{ .Values.service.name }}-web
selector:
app: {{ template "fullname" . }}

View File

@@ -1,126 +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.
{{- if .Capabilities.APIVersions.Has "apps/v1beta2" }}
apiVersion: apps/v1beta2
{{- else }}
apiVersion: apps/v1beta1
{{- end }}
kind: StatefulSet
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
selector:
matchLabels:
app: {{ template "fullname" . }}
serviceName: {{ .Values.service.name }}
replicas: 1
{{- if and (.Capabilities.KubeVersion.Major | hasPrefix "1") (.Capabilities.KubeVersion.Minor | hasPrefix "7") }}
# Set updateStrategy to "RollingUpdate", if we're on Kubernetes 1.7.
# It's already the default for apps/v1beta2 (Kubernetes 1.8 onwards)
updateStrategy:
type: RollingUpdate
{{- end }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
QM_IDENTIFIER: "{{ .Release.Name }}"
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: beta.kubernetes.io/arch
operator: In
values:
- amd64
- key: beta.kubernetes.io/os
operator: In
values:
- linux
{{- if .Values.image.pullSecret }}
imagePullSecrets:
- name: {{ .Values.image.pullSecret }}
{{- end }}
containers:
- name: qmgr
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 1414
- containerPort: 9443
env:
- name: LICENSE
value: {{ .Values.license }}
- name: MQ_QMGR_NAME
value: {{ .Values.queueManager.name | default .Release.Name | replace "-" "" }}
#- name: MQ_DISABLE_WEB_CONSOLE
# value: "true"
- name: MQ_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: adminPassword
{{- if .Values.queueManager.dev.appPassword }}
- name: MQ_APP_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: appPassword
{{- end }}
{{- if .Values.persistence.enabled }}
volumeMounts:
- mountPath: "/mnt/mqm"
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
{{- end }}
resources:
limits:
{{ toYaml .Values.resources.limits | indent 14 }}
requests:
{{ toYaml .Values.resources.requests | indent 14 }}
volumeClaimTemplates:
{{- if .Values.persistence.enabled }}
- metadata:
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
{{- if .Values.persistence.useDynamicProvisioning }}
# If present, use the storageClassName from the values.yaml, else use the
# default storageClass setup by Kubernetes Administrator
#
# Setting storageClassName to nil means use the default storage class
storageClassName: {{ default nil .Values.dataPVC.storageClassName | quote }}
{{- else }}
# Disable dynamic provisioning
storageClassName: ""
{{- end }}
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: {{ .Values.dataPVC.size | quote }}
{{- end }}

View File

@@ -1,40 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Pod
metadata:
name: "{{.Release.Name}}-test"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{.Release.Name}}-test
image: alpine:latest
env:
# Host name for the service running an MQ queue manager
- name: MQ_HOST
value: {{ template "fullname" . }}
# Time to try before giving up and failing the test (in seconds)
- name: TIMEOUT
value: "10"
command: ["sh"]
# Check that port 1414 is listening
args: ["-xc", "nc -v -z -w$(TIMEOUT) $(MQ_HOST) 1414"]
restartPolicy: Never

View File

@@ -1,176 +0,0 @@
license:
__metadata:
label: "License"
type: "string"
required: true
options:
- label: "Accepted"
value: "accept"
- label: "Not accepted"
value: "not accepted"
image:
__metadata:
label: "Image"
repository:
__metadata:
label: "Image repository"
description: "Docker image location"
type: "string"
immutable: false
required: true
tag:
__metadata:
label: "Image tag"
description: "Docker image tag"
type: "string"
immutable: false
required: true
pullPolicy:
__metadata:
name: "pullPolicy"
label: "Image pull policy"
description: "Always, Never, or IfNotPresent. Defaults to Always"
type: "string"
immutable: false
required: true
options:
- label: "Always"
value: "Always"
- label: "Never"
value: "Never"
- label: "IfNotPresent"
value: "IfNotPresent"
pullSecret:
__metadata:
label: "Image pull secret"
description: "Secret to use when pulling the image. Set this when using an image from a private registry"
type: "string"
required: false
## global persistence parameters
persistence:
__metadata:
label: "Persistence"
enabled:
__metadata:
label: "Enable persistence"
description: "Whether or not to store MQ messages and configuration on a Persistent Volume"
type: "boolean"
required: true
useDynamicProvisioning:
__metadata:
label: "Use dynamic provisioning"
description: "Whether or not to use Storage Classes to provision a Persisent Volume automatically"
type: "boolean"
required: true
dataPVC:
__metadata:
label: "Data PVC"
name:
__metadata:
label: "Name"
description: "Name of Persistent Volume Claim, used for MQ objects and messages"
type: "string"
required: true
storageClassName:
__metadata:
label: "Storage Class name"
description: "Storage class of Persistent Volume Claim, used for MQ objects and messages"
type: "string"
required: false
size:
__metadata:
label: "Size"
description: "Size of Persistent Volume Claim, used for MQ objects and messages"
type: "string"
required: true
service:
__metadata:
label: "Service"
name:
__metadata:
label: "Service name"
description: "Service name"
type: "string"
required: true
type:
__metadata:
label: "Service type"
description: "Type of service"
type: "string"
required: true
options:
- label: "ClusterIP"
value: "ClusterIP"
- label: "NodePort"
value: "NodePort"
- label: "LoadBalancer"
value: "LoadBalancer"
- label: "ExternalName"
value: "ExternalName"
resources:
__metadata:
label: "Resources"
requests:
cpu:
__metadata:
label: "CPU request"
description: "The requested CPU"
type: "string"
required: true
memory:
__metadata:
label: "Memory request"
description: "The requested memory"
type: "string"
required: true
limits:
cpu:
__metadata:
label: "CPU limit"
description: "The CPU limit"
type: "string"
required: true
memory:
__metadata:
label: "Memory limit"
description: "The memory limit"
type: "string"
required: true
queueManager:
__metadata:
label: "Queue manager"
name:
__metadata:
label: "Queue manager name"
description: "MQ queue manager name, which defaults to the Helm release name"
type: "string"
required: false
dev:
__metadata:
label: "Default Developer Configuration"
description: "Configure some queue manager basics, suitable for developer use"
adminPassword:
__metadata:
label: "Admin password"
description: "Password for 'admin' user"
type: "password"
required: false
appPassword:
__metadata:
label: "App password"
description: "Password for 'app' user to use for messaging"
type: "password"
required: false
nameOverride:
__metadata:
label: "Name override"
description: "This can be set to partially override the name of the resources created by this chart"
type: "string"
required: false

View File

@@ -1,68 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# license must be set to "accept" to accept the terms of the IBM license
license: "not accepted"
image:
# repository is the container repository to use, which must contain IBM MQ Advanced for Developers
repository: ibmcom/mq
# tag is the tag to use for the container repository
tag: 9
# pullSecret is the secret to use when pulling the image from a private registry
pullSecret:
# pullPolicy is either IfNotPresent or Always (https://kubernetes.io/docs/concepts/containers/images/)
pullPolicy: IfNotPresent
# persistence section specifies persistence settings which apply to the whole chart
persistence:
# enabled is whether to use Persistent Volumes or not
enabled: true
# useDynamicProvisioning is whether or not to use Storage Classes to dynamically create Persistent Volumes
useDynamicProvisioning: true
# dataPVC section specifies settings for the main Persistent Volume Claim, which is used for data in /var/mqm
dataPVC:
# name sets part of the name for this Persistent Volume Claim
name: "data"
## storageClassName is the name of the Storage Class to use, or an empty string for no Storage Class
storageClassName: ""
## size is the minimum size of the Persistent Volume
size: 2Gi
service:
name: qmgr
type: ClusterIP
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 500m
memory: 512Mi
# queueManager section specifies settings for the MQ Queue Manager
queueManager:
# name allows you to specify the name to use for the queue manager. Defaults to the Helm release name.
name:
# dev section specifies settings for the MQ developer defaults available in the MQ Advanced for Developers image.
dev:
# adminPassword sets the password of the admin user
adminPassword:
# appPassword sets the password of the app user
appPassword:
# nameOverride can be set to partially override the name of the resources created by this chart
nameOverride: ibm-mq

View File

@@ -1,20 +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
description: IBM MQ queue manager
name: ibm-mqadvanced-server-prod
version: 1.1.0
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/12/ibm_mq_200.png
tillerVersion: ">=2.4.0"

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
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]
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.

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -1,29 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -1,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" . }}

View File

@@ -1,129 +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.
{{- if .Capabilities.APIVersions.Has "apps/v1beta2" }}
apiVersion: apps/v1beta2
{{- else }}
apiVersion: apps/v1beta1
{{- end }}
kind: StatefulSet
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
selector:
matchLabels:
app: {{ template "fullname" . }}
serviceName: {{ .Values.service.name }}
replicas: 1
{{- if and (.Capabilities.KubeVersion.Major | hasPrefix "1") (.Capabilities.KubeVersion.Minor | hasPrefix "7") }}
# Set updateStrategy to "RollingUpdate", if we're on Kubernetes 1.7.
# It's already the default for apps/v1beta2 (Kubernetes 1.8 onwards)
updateStrategy:
type: RollingUpdate
{{- end }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
QM_IDENTIFIER: "{{ .Release.Name }}"
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: beta.kubernetes.io/arch
operator: In
values:
- amd64
- key: beta.kubernetes.io/os
operator: In
values:
- linux
{{- if .Values.image.pullSecret }}
imagePullSecrets:
- name: {{ .Values.image.pullSecret }}
{{- end }}
containers:
- name: qmgr
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 1414
env:
- name: LICENSE
value: {{ .Values.license }}
- name: MQ_QMGR_NAME
value: {{ .Values.queueManager.name | default .Release.Name | replace "-" "" }}
{{- if .Values.persistence.enabled }}
volumeMounts:
- mountPath: "/mnt/mqm"
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
{{- end }}
# Set liveness probe to determine if the queue manager is running
livenessProbe:
exec:
command:
- chkmqhealthy
initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
# Set readiness probe to determine if the MQ listener is running
readinessProbe:
exec:
command:
- chkmqready
initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
resources:
limits:
{{ toYaml .Values.resources.limits | indent 14 }}
requests:
{{ toYaml .Values.resources.requests | indent 14 }}
volumeClaimTemplates:
{{- if .Values.persistence.enabled }}
- metadata:
name: "{{ template "fullname" . }}-{{ .Values.dataPVC.name }}"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
{{- if .Values.persistence.useDynamicProvisioning }}
## If present, use the storageClassName from the values.yaml, else use the
## default storageClass setup by Kubernetes Administrator
##
## Setting storageClassName to nil means use the default storage class
storageClassName: {{ default nil .Values.dataPVC.storageClassName | quote }}
{{- else }}
## Disable dynamic provisioning
storageClassName: ""
{{- end }}
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: {{ .Values.dataPVC.size | quote }}
{{- end }}

View File

@@ -1,40 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Pod
metadata:
name: "{{.Release.Name}}-test"
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{.Release.Name}}-test
image: alpine:latest
env:
# Host name for the service running an MQ queue manager
- name: MQ_HOST
value: {{ template "fullname" . }}
# Time to try before giving up and failing the test (in seconds)
- name: TIMEOUT
value: "10"
command: ["sh"]
# Check that port 1414 is listening
args: ["-xc", "nc -v -z -w$(TIMEOUT) $(MQ_HOST) 1414"]
restartPolicy: Never

View File

@@ -1,219 +0,0 @@
license:
__metadata:
label: "License"
type: "string"
required: true
options:
- label: "Accepted"
value: "accept"
- label: "Not accepted"
value: "not accepted"
image:
__metadata:
label: "Image"
repository:
__metadata:
label: "Image repository"
description: "Docker image location"
type: "string"
immutable: false
required: true
tag:
__metadata:
label: "Image tag"
description: "Docker image tag"
type: "string"
immutable: false
required: true
pullPolicy:
__metadata:
name: "pullPolicy"
label: "Image pull policy"
description: "Always, Never, or IfNotPresent. Defaults to Always"
type: "string"
immutable: false
required: true
options:
- label: "Always"
value: "Always"
- label: "Never"
value: "Never"
- label: "IfNotPresent"
value: "IfNotPresent"
pullSecret:
__metadata:
label: "Image pull secret"
description: "Secret to use when pulling the image. Set this when using an image from a private registry"
type: "string"
required: false
## global persistence parameters
persistence:
__metadata:
label: "Persistence"
enabled:
__metadata:
label: "Enable persistence"
description: "Whether or not to store MQ messages and configuration on a Persistent Volume"
type: "boolean"
required: true
useDynamicProvisioning:
__metadata:
label: "Use dynamic provisioning"
description: "Whether or not to use Storage Classes to provision a Persisent Volume automatically"
type: "boolean"
required: true
dataPVC:
__metadata:
label: "Data PVC"
name:
__metadata:
label: "Name"
description: "Name of Persistent Volume Claim, used for MQ objects and messages"
type: "string"
required: true
storageClassName:
__metadata:
label: "Storage Class name"
description: "Storage class of Persistent Volume Claim, used for MQ objects and messages"
type: "string"
required: false
size:
__metadata:
label: "Size"
description: "Size of Persistent Volume Claim, used for MQ objects and messages"
type: "string"
required: true
service:
__metadata:
label: "Service"
name:
__metadata:
label: "Service name"
description: "Service name"
type: "string"
required: true
type:
__metadata:
label: "Service type"
description: "Type of service"
type: "string"
required: true
options:
- label: "ClusterIP"
value: "ClusterIP"
- label: "NodePort"
value: "NodePort"
- label: "LoadBalancer"
value: "LoadBalancer"
- label: "ExternalName"
value: "ExternalName"
resources:
__metadata:
label: "Resources"
requests:
cpu:
__metadata:
label: "CPU request"
description: "The requested CPU"
type: "string"
required: true
memory:
__metadata:
label: "Memory request"
description: "The requested memory"
type: "string"
required: true
limits:
cpu:
__metadata:
label: "CPU limit"
description: "The CPU limit"
type: "string"
required: true
memory:
__metadata:
label: "Memory limit"
description: "The memory limit"
type: "string"
required: true
queueManager:
__metadata:
label: "Queue manager"
name:
__metadata:
label: "Queue manager name"
description: "MQ queue manager name, which defaults to the Helm release name"
type: "string"
required: false
nameOverride:
__metadata:
label: "Name override"
description: "This can be set to partially override the name of the resources created by this chart"
type: "string"
required: false
# livenessProbe section specifies setting for the MQ liveness probe, which checks for a running Queue Manager
livenessProbe:
__metadata:
label: "Liveness probe"
# initialDelaySeconds should be raised if your system cannot start the Queue Manager in 60 seconds
initialDelaySeconds:
__metadata:
label: "Initial delay (seconds)"
description: "How long to wait before starting the probe. Raise this delay if your system cannot start the Queue Manager in the default time period"
type: "number"
required: false
periodSeconds:
__metadata:
label: "Period (seconds)"
description: "How often to perform the probe"
type: "number"
required: false
timeoutSeconds:
__metadata:
label: "Timeout (seconds)"
description: "How long before a probe times out"
type: "number"
required: false
failureThreshold:
__metadata:
label: "Failure threshold"
description: "Number of times the probe can fail before taking action"
type: "number"
required: false
# readinessProbe section specifies setting for the MQ readiness probe, which checks when the MQ listener is running
readinessProbe:
__metadata:
label: "Readiness probe"
initialDelaySeconds:
__metadata:
label: "Initial delay (seconds)"
description: "How long to wait before starting the probe"
type: "number"
required: false
periodSeconds:
__metadata:
label: "Period (seconds)"
description: "How often to perform the probe"
type: "number"
required: false
timeoutSeconds:
__metadata:
label: "Timeout (seconds)"
description: "How long before a probe times out"
type: "number"
required: false
failureThreshold:
__metadata:
label: "Failure threshold"
description: "Number of times the probe can fail before taking action"
type: "number"
required: false

View File

@@ -1,77 +0,0 @@
# © Copyright IBM Corporation 2017
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# license must be set to "accept" to accept the terms of the IBM license
license: "not accepted"
image:
# repository is the container repository to use, which must contain IBM MQ Advanced
repository: ibm-mqadvanced-server
# tag is the tag to use for the container repository
tag: 9.0.4.0-x86_64
# pullSecret is the secret to use when pulling the image from a private registry
pullSecret:
# pullPolicy is either IfNotPresent or Always (https://kubernetes.io/docs/concepts/containers/images/)
pullPolicy: IfNotPresent
# persistence section specifies persistence settings which apply to the whole chart
persistence:
# enabled is whether to use Persistent Volumes or not
enabled: true
# useDynamicProvisioning is whether or not to use Storage Classes to dynamically create Persistent Volumes
useDynamicProvisioning: true
# dataPVC section specifies settings for the main Persistent Volume Claim, which is used for data in /var/mqm
dataPVC:
# name sets part of the name for this Persistent Volume Claim
name: "data"
# storageClassName is the name of the Storage Class to use, or an empty string for no Storage Class
storageClassName: ""
# size is the minimum size of the Persistent Volume
size: 2Gi
service:
name: qmgr
type: ClusterIP
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
# queueManager section specifies settings for the MQ Queue Manager
queueManager:
# name allows you to specify the name to use for the queue manager. Defaults to the Helm release name.
name:
# nameOverride can be set to partially override the name of the resources created by this chart
nameOverride: ibm-mq
# livenessProbe section specifies setting for the MQ liveness probe, which checks for a running Queue Manager
livenessProbe:
# initialDelaySeconds should be raised if your system cannot start the Queue Manager in 60 seconds
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 1
# readinessProbe section specifies setting for the MQ readiness probe, which checks when the MQ listener is running
readinessProbe:
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 1

View File

@@ -0,0 +1,136 @@
/*
© 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 (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
)
type KeyStore struct {
Filename string
Password string
keyStoreType string
command string
}
// NewJKSKeyStore creates a new Java Key Store, managed by the runmqckm command
func NewJKSKeyStore(filename, password string) *KeyStore {
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "jks",
command: "/opt/mqm/bin/runmqckm",
}
}
// NewCMSKeyStore creates a new MQ CMS Key Store, managed by the runmqakm command
func NewCMSKeyStore(filename, password string) *KeyStore {
return &KeyStore{
Filename: filename,
Password: password,
keyStoreType: "cms",
command: "/opt/mqm/bin/runmqakm",
}
}
// Create a key store, if it doesn't already exist
func (ks *KeyStore) Create() error {
_, err := os.Stat(ks.Filename)
if err != nil {
if os.IsNotExist(err) {
_, _, err := command.Run(ks.command, "-keydb", "-create", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password, "-stash")
if err != nil {
return fmt.Errorf("error running \"%v -keydb -create\": %v", ks.command, err)
}
}
}
// TODO: Lookup value for MQM user here?
err = os.Chown(ks.Filename, 999, 999)
if err != nil {
log.Error(err)
return err
}
return nil
}
// Create a key stash, if it doesn't already exist
func (ks *KeyStore) CreateStash() error {
extension := filepath.Ext(ks.Filename)
stashFile := ks.Filename[0:len(ks.Filename)-len(extension)] + ".sth"
log.Debugf("TLS stash file: %v", stashFile)
_, err := os.Stat(stashFile)
if err != nil {
if os.IsNotExist(err) {
_, _, err := command.Run(ks.command, "-keydb", "-stashpw", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return fmt.Errorf("error running \"%v -keydb -stashpw\": %v", ks.command, err)
}
}
return err
}
// TODO: Lookup value for MQM user here?
err = os.Chown(stashFile, 999, 999)
if err != nil {
log.Error(err)
return err
}
return nil
}
func (ks *KeyStore) Import(inputFile, password string) error {
_, _, err := command.Run(ks.command, "-cert", "-import", "-file", inputFile, "-pw", password, "-target", ks.Filename, "-target_pw", ks.Password, "-target_type", ks.keyStoreType)
if err != nil {
return fmt.Errorf("error running \"%v -cert -import\": %v", ks.command, err)
}
return nil
}
// GetCertificateLabels returns the labels of all certificates in the key store
func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
if err != nil {
return nil, fmt.Errorf("error running \"%v -cert -list\": %v", ks.command, err)
}
scanner := bufio.NewScanner(strings.NewReader(out))
var labels []string
for scanner.Scan() {
s := scanner.Text()
if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") {
s := strings.TrimLeft(s, "-*")
labels = append(labels, strings.TrimSpace(s))
}
}
err = scanner.Err()
if err != nil {
return nil, err
}
return labels, nil
}
// RenameCertificate renames the specified certificate
func (ks *KeyStore) RenameCertificate(from, to string) error {
_, _, err := command.Run(ks.command, "-cert", "-rename", "-db", ks.Filename, "-pw", ks.Password, "-label", from, "-new_label", to)
if err != nil {
return fmt.Errorf("error running \"%v -cert -rename\": %v", ks.command, err)
}
return nil
}

View File

@@ -83,6 +83,11 @@ func configureLogger() error {
return nil return nil
} }
func configureWeb(qmName string) error {
out := "/etc/mqm/web/installations/Installation1/angular.persistence/admin.json"
return processTemplateFile("/etc/mqm/admin.json.tpl", out, map[string]string{"QueueManagerName": qmName})
}
func logTerminationf(format string, args ...interface{}) { func logTerminationf(format string, args ...interface{}) {
logTermination(fmt.Sprintf(format, args)) logTermination(fmt.Sprintf(format, args))
} }
@@ -129,6 +134,26 @@ func doMain() error {
return err return err
} }
name, err := name.GetQueueManagerName()
if err != nil {
logTerminationf("Error getting queue manager name: %v", err)
return err
}
ks, set := os.LookupEnv("MQ_TLS_KEYSTORE")
if set {
err = configureTLS(name, ks, os.Getenv("MQ_TLS_PASSPHRASE"))
if err != nil {
logTerminationf("Error configuring TLS: %v", err)
return err
}
}
err = configureWeb(name)
if err != nil {
logTermination("Error configuring admin.json")
return err
}
return nil return nil
} }

View File

@@ -16,7 +16,6 @@ limitations under the License.
package main package main
import ( import (
"html/template"
"os" "os"
) )
@@ -27,29 +26,14 @@ func updateMQSC(appPasswordRequired bool) error {
} else { } else {
checkClient = "ASQMGR" checkClient = "ASQMGR"
} }
const mqsc string = "/etc/mqm/dev.mqsc" const mqsc string = "/etc/mqm/10-dev.mqsc"
if os.Getenv("MQ_DEV") == "true" { if os.Getenv("MQ_DEV") == "true" {
const mqscTemplate string = mqsc + ".tpl" const mqscTemplate string = mqsc + ".tpl"
// Re-configure channel if app password not set // Re-configure channel if app password not set
t, err := template.ParseFiles(mqscTemplate) err := processTemplateFile(mqsc+".tpl", mqsc, map[string]string{"ChckClnt": checkClient})
if err != nil { if err != nil {
log.Error(err)
return err return err
} }
f, err := os.OpenFile(mqsc, os.O_CREATE|os.O_WRONLY, 0660)
defer f.Close()
err = t.Execute(f, map[string]string{"ChckClnt": checkClient})
if err != nil {
log.Error(err)
return err
}
// TODO: Lookup value for MQM user here?
err = os.Chown(mqsc, 999, 999)
if err != nil {
log.Error(err)
return err
}
// os.Remove(mqscTemplate)
} else { } else {
os.Remove(mqsc) os.Remove(mqsc)
} }

View File

@@ -0,0 +1,62 @@
/*
© 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 (
"os"
"path"
"text/template"
)
// processTemplateFile takes a Go templateFile, and processes it with the
// supplied data, writing to destFile
func processTemplateFile(templateFile, destFile string, data interface{}) error {
// Re-configure channel if app password not set
t, err := template.ParseFiles(templateFile)
if err != nil {
log.Error(err)
return err
}
dir := path.Dir(destFile)
_, err = os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
os.MkdirAll(dir, 0660)
// TODO: Lookup value for MQM user here?
err = os.Chown(dir, 999, 999)
if err != nil {
log.Error(err)
return err
}
} else {
return err
}
}
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0660)
defer f.Close()
err = t.Execute(f, data)
if err != nil {
log.Error(err)
return err
}
// TODO: Lookup value for MQM user here?
err = os.Chown(destFile, 999, 999)
if err != nil {
log.Error(err)
return err
}
return nil
}

141
cmd/runmqdevserver/tls.go Normal file
View File

@@ -0,0 +1,141 @@
/*
© 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"
)
func configureWebTLS(cms *KeyStore) error {
dir := "/run/runmqdevserver/tls"
ks := NewJKSKeyStore(filepath.Join(dir, "key.jks"), cms.Password)
ts := NewJKSKeyStore(filepath.Join(dir, "trust.jks"), cms.Password)
log.Debug("Creating key store")
err := ks.Create()
if err != nil {
return err
}
log.Debug("Creating trust store")
err = ts.Create()
if err != nil {
return err
}
log.Debug("Importing keys")
err = ks.Import(cms.Filename, cms.Password)
if err != nil {
return err
}
webConfigDir := "/etc/mqm/web/installations/Installation1/servers/mqweb"
tlsConfig := filepath.Join(webConfigDir, "tls.xml")
newTLSConfig := filepath.Join(webConfigDir, "tls-dev.xml")
err = os.Remove(tlsConfig)
if err != nil {
return err
}
err = os.Rename(newTLSConfig, tlsConfig)
if err != nil {
return err
}
return nil
}
func configureTLS(qmName string, inputFile string, passPhrase string) error {
log.Debug("Configuring TLS")
_, err := os.Stat(inputFile)
if err != nil {
return err
}
// TODO: Use a persisted file (on the volume) instead?
dir := "/run/runmqdevserver/tls"
keyFile := filepath.Join(dir, "key.kdb")
_, err = os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
err = os.MkdirAll(dir, 0770)
if err != nil {
return err
}
err = os.Chown(dir, 999, 999)
if err != nil {
log.Debug(err)
return err
}
} else {
return err
}
}
cms := NewCMSKeyStore(keyFile, passPhrase)
err = cms.Create()
if err != nil {
return err
}
err = cms.CreateStash()
if err != nil {
return err
}
err = cms.Import(inputFile, passPhrase)
if err != nil {
return err
}
labels, err := cms.GetCertificateLabels()
if err != nil {
return err
}
if len(labels) == 0 {
return fmt.Errorf("unable to find certificate label")
}
log.Debugf("Renaming certificate from %v", labels[0])
const newLabel string = "devcert"
err = cms.RenameCertificate(labels[0], newLabel)
if err != nil {
return err
}
f, err := os.OpenFile("/etc/mqm/20-dev-tls.mqsc", os.O_WRONLY|os.O_CREATE, 0770)
if err != nil {
return err
}
defer f.Close()
// Change the Queue Manager's Key Repository to point at the new TLS key store
fmt.Fprintf(f, "ALTER QMGR SSLKEYR('%s')\n", filepath.Join(dir, "key"))
fmt.Fprintf(f, "ALTER QMGR CERTLABL('%s')\n", newLabel)
if os.Getenv("MQ_DEV") == "true" {
// Alter the DEV channels to use TLS
fmt.Fprintln(f, "ALTER CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(TLS_RSA_WITH_AES_128_CBC_SHA256) SSLCAUTH(OPTIONAL)")
fmt.Fprintln(f, "ALTER CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) SSLCIPH(TLS_RSA_WITH_AES_128_CBC_SHA256) SSLCAUTH(OPTIONAL)")
}
err = configureWebTLS(cms)
if err != nil {
return err
}
return nil
}

View File

@@ -17,7 +17,9 @@ limitations under the License.
*/ */
package main package main
import "os" import (
"os"
)
// postInit is run after /var/mqm is set up // postInit is run after /var/mqm is set up
// This version of postInit is only included as part of the MQ Advanced for Developers build // This version of postInit is only included as part of the MQ Advanced for Developers build

View File

@@ -19,6 +19,7 @@ package main
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"path/filepath" "path/filepath"
@@ -41,6 +42,26 @@ func startWebServer() error {
return nil return nil
} }
// CopyFile copies the specified file
func CopyFile(src, dest string) error {
log.Debugf("Copying file %v to %v", src, dest)
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0770)
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
err = out.Close()
return err
}
func configureWebServer() error { func configureWebServer() error {
_, err := os.Stat("/opt/mqm/bin/strmqweb") _, err := os.Stat("/opt/mqm/bin/strmqweb")
if err != nil { if err != nil {
@@ -76,7 +97,6 @@ func configureWebServer() error {
return err return err
} }
} }
if info.IsDir() { if info.IsDir() {
if !exists { if !exists {
err := os.MkdirAll(to, 0770) err := os.MkdirAll(to, 0770)
@@ -84,7 +104,6 @@ func configureWebServer() error {
return err return err
} }
} }
log.Printf("Directory: %v --> %v", from, to)
} else { } else {
if exists { if exists {
err := os.Remove(to) err := os.Remove(to)
@@ -92,13 +111,11 @@ func configureWebServer() error {
return err return err
} }
} }
// TODO: Permissions. Can't rely on them being set in Dockerfile err := CopyFile(from, to)
err := os.Link(from, to)
if err != nil { if err != nil {
log.Debug(err) log.Debug(err)
return err return err
} }
log.Printf("File: %v", from)
} }
err = os.Chown(to, uid, gid) err = os.Chown(to, uid, gid)
if err != nil { if err != nil {

View File

@@ -9,7 +9,7 @@ You need to ensure you have the following tools installed:
This procedure works for building the MQ Continuous Delivery release, on `x86_64`, `ppc64le` and `s390x` architectures. This procedure works for building the MQ Continuous Delivery release, on `x86_64`, `ppc64le` and `s390x` architectures.
1. Create a `downloads` directory in the root of this repository 1. Create a `downloads` directory in the root of this repository
2. Download MQ from IBM Passport Advantage, and place the downloaded file (for example, `IBM_MQ_9.0.4.0_UBUNTU_X86-64.tar.gz` for MQ V9.0.4 for Ubuntu on x86_64 architecture) in the `downloads` directory 2. Download MQ from IBM Passport Advantage, and place the downloaded file (for example, `IBM_MQ_9.0.5.0_UBUNTU_X86-64.tar.gz` for MQ V9.0.5 for Ubuntu on x86_64 architecture) in the `downloads` directory
2. Run `make build-advancedserver` 2. Run `make build-advancedserver`
> **Warning**: Note that MQ offers two different sets of packaging on Linux: one is called "MQ for Linux" and contains RPM files for installing on Red Hat Enterprise Linux and SUSE Linux Enterprise Server. The other package is called "MQ for Ubuntu", and contains DEB files for installing on Ubuntu. > **Warning**: Note that MQ offers two different sets of packaging on Linux: one is called "MQ for Linux" and contains RPM files for installing on Red Hat Enterprise Linux and SUSE Linux Enterprise Server. The other package is called "MQ for Ubuntu", and contains DEB files for installing on Ubuntu.
@@ -38,6 +38,12 @@ By default, the MQ images use Ubuntu as the base layer. You can build using a R
BASE_IMAGE=centos:7 make build-advancedserver BASE_IMAGE=centos:7 make build-advancedserver
``` ```
The `make` tool will try and locate the right archive file under the `downloads` directory, based on your platform architecture and your `MQ_VERSION` environment variable, for example `IBM_MQ_9.0.4.0_LINUX_X86_64.tar.gz` for MQ V9.0.4.0 on x86_64. You can also set the `MQ_ARCHIVE` environment variable to set the specific file name. The `make` tool will try and locate the right archive file under the `downloads` directory, based on your platform architecture and your `MQ_VERSION` environment variable, for example `IBM_MQ_9.0.5.0_LINUX_X86_64.tar.gz` for MQ V9.0.5.0 on x86_64. You can also set the `MQ_ARCHIVE` environment variable to set the specific file name.
Note that if you are using Red Hat Enterprise Linux, you will need to create your own base image layer, with your subscription enabled, as described [here](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/getting_started_with_containers/get_started_with_docker_formatted_container_images). The MQ image build needs to install some additional packages, and a subscription is required to access the Red Hat repositories.
## Installed components
This image includes the core MQ server, Java, language packs, and GSKit. This can be configured by setting the `MQ_PACKAGES` argument to `make`, or directly as a [Docker build argument](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables-build-arg).
Note that if you are using Red Hat Enterprise Linux, you will need to create your own base image layer, with your subscription enabled, as described [here](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/getting_started_with_containers/get_started_with_docker_formatted_container_images). The MQ image build needs to install some additional packages, and a subscription is required to access the Red Hat repositories.

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

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

View File

@@ -8,6 +8,7 @@ The resulting Docker image contains the following:
* MQ installation (under `/opt/mqm`) * MQ installation (under `/opt/mqm`)
* Three additional programs, to enable running in a containerized environment: * Three additional programs, to enable running in a containerized environment:
- `runmqserver` - The main process, which creates and runs a queue manager - `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. - `chkmqhealthy` - Checks the health of the queue manager. This can be used by (say) a Kubernetes liveness probe.
- `chkmqready` - Checks if the queue manager is ready for work. This can be used by (say) a Kubernetes readiness probe. - `chkmqready` - Checks if the queue manager is ready for work. This can be used by (say) a Kubernetes readiness probe.
@@ -23,3 +24,15 @@ The `runmqserver` command has the following responsibilities:
- 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/) - 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 * Creating and starting a queue manager
* Configuring the queue manager, by running any MQSC scripts found under `/etc/mqm` * Configuring the queue manager, by running any MQSC scripts found under `/etc/mqm`
* 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
A special version of `runmqserver` is used in the developer image, which performs extra actions like starting the web server. This is built using the `mqdev` [build constraint](https://golang.org/pkg/go/build/#hdr-Build_Constraints).

View File

@@ -18,11 +18,10 @@ make deps
``` ```
## Running the tests ## Running the tests
There are three main sets of tests: There are two main sets of tests:
1. Unit tests, which are run during a build 1. Unit tests, which are run during a build
2. Docker tests, which test a complete Docker image, using the Docker API 2. Docker tests, which test a complete Docker image, using the Docker API
3. Kubernetes tests, which test the Helm charts (and the Docker image) via [Helm](https://helm.sh)
### Running the Docker tests ### Running the Docker tests
The Docker tests can be run locally on a machine with Docker. For example: The Docker tests can be run locally on a machine with Docker. For example:
@@ -35,7 +34,7 @@ make test-advancedserver
You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example: You can specify the image to use directly by using the `MQ_IMAGE_ADVANCEDSERVER` or `MQ_IMAGE_DEVSERVER` variables, for example:
``` ```
MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server9.0.4.0-x86_64-ubuntu-16.04 make test-advancedserver MQ_IMAGE_ADVANCEDSERVER=mqadvanced-server:9.0.5.0-x86_64-ubuntu-16.04 make test-advancedserver
``` ```
You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command:: You can pass parameters to `go test` with an environment variable. For example, to run the "TestGoldenPath" test, run the following command::
@@ -44,10 +43,10 @@ You can pass parameters to `go test` with an environment variable. For example,
TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver TEST_OPTS_DOCKER="-run TestGoldenPath" make test-advancedserver
``` ```
You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `mqadvanced-server9.0.3.0-x86_64-ubuntu-16.04`: You can also use the same environment variables you specified when [building](./building), for example, the following will try and test an image called `mqadvanced-server:9.0.4.0-x86_64-ubuntu-16.04`:
``` ```
MQ_VERSION=9.0.3.0 make test-advancedserver MQ_VERSION=9.0.4.0 make test-advancedserver
``` ```
### Running the Docker tests with code coverage ### Running the Docker tests with code coverage

17
docs/troubleshooting.md Normal file
View File

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

81
docs/usage.md Normal file
View File

@@ -0,0 +1,81 @@
# 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.
## 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:
```
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--publish 1414:1414 \
--publish 9443:9443 \
--detach \
ibmcom/mq
```
## Running with the default configuration and a volume
The above example will not persist any configuration data or messages across container runs. In order to do this, you need to use a [volume](https://docs.docker.com/engine/admin/volumes/volumes/). For example, you can create a volume with the following command:
```
docker volume create qm1data
```
You can then run a queue manager using this volume as follows:
```
docker run \
--env LICENSE=accept \
--env MQ_QMGR_NAME=QM1 \
--publish 1414:1414 \
--publish 9443:9443 \
--detach \
--volume qm1data:/mnt/mqm \
ibmcom/mq
```
The Docker image always uses `/mnt/mqm` for MQ data, which is correctly linked for you under `/var/mqm` at runtime. This is to handle problems with file permissions on some platforms.
## 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](http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.adm.doc/q021090_.htm), via an MQ command server, the MQ HTTP APIs, or using a tool such as the MQ web console or MQ Explorer.
Note that a listener is always created on port 1414 inside the container. This port can be mapped to any port on the Docker host.
The following is an *example* `Dockerfile` for creating your own pre-configured image, which adds a custom `config.mqsc` and an administrative user `alice`. Note that it is not normally recommended to include passwords in this way:
```dockerfile
FROM ibmcom/mq
RUN useradd alice -G mqm && \
echo alice:passw0rd | chpasswd
COPY 20-config.mqsc /etc/mqm/
```
Here is an example corresponding `20-config.mqsc` script from the [mqdev blog](https://www.ibm.com/developerworks/community/blogs/messaging/entry/getting_going_without_turning_off_mq_security?lang=en), which allows users with passwords to connect on the `PASSWORD.SVRCONN` channel:
```
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)
REFRESH SECURITY TYPE(CONNAUTH)
```
## 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:
```
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.

View File

@@ -32,9 +32,10 @@ DEFINE AUTHINFO('DEV.AUTHINFO') AUTHTYPE(IDPWOS) CHCKCLNT(REQDADM) CHCKLOCL(OPTI
ALTER QMGR CONNAUTH('DEV.AUTHINFO') ALTER QMGR CONNAUTH('DEV.AUTHINFO')
REFRESH SECURITY(*) TYPE(CONNAUTH) REFRESH SECURITY(*) TYPE(CONNAUTH)
* Developer channels (Application + Admin)
* Developer channels (Application + Admin) * Developer channels (Application + Admin)
DEFINE CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) REPLACE DEFINE CHANNEL('DEV.ADMIN.SVRCONN') CHLTYPE(SVRCONN) REPLACE
DEFINE CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) REPLACE DEFINE CHANNEL('DEV.APP.SVRCONN') CHLTYPE(SVRCONN) MCAUSER('app') REPLACE
* Developer channel authentication rules * Developer channel authentication rules
SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('Back-stop rule - Blocks everyone') ACTION(REPLACE) SET CHLAUTH('*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(NOACCESS) DESCR('Back-stop rule - Blocks everyone') ACTION(REPLACE)
@@ -43,8 +44,7 @@ SET CHLAUTH('DEV.ADMIN.SVRCONN') TYPE(BLOCKUSER) USERLIST('nobody') DESCR('Allow
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(CHANNEL) DESCR('Allows admin user to connect via ADMIN channel') ACTION(REPLACE)
* Developer authority records * Developer authority records
SET AUTHREC PROFILE('DEV.AUTHINFO') GROUP('root') OBJTYPE(AUTHINFO) AUTHADD(CHG,DLT,DSP,INQ) SET AUTHREC PROFILE('self') GROUP('mqclient') OBJTYPE(QMGR) AUTHADD(CONNECT,INQ)
SET AUTHREC PROFILE('DEV.AUTHINFO') GROUP('mqm') OBJTYPE(AUTHINFO) AUTHADD(CHG,DLT,DSP,INQ)
SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(QUEUE) AUTHADD(BROWSE,GET,INQ,PUT) SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(QUEUE) AUTHADD(BROWSE,GET,INQ,PUT)
SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(TOPIC) AUTHADD(PUB,SUB) SET AUTHREC PROFILE('DEV.**') GROUP('mqclient') OBJTYPE(TOPIC) AUTHADD(PUB,SUB)

View File

@@ -40,13 +40,19 @@ ENV MQ_ADMIN_PASSWORD=passw0rd
## Add admin and app users, and set a default password for admin ## Add admin and app users, and set a default password for admin
RUN useradd admin -G mqm \ RUN useradd admin -G mqm \
&& groupadd mqclient \ && groupadd mqclient \
&& useradd app -G mqclient,mqm \ && useradd app -G mqclient \
&& echo admin:$MQ_ADMIN_PASSWORD | chpasswd && echo admin:$MQ_ADMIN_PASSWORD | chpasswd
# Create a directory for runtime data from runmqserver
RUN mkdir -p /run/runmqdevserver \
&& chown mqm:mqm /run/runmqdevserver
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqserver /usr/local/bin/ COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqserver /usr/local/bin/
COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/ COPY --from=builder /go/src/github.com/ibm-messaging/mq-container/runmqdevserver /usr/local/bin/
# Copy template MQSC for default developer configuration # Copy template MQSC for default developer configuration
COPY incubating/mqadvanced-server-dev/dev.mqsc.tpl /etc/mqm/ COPY incubating/mqadvanced-server-dev/10-dev.mqsc.tpl /etc/mqm/
# Copy template JSON for default web console configuration
COPY incubating/mqadvanced-server-dev/admin.json.tpl /etc/mqm/
# Copy web XML files for default developer configuration # Copy web XML files for default developer configuration
COPY incubating/mqadvanced-server-dev/web /etc/mqm/web COPY incubating/mqadvanced-server-dev/web /etc/mqm/web
RUN chmod +x /usr/local/bin/runmq* RUN chmod +x /usr/local/bin/runmq*

View File

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

View File

@@ -25,6 +25,5 @@
</group> </group>
</basicRegistry> </basicRegistry>
<variable name="httpHost" value="*"/> <variable name="httpHost" value="*"/>
<httpDispatcher enableWelcomePage="false" appOrContextRootMissingMessage='Redirecting to console.&lt;script&gt;document.location.href="/ibmmq/console";&lt;/script&gt;' />
<include location="tls.xml"/> <include location="tls.xml"/>
</server> </server>

View File

@@ -1,4 +1,7 @@
<keyStore id="MQWebKeyStore" location="/var/mqm/web/installations/Installation1/servers/mqweb/key.jks" type="JKS" password="${env.MQ_TLS_PASSPHRASE}"/> <?xml version="1.0" encoding="UTF-8"?>
<keyStore id="MQWebTrustStore" location="/var/mqm/web/installations/Installation1/servers/mqweb/trust.jks" type="JKS" password="${env.MQ_TLS_PASSPHRASE}"/> <server>
<ssl id="thisSSLConfig" clientAuthenticationSupported="true" keyStoreRef="MQWebKeyStore" trustStoreRef="MQWebTrustStore" sslProtocol="TLSv1.2" serverKeyAlias="webcert"/> <keyStore id="MQWebKeyStore" location="/run/runmqdevserver/tls/key.jks" type="JKS" password="${env.MQ_TLS_PASSPHRASE}"/>
<keyStore id="MQWebTrustStore" location="/run/runmqdevserver/tls/trust.jks" type="JKS" password="${env.MQ_TLS_PASSPHRASE}"/>
<ssl id="thisSSLConfig" clientAuthenticationSupported="true" keyStoreRef="MQWebKeyStore" trustStoreRef="MQWebTrustStore" sslProtocol="TLSv1.2" serverKeyAlias="devcert"/>
<sslDefault sslRef="thisSSLConfig"/> <sslDefault sslRef="thisSSLConfig"/>
</server>

View File

@@ -1 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<server>
<sslDefault sslRef="mqDefaultSSLConfig"/> <sslDefault sslRef="mqDefaultSSLConfig"/>
</server>

View File

@@ -18,16 +18,19 @@ limitations under the License.
package main package main
import ( import (
"crypto/tls" "context"
"fmt" "path/filepath"
"net/http" "strings"
"testing" "testing"
"time"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
) )
// TestDevGoldenPath tests using the default values for the default developer config.
// Note: This test requires a separate container image to be available for the JMS tests.
func TestDevGoldenPath(t *testing.T) { func TestDevGoldenPath(t *testing.T) {
t.Parallel() t.Parallel()
cli, err := client.NewEnvClient() cli, err := client.NewEnvClient()
@@ -35,38 +38,124 @@ func TestDevGoldenPath(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
containerConfig := container.Config{ containerConfig := container.Config{
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"}, Env: []string{
} "LICENSE=accept",
id := runContainer(t, cli, &containerConfig) "MQ_QMGR_NAME=qm1",
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
waitForWebReady(t, cli, id)
timeout := time.Duration(30 * time.Second)
// Disable TLS verification (server uses a self-signed certificate by default,
// so verification isn't useful anyway)
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
}, },
} }
httpClient := http.Client{ id := runContainer(t, cli, &containerConfig)
Timeout: timeout, defer cleanContainer(t, cli, id)
Transport: tr, waitForReady(t, cli, id)
} waitForWebReady(t, cli, id, insecureTLSConfig)
t.Run("JMS", func(t *testing.T) {
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getWebPort(t, cli, id)) // Run the JMS tests, with no password specified
req, err := http.NewRequest("GET", url, nil) runJMSTests(t, cli, id, false, "app", "")
req.SetBasicAuth("admin", "passw0rd") })
resp, err := httpClient.Do(req) // Stop the container cleanly
if err != nil { stopContainer(t, cli, id)
t.Fatal(err) }
}
if resp.StatusCode != http.StatusOK { // TestDevSecure tests the default developer config using the a custom TLS key store and password.
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode) // Note: This test requires a separate container image to be available for the JMS tests
} func TestDevSecure(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
const tlsPassPhrase string = "passw0rd"
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=qm1",
"MQ_APP_PASSWORD=" + devAppPassword,
"MQ_TLS_KEYSTORE=/var/tls/server.p12",
"MQ_TLS_PASSPHRASE=" + tlsPassPhrase,
"DEBUG=1",
},
Image: imageName(),
}
hostConfig := container.HostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t) + ":/var/tls",
},
// Assign a random port for the web server on the host
// TODO: Don't do this for all tests
PortBindings: nat.PortMap{
"9443/tcp": []nat.PortBinding{
{
HostIP: "0.0.0.0",
},
},
},
}
networkingConfig := network.NetworkingConfig{}
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
if err != nil {
t.Fatal(err)
}
defer cleanContainer(t, cli, ctr.ID)
startContainer(t, cli, ctr.ID)
waitForReady(t, cli, ctr.ID)
cert := filepath.Join(tlsDir(t), "server.crt")
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
runJMSTests(t, cli, ctr.ID, true, "app", devAppPassword)
// Stop the container cleanly
stopContainer(t, cli, ctr.ID)
}
func TestDevWebDisabled(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=qm1",
"MQ_DISABLE_WEB_CONSOLE=true",
},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
t.Run("Web", func(t *testing.T) {
dspmqweb := execContainerWithOutput(t, cli, id, "mqm", []string{"dspmqweb"})
if !strings.Contains(dspmqweb, "Server mqweb is not running.") {
t.Errorf("Expected dspmqweb to say server is not running; got \"%v\"", dspmqweb)
}
})
t.Run("JMS", func(t *testing.T) {
// Run the JMS tests, with no password specified
runJMSTests(t, cli, id, false, "app", "")
})
// Stop the container cleanly
stopContainer(t, cli, id)
}
func TestDevConfigDisabled(t *testing.T) {
t.Parallel()
cli, err := client.NewEnvClient()
if err != nil {
t.Fatal(err)
}
containerConfig := container.Config{
Env: []string{
"LICENSE=accept",
"MQ_QMGR_NAME=qm1",
"MQ_DEV=false",
},
}
id := runContainer(t, cli, &containerConfig)
defer cleanContainer(t, cli, id)
waitForReady(t, cli, id)
waitForWebReady(t, cli, id, insecureTLSConfig)
rc := execContainerWithExitCode(t, cli, id, "mqm", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"})
if rc == 0 {
t.Errorf("Expected DEV queues to be missing")
}
// Stop the container cleanly // Stop the container cleanly
stopContainer(t, cli, id) stopContainer(t, cli, id)
} }

View File

@@ -18,25 +18,150 @@ limitations under the License.
package main package main
import ( import (
"context"
"crypto/tls" "crypto/tls"
"crypto/x509"
"fmt" "fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
"testing" "testing"
"time" "time"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client" "github.com/docker/docker/client"
) )
func waitForWebReady(t *testing.T, cli *client.Client, ID string) { const devAdminPassword string = "passw0rd"
config := tls.Config{InsecureSkipVerify: true} const devAppPassword string = "passw0rd"
a := fmt.Sprintf("localhost:%s", getWebPort(t, cli, ID))
// Disable TLS verification (server uses a self-signed certificate by default,
// so verification isn't useful anyway)
var insecureTLSConfig *tls.Config = &tls.Config{
InsecureSkipVerify: true,
}
func waitForWebReady(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
httpClient := http.Client{
Timeout: time.Duration(3 * time.Second),
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
}
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getWebPort(t, cli, ID))
for { for {
conn, err := tls.Dial("tcp", a, &config) req, err := http.NewRequest("GET", url, nil)
if err == nil { req.SetBasicAuth("admin", devAdminPassword)
conn.Close() resp, err := httpClient.Do(req)
// Extra sleep to allow web apps to start if err == nil && resp.StatusCode == http.StatusOK {
time.Sleep(3 * time.Second)
t.Log("MQ web server is ready") t.Log("MQ web server is ready")
return return
} }
// conn, err := tls.Dial("tcp", a, &config)
// if err == nil {
// conn.Close()
// // Extra sleep to allow web apps to start
// time.Sleep(5 * time.Second)
// t.Log("MQ web server is ready")
// return
// }
time.Sleep(1 * time.Second)
}
}
// tlsDir returns the host directory where the test certificate(s) are located
func tlsDir(t *testing.T) string {
dir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
return filepath.Join(dir, "../tls")
}
// runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID
func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string) {
containerConfig := container.Config{
// -e MQ_PORT_1414_TCP_ADDR=9.145.14.173 -e MQ_USERNAME=app -e MQ_PASSWORD=passw0rd -e MQ_CHANNEL=DEV.APP.SVRCONN -e MQ_TLS_KEYSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest
Env: []string{
"MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID),
"MQ_USERNAME=" + user,
"MQ_CHANNEL=DEV.APP.SVRCONN",
},
Image: imageNameDevJMS(),
}
// Set a password for the client to use, if one is specified
if password != "" {
containerConfig.Env = append(containerConfig.Env, "MQ_PASSWORD="+password)
}
if tls {
t.Log("Using TLS from JMS client")
containerConfig.Env = append(containerConfig.Env, []string{
"MQ_TLS_TRUSTSTORE=/var/tls/client-trust.jks",
"MQ_TLS_PASSPHRASE=passw0rd",
}...)
}
hostConfig := container.HostConfig{
Binds: []string{
coverageBind(t),
tlsDir(t) + ":/var/tls",
},
}
networkingConfig := network.NetworkingConfig{}
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, strings.Replace(t.Name()+"JMS", "/", "", -1))
if err != nil {
t.Fatal(err)
}
startContainer(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 10)
if rc != 0 {
t.Errorf("JUnit container failed with rc=%v", rc)
}
defer cleanContainer(t, cli, ctr.ID)
}
// createTLSConfig creates a tls.Config which trusts the specified certificate
func createTLSConfig(t *testing.T, certFile, password string) *tls.Config {
// Get the SystemCertPool, continue with an empty pool on error
certs, err := x509.SystemCertPool()
if err != nil {
t.Fatal(err)
}
// Read in the cert file
cert, err := ioutil.ReadFile(certFile)
if err != nil {
t.Fatal(err)
}
// Append our cert to the system pool
ok := certs.AppendCertsFromPEM(cert)
if !ok {
t.Fatal("No certs appended")
}
// Trust the augmented cert pool in our client
return &tls.Config{
InsecureSkipVerify: false,
RootCAs: certs,
}
}
func testREST(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
httpClient := http.Client{
Timeout: time.Duration(30 * time.Second),
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
}
url := fmt.Sprintf("https://localhost:%s/ibmmq/rest/v1/admin/installation", getWebPort(t, cli, ID))
req, err := http.NewRequest("GET", url, nil)
req.SetBasicAuth("admin", devAdminPassword)
resp, err := httpClient.Do(req)
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode)
} }
} }

View File

@@ -24,7 +24,6 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
@@ -50,6 +49,14 @@ func imageName() string {
return image return image
} }
func imageNameDevJMS() string {
image, ok := os.LookupEnv("DEV_JMS_IMAGE")
if !ok {
image = "mq-dev-jms-test"
}
return image
}
func coverage() bool { func coverage() bool {
cover := os.Getenv("TEST_COVER") cover := os.Getenv("TEST_COVER")
if cover == "true" || cover == "1" { if cover == "true" || cover == "1" {
@@ -330,7 +337,7 @@ func execContainerWithOutput(t *testing.T, cli *client.Client, ID string, user s
// Each output line has a header, which needs to be removed // Each output line has a header, which needs to be removed
_, err = stdcopy.StdCopy(buf, buf, hijack.Reader) _, err = stdcopy.StdCopy(buf, buf, hijack.Reader)
if err != nil { if err != nil {
log.Fatal(err) t.Fatal(err)
} }
return strings.TrimSpace(buf.String()) return strings.TrimSpace(buf.String())
} }
@@ -399,16 +406,15 @@ func inspectTextLogs(t *testing.T, cli *client.Client, ID string) string {
jsonLogs := inspectLogs(t, cli, ID) jsonLogs := inspectLogs(t, cli, ID)
scanner := bufio.NewScanner(strings.NewReader(jsonLogs)) scanner := bufio.NewScanner(strings.NewReader(jsonLogs))
b := make([]byte, 64*1024) b := make([]byte, 64*1024)
scanner.Buffer(b, 1024*1024)
buf := bytes.NewBuffer(b) buf := bytes.NewBuffer(b)
for scanner.Scan() { for scanner.Scan() {
t := scanner.Text() text := scanner.Text()
if strings.HasPrefix(t, "{") { if strings.HasPrefix(text, "{") {
var e map[string]interface{} var e map[string]interface{}
json.Unmarshal([]byte(scanner.Text()), &e) json.Unmarshal([]byte(text), &e)
fmt.Fprintf(buf, "{\"message\": \"%v\"}\n", e["message"]) fmt.Fprintf(buf, "{\"message\": \"%v\"}\n", e["message"])
} else { } else {
fmt.Fprintln(buf, t) fmt.Fprintln(buf, text)
} }
} }
err := scanner.Err() err := scanner.Err()
@@ -426,13 +432,13 @@ func inspectLogs(t *testing.T, cli *client.Client, ID string) string {
ShowStderr: true, ShowStderr: true,
}) })
if err != nil { if err != nil {
log.Fatal(err) t.Fatal(err)
} }
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
// Each output line has a header, which needs to be removed // Each output line has a header, which needs to be removed
_, err = stdcopy.StdCopy(buf, buf, reader) _, err = stdcopy.StdCopy(buf, buf, reader)
if err != nil { if err != nil {
log.Fatal(err) t.Fatal(err)
} }
return buf.String() return buf.String()
} }

View File

@@ -1,219 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/PuerkitoBio/purell"
packages = ["."]
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/PuerkitoBio/urlesc"
packages = ["."]
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
name = "github.com/asaskevich/govalidator"
packages = ["."]
revision = "73945b6115bfbbcc57d89b7316e28109364124e1"
version = "v7"
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
name = "github.com/docker/distribution"
packages = ["digest","reference"]
revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89"
version = "v2.6.2"
[[projects]]
name = "github.com/emicklei/go-restful"
packages = [".","log"]
revision = "68c9750c36bb8cb433f1b88c807b4b30df4acc40"
version = "v2.2.1"
[[projects]]
name = "github.com/emicklei/go-restful-swagger12"
packages = ["."]
revision = "dcef7f55730566d41eae5db10e7d6981829720f6"
version = "1.0.1"
[[projects]]
name = "github.com/ghodss/yaml"
packages = ["."]
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/go-openapi/analysis"
packages = ["."]
revision = "8ed83f2ea9f00f945516462951a288eaa68bf0d6"
[[projects]]
branch = "master"
name = "github.com/go-openapi/errors"
packages = ["."]
revision = "03cfca65330da08a5a440053faf994a3c682b5bf"
[[projects]]
branch = "master"
name = "github.com/go-openapi/jsonpointer"
packages = ["."]
revision = "779f45308c19820f1a69e9a4cd965f496e0da10f"
[[projects]]
branch = "master"
name = "github.com/go-openapi/jsonreference"
packages = ["."]
revision = "36d33bfe519efae5632669801b180bf1a245da3b"
[[projects]]
branch = "master"
name = "github.com/go-openapi/loads"
packages = ["."]
revision = "a80dea3052f00e5f032e860dd7355cd0cc67e24d"
[[projects]]
branch = "master"
name = "github.com/go-openapi/spec"
packages = ["."]
revision = "3faa0055dbbf2110abc1f3b4e3adbb22721e96e7"
[[projects]]
branch = "master"
name = "github.com/go-openapi/strfmt"
packages = ["."]
revision = "610b6cacdcde6852f4de68998bd20ce1dac85b22"
[[projects]]
branch = "master"
name = "github.com/go-openapi/swag"
packages = ["."]
revision = "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
[[projects]]
name = "github.com/gogo/protobuf"
packages = ["proto","sortkeys"]
revision = "100ba4e885062801d56799d78530b73b178a78f3"
version = "v0.4"
[[projects]]
branch = "master"
name = "github.com/golang/glog"
packages = ["."]
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
branch = "master"
name = "github.com/google/gofuzz"
packages = ["."]
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]]
branch = "master"
name = "github.com/howeyc/gopass"
packages = ["."]
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
[[projects]]
name = "github.com/imdario/mergo"
packages = ["."]
revision = "3e95a51e0639b4cf372f2ccf74c86749d747fbdc"
version = "0.2.2"
[[projects]]
branch = "master"
name = "github.com/juju/ratelimit"
packages = ["."]
revision = "5b9ff866471762aa2ab2dced63c9fb6f53921342"
[[projects]]
branch = "master"
name = "github.com/mailru/easyjson"
packages = ["buffer","jlexer","jwriter"]
revision = "2a92e673c9a6302dd05c3a691ae1f24aef46457d"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "d0303fe809921458f417bcf828397a65db30a7e4"
[[projects]]
name = "github.com/spf13/pflag"
packages = ["."]
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/ugorji/go"
packages = ["codec"]
revision = "8c0409fcbb70099c748d71f714529204975f6c3f"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "81e90905daefcd6fd217b62423c0908922eadb30"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["http2","http2/hpack","idna","lex/httplex"]
revision = "66aacef3dd8a676686c7ae3716979581e8b03c47"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix","windows"]
revision = "9aade4d3a3b7e6d876cd3823ad20ec45fc035402"
[[projects]]
branch = "master"
name = "golang.org/x/text"
packages = ["internal/gen","internal/triegen","internal/ucd","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable","width"]
revision = "bd91bbf73e9a4a801adbfb97133c992678533126"
[[projects]]
name = "gopkg.in/inf.v0"
packages = ["."]
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
version = "v0.9.0"
[[projects]]
branch = "v2"
name = "gopkg.in/mgo.v2"
packages = ["bson","internal/json"]
revision = "3f83fa5005286a7fe593b055f0d7771a7dce4655"
[[projects]]
branch = "v2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
[[projects]]
branch = "release-1.7"
name = "k8s.io/apimachinery"
packages = ["pkg/api/equality","pkg/api/errors","pkg/api/meta","pkg/api/resource","pkg/apimachinery","pkg/apimachinery/announced","pkg/apimachinery/registered","pkg/apis/meta/v1","pkg/apis/meta/v1/unstructured","pkg/apis/meta/v1alpha1","pkg/conversion","pkg/conversion/queryparams","pkg/conversion/unstructured","pkg/fields","pkg/labels","pkg/openapi","pkg/runtime","pkg/runtime/schema","pkg/runtime/serializer","pkg/runtime/serializer/json","pkg/runtime/serializer/protobuf","pkg/runtime/serializer/recognizer","pkg/runtime/serializer/streaming","pkg/runtime/serializer/versioning","pkg/selection","pkg/types","pkg/util/clock","pkg/util/diff","pkg/util/errors","pkg/util/framer","pkg/util/intstr","pkg/util/json","pkg/util/net","pkg/util/rand","pkg/util/runtime","pkg/util/sets","pkg/util/validation","pkg/util/validation/field","pkg/util/wait","pkg/util/yaml","pkg/version","pkg/watch","third_party/forked/golang/reflect"]
revision = "8ab5f3d8a330c2e9baaf84e39042db8d49034ae2"
[[projects]]
name = "k8s.io/client-go"
packages = ["discovery","kubernetes","kubernetes/scheme","kubernetes/typed/admissionregistration/v1alpha1","kubernetes/typed/apps/v1beta1","kubernetes/typed/authentication/v1","kubernetes/typed/authentication/v1beta1","kubernetes/typed/authorization/v1","kubernetes/typed/authorization/v1beta1","kubernetes/typed/autoscaling/v1","kubernetes/typed/autoscaling/v2alpha1","kubernetes/typed/batch/v1","kubernetes/typed/batch/v2alpha1","kubernetes/typed/certificates/v1beta1","kubernetes/typed/core/v1","kubernetes/typed/extensions/v1beta1","kubernetes/typed/networking/v1","kubernetes/typed/policy/v1beta1","kubernetes/typed/rbac/v1alpha1","kubernetes/typed/rbac/v1beta1","kubernetes/typed/settings/v1alpha1","kubernetes/typed/storage/v1","kubernetes/typed/storage/v1beta1","pkg/api","pkg/api/v1","pkg/api/v1/ref","pkg/apis/admissionregistration","pkg/apis/admissionregistration/v1alpha1","pkg/apis/apps","pkg/apis/apps/v1beta1","pkg/apis/authentication","pkg/apis/authentication/v1","pkg/apis/authentication/v1beta1","pkg/apis/authorization","pkg/apis/authorization/v1","pkg/apis/authorization/v1beta1","pkg/apis/autoscaling","pkg/apis/autoscaling/v1","pkg/apis/autoscaling/v2alpha1","pkg/apis/batch","pkg/apis/batch/v1","pkg/apis/batch/v2alpha1","pkg/apis/certificates","pkg/apis/certificates/v1beta1","pkg/apis/extensions","pkg/apis/extensions/v1beta1","pkg/apis/networking","pkg/apis/networking/v1","pkg/apis/policy","pkg/apis/policy/v1beta1","pkg/apis/rbac","pkg/apis/rbac/v1alpha1","pkg/apis/rbac/v1beta1","pkg/apis/settings","pkg/apis/settings/v1alpha1","pkg/apis/storage","pkg/apis/storage/v1","pkg/apis/storage/v1beta1","pkg/util","pkg/util/parsers","pkg/version","rest","rest/watch","tools/auth","tools/clientcmd","tools/clientcmd/api","tools/clientcmd/api/latest","tools/clientcmd/api/v1","tools/metrics","transport","util/cert","util/flowcontrol","util/homedir","util/integer"]
revision = "d92e8497f71b7b4e0494e5bd204b48d34bd6f254"
version = "v4.0.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "caae962961e20347a5f6f9001a55d7baa94307f6bf6aecc001165a28a51e3919"
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,33 +0,0 @@
# © Copyright IBM Corporation 2017, 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[[constraint]]
branch = "master"
name = "golang.org/x/sys"
# The version of client-go corresponds to a specific Kubernetes version
# (e.g. client-go 4.0.0 is for kubernetes 1.7)
# If you change this version, you also need to update the corresponding
# branch for k8s.io/apimachinery (below)
[[constraint]]
name = "k8s.io/client-go"
version = "4.0.0"
[[constraint]]
name = "k8s.io/apimachinery"
branch = "release-1.7"
[prune]
unused-packages = true
go-tests = true

View File

@@ -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 (
"strings"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var namespace = "default"
// Prior to running this test, a Persistent Volume must be created
func TestHelmPredefinedVolume(t *testing.T) {
cs := kubeLogin(t)
release := strings.ToLower(t.Name())
if !volumesAvailable(t, cs) {
t.Skipf("Skipping test because no persistent volumes were found")
}
helmInstall(t, cs, release, "license=accept", "persistence.useDynamicProvisioning=false")
defer helmDelete(t, cs, release)
defer helmDeletePVC(t, cs, release)
waitForReady(t, cs, release)
}
func TestHelmStorageClass(t *testing.T) {
cs := kubeLogin(t)
release := strings.ToLower(t.Name())
assertKubeVersion(t, cs, 1, 6)
if !storageClassesDefined(t, cs) {
t.Skipf("Skipping test because no storage classes were found")
}
helmInstall(t, cs, release, "license=accept", "persistence.useDynamicProvisioning=true")
defer helmDelete(t, cs, release)
defer helmDeletePVC(t, cs, release)
waitForReady(t, cs, release)
}
func TestPersistenceDisabled(t *testing.T) {
cs := kubeLogin(t)
release := strings.ToLower(t.Name())
helmInstall(t, cs, release, "license=accept", "persistence.enabled=false")
defer helmDelete(t, cs, release)
waitForReady(t, cs, release)
// Check that no PVCs were created
pvcs, err := cs.CoreV1().PersistentVolumeClaims(namespace).List(metav1.ListOptions{
LabelSelector: "release=" + release,
})
if err != nil {
t.Fatal(err)
}
if len(pvcs.Items) > 0 {
t.Errorf("Expected no PVC, found %v (%+v)", len(pvcs.Items), pvcs.Items)
}
}
// TestPassThroughValues tests several values which are set when installing
// the Helm chart, and should be passed straight through to Kubernetes
func TestPassThroughValues(t *testing.T) {
cs := kubeLogin(t)
release := strings.ToLower(t.Name())
queueManagerName := "foo"
requestCPU := "501m"
requestMem := "501Mi"
limitCPU := "502m"
limitMem := "502Mi"
helmInstall(t, cs, release,
"license=accept",
"persistence.enabled=false",
"resources.requests.cpu="+requestCPU,
"resources.requests.memory="+requestMem,
"resources.limits.cpu="+limitCPU,
"resources.limits.memory="+limitMem,
"queueManager.name="+queueManagerName,
)
defer helmDelete(t, cs, release)
waitForReady(t, cs, release)
pods := getPodsForHelmRelease(t, cs, release)
pod := pods.Items[0]
t.Run("resources.requests.cpu", func(t *testing.T) {
cpu := pod.Spec.Containers[0].Resources.Requests.Cpu()
if cpu.String() != requestCPU {
t.Errorf("Expected requested CPU to be %v, got %v", requestCPU, cpu.String())
}
})
t.Run("resources.requests.memory", func(t *testing.T) {
mem := pod.Spec.Containers[0].Resources.Requests.Memory()
if mem.String() != requestMem {
t.Errorf("Expected requested memory to be %v, got %v", requestMem, mem.String())
}
})
t.Run("resources.limits.cpu", func(t *testing.T) {
cpu := pod.Spec.Containers[0].Resources.Limits.Cpu()
if cpu.String() != limitCPU {
t.Errorf("Expected CPU limits to be %v, got %v", limitCPU, cpu.String())
}
})
t.Run("resources.limits.memory", func(t *testing.T) {
mem := pod.Spec.Containers[0].Resources.Limits.Memory()
if mem.String() != limitMem {
t.Errorf("Expected memory to be %v, got %v", limitMem, mem.String())
}
})
t.Run("queueManager.name", func(t *testing.T) {
out, _, err := kubeExec(t, pod.Name, "dspmq", "-n")
if err != nil {
t.Fatal(err)
}
// Example output of `dspmq -n`:
// QMNAME(qm1) STATUS(RUNNING)
n := strings.Fields(out)[0]
n = strings.Split(n, "(")[1]
n = strings.Trim(n, "() ")
t.Logf("Queue manager name detected: %v", n)
if n != queueManagerName {
t.Errorf("Expected queue manager name to be %v, got %v", queueManagerName, n)
}
})
}

View File

@@ -1,270 +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 (
"bytes"
"os"
"strconv"
"strings"
"testing"
"time"
"unicode"
"github.com/ibm-messaging/mq-container/internal/command"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/tools/clientcmd"
)
func image(t *testing.T) string {
v, ok := os.LookupEnv("TEST_IMAGE")
if !ok {
t.Fatal("TEST_IMAGE environment variable not set")
}
return v
}
func imageName(t *testing.T) string {
return strings.Fields(strings.Replace(image(t), ":", " ", -1))[0]
}
func imageTag(t *testing.T) string {
return strings.Fields(strings.Replace(image(t), ":", " ", -1))[1]
}
func chartName() string {
v, ok := os.LookupEnv("TEST_CHART")
if !ok {
v = "../../charts/ibm-mqadvanced-server-dev"
}
return v
}
func inspectLogs(t *testing.T, cs *kubernetes.Clientset, release string) string {
pods := getPodsForHelmRelease(t, cs, release)
opt := v1.PodLogOptions{}
r := cs.CoreV1().Pods(namespace).GetLogs(pods.Items[0].Name, &opt)
buf := new(bytes.Buffer)
rc, err := r.Stream()
if err != nil {
t.Fatal(err)
}
buf.ReadFrom(rc)
return buf.String()
}
func helmInstall(t *testing.T, cs *kubernetes.Clientset, release string, values ...string) {
chart := chartName()
tag := imageTag(t)
arg := []string{
"install",
"--debug",
chart,
"--name",
release,
"--set",
"image.repository=" + imageName(t),
"--set",
"image.tag=" + tag,
"--set",
"image.pullSecret=admin.registrykey",
}
// Add any extra values to the Helm command
for _, value := range values {
arg = append(arg, "--set", value)
}
out, _, err := command.Run("helm", arg...)
t.Log(out)
if err != nil {
t.Error(out)
t.Fatal(err)
}
}
func helmDelete(t *testing.T, cs *kubernetes.Clientset, release string) {
t.Log("Deleting Helm release")
t.Log(inspectLogs(t, cs, release))
out, _, err := command.Run("helm", "delete", "--purge", release)
if err != nil {
t.Error(out)
t.Fatal(err)
}
}
func helmDeletePVC(t *testing.T, cs *kubernetes.Clientset, release string) {
pvcs, err := cs.CoreV1().PersistentVolumeClaims(namespace).List(metav1.ListOptions{
LabelSelector: "release=" + release,
})
if err != nil {
t.Error(err)
}
for _, pvc := range pvcs.Items {
t.Logf("Deleting persistent volume claim: %v", pvc.Name)
err := cs.CoreV1().PersistentVolumeClaims(namespace).Delete(pvc.Name, &metav1.DeleteOptions{})
if err != nil {
t.Fatal(err)
}
}
}
func kubeLogin(t *testing.T) *kubernetes.Clientset {
kc := os.Getenv("KUBECONFIG")
if kc == "" {
kc = os.Getenv("HOME") + "/.kube/config"
}
c, err := clientcmd.BuildConfigFromFlags("", kc)
if err != nil {
t.Fatal(err)
}
cs, err := kubernetes.NewForConfig(c)
if err != nil {
t.Fatal(err)
}
return cs
}
func kubeExec(t *testing.T, podName string, name string, arg ...string) (string, int, error) {
// Current version of Kubernetes Go client doesn't support "exec", so run this via the command line
param := []string{"exec", podName, "--", name}
param = append(param, arg...)
return command.Run("kubectl", param...)
}
func waitForReady(t *testing.T, cs *kubernetes.Clientset, release string) {
pods := getPodsForHelmRelease(t, cs, release)
if len(pods.Items) != 1 {
t.Fatalf("Expected 1 pod, found %v", len(pods.Items))
}
pod := pods.Items[0]
podName := pod.Name
// Wait for the queue manager container to be started
running := false
for !running {
pod, err := cs.CoreV1().Pods(namespace).Get(podName, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
if len(pod.Status.ContainerStatuses) > 0 {
state := pod.Status.ContainerStatuses[0].State
switch {
case state.Waiting != nil:
t.Logf("Waiting for container")
time.Sleep(1 * time.Second)
case state.Running != nil:
running = true
}
}
}
// Exec into the container to check if it's ready
for {
// Current version of Kubernetes Go client doesn't support "exec", so run this via the command line
// TODO: If we run "chkmqready" here, it doesn't seem to work
//out, _, err := command.Run(t, "kubectl", "exec", podName, "--", "dspmq")
out, _, err := kubeExec(t, podName, "dspmq")
//out, rc, err := command.Run(t, "kubectl", "exec", podName, "--", "chkmqready")
if err != nil {
t.Error(out)
out2, _, err2 := command.Run("kubectl", "describe", "pod", podName)
if err2 == nil {
t.Log(out2)
}
t.Fatal(err)
}
if strings.Contains(out, "Running") {
t.Log("MQ is ready")
return
}
// if rc == 0 {
// return
// }
time.Sleep(1 * time.Second)
}
}
func getPodsForHelmRelease(t *testing.T, cs *kubernetes.Clientset, release string) *v1.PodList {
pods, err := cs.CoreV1().Pods(namespace).List(metav1.ListOptions{
LabelSelector: "release=" + release,
})
if err != nil {
t.Fatal(err)
}
return pods
}
func storageClassesDefined(t *testing.T, cs *kubernetes.Clientset) bool {
c, err := cs.Storage().StorageClasses().List(metav1.ListOptions{})
if err != nil {
t.Fatal(err)
}
if len(c.Items) > 0 {
return true
}
return false
}
// volumesAvailable checks to see if any persistent volumes are available.
// On some Kubernetes clusters, only storage classes are used, so there won't
// be any volumes pre-created.
func volumesAvailable(t *testing.T, cs *kubernetes.Clientset) bool {
pvs, err := cs.CoreV1().PersistentVolumes().List(metav1.ListOptions{})
if err != nil {
t.Fatal(err)
}
for _, pv := range pvs.Items {
if pv.Status.Phase == v1.VolumeAvailable {
return true
}
}
return false
}
// digitsOnly returns only the digits from the supplied string
func digitsOnly(s string) string {
return strings.Map(
func(r rune) rune {
if unicode.IsDigit(r) {
return r
}
return -1
},
s,
)
}
// assertKubeVersion is used to assert that a test requires a specific version of Kubernetes
func assertKubeVersion(t *testing.T, cs *kubernetes.Clientset, major int, minor int) {
v, err := cs.Discovery().ServerVersion()
if err != nil {
t.Fatal(err)
}
// Make sure we use only the digits from the version, to account for things like "1.8+"
maj, err := strconv.Atoi(digitsOnly(v.Major))
if err != nil {
t.Fatal(err)
}
// Make sure we use only the digits from the version, to account for things like "1.8+"
min, err := strconv.Atoi(digitsOnly(v.Minor))
if err != nil {
t.Fatal(err)
}
if maj <= major && min < minor {
t.Skipf("Skipping test because it's not suitable for Kubernetes %v.%v", v.Major, v.Minor)
}
}
// TODO: On Minikube, need to make sure Helm is initialized first

6
test/messaging/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.classpath
.gradle
.project
.settings
bin

38
test/messaging/Dockerfile Normal file
View File

@@ -0,0 +1,38 @@
# © 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.
###############################################################################
# Application build environment (Gradle)
###############################################################################
FROM gradle as builder
ENV GRADLE_OPTS="-Dorg.gradle.daemon=false"
# Change where Gradle stores its cache, so that it's not under a volume
# (and therefore gets cached by Docker)
ENV GRADLE_USER_HOME=/home/gradle/gradle
RUN mkdir -p $GRADLE_USER_HOME
COPY --chown=gradle build.gradle /app/
WORKDIR /app
# Download dependencies separately, so Docker caches them
RUN gradle download
# Copy source
COPY --chown=gradle src /app/src
# Run the main build
RUN gradle install
###############################################################################
# Application runtime (JRE only, no build environment)
###############################################################################
FROM ibmjava:sfj
COPY --from=builder /app/lib/*.jar /opt/app/
ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]

View File

@@ -0,0 +1,39 @@
// © 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.
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.ibm.mq', name: 'com.ibm.mq.allclient', version: '9.0.4.0'
compile "org.junit.jupiter:junit-jupiter-api:5.0.3"
runtime "org.junit.jupiter:junit-jupiter-engine:5.0.3"
runtime "org.junit.platform:junit-platform-console-standalone:1.0.3"
}
task download(type: Exec) {
configurations.runtime.files
commandLine 'echo', 'Downloaded all dependencies'
}
// Copy all dependencies to the lib directory
task install(type: Copy) {
dependsOn build
from configurations.runtime
from jar
into "${project.projectDir}/lib"
}

View File

@@ -0,0 +1,144 @@
/*
© 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 com.ibm.mqcontainer.test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.logging.Logger;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import com.ibm.mq.jms.MQConnectionFactory;
import com.ibm.mq.jms.MQQueue;
import com.ibm.msg.client.wmq.WMQConstants;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
class JMSTests {
private static final Logger LOGGER = Logger.getLogger(JMSTests.class.getName());
protected static final String ADDR = System.getenv("MQ_PORT_1414_TCP_ADDR");
protected static final String USER = System.getenv("MQ_USERNAME");
protected static final String PASSWORD = System.getenv("MQ_PASSWORD");
protected static final String CHANNEL = System.getenv("MQ_CHANNEL");
protected static final String TRUSTSTORE = System.getenv("MQ_TLS_TRUSTSTORE");
protected static final String PASSPHRASE = System.getenv("MQ_TLS_PASSPHRASE");
private JMSContext context;
static SSLSocketFactory createSSLSocketFactory() throws IOException, GeneralSecurityException {
KeyStore ts=KeyStore.getInstance("jks");
ts.load(new FileInputStream(TRUSTSTORE), PASSPHRASE.toCharArray());
// KeyManagerFactory kmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
TrustManagerFactory tmf=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
// tmf.init();
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
// Security.setProperty("crypto.policy", "unlimited");
ctx.init(null, tmf.getTrustManagers(), null);
return ctx.getSocketFactory();
}
static JMSContext create(String channel, String addr, String user, String password) throws JMSException, IOException, GeneralSecurityException {
LOGGER.info(String.format("Connecting to %s/TCP/%s(1414) as %s", channel, addr, user));
MQConnectionFactory factory = new MQConnectionFactory();
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
factory.setChannel(channel);
factory.setConnectionNameList(String.format("%s(1414)", addr));
// factory.setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT);
if (TRUSTSTORE == null) {
LOGGER.info("Not using TLS");
}
else {
LOGGER.info(String.format("Using TLS. Trust store=%s", TRUSTSTORE));
SSLSocketFactory ssl = createSSLSocketFactory();
factory.setSSLSocketFactory(ssl);
factory.setSSLCipherSuite("SSL_RSA_WITH_AES_128_CBC_SHA256");
// LOGGER.info(Arrays.toString(ssl.getSupportedCipherSuites()));
}
// Give up if unable to reconnect for 10 minutes
// factory.setClientReconnectTimeout(600);
// LOGGER.info(String.format("user=%s pw=%s", user, password));
return factory.createContext(user, password);
}
@BeforeAll
private static void waitForQueueManager() {
for (int i = 0; i < 20; i++) {
try {
Socket s = new Socket(ADDR, 1414);
s.close();
return;
} catch (IOException e) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
}
}
}
@BeforeEach
void connect() throws Exception {
context = create(CHANNEL, ADDR, USER, PASSWORD);
}
@Test
void succeedingTest(TestInfo t) throws JMSException {
Queue queue = new MQQueue("DEV.QUEUE.1");
context.createProducer().send(queue, t.getDisplayName());
Message m = context.createConsumer(queue).receive();
assertNotNull(m.getBody(String.class));
}
// @Test
// void failingTest() {
// fail("a failing test");
// }
@Test
@Disabled("for demonstration purposes")
void skippedTest() {
// not executed
}
@AfterEach
void tearDown() {
if (context != null) {
context.close();
}
}
@AfterAll
static void tearDownAll() {
}
}

BIN
test/tls/client-trust.jks Normal file

Binary file not shown.

41
test/tls/generate-test-cert.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
# -*- mode: sh -*-
# © Copyright IBM Corporation 2018
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
KEY=server.key
CERT=server.crt
PKCS=server.p12
PASSWORD=passw0rd
# Create a private key and certificate in PEM format, for the server to use
openssl req \
-newkey rsa:2048 -nodes -keyout ${KEY} \
-subj "/CN=localhost" \
-x509 -days 365 -out ${CERT}
# Add the key and certificate to a PKCS #12 key store, for the server to use
openssl pkcs12 \
-inkey ${KEY} \
-in ${CERT} \
-export -out ${PKCS} \
-password pass:${PASSWORD}
# Add the certificate to a trust store in JKS format, for Java clients to use when connecting
keytool -import \
-alias server-cert \
-file ${CERT} \
-keystore client-trust.jks \
-storepass ${PASSWORD} \
-noprompt

17
test/tls/server.crt Normal file
View File

@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICpDCCAYwCCQDft9xlN4fNFTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMTgwMzIwMTUxODMwWhcNMTkwMzIwMTUxODMwWjAUMRIwEAYD
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDk
XzX0xQIZzKVX8/lDQh5lSHr5U9cBL+kURA3fEgl3ks9KjZPggfxWl4Y5dekChW/s
iknVssoNw9vI1W25qtQ81zRFQbHbpej0lLdYsS8/yZCuAVjMTp6Q9IswTwhVA6OD
5orag5dH3XQH+GsnmGXRCY7Gs93onAe3i3ShX9qpUFOJXyxCX+pLAC6kWQ3f/HI8
dujVXKsg1vHgOgGqQGwnh8gm5OeWUeuTMdD2v7Hn1OxilgNMbcewA7bpvipgm2xt
ZD0PKFDmtQ4comr25Oo+eUf1N7jSpRPOWJNxoyS9/coQUPp1Gpbk7khYHjGn7f5a
EZqQ4Hmwwh50uT+vKVxDAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAHaywC7ZLOi
3PKlidj6PWe33dEVsDL6RRb3cOqR86Ld2aD91oLrpELRhz4v2mt/GfQMIg7rc6z7
26SuPzV/7zZAv1N/vGoIFyvBXWLYP5qCwUrmykcH/wfFM80S6FJxz5Wy5MA5UzTB
HdpiQCPu4U0IKgATLDraz0xlQ61Rog56YhgJI8ulHuav5iYxqV2mwU09Hs0kXPJ7
g0PLRaSyidsXafxBKukeM9QHl8z8HN8er23oqecYo59b/Bt0c6jSrJCK39EUcoLP
HxR+Ma1SPhVKGqa3lPmaoAzsFTqaJ6fsIcbp+oEFAq0LPeqMPK7u3ygT4iTblAl8
q3isCz4Ytx4=
-----END CERTIFICATE-----

28
test/tls/server.key Normal file
View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDkXzX0xQIZzKVX
8/lDQh5lSHr5U9cBL+kURA3fEgl3ks9KjZPggfxWl4Y5dekChW/siknVssoNw9vI
1W25qtQ81zRFQbHbpej0lLdYsS8/yZCuAVjMTp6Q9IswTwhVA6OD5orag5dH3XQH
+GsnmGXRCY7Gs93onAe3i3ShX9qpUFOJXyxCX+pLAC6kWQ3f/HI8dujVXKsg1vHg
OgGqQGwnh8gm5OeWUeuTMdD2v7Hn1OxilgNMbcewA7bpvipgm2xtZD0PKFDmtQ4c
omr25Oo+eUf1N7jSpRPOWJNxoyS9/coQUPp1Gpbk7khYHjGn7f5aEZqQ4Hmwwh50
uT+vKVxDAgMBAAECggEBAL91kybChCBdEcHLKQ7aP+FqAq9FOtwj7qSu6XI7DPTS
gDdgurleQM/X+Q/zaoZSmKMWzQ/79KnVqk2VoYgnUAgx5ACsMxCS59slUxFoetRf
iIxZVLj0sLuWSZsWp0We51eN0Juh9xKo9r435p4rhjDacnjkEwcQyOd4Yy9nzUpk
GDD5Vu1J9bOOKUQZ0qgjPyl/xWiwD1yfGJ0nHpQ5ucfrCO9p+n7SYsx01WcAkC8J
WP9XSXgi5uIefTWb/4m2b32jzjIgzAHkNx6yktRTjBJ7QILnKq1P8JjkNA/Awj4P
OxAz9hHHnVRuq4ZlEqfvo9p9YAbN2IH5TnmN3rGCXwECgYEA9JitVIeXCS0qIMFA
dKCmm9CT7JXccdpVllwaaYCNTb+G2RBrJqAvQEetoYJodWTIm1mNwSEORFFw0W+N
eaMzibJoJ+MZHRhiulDJaY0vwAKHkSJjDPJrPLgGMCUOLiWSAAnR4z35WfeY0e//
JbdZZemrJRyzy3o6rkRN9TQcUMUCgYEA7wTj5w5GZ8NQ7Nn8nIS2ayk+woIMHS+g
RVFufJoBeopsNJfNzGak0s+nz5q0nMGMzQsxXkbmAOLMTU3woQ7cEGjkLAfoch23
ACOe7M4rZbIk6kVNOlFESWdVdWViVd/B2a7oBqOIykoqX6VSqqrw+xghAUmd/2W1
uxjg9v01OWcCgYApE5LYRUUKF3mhspKeg3Q3apnM+4Xf4OjKrYEKArq4OdftkCJO
hEwrIV55Zysfu+Mso6d4rZJ1yq+FnJRHvy6ii0GOoUbQag36eCK7BSjluAcISpwT
yopT0hvH7hEpksmoE/4ZiYjcoQYbC5DvxpDO2qURQHa5TzeXmIT3Dt9KeQKBgQC6
UKeOXrRHAhs85ZdiMpk340jGujTTM2LNZfKoMixg5zH9tS9427IzmicHT2LmpoEo
/EaZZM65dhEnWU/vW/Py3rCuGeP5wGv8Mcgac4OknD7mVusiQGLojSIyhrsmkWs8
UnkPY76nYTSypd5Qpzt9n4tqw4XjpdcJZxVFso8glQKBgQCHlb15As73En/Q2AxL
5FY1Q1lLuO8y33ZZIRK4eynOKkbiuAh7X+ONZ4T9NtTm2J7mnltvTHZ7yeOI+VLS
LrTTBwnnNfdpp8UVPQlwzeizoDqSbr1sjFYvKOfdDDfxuzieT/4tfW9VTAxn4uOg
qpg7aRMUYUuLAH+S5atdOqXB+g==
-----END PRIVATE KEY-----

BIN
test/tls/server.p12 Normal file

Binary file not shown.