Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3721dbdb31 | ||
|
|
0fdda62e34 | ||
|
|
781ce07e9c | ||
|
|
d4fae78a66 | ||
|
|
7c91187ce3 | ||
|
|
3cc1a09d48 | ||
|
|
f720eb2338 | ||
|
|
de28a7030a | ||
|
|
8c4daa9554 | ||
|
|
9c9a2e1e91 | ||
|
|
e6c4a21726 | ||
|
|
0ffa87be31 | ||
|
|
7efcef67e0 | ||
|
|
c7c1db9b1a | ||
|
|
6195ff892e | ||
|
|
a8bb8084b3 | ||
|
|
721c2e616e | ||
|
|
9a05a1d5d1 | ||
|
|
ab12ded727 | ||
|
|
68f679d0be | ||
|
|
774cf26ac6 | ||
|
|
72228f3119 | ||
|
|
ef92f58805 |
@@ -1,6 +1,3 @@
|
|||||||
charts
|
charts
|
||||||
cmd
|
|
||||||
downloads
|
downloads
|
||||||
pkg
|
|
||||||
test
|
test
|
||||||
vendor
|
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ services:
|
|||||||
- docker
|
- docker
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||||
|
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get -y install docker-ce
|
||||||
- curl https://glide.sh/get | sh
|
- curl https://glide.sh/get | sh
|
||||||
- curl -LO https://github.com/golang/dep/releases/download/v0.3.0/dep-linux-amd64.zip
|
- curl -LO https://github.com/golang/dep/releases/download/v0.3.0/dep-linux-amd64.zip
|
||||||
- unzip dep-linux-amd64.zip
|
- unzip dep-linux-amd64.zip
|
||||||
|
|||||||
13
CHANGELOG.md
Normal file
13
CHANGELOG.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Change log
|
||||||
|
|
||||||
|
## 9.0.4 (2017-11-06)
|
||||||
|
* Updated to MQ version 9.0.4.0
|
||||||
|
* Updated to Go version 9
|
||||||
|
* Removed packages `curl`, `ca-certificates`, and their dependencies, which were only used at build time
|
||||||
|
* Improved logging
|
||||||
|
* Helm charts now work on Kubernetes V1.6
|
||||||
|
* Production Helm chart now includes a default image repository and tag
|
||||||
|
* Updated to use multi-stage Docker build, so that Go code is built inside a container
|
||||||
|
|
||||||
|
## 9.0.3 (2017-10-17)
|
||||||
|
* Initial version
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# © Copyright IBM Corporation 2015, 2017
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
FROM ubuntu:16.04
|
|
||||||
|
|
||||||
LABEL "ProductID"="4486e8c4cc9146fd9b3ce1f14a2dfc5b" \
|
|
||||||
"ProductName"="IBM MQ Advanced for Developers" \
|
|
||||||
"ProductVersion"="9.0.3"
|
|
||||||
|
|
||||||
# The URL to download the MQ installer from in tar.gz format
|
|
||||||
# This assumes an archive containing the MQ Debian (.deb) install packages
|
|
||||||
ARG MQ_URL=https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz
|
|
||||||
|
|
||||||
# The MQ packages to install
|
|
||||||
ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams"
|
|
||||||
|
|
||||||
COPY install-mq.sh /usr/local/bin/
|
|
||||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
|
||||||
# To avoid a "text file busy" error here we sleep before installing.
|
|
||||||
&& sleep 1 && install-mq.sh
|
|
||||||
|
|
||||||
COPY build/runmqserver /usr/local/bin/
|
|
||||||
COPY build/chkmq* /usr/local/bin/
|
|
||||||
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
|
||||||
|
|
||||||
# MQ default developer config
|
|
||||||
COPY dev/mq-dev-config /etc/mqm/mq-dev-config
|
|
||||||
COPY dev/mq-dev-config.sh /usr/local/bin/
|
|
||||||
COPY dev/admin.json /etc/mqm/
|
|
||||||
|
|
||||||
RUN chmod +x /usr/local/bin/runmqserver \
|
|
||||||
&& chmod +x /usr/local/bin/chk*
|
|
||||||
|
|
||||||
# Always use port 1414
|
|
||||||
EXPOSE 1414
|
|
||||||
|
|
||||||
ENV LANG=en_US.UTF-8 AMQ_DIAGNOSTIC_MSG_SEVERITY=1
|
|
||||||
|
|
||||||
ENTRYPOINT ["runmqserver"]
|
|
||||||
@@ -12,11 +12,24 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM ubuntu:16.04
|
# Build stage to build Go code
|
||||||
|
FROM golang:1.9 as builder
|
||||||
|
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
|
||||||
|
COPY cmd/ ./cmd
|
||||||
|
COPY pkg/ ./pkg
|
||||||
|
COPY vendor/ ./vendor
|
||||||
|
RUN go build ./cmd/runmqserver/
|
||||||
|
RUN go build ./cmd/chkmqready/
|
||||||
|
RUN go build ./cmd/chkmqhealthy/
|
||||||
|
|
||||||
ARG IBM_PRODUCT_ID
|
# Build stage to run Go unit tests
|
||||||
ARG IBM_PRODUCT_NAME
|
FROM golang:1.9 as tester
|
||||||
ARG IBM_PRODUCT_VERSION
|
COPY pkg/ ./pkg
|
||||||
|
RUN cd pkg/name && go test
|
||||||
|
RUN cd pkg/linux/capabilities && go test
|
||||||
|
|
||||||
|
# Main build stage, to build MQ image
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
# The URL to download the MQ installer from in tar.gz format
|
# The URL to download the MQ installer from in tar.gz format
|
||||||
# This assumes an archive containing the MQ Debian (.deb) install packages
|
# This assumes an archive containing the MQ Debian (.deb) install packages
|
||||||
@@ -25,17 +38,15 @@ ARG MQ_URL
|
|||||||
# The MQ packages to install
|
# The MQ packages to install
|
||||||
ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams"
|
ARG MQ_PACKAGES="ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams"
|
||||||
|
|
||||||
LABEL "ProductID"=$IBM_PRODUCT_ID \
|
|
||||||
"ProductName"=$IBM_PRODUCT_NAME \
|
|
||||||
"ProductVersion"=$IBM_PRODUCT_VERSION
|
|
||||||
|
|
||||||
COPY install-mq.sh /usr/local/bin/
|
COPY install-mq.sh /usr/local/bin/
|
||||||
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
|
||||||
# To avoid a "text file busy" error here we sleep before installing.
|
|
||||||
&& sleep 1 && install-mq.sh
|
|
||||||
|
|
||||||
COPY build/runmqserver /usr/local/bin/
|
# Install MQ. To avoid a "text file busy" error here, we sleep before installing.
|
||||||
COPY build/chkmq* /usr/local/bin/
|
RUN chmod u+x /usr/local/bin/install-mq.sh \
|
||||||
|
&& sleep 1 \
|
||||||
|
&& install-mq.sh
|
||||||
|
|
||||||
|
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/chkmq* /usr/local/bin/
|
||||||
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
COPY NOTICES.txt /opt/mqm/licenses/notices-container.txt
|
||||||
|
|
||||||
RUN chmod +x /usr/local/bin/runmqserver \
|
RUN chmod +x /usr/local/bin/runmqserver \
|
||||||
|
|||||||
72
Makefile
72
Makefile
@@ -13,9 +13,12 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
BUILD_SERVER_CONTAINER=build-server
|
BUILD_SERVER_CONTAINER=build-server
|
||||||
|
# Set architecture for Go code. Don't set GOOS globally, so that tests can be run locally
|
||||||
export GOARCH ?= amd64
|
export GOARCH ?= amd64
|
||||||
# Don't set GOOS globally, so that tests can be run locally
|
|
||||||
DOCKER_TAG_ARCH ?= x86_64
|
DOCKER_TAG_ARCH ?= x86_64
|
||||||
|
# By default, all Docker client commands are run inside a Docker container.
|
||||||
|
# This means that newer features of the client can be used, even with an older daemon.
|
||||||
|
DOCKER ?= docker run --tty --interactive --rm --volume /var/run/docker.sock:/var/run/docker.sock --volume "$(CURDIR)":/var/src --workdir /var/src docker:stable docker
|
||||||
DOCKER_TAG ?= latest-$(DOCKER_TAG_ARCH)
|
DOCKER_TAG ?= latest-$(DOCKER_TAG_ARCH)
|
||||||
DOCKER_REPO_DEVSERVER ?= mq-devserver
|
DOCKER_REPO_DEVSERVER ?= mq-devserver
|
||||||
DOCKER_REPO_ADVANCEDSERVER ?= mq-advancedserver
|
DOCKER_REPO_ADVANCEDSERVER ?= mq-advancedserver
|
||||||
@@ -60,43 +63,28 @@ deps:
|
|||||||
cd test/docker && dep ensure -vendor-only
|
cd test/docker && dep ensure -vendor-only
|
||||||
cd test/kubernetes && dep ensure -vendor-only
|
cd test/kubernetes && dep ensure -vendor-only
|
||||||
|
|
||||||
build/runmqserver:
|
|
||||||
mkdir -p build
|
|
||||||
cd build; GOOS=linux go build ../cmd/runmqserver/
|
|
||||||
|
|
||||||
build/chkmqready:
|
|
||||||
mkdir -p build
|
|
||||||
cd build; GOOS=linux go build ../cmd/chkmqready/
|
|
||||||
|
|
||||||
build/chkmqhealthy:
|
|
||||||
mkdir -p build
|
|
||||||
cd build; GOOS=linux go build ../cmd/chkmqhealthy/
|
|
||||||
|
|
||||||
.PHONY: build
|
|
||||||
build: build/runmqserver build/chkmqready build/chkmqhealthy
|
|
||||||
|
|
||||||
.PHONY: build-cov
|
.PHONY: build-cov
|
||||||
build-cov:
|
build-cov:
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build; go test -c -covermode=count ../cmd/runmqserver
|
cd build; go test -c -covermode=count ../cmd/runmqserver
|
||||||
|
|
||||||
.PHONY: test-advancedserver
|
.PHONY: test-advancedserver
|
||||||
test-advancedserver: build
|
test-advancedserver:
|
||||||
cd pkg/name && go test
|
cd pkg/name && go test
|
||||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_ADVANCEDSERVER) go test $(TEST_OPTS_DOCKER)
|
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_ADVANCEDSERVER) go test $(TEST_OPTS_DOCKER)
|
||||||
|
|
||||||
.PHONY: test-devserver
|
.PHONY: test-devserver
|
||||||
test-devserver: build
|
test-devserver:
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_DEVSERVER)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_DEVSERVER)"$(END)))
|
||||||
cd pkg/name && go test
|
cd pkg/name && go test
|
||||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_DEVSERVER) go test
|
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_DEVSERVER) go test
|
||||||
|
|
||||||
.PHONY: test-kubernetes-devserver
|
.PHONY: test-kubernetes-devserver
|
||||||
test-kubernetes-devserver: build
|
test-kubernetes-devserver:
|
||||||
$(call test-kubernetes,$(DOCKER_REPO_DEVSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-dev")
|
$(call test-kubernetes,$(DOCKER_REPO_DEVSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-dev")
|
||||||
|
|
||||||
.PHONY: test-kubernetes-advancedserver
|
.PHONY: test-kubernetes-advancedserver
|
||||||
test-kubernetes-advancedserver: build
|
test-kubernetes-advancedserver:
|
||||||
$(call test-kubernetes,$(DOCKER_REPO_ADVANCEDSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-prod")
|
$(call test-kubernetes,$(DOCKER_REPO_ADVANCEDSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-prod")
|
||||||
|
|
||||||
define test-kubernetes
|
define test-kubernetes
|
||||||
@@ -106,9 +94,9 @@ 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
|
||||||
# Start a web server to host the MQ downloadable (tar.gz) file
|
# Start a web server to host the MQ downloadable (tar.gz) file
|
||||||
docker run \
|
$(DOCKER) run \
|
||||||
--rm \
|
--rm \
|
||||||
--name $(BUILD_SERVER_CONTAINER) \
|
--name $(BUILD_SERVER_CONTAINER) \
|
||||||
--network build \
|
--network build \
|
||||||
@@ -117,48 +105,58 @@ define docker-build-mq
|
|||||||
--detach \
|
--detach \
|
||||||
nginx:alpine
|
nginx:alpine
|
||||||
# Build the new image
|
# Build the new image
|
||||||
docker build \
|
$(DOCKER) build \
|
||||||
|
--pull \
|
||||||
--tag $1 \
|
--tag $1 \
|
||||||
--file $2 \
|
--file $2 \
|
||||||
--network build \
|
--network build \
|
||||||
--build-arg MQ_URL=http://build:80/$3 \
|
--build-arg MQ_URL=http://build:80/$3 \
|
||||||
--build-arg IBM_PRODUCT_ID=$4 \
|
--label IBM_PRODUCT_ID=$4 \
|
||||||
--build-arg IBM_PRODUCT_NAME=$5 \
|
--label IBM_PRODUCT_NAME=$5 \
|
||||||
--build-arg IBM_PRODUCT_VERSION=$6 \
|
--label IBM_PRODUCT_VERSION=$6 \
|
||||||
.
|
.
|
||||||
# Stop the web server (will also remove the container)
|
# Stop the web server (will also remove the container)
|
||||||
docker kill $(BUILD_SERVER_CONTAINER)
|
$(DOCKER) kill $(BUILD_SERVER_CONTAINER)
|
||||||
# Delete the temporary network
|
# Delete the temporary network
|
||||||
docker network rm build
|
$(DOCKER) network rm build
|
||||||
endef
|
endef
|
||||||
|
|
||||||
.PHONY: build-advancedserver
|
# .PHONY: build-advancedserver-903
|
||||||
build-advancedserver: build downloads/CNJR7ML.tar.gz
|
# build-advancedserver-903: build downloads/CNJR7ML.tar.gz
|
||||||
|
# $(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
|
||||||
|
# $(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,CNJR7ML.tar.gz,"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced","9.0.3")
|
||||||
|
# $(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):9.0.3-$(DOCKER_TAG_ARCH)
|
||||||
|
|
||||||
|
.PHONY: build-advancedserver-904
|
||||||
|
build-advancedserver-904: downloads/CNLE4ML.tar.gz
|
||||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
|
$(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
|
||||||
$(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,CNJR7ML.tar.gz,"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced","9.0.3")
|
$(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,CNLE4ML.tar.gz,"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced","9.0.4")
|
||||||
docker tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):9.0.3-$(DOCKER_TAG_ARCH)
|
$(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):9.0.4-$(DOCKER_TAG_ARCH)
|
||||||
|
|
||||||
|
.PHONY: build-advancedserver
|
||||||
|
build-advancedserver: build-advancedserver-904
|
||||||
|
|
||||||
.PHONY: build-devserver
|
.PHONY: build-devserver
|
||||||
build-devserver: build downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
|
build-devserver: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||||
$(info $(shell printf $(TITLE)"Build $(DOCKER_FULL_DEVSERVER)"$(END)))
|
$(info $(shell printf $(TITLE)"Build $(DOCKER_FULL_DEVSERVER)"$(END)))
|
||||||
$(call docker-build-mq,$(DOCKER_FULL_DEVSERVER),Dockerfile-server,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
|
$(call docker-build-mq,$(DOCKER_FULL_DEVSERVER),Dockerfile-server,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
|
||||||
docker tag $(DOCKER_FULL_DEVSERVER) $(DOCKER_REPO_DEVSERVER):9.0.3-$(DOCKER_TAG_ARCH)
|
$(DOCKER) tag $(DOCKER_FULL_DEVSERVER) $(DOCKER_REPO_DEVSERVER):9.0.3-$(DOCKER_TAG_ARCH)
|
||||||
|
|
||||||
# .PHONY: build-server
|
# .PHONY: build-server
|
||||||
# build-server: build downloads/CNJR7ML.tar.gz
|
# build-server: build downloads/CNJR7ML.tar.gz
|
||||||
# $(call docker-build-mq,mq-server:latest-$(DOCKER_TAG_ARCH),Dockerfile-server,"79afd716d55b4f149a87bec52c9dc1aa","IBM MQ","9.0.3")
|
# $(call docker-build-mq,mq-server:latest-$(DOCKER_TAG_ARCH),Dockerfile-server,"79afd716d55b4f149a87bec52c9dc1aa","IBM MQ","9.0.3")
|
||||||
# docker tag mq-server:latest-$(DOCKER_TAG_ARCH) mq-server:9.0.3-$(DOCKER_TAG_ARCH)
|
# $(DOCKER) tag mq-server:latest-$(DOCKER_TAG_ARCH) mq-server:9.0.3-$(DOCKER_TAG_ARCH)
|
||||||
|
|
||||||
.PHONY: build-advancedserver-cover
|
.PHONY: build-advancedserver-cover
|
||||||
build-advancedserver-cover: build-advanced-server build-cov
|
build-advancedserver-cover: build-advanced-server build-cov
|
||||||
docker build -t mq-advancedserver:cover -f Dockerfile-server.cover .
|
$(DOCKER) build -t mq-advancedserver:cover -f Dockerfile-server.cover .
|
||||||
|
|
||||||
# .PHONY: build-web
|
# .PHONY: build-web
|
||||||
# build-web: build downloads/CNJR7ML.tar.gz
|
# build-web: build downloads/CNJR7ML.tar.gz
|
||||||
# $(call docker-build-mq,mq-web:latest-$(DOCKER_TAG_ARCH),Dockerfile-mq-web)
|
# $(call docker-build-mq,mq-web:latest-$(DOCKER_TAG_ARCH),Dockerfile-mq-web)
|
||||||
|
|
||||||
.PHONY: build-explorer
|
.PHONY: build-explorer
|
||||||
build-explorer: build downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
|
build-explorer: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||||
$(call docker-build-mq,mq-explorer:latest-$(DOCKER_TAG_ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
|
$(call docker-build-mq,mq-explorer:latest-$(DOCKER_TAG_ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
|
||||||
|
|
||||||
include formatting.mk
|
include formatting.mk
|
||||||
|
|||||||
@@ -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/) chart can be used to run the container on a [Kubernetes](https://kubernetes.io) cluster, such as [IBM Cloud private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Bluemix Container Service](https://www.ibm.com/cloud-computing/bluemix/containers).
|
Run [IBM® MQ](http://www-03.ibm.com/software/products/en/ibm-mq) in a container. The supplied [Helm](https://helm.sh/) chart can be used to run the container on a [Kubernetes](https://kubernetes.io) cluster, such as [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/) or the [IBM Bluemix Container Service](https://www.ibm.com/cloud-computing/bluemix/containers).
|
||||||
|
|
||||||
# Current status
|
# Current status
|
||||||
MQ Advanced for Developers image - [](https://travis-ci.org/ibm-messaging/mq-container)
|
MQ Advanced for Developers image - [](https://travis-ci.org/ibm-messaging/mq-container)
|
||||||
@@ -27,7 +27,6 @@ In order to use the image, it is necessary to accept the terms of the IBM MQ lic
|
|||||||
* **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
|
* **LICENSE** - Set this to `accept` to agree to the MQ Advanced for Developers license. If you wish to see the license you can set this to `view`.
|
||||||
* **LANG** - Set this to the language you would like the license to be printed in.
|
* **LANG** - Set this to the language you would like the license to be printed in.
|
||||||
* **MQ_QMGR_NAME** - Set this to the name you want your Queue Manager to be created with.
|
* **MQ_QMGR_NAME** - Set this to the name you want your Queue Manager to be created with.
|
||||||
* **MQ_QMGR_CMDLEVEL** - Set this to the `CMDLEVEL` you wish your Queue Manager to be started with.
|
|
||||||
|
|
||||||
|
|
||||||
# Issues and contributions
|
# Issues and contributions
|
||||||
|
|||||||
@@ -15,6 +15,6 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
description: IBM MQ queue manager
|
description: IBM MQ queue manager
|
||||||
name: ibm-mqadvanced-server-dev
|
name: ibm-mqadvanced-server-dev
|
||||||
version: 1.0.1
|
version: 1.0.2
|
||||||
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png
|
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png
|
||||||
tillerVersion: ">=2.4.0"
|
tillerVersion: ">=2.4.0"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ This chart deploys a single IBM MQ Advanced for Developers server (queue manager
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Kubernetes 1.7 or greater, with beta APIs enabled
|
- 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.
|
- 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
|
## Installing the Chart
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
serviceName: {{ .Values.service.name }}
|
serviceName: {{ .Values.service.name }}
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
{{- if and (ge (.Capabilities.KubeVersion.Major | int) 1) (ge (.Capabilities.KubeVersion.Minor | int) 7) }}
|
||||||
updateStrategy:
|
updateStrategy:
|
||||||
type: RollingUpdate
|
type: RollingUpdate
|
||||||
|
{{- end }}
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -15,6 +15,6 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
description: IBM MQ queue manager
|
description: IBM MQ queue manager
|
||||||
name: ibm-mqadvanced-server-prod
|
name: ibm-mqadvanced-server-prod
|
||||||
version: 1.0.1
|
version: 1.0.2
|
||||||
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png
|
icon: https://developer.ibm.com/messaging/wp-content/uploads/sites/18/2017/07/IBM-MQ-Square-200.png
|
||||||
tillerVersion: ">=2.4.0"
|
tillerVersion: ">=2.4.0"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ This chart deploys a single IBM MQ Advanced server (queue manager) into an IBM C
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Kubernetes 1.7 or greater, with beta APIs enabled
|
- 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.
|
- 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
|
## Installing the Chart
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
serviceName: {{ .Values.service.name }}
|
serviceName: {{ .Values.service.name }}
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
{{- if and (ge (.Capabilities.KubeVersion.Major | int) 1) (ge (.Capabilities.KubeVersion.Minor | int) 7) }}
|
||||||
updateStrategy:
|
updateStrategy:
|
||||||
type: RollingUpdate
|
type: RollingUpdate
|
||||||
|
{{- end }}
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ license: "not accepted"
|
|||||||
|
|
||||||
image:
|
image:
|
||||||
# repository is the container repository to use, which must contain IBM MQ Advanced
|
# repository is the container repository to use, which must contain IBM MQ Advanced
|
||||||
repository:
|
repository: ibm-mqadvanced-server
|
||||||
# tag is the tag to use for the container repository
|
# tag is the tag to use for the container repository
|
||||||
tag:
|
tag: 9.0.4.0-x86_64
|
||||||
# pullSecret is the secret to use when pulling the image from a private registry
|
# pullSecret is the secret to use when pulling the image from a private registry
|
||||||
pullSecret:
|
pullSecret:
|
||||||
# pullPolicy is either IfNotPresent or Always (https://kubernetes.io/docs/concepts/containers/images/)
|
# pullPolicy is either IfNotPresent or Always (https://kubernetes.io/docs/concepts/containers/images/)
|
||||||
|
|||||||
@@ -23,22 +23,10 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
//const mainDir string := "/mnt/mqm"
|
|
||||||
const mqmUID uint32 = 999
|
const mqmUID uint32 = 999
|
||||||
const mqmGID uint32 = 999
|
const mqmGID uint32 = 999
|
||||||
|
|
||||||
func createVolume(path string) error {
|
func createVolume(path string) error {
|
||||||
// fi, err := os.Stat(path)
|
|
||||||
// if err != nil {
|
|
||||||
// if os.IsNotExist(err) {
|
|
||||||
// // TODO: Should this be fatal?
|
|
||||||
// //log.Warnf("No volume found under %v", path)
|
|
||||||
// return nil
|
|
||||||
// } else {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//log.Printf("%v details: %v", path, fi.Sys())
|
|
||||||
dataPath := filepath.Join(path, "data")
|
dataPath := filepath.Join(path, "data")
|
||||||
fi, err := os.Stat(dataPath)
|
fi, err := os.Stat(dataPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,8 +45,6 @@ func createVolume(path string) error {
|
|||||||
}
|
}
|
||||||
sys := fi.Sys()
|
sys := fi.Sys()
|
||||||
if sys != nil && runtime.GOOS == "linux" {
|
if sys != nil && runtime.GOOS == "linux" {
|
||||||
// log.Printf("Checking UID/GID for %v", dataPath)
|
|
||||||
//log.Debugf("Checking UID/GID for %v", dataPath)
|
|
||||||
stat := sys.(*syscall.Stat_t)
|
stat := sys.(*syscall.Stat_t)
|
||||||
if stat.Uid != mqmUID || stat.Gid != mqmGID {
|
if stat.Uid != mqmUID || stat.Gid != mqmGID {
|
||||||
err = os.Chown(dataPath, int(mqmUID), int(mqmGID))
|
err = os.Chown(dataPath, int(mqmUID), int(mqmGID))
|
||||||
@@ -70,18 +56,3 @@ func createVolume(path string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If /mnt/mqm exists
|
|
||||||
// If /mnt/mqm contains a "data" directory AND data is owned by mqm:mqm AND data is writeable by mqm:mqm then
|
|
||||||
// Create Symlink from /var/mqm to /mnt/mqm/data
|
|
||||||
// Else
|
|
||||||
// // Try to sort it out
|
|
||||||
// Create directory /mnt/mqm/data
|
|
||||||
// If directory not already owned by mqm:mqm
|
|
||||||
// chown mqm:mqm
|
|
||||||
// if error
|
|
||||||
// delete directory again if empty
|
|
||||||
// if directory not already 0755
|
|
||||||
// chmod 0755
|
|
||||||
// if error
|
|
||||||
// delete directory again if empty
|
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ func getQueueManagerName() (string, error) {
|
|||||||
// runCommand runs an OS command. On Linux it waits for the command to
|
// runCommand runs an OS command. On Linux it waits for the command to
|
||||||
// complete and returns the exit status (return code).
|
// complete and returns the exit status (return code).
|
||||||
func runCommand(name string, arg ...string) (string, int, error) {
|
func runCommand(name string, arg ...string) (string, int, error) {
|
||||||
// log.Debugf("Running command %v %v", name, arg)
|
|
||||||
cmd := exec.Command(name, arg...)
|
cmd := exec.Command(name, arg...)
|
||||||
// Run the command and wait for completion
|
// Run the command and wait for completion
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
@@ -133,12 +132,8 @@ func runCommand(name string, arg ...string) (string, int, error) {
|
|||||||
var rc int
|
var rc int
|
||||||
// Only works on Linux
|
// Only works on Linux
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
// func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error)
|
|
||||||
var ws unix.WaitStatus
|
var ws unix.WaitStatus
|
||||||
//var rusage syscall.Rusage
|
|
||||||
unix.Wait4(cmd.Process.Pid, &ws, 0, nil)
|
unix.Wait4(cmd.Process.Pid, &ws, 0, nil)
|
||||||
//ee := err.(*os.SyscallError)
|
|
||||||
//ws := ee.Sys().(syscall.WaitStatus)
|
|
||||||
rc = ws.ExitStatus()
|
rc = ws.ExitStatus()
|
||||||
} else {
|
} else {
|
||||||
rc = -1
|
rc = -1
|
||||||
@@ -191,6 +186,7 @@ func startQueueManager() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error %v starting queue manager: %v", rc, string(out))
|
log.Fatalf("Error %v starting queue manager: %v", rc, string(out))
|
||||||
}
|
}
|
||||||
|
log.Println("Started queue manager")
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureQueueManager() {
|
func configureQueueManager() {
|
||||||
@@ -273,40 +269,9 @@ func createReaper() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// mirrorLog tails the specified file, and logs each line.
|
|
||||||
// This is useful for usability, as the container console log can show
|
|
||||||
// messages from the MQ log.
|
|
||||||
// func mirrorLog(path string) error {
|
|
||||||
// tail, err := tail.TailFile(path, tail.Config{
|
|
||||||
// ReOpen: true,
|
|
||||||
// Follow: true,
|
|
||||||
// Poll: true,
|
|
||||||
// Location: &tail.SeekInfo{
|
|
||||||
// Offset: 0,
|
|
||||||
// // End of file
|
|
||||||
// Whence: 2,
|
|
||||||
// },
|
|
||||||
// Logger: tail.DiscardingLogger,
|
|
||||||
// })
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// go func() {
|
|
||||||
// for line := range tail.Lines {
|
|
||||||
// // TODO: Unless we parse the message, the timestamp will be (slightly) wrong
|
|
||||||
// if strings.HasPrefix(line.Text, "AMQ") {
|
|
||||||
// // TODO: Extended characters don't print correctly
|
|
||||||
// log.Println(line.Text)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
createReaper()
|
createReaper()
|
||||||
checkLicense()
|
checkLicense()
|
||||||
|
|
||||||
// Start SIGTERM handler channel
|
// Start SIGTERM handler channel
|
||||||
done := createTerminateChannel()
|
done := createTerminateChannel()
|
||||||
|
|
||||||
@@ -315,13 +280,13 @@ func main() {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
log.Printf("Using queue manager name: %v", name)
|
log.Printf("Using queue manager name: %v", name)
|
||||||
|
|
||||||
logConfig()
|
logConfig()
|
||||||
err = createVolume("/mnt/mqm")
|
err = createVolume("/mnt/mqm")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
createDirStructure()
|
createDirStructure()
|
||||||
//mirrorLog("/var/mqm/qmgrs/" + name + "/errors/AMQERR01.LOG")
|
|
||||||
createQueueManager(name)
|
createQueueManager(name)
|
||||||
updateCommandLevel()
|
updateCommandLevel()
|
||||||
startQueueManager()
|
startQueueManager()
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"os/user"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/pkg/linux/capabilities"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,6 +56,25 @@ func logBaseImage() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logUser() {
|
||||||
|
u, err := user.Current()
|
||||||
|
if err == nil {
|
||||||
|
log.Printf("Running as user ID %v (%v) with primary group %v", u.Uid, u.Name, u.Gid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logCapabilities() {
|
||||||
|
status, err := readProc("/proc/1/status")
|
||||||
|
if err != nil {
|
||||||
|
// Ignore
|
||||||
|
return
|
||||||
|
}
|
||||||
|
caps, err := capabilities.DetectCapabilities(status)
|
||||||
|
if err == nil {
|
||||||
|
log.Printf("Detected capabilities: %v", strings.Join(caps, ","))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func readProc(filename string) (value string, err error) {
|
func readProc(filename string) (value string, err error) {
|
||||||
buf, err := ioutil.ReadFile(filename)
|
buf, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -106,13 +127,6 @@ func checkFS(path string) {
|
|||||||
|
|
||||||
func logConfig() {
|
func logConfig() {
|
||||||
log.Printf("CPU architecture: %v", runtime.GOARCH)
|
log.Printf("CPU architecture: %v", runtime.GOARCH)
|
||||||
// TODO: You can't use os.user if you're cross-compiling
|
|
||||||
// u, err := user.Current()
|
|
||||||
// if err != nil {
|
|
||||||
// log.Println(err)
|
|
||||||
// } else {
|
|
||||||
// log.Printf("Running as user ID %v (%v) with primary group %v", u.Uid, u.Name, u.Gid)
|
|
||||||
// }
|
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
var err error
|
var err error
|
||||||
osr, err := readProc("/proc/sys/kernel/osrelease")
|
osr, err := readProc("/proc/sys/kernel/osrelease")
|
||||||
@@ -128,6 +142,8 @@ func logConfig() {
|
|||||||
} else {
|
} else {
|
||||||
log.Printf("Maximum file handles: %v", fileMax)
|
log.Printf("Maximum file handles: %v", fileMax)
|
||||||
}
|
}
|
||||||
|
logUser()
|
||||||
|
logCapabilities()
|
||||||
readMounts()
|
readMounts()
|
||||||
} else {
|
} else {
|
||||||
log.Fatalf("Unsupported platform: %v", runtime.GOOS)
|
log.Fatalf("Unsupported platform: %v", runtime.GOOS)
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ apt-get install -y --no-install-recommends \
|
|||||||
gawk \
|
gawk \
|
||||||
grep \
|
grep \
|
||||||
libc-bin \
|
libc-bin \
|
||||||
lsb-release \
|
|
||||||
mount \
|
mount \
|
||||||
passwd \
|
passwd \
|
||||||
procps \
|
procps \
|
||||||
@@ -43,20 +42,33 @@ apt-get install -y --no-install-recommends \
|
|||||||
util-linux
|
util-linux
|
||||||
|
|
||||||
# Download and extract the MQ installation files
|
# Download and extract the MQ installation files
|
||||||
mkdir -p /tmp/mq
|
DIR_EXTRACT=/tmp/mq
|
||||||
cd /tmp/mq
|
mkdir -p ${DIR_EXTRACT}
|
||||||
|
cd ${DIR_EXTRACT}
|
||||||
curl -LO $MQ_URL
|
curl -LO $MQ_URL
|
||||||
tar -zxvf ./*.tar.gz
|
tar -zxvf ./*.tar.gz
|
||||||
|
|
||||||
|
# Remove packages only needed by this script
|
||||||
|
apt-get purge -y \
|
||||||
|
ca-certificates \
|
||||||
|
curl
|
||||||
|
|
||||||
|
# Remove any orphaned packages
|
||||||
|
apt-get autoremove -y
|
||||||
|
|
||||||
# Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images
|
# Recommended: Create the mqm user ID with a fixed UID and group, so that the file permissions work between different images
|
||||||
groupadd --system --gid 999 mqm
|
groupadd --system --gid 999 mqm
|
||||||
useradd --system --uid 999 --gid mqm mqm
|
useradd --system --uid 999 --gid mqm mqm
|
||||||
usermod -G mqm root
|
usermod -G mqm root
|
||||||
cd /tmp/mq/DebianMQServer
|
|
||||||
|
# Find directory containing .deb files
|
||||||
|
DIR_DEB=$(find ${DIR_EXTRACT} -name "*.deb" -printf "%h\n" | sort -u | head -1)
|
||||||
|
# Find location of mqlicense.sh
|
||||||
|
MQLICENSE=$(find ${DIR_EXTRACT} -name "mqlicense.sh")
|
||||||
|
|
||||||
# Accept the MQ license
|
# Accept the MQ license
|
||||||
./mqlicense.sh -text_only -accept
|
${MQLICENSE} -text_only -accept
|
||||||
echo "deb [trusted=yes] file:/tmp/mq/DebianMQServer ./" > /etc/apt/sources.list.d/IBM_MQ.list
|
echo "deb [trusted=yes] file:${DIR_DEB} ./" > /etc/apt/sources.list.d/IBM_MQ.list
|
||||||
|
|
||||||
# Install MQ using the DEB packages
|
# Install MQ using the DEB packages
|
||||||
apt-get update
|
apt-get update
|
||||||
@@ -73,7 +85,7 @@ find /opt/mqm -name '*.tar.gz' -delete
|
|||||||
|
|
||||||
# Clean up all the downloaded files
|
# Clean up all the downloaded files
|
||||||
rm -f /etc/apt/sources.list.d/IBM_MQ.list
|
rm -f /etc/apt/sources.list.d/IBM_MQ.list
|
||||||
rm -rf /tmp/mq
|
rm -rf ${DIR_EXTRACT}
|
||||||
|
|
||||||
# Apply any bug fixes not included in base Ubuntu or MQ image.
|
# Apply any bug fixes not included in base Ubuntu or MQ image.
|
||||||
# Don't upgrade everything based on Docker best practices https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#run
|
# Don't upgrade everything based on Docker best practices https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#run
|
||||||
@@ -81,6 +93,8 @@ apt-get upgrade -y libkrb5-26-heimdal
|
|||||||
apt-get upgrade -y libexpat1
|
apt-get upgrade -y libexpat1
|
||||||
|
|
||||||
# End of bug fixes
|
# End of bug fixes
|
||||||
|
|
||||||
|
# Clean up cached apt files
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Optional: Update the command prompt with the MQ version
|
# Optional: Update the command prompt with the MQ version
|
||||||
|
|||||||
158
pkg/linux/capabilities/capabilities.go
Normal file
158
pkg/linux/capabilities/capabilities.go
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
© 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// capabilities allows querying of information on Linux capabilities
|
||||||
|
package capabilities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DetectCapabilities determines Linux capabilities, based on the contents of a Linux "status" file.
|
||||||
|
// For example, the contents of file `/proc/1/status`
|
||||||
|
func DetectCapabilities(status string) ([]string, error) {
|
||||||
|
lines := strings.Split(status, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.HasPrefix(strings.TrimSpace(line), "CapPrm:") {
|
||||||
|
words := strings.Fields(line)
|
||||||
|
cap, err := strconv.ParseUint(words[1], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return getCapabilities(cap), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Unable to detect capabilities")
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCapabilities converts an encoded uint64 into a slice of string names of Linux capabilities
|
||||||
|
func getCapabilities(cap uint64) []string {
|
||||||
|
caps := make([]string, 0, 37)
|
||||||
|
if cap&0x0000000040000000 == 0x0000000040000000 {
|
||||||
|
caps = append(caps, "AUDIT_CONTROL")
|
||||||
|
}
|
||||||
|
if cap&0x0000000020000000 == 0x0000000020000000 {
|
||||||
|
caps = append(caps, "AUDIT_WRITE")
|
||||||
|
}
|
||||||
|
if cap&0x0000001000000000 == 0x0000001000000000 {
|
||||||
|
caps = append(caps, "BLOCK_SUSPEND")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000001 == 0x0000000000000001 {
|
||||||
|
caps = append(caps, "CHOWN")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000002 == 0x0000000000000002 {
|
||||||
|
caps = append(caps, "DAC_OVERRIDE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000004 == 0x0000000000000004 {
|
||||||
|
caps = append(caps, "DAC_READ_SEARCH")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000008 == 0x0000000000000008 {
|
||||||
|
caps = append(caps, "FOWNER")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000010 == 0x0000000000000010 {
|
||||||
|
caps = append(caps, "FSETID")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000004000 == 0x0000000000004000 {
|
||||||
|
caps = append(caps, "IPC_LOCK")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000008000 == 0x0000000000008000 {
|
||||||
|
caps = append(caps, "IPC_OWNER")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000020 == 0x0000000000000020 {
|
||||||
|
caps = append(caps, "KILL")
|
||||||
|
}
|
||||||
|
if cap&0x0000000010000000 == 0x0000000010000000 {
|
||||||
|
caps = append(caps, "LEASE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000200 == 0x0000000000000200 {
|
||||||
|
caps = append(caps, "LINUX_IMMUTABLE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000200000000 == 0x0000000200000000 {
|
||||||
|
caps = append(caps, "MAC_ADMIN")
|
||||||
|
}
|
||||||
|
if cap&0x0000000100000000 == 0x0000000100000000 {
|
||||||
|
caps = append(caps, "MAC_OVERRIDE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000008000000 == 0x0000000008000000 {
|
||||||
|
caps = append(caps, "MKNOD")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000001000 == 0x0000000000001000 {
|
||||||
|
caps = append(caps, "NET_ADMIN")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000400 == 0x0000000000000400 {
|
||||||
|
caps = append(caps, "NET_BIND_SERVICE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000800 == 0x0000000000000800 {
|
||||||
|
caps = append(caps, "NET_BROADCAST")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000002000 == 0x0000000000002000 {
|
||||||
|
caps = append(caps, "NET_RAW")
|
||||||
|
}
|
||||||
|
if cap&0x0000000080000000 == 0x0000000080000000 {
|
||||||
|
caps = append(caps, "SETFCAP")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000040 == 0x0000000000000040 {
|
||||||
|
caps = append(caps, "SETGID")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000100 == 0x0000000000000100 {
|
||||||
|
caps = append(caps, "SETPCAP")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000000080 == 0x0000000000000080 {
|
||||||
|
caps = append(caps, "SETUID")
|
||||||
|
}
|
||||||
|
if cap&0x0000000400000000 == 0x0000000400000000 {
|
||||||
|
caps = append(caps, "SYSLOG")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000200000 == 0x0000000000200000 {
|
||||||
|
caps = append(caps, "SYS_ADMIN")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000400000 == 0x0000000000400000 {
|
||||||
|
caps = append(caps, "SYS_BOOT")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000040000 == 0x0000000000040000 {
|
||||||
|
caps = append(caps, "SYS_CHROOT")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000010000 == 0x0000000000010000 {
|
||||||
|
caps = append(caps, "SYS_MODULE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000800000 == 0x0000000000800000 {
|
||||||
|
caps = append(caps, "SYS_NICE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000100000 == 0x0000000000100000 {
|
||||||
|
caps = append(caps, "SYS_PACCT")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000080000 == 0x0000000000080000 {
|
||||||
|
caps = append(caps, "SYS_PTRACE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000000020000 == 0x0000000000020000 {
|
||||||
|
caps = append(caps, "SYS_RAWIO")
|
||||||
|
}
|
||||||
|
if cap&0x0000000001000000 == 0x0000000001000000 {
|
||||||
|
caps = append(caps, "SYS_RESOURCE")
|
||||||
|
}
|
||||||
|
if cap&0x0000000002000000 == 0x0000000002000000 {
|
||||||
|
caps = append(caps, "SYS_TIME")
|
||||||
|
}
|
||||||
|
if cap&0x0000000004000000 == 0x0000000004000000 {
|
||||||
|
caps = append(caps, "SYS_TTY_CONFIG")
|
||||||
|
}
|
||||||
|
if cap&0x0000000800000000 == 0x0000000800000000 {
|
||||||
|
caps = append(caps, "WAKE_ALARM")
|
||||||
|
}
|
||||||
|
return caps
|
||||||
|
}
|
||||||
39
pkg/linux/capabilities/capabilities_test.go
Normal file
39
pkg/linux/capabilities/capabilities_test.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
© 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 capabilities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var capTests = []struct {
|
||||||
|
in uint64
|
||||||
|
out []string
|
||||||
|
}{
|
||||||
|
{0x0000000040000000, []string{"AUDIT_CONTROL"}},
|
||||||
|
// Default values when you run a Docker container without changing capabilities:
|
||||||
|
{0x00000000a80425fb, []string{"AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "NET_RAW", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCapabilities(t *testing.T) {
|
||||||
|
for _, table := range capTests {
|
||||||
|
caps := getCapabilities(table.in)
|
||||||
|
if !reflect.DeepEqual(caps, table.out) {
|
||||||
|
t.Errorf("getCapabilities(%v) - expected %v, got %v", table.in, table.out, caps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ func TestHelmPredefinedVolume(t *testing.T) {
|
|||||||
func TestHelmStorageClass(t *testing.T) {
|
func TestHelmStorageClass(t *testing.T) {
|
||||||
cs := kubeLogin(t)
|
cs := kubeLogin(t)
|
||||||
release := strings.ToLower(t.Name())
|
release := strings.ToLower(t.Name())
|
||||||
|
assertKubeVersion(t, cs, 1, 6)
|
||||||
if !storageClassesDefined(t, cs) {
|
if !storageClassesDefined(t, cs) {
|
||||||
t.Skipf("Skipping test because no storage classes were found")
|
t.Skipf("Skipping test because no storage classes were found")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -257,4 +258,23 @@ func volumesAvailable(t *testing.T, cs *kubernetes.Clientset) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
maj, err := strconv.Atoi(v.Major)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
min, err := strconv.Atoi(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
|
// TODO: On Minikube, need to make sure Helm is initialized first
|
||||||
|
|||||||
Reference in New Issue
Block a user