Merge pull request #19 from arthurbarr/master
Miscellaneous improvements
This commit is contained in:
@@ -12,23 +12,23 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
###############################################################################
|
||||
# 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 internal/ ./internal
|
||||
COPY vendor/ ./vendor
|
||||
RUN go build ./cmd/runmqserver/
|
||||
RUN go build ./cmd/chkmqready/
|
||||
RUN go build ./cmd/chkmqhealthy/
|
||||
# Run all unit tests
|
||||
RUN go test -v ./cmd/... ./internal/...
|
||||
|
||||
# Build stage to run Go unit tests
|
||||
FROM golang:1.9 as tester
|
||||
COPY pkg/ ./pkg
|
||||
RUN cd pkg/name && go test
|
||||
RUN cd pkg/linux/capabilities && go test
|
||||
|
||||
###############################################################################
|
||||
# Main build stage, to build MQ image
|
||||
###############################################################################
|
||||
FROM ubuntu:16.04
|
||||
|
||||
# The URL to download the MQ installer from in tar.gz format
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
FROM golang:1.9 as builder
|
||||
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
|
||||
COPY cmd/ ./cmd
|
||||
COPY pkg/ ./pkg
|
||||
COPY internal/ ./internal
|
||||
COPY vendor/ ./vendor
|
||||
RUN go test -c -covermode=count ./cmd/runmqserver
|
||||
RUN go test -c -covermode=count -coverpkg $(go list ./cmd/runmqserver ./internal/... | paste -s -d, -) ./cmd/runmqserver
|
||||
|
||||
FROM mq-advancedserver:latest-x86_64
|
||||
|
||||
|
||||
85
Makefile
85
Makefile
@@ -13,9 +13,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
BUILD_SERVER_CONTAINER=build-server
|
||||
# Set architecture for Go code. Don't set GOOS globally, so that tests can be run locally
|
||||
export GOARCH ?= amd64
|
||||
DOCKER_TAG_ARCH ?= x86_64
|
||||
DOCKER_TAG_ARCH ?= $(shell uname -m)
|
||||
# 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
|
||||
@@ -24,7 +22,22 @@ DOCKER_REPO_DEVSERVER ?= mq-devserver
|
||||
DOCKER_REPO_ADVANCEDSERVER ?= mq-advancedserver
|
||||
DOCKER_FULL_DEVSERVER = $(DOCKER_REPO_DEVSERVER):$(DOCKER_TAG)
|
||||
DOCKER_FULL_ADVANCEDSERVER = $(DOCKER_REPO_ADVANCEDSERVER):$(DOCKER_TAG)
|
||||
# MQ_PACKAGES is the list of MQ packages to install
|
||||
MQ_PACKAGES ?=ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams
|
||||
# MQ_VERSION is the fully qualified MQ version number to build
|
||||
MQ_VERSION ?= 9.0.4.0
|
||||
# Archive names for IBM MQ Continuous Delivery Release for Ubuntu
|
||||
MQ_ARCHIVE_9.0.3.0_ppc64le=CNJR5ML.tar.gz
|
||||
MQ_ARCHIVE_9.0.3.0_s390x=CNJR6ML.tar.gz
|
||||
MQ_ARCHIVE_9.0.3.0_x86_64=CNJR7ML.tar.gz
|
||||
MQ_ARCHIVE_9.0.4.0_ppc64le=CNLE2ML.tar.gz
|
||||
MQ_ARCHIVE_9.0.4.0_s390x=CNLE3ML.tar.gz
|
||||
MQ_ARCHIVE_9.0.4.0_x86_64=CNLE4ML.tar.gz
|
||||
# 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 ?= $(MQ_ARCHIVE_$(MQ_VERSION)_$(DOCKER_TAG_ARCH))
|
||||
MQ_ARCHIVE_DEV=$(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
||||
# Options to `go test` for the Docker tests
|
||||
TEST_OPTS_DOCKER ?=
|
||||
# Options to `go test` for the Kubernetes tests
|
||||
@@ -51,13 +64,13 @@ clean:
|
||||
rm -rf ./build
|
||||
rm -rf ./deps
|
||||
|
||||
downloads/mqadv_dev903_ubuntu_x86-64.tar.gz:
|
||||
downloads/$(MQ_ARCHIVE_DEV):
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Downloading IBM MQ Advanced for Developers"$(END)))
|
||||
mkdir -p downloads
|
||||
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||
cd downloads; curl -LO https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/$(MQ_ARCHIVE_DEV)
|
||||
|
||||
.PHONY: downloads
|
||||
downloads: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||
downloads: downloads/$(MQ_ARCHIVE_DEV)
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
@@ -72,18 +85,24 @@ build-cov:
|
||||
|
||||
.PHONY: test-advancedserver
|
||||
test-advancedserver:
|
||||
cd pkg/name && go test
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_ADVANCEDSERVER) on Docker"$(END)))
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_ADVANCEDSERVER) go test $(TEST_OPTS_DOCKER)
|
||||
|
||||
.PHONY: test-devserver
|
||||
test-devserver:
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_DEVSERVER)"$(END)))
|
||||
cd pkg/name && go test
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_FULL_DEVSERVER) on Docker"$(END)))
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_FULL_DEVSERVER) go test
|
||||
|
||||
.PHONY: test-advancedserver-cover
|
||||
test-advancedserver-cover:
|
||||
cd pkg/name && go test
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Test $(DOCKER_REPO_ADVANCEDSERVER) on Docker with code coverage"$(END)))
|
||||
rm -f ./coverage/unit*.cov
|
||||
# Run unit tests with coverage, for each package under 'internal'
|
||||
go list -f '{{.Name}}' ./internal/... | xargs -I {} go test -cover -covermode count -coverprofile ./coverage/unit-{}.cov ./internal/{}
|
||||
echo 'mode: count' > ./coverage/unit.cov
|
||||
tail -q -n +2 ./coverage/unit-*.cov >> ./coverage/unit.cov
|
||||
go tool cover -html=./coverage/unit.cov -o ./coverage/unit.html
|
||||
|
||||
rm -f ./test/docker/coverage/*.cov
|
||||
rm -f ./coverage/docker.*
|
||||
cd test/docker && TEST_IMAGE=$(DOCKER_REPO_ADVANCEDSERVER):cover go test $(TEST_OPTS_DOCKER)
|
||||
@@ -91,6 +110,10 @@ test-advancedserver-cover:
|
||||
tail -q -n +2 ./test/docker/coverage/*.cov >> ./coverage/docker.cov
|
||||
go tool cover -html=./coverage/docker.cov -o ./coverage/docker.html
|
||||
|
||||
echo 'mode: count' > ./coverage/combined.cov
|
||||
tail -q -n +2 ./coverage/unit.cov ./coverage/docker.cov >> ./coverage/combined.cov
|
||||
go tool cover -html=./coverage/combined.cov -o ./coverage/combined.html
|
||||
|
||||
.PHONY: test-kubernetes-devserver
|
||||
test-kubernetes-devserver:
|
||||
$(call test-kubernetes,$(DOCKER_REPO_DEVSERVER),$(DOCKER_TAG),"../../charts/ibm-mqadvanced-server-dev")
|
||||
@@ -127,38 +150,24 @@ define docker-build-mq
|
||||
--label IBM_PRODUCT_NAME=$5 \
|
||||
--label IBM_PRODUCT_VERSION=$6 \
|
||||
--build-arg MQ_PACKAGES="$(MQ_PACKAGES)" \
|
||||
.
|
||||
# Stop the web server (will also remove the container)
|
||||
$(DOCKER) kill $(BUILD_SERVER_CONTAINER)
|
||||
# Delete the temporary network
|
||||
$(DOCKER) network rm build
|
||||
. ; $(DOCKER) kill $(BUILD_SERVER_CONTAINER) && $(DOCKER) network rm build
|
||||
endef
|
||||
|
||||
# .PHONY: build-advancedserver-903
|
||||
# build-advancedserver-903: build downloads/CNJR7ML.tar.gz
|
||||
# $(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
|
||||
# $(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,CNJR7ML.tar.gz,"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced","9.0.3")
|
||||
# $(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):9.0.3-$(DOCKER_TAG_ARCH)
|
||||
|
||||
.PHONY: build-advancedserver-904
|
||||
build-advancedserver-904: downloads/CNLE4ML.tar.gz
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
|
||||
$(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,CNLE4ML.tar.gz,"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced","9.0.4")
|
||||
$(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):9.0.4-$(DOCKER_TAG_ARCH)
|
||||
|
||||
.PHONY: build-advancedserver
|
||||
build-advancedserver: build-advancedserver-904
|
||||
build-advancedserver: downloads/$(MQ_ARCHIVE)
|
||||
$(info $(SPACER)$(shell printf $(TITLE)"Build $(DOCKER_FULL_ADVANCEDSERVER)"$(END)))
|
||||
$(call docker-build-mq,$(DOCKER_FULL_ADVANCEDSERVER),Dockerfile-server,$(MQ_ARCHIVE),"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced",$(MQ_VERSION))
|
||||
$(DOCKER) tag $(DOCKER_FULL_ADVANCEDSERVER) $(DOCKER_REPO_ADVANCEDSERVER):$(MQ_VERSION)-$(DOCKER_TAG_ARCH)
|
||||
|
||||
.PHONY: build-devserver
|
||||
build-devserver: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||
build-devserver: downloads/$(MQ_ARCHIVE_DEV)
|
||||
ifneq "x86_64" "$(shell uname -m)"
|
||||
$(error MQ Advanced for Developers is only available for x86_64 architecture)
|
||||
else
|
||||
$(info $(shell printf $(TITLE)"Build $(DOCKER_FULL_DEVSERVER)"$(END)))
|
||||
$(call docker-build-mq,$(DOCKER_FULL_DEVSERVER),Dockerfile-server,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
|
||||
$(DOCKER) tag $(DOCKER_FULL_DEVSERVER) $(DOCKER_REPO_DEVSERVER):9.0.3-$(DOCKER_TAG_ARCH)
|
||||
|
||||
# .PHONY: build-server
|
||||
# build-server: build downloads/CNJR7ML.tar.gz
|
||||
# $(call docker-build-mq,mq-server:latest-$(DOCKER_TAG_ARCH),Dockerfile-server,"79afd716d55b4f149a87bec52c9dc1aa","IBM MQ","9.0.3")
|
||||
# $(DOCKER) tag mq-server:latest-$(DOCKER_TAG_ARCH) mq-server:9.0.3-$(DOCKER_TAG_ARCH)
|
||||
$(call docker-build-mq,$(DOCKER_FULL_DEVSERVER),Dockerfile-server,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
|
||||
$(DOCKER) tag $(DOCKER_FULL_DEVSERVER) $(DOCKER_REPO_DEVSERVER):$(MQ_VERSION)-$(DOCKER_TAG_ARCH)
|
||||
endif
|
||||
|
||||
.PHONY: build-advancedserver-cover
|
||||
build-advancedserver-cover:
|
||||
@@ -169,7 +178,7 @@ build-advancedserver-cover:
|
||||
# $(call docker-build-mq,mq-web:latest-$(DOCKER_TAG_ARCH),Dockerfile-mq-web)
|
||||
|
||||
.PHONY: build-explorer
|
||||
build-explorer: downloads/mqadv_dev903_ubuntu_x86-64.tar.gz
|
||||
$(call docker-build-mq,mq-explorer:latest-$(DOCKER_TAG_ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,mqadv_dev903_ubuntu_x86-64.tar.gz,"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)","9.0.3")
|
||||
build-explorer: downloads/$(MQ_ARCHIVE_DEV)
|
||||
$(call docker-build-mq,mq-explorer:latest-$(DOCKER_TAG_ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
|
||||
|
||||
include formatting.mk
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/pkg/name"
|
||||
"github.com/ibm-messaging/mq-container/internal/name"
|
||||
)
|
||||
|
||||
func queueManagerHealthy() (bool, error) {
|
||||
|
||||
91
cmd/runmqserver/license.go
Normal file
91
cmd/runmqserver/license.go
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
© 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 (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// resolveLicenseFile returns the file name of the MQ license file, taking into
|
||||
// account the language set by the LANG environment variable
|
||||
func resolveLicenseFile() string {
|
||||
lang, ok := os.LookupEnv("LANG")
|
||||
if !ok {
|
||||
return "English.txt"
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(lang, "zh_TW"):
|
||||
return "Chinese_TW.txt"
|
||||
case strings.HasPrefix(lang, "zh"):
|
||||
return "Chinese.txt"
|
||||
case strings.HasPrefix(lang, "cs"):
|
||||
return "Czech.txt"
|
||||
case strings.HasPrefix(lang, "fr"):
|
||||
return "French.txt"
|
||||
case strings.HasPrefix(lang, "de"):
|
||||
return "German.txt"
|
||||
case strings.HasPrefix(lang, "el"):
|
||||
return "Greek.txt"
|
||||
case strings.HasPrefix(lang, "id"):
|
||||
return "Indonesian.txt"
|
||||
case strings.HasPrefix(lang, "it"):
|
||||
return "Italian.txt"
|
||||
case strings.HasPrefix(lang, "ja"):
|
||||
return "Japanese.txt"
|
||||
case strings.HasPrefix(lang, "ko"):
|
||||
return "Korean.txt"
|
||||
case strings.HasPrefix(lang, "lt"):
|
||||
return "Lithuanian.txt"
|
||||
case strings.HasPrefix(lang, "pl"):
|
||||
return "Polish.txt"
|
||||
case strings.HasPrefix(lang, "pt"):
|
||||
return "Portugese.txt"
|
||||
case strings.HasPrefix(lang, "ru"):
|
||||
return "Russian.txt"
|
||||
case strings.HasPrefix(lang, "sl"):
|
||||
return "Slovenian.txt"
|
||||
case strings.HasPrefix(lang, "es"):
|
||||
return "Spanish.txt"
|
||||
case strings.HasPrefix(lang, "tr"):
|
||||
return "Turkish.txt"
|
||||
}
|
||||
return "English.txt"
|
||||
}
|
||||
|
||||
func checkLicense() (bool, error) {
|
||||
lic, ok := os.LookupEnv("LICENSE")
|
||||
switch {
|
||||
case ok && lic == "accept":
|
||||
return true, nil
|
||||
case ok && lic == "view":
|
||||
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
|
||||
buf, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false, err
|
||||
}
|
||||
log.Println(string(buf))
|
||||
return false, nil
|
||||
}
|
||||
log.Println("Error: Set environment variable LICENSE=accept to indicate acceptance of license terms and conditions.")
|
||||
log.Println("License agreements and information can be viewed by setting the environment variable LICENSE=view. You can also set the LANG environment variable to view the license in a different language.")
|
||||
return false, errors.New("Set environment variable LICENSE=accept to indicate acceptance of license terms and conditions")
|
||||
}
|
||||
@@ -18,182 +18,73 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"github.com/ibm-messaging/mq-container/internal/command"
|
||||
"github.com/ibm-messaging/mq-container/internal/name"
|
||||
)
|
||||
|
||||
// resolveLicenseFile returns the file name of the MQ license file, taking into
|
||||
// account the language set by the LANG environment variable
|
||||
func resolveLicenseFile() string {
|
||||
lang, ok := os.LookupEnv("LANG")
|
||||
if !ok {
|
||||
return "English.txt"
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(lang, "zh_TW"):
|
||||
return "Chinese_TW.txt"
|
||||
case strings.HasPrefix(lang, "zh"):
|
||||
return "Chinese.txt"
|
||||
case strings.HasPrefix(lang, "cs"):
|
||||
return "Czech.txt"
|
||||
case strings.HasPrefix(lang, "fr"):
|
||||
return "French.txt"
|
||||
case strings.HasPrefix(lang, "de"):
|
||||
return "German.txt"
|
||||
case strings.HasPrefix(lang, "el"):
|
||||
return "Greek.txt"
|
||||
case strings.HasPrefix(lang, "id"):
|
||||
return "Indonesian.txt"
|
||||
case strings.HasPrefix(lang, "it"):
|
||||
return "Italian.txt"
|
||||
case strings.HasPrefix(lang, "ja"):
|
||||
return "Japanese.txt"
|
||||
case strings.HasPrefix(lang, "ko"):
|
||||
return "Korean.txt"
|
||||
case strings.HasPrefix(lang, "lt"):
|
||||
return "Lithuanian.txt"
|
||||
case strings.HasPrefix(lang, "pl"):
|
||||
return "Polish.txt"
|
||||
case strings.HasPrefix(lang, "pt"):
|
||||
return "Portugese.txt"
|
||||
case strings.HasPrefix(lang, "ru"):
|
||||
return "Russian.txt"
|
||||
case strings.HasPrefix(lang, "sl"):
|
||||
return "Slovenian.txt"
|
||||
case strings.HasPrefix(lang, "es"):
|
||||
return "Spanish.txt"
|
||||
case strings.HasPrefix(lang, "tr"):
|
||||
return "Turkish.txt"
|
||||
}
|
||||
return "English.txt"
|
||||
}
|
||||
|
||||
func checkLicense() {
|
||||
lic, ok := os.LookupEnv("LICENSE")
|
||||
switch {
|
||||
case ok && lic == "accept":
|
||||
return
|
||||
case ok && lic == "view":
|
||||
file := filepath.Join("/opt/mqm/licenses", resolveLicenseFile())
|
||||
buf, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(string(buf))
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Error: Set environment variable LICENSE=accept to indicate acceptance of license terms and conditions.")
|
||||
fmt.Println("License agreements and information can be viewed by setting the environment variable LICENSE=view. You can also set the LANG environment variable to view the license in a different language.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// sanitizeQueueManagerName removes any invalid characters from a queue manager name
|
||||
func sanitizeQueueManagerName(name string) string {
|
||||
var re = regexp.MustCompile("[^a-zA-Z0-9._%/]")
|
||||
return re.ReplaceAllString(name, "")
|
||||
}
|
||||
|
||||
// GetQueueManagerName resolves the queue manager name to use. Resolved from
|
||||
// either an environment variable, or the hostname.
|
||||
func getQueueManagerName() (string, error) {
|
||||
var name string
|
||||
var err error
|
||||
name, ok := os.LookupEnv("MQ_QMGR_NAME")
|
||||
if !ok || name == "" {
|
||||
name, err = os.Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name = sanitizeQueueManagerName(name)
|
||||
}
|
||||
// TODO: What if the specified env variable is an invalid name?
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// runCommand runs an OS command. On Linux it waits for the command to
|
||||
// complete and returns the exit status (return code).
|
||||
func runCommand(name string, arg ...string) (string, int, error) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
// Run the command and wait for completion
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
var rc int
|
||||
// Only works on Linux
|
||||
if runtime.GOOS == "linux" {
|
||||
var ws unix.WaitStatus
|
||||
unix.Wait4(cmd.Process.Pid, &ws, 0, nil)
|
||||
rc = ws.ExitStatus()
|
||||
} else {
|
||||
rc = -1
|
||||
}
|
||||
if rc == 0 {
|
||||
return string(out), rc, nil
|
||||
}
|
||||
return string(out), rc, err
|
||||
}
|
||||
return string(out), 0, nil
|
||||
}
|
||||
|
||||
// createDirStructure creates the default MQ directory structure under /var/mqm
|
||||
func createDirStructure() {
|
||||
out, _, err := runCommand("/opt/mqm/bin/crtmqdir", "-f", "-s")
|
||||
func createDirStructure() error {
|
||||
out, _, err := command.Run("/opt/mqm/bin/crtmqdir", "-f", "-s")
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating directory structure: %v\n", string(out))
|
||||
log.Printf("Error creating directory structure: %v\n", string(out))
|
||||
return err
|
||||
}
|
||||
log.Println("Created directory structure under /var/mqm")
|
||||
return nil
|
||||
}
|
||||
|
||||
func createQueueManager(name string) {
|
||||
func createQueueManager(name string) error {
|
||||
log.Printf("Creating queue manager %v", name)
|
||||
out, rc, err := runCommand("crtmqm", "-q", "-p", "1414", name)
|
||||
out, rc, err := command.Run("crtmqm", "-q", "-p", "1414", name)
|
||||
if err != nil {
|
||||
// 8=Queue manager exists, which is fine
|
||||
if rc != 8 {
|
||||
log.Printf("crtmqm returned %v", rc)
|
||||
log.Fatalln(string(out))
|
||||
} else {
|
||||
log.Printf("Detected existing queue manager %v", name)
|
||||
return
|
||||
log.Println(string(out))
|
||||
return err
|
||||
}
|
||||
log.Printf("Detected existing queue manager %v", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateCommandLevel() {
|
||||
func updateCommandLevel() error {
|
||||
level, ok := os.LookupEnv("MQ_CMDLEVEL")
|
||||
if ok && level != "" {
|
||||
out, rc, err := runCommand("strmqm", "-e", "CMDLEVEL="+level)
|
||||
out, rc, err := command.Run("strmqm", "-e", "CMDLEVEL="+level)
|
||||
if err != nil {
|
||||
log.Fatalf("Error %v setting CMDLEVEL: %v", rc, string(out))
|
||||
log.Printf("Error %v setting CMDLEVEL: %v", rc, string(out))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startQueueManager() {
|
||||
func startQueueManager() error {
|
||||
log.Println("Starting queue manager")
|
||||
out, rc, err := runCommand("strmqm")
|
||||
out, rc, err := command.Run("strmqm")
|
||||
if err != nil {
|
||||
log.Fatalf("Error %v starting queue manager: %v", rc, string(out))
|
||||
log.Printf("Error %v starting queue manager: %v", rc, string(out))
|
||||
return err
|
||||
}
|
||||
log.Println("Started queue manager")
|
||||
return nil
|
||||
}
|
||||
|
||||
func configureQueueManager() {
|
||||
func configureQueueManager() error {
|
||||
const configDir string = "/etc/mqm"
|
||||
files, err := ioutil.ReadDir(configDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
@@ -201,12 +92,14 @@ func configureQueueManager() {
|
||||
abs := filepath.Join(configDir, file.Name())
|
||||
mqsc, err := ioutil.ReadFile(abs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command("runmqsc")
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
stdin.Write(mqsc)
|
||||
stdin.Close()
|
||||
@@ -219,78 +112,78 @@ func configureQueueManager() {
|
||||
log.Printf("Output for \"runmqsc\" with %v:\n\t%v", abs, strings.Replace(string(out), "\n", "\n\t", -1))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopQueueManager() {
|
||||
func stopQueueManager(name string) error {
|
||||
log.Println("Stopping queue manager")
|
||||
out, _, err := runCommand("endmqm", "-w")
|
||||
out, _, err := command.Run("endmqm", "-w", name)
|
||||
if err != nil {
|
||||
log.Fatalf("Error stopping queue manager: %v", string(out))
|
||||
log.Printf("Error stopping queue manager: %v", string(out))
|
||||
return err
|
||||
}
|
||||
log.Println("Stopped queue manager")
|
||||
return nil
|
||||
}
|
||||
|
||||
// createTerminateChannel creates a channel which will be closed when SIGTERM
|
||||
// is received.
|
||||
func createTerminateChannel() chan struct{} {
|
||||
done := make(chan struct{})
|
||||
// Handle SIGTERM
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
|
||||
go func() {
|
||||
sig := <-c
|
||||
log.Printf("Signal received: %v", sig)
|
||||
stopQueueManager()
|
||||
close(done)
|
||||
}()
|
||||
return done
|
||||
}
|
||||
|
||||
// createReaperChannel creates a channel which will be used to reap zombie
|
||||
// (defunct) processes. This is a responsibility of processes running
|
||||
// as PID 1.
|
||||
func createReaper() {
|
||||
// Handle SIGCHLD
|
||||
c := make(chan os.Signal, 3)
|
||||
signal.Notify(c, syscall.SIGCHLD)
|
||||
go func() {
|
||||
for {
|
||||
<-c
|
||||
for {
|
||||
var ws unix.WaitStatus
|
||||
_, err := unix.Wait4(-1, &ws, 0, nil)
|
||||
// If err indicates "no child processes" left to reap, then
|
||||
// wait for next SIGCHLD signal
|
||||
if err == unix.ECHILD {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func main() {
|
||||
createReaper()
|
||||
checkLicense()
|
||||
// Start SIGTERM handler channel
|
||||
done := createTerminateChannel()
|
||||
|
||||
name, err := getQueueManagerName()
|
||||
func doMain() error {
|
||||
accepted, err := checkLicense()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
return err
|
||||
}
|
||||
if !accepted {
|
||||
return errors.New("License not accepted")
|
||||
}
|
||||
|
||||
name, err := name.GetQueueManagerName()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
log.Printf("Using queue manager name: %v", name)
|
||||
|
||||
// Start signal handler
|
||||
signalControl := signalHandler(name)
|
||||
|
||||
logConfig()
|
||||
err = createVolume("/mnt/mqm")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
err = createDirStructure()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = createQueueManager(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = updateCommandLevel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = startQueueManager()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createDirStructure()
|
||||
createQueueManager(name)
|
||||
updateCommandLevel()
|
||||
startQueueManager()
|
||||
configureQueueManager()
|
||||
// Start reaping zombies from now on.
|
||||
// Start this here, so that we don't reap any sub-processes created
|
||||
// by this process (e.g. for crtmqm or strmqm)
|
||||
signalControl <- startReaping
|
||||
// Reap zombies now, just in case we've already got some
|
||||
signalControl <- reapNow
|
||||
// Wait for terminate signal
|
||||
<-done
|
||||
<-signalControl
|
||||
return nil
|
||||
}
|
||||
|
||||
var osExit = os.Exit
|
||||
|
||||
func main() {
|
||||
err := doMain()
|
||||
if err != nil {
|
||||
osExit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -29,6 +32,15 @@ func init() {
|
||||
// Test started when the test binary is started. Only calls main.
|
||||
func TestSystem(t *testing.T) {
|
||||
if *test {
|
||||
var oldExit = osExit
|
||||
defer func() {
|
||||
osExit = oldExit
|
||||
}()
|
||||
osExit = func(rc int) {
|
||||
// Write the exit code to a file instead
|
||||
log.Printf("Writing exit code %v to file", strconv.Itoa(rc))
|
||||
ioutil.WriteFile("/var/coverage/exitCode", []byte(strconv.Itoa(rc)), 0644)
|
||||
}
|
||||
main()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/ibm-messaging/mq-container/pkg/linux/capabilities"
|
||||
"github.com/ibm-messaging/mq-container/internal/capabilities"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
|
||||
79
cmd/runmqserver/signals.go
Normal file
79
cmd/runmqserver/signals.go
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
© 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 (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
startReaping = iota
|
||||
reapNow = iota
|
||||
)
|
||||
|
||||
func signalHandler(qmgr string) chan int {
|
||||
control := make(chan int)
|
||||
// Use separate channels for the signals, to avoid SIGCHLD signals swamping
|
||||
// the buffer, and preventing other signals.
|
||||
stopSignals := make(chan os.Signal)
|
||||
reapSignals := make(chan os.Signal)
|
||||
signal.Notify(stopSignals, syscall.SIGTERM, syscall.SIGINT)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case sig := <-stopSignals:
|
||||
log.Printf("Signal received: %v", sig)
|
||||
signal.Stop(reapSignals)
|
||||
signal.Stop(stopSignals)
|
||||
stopQueueManager(qmgr)
|
||||
// One final reap
|
||||
reapZombies()
|
||||
close(control)
|
||||
// End the goroutine
|
||||
return
|
||||
case <-reapSignals:
|
||||
reapZombies()
|
||||
case job := <-control:
|
||||
switch {
|
||||
case job == startReaping:
|
||||
// Add SIGCHLD to the list of signals we're listening to
|
||||
signal.Notify(reapSignals, syscall.SIGCHLD)
|
||||
case job == reapNow:
|
||||
reapZombies()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return control
|
||||
}
|
||||
|
||||
// reapZombies reaps any zombie (terminated) processes now.
|
||||
// This function should be called before exiting.
|
||||
func reapZombies() {
|
||||
for {
|
||||
var ws unix.WaitStatus
|
||||
pid, err := unix.Wait4(-1, &ws, unix.WNOHANG, nil)
|
||||
// If err or pid indicate "no child processes"
|
||||
if pid == 0 || err == unix.ECHILD {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,18 +8,37 @@ You need to ensure you have the following tools installed:
|
||||
* [Glide](https://glide.sh/)
|
||||
* [dep](https://github.com/golang/dep) (official Go dependency management tool)
|
||||
* make
|
||||
* [Helm](https://helm.sh) - only needed for running the Kubernetes tests
|
||||
|
||||
For running the Kubernetes tests, a Kubernetes environment is needed, for example [Minikube](https://github.com/kubernetes/minikube) or [IBM Cloud Private](https://www.ibm.com/cloud-computing/products/ibm-cloud-private/).
|
||||
|
||||
## Building a production image
|
||||
This procedure works for building the MQ Continuous Delivery release, on `x86_64`, `ppc64le` and `s390x` architectures.
|
||||
|
||||
1. Download MQ from IBM Passport Advantage, and place the downloaded file (for example, `CNLE4ML.tar.gz` for MQ V9.0.4 on x86_64 architecture) in the `downloads` directory
|
||||
2. Run `make build-advancedserver`
|
||||
|
||||
You can build a different version of MQ by setting the `MQ_VERSION` environment variable, for example:
|
||||
|
||||
```bash
|
||||
MQ_VERSION=9.0.3.0 make build-advancedserver
|
||||
```
|
||||
|
||||
## Running the tests
|
||||
There are three main sets of tests:
|
||||
|
||||
1. Unit tests
|
||||
1. Unit tests, which are run during a build
|
||||
2. Docker tests, which test a complete Docker image, using the Docker API
|
||||
3. Kubernetes tests, which test the Helm charts (and the Docker image) via [Helm](https://helm.sh)
|
||||
|
||||
### Running the tests
|
||||
The unit and Docker tests can be run locally. For example:
|
||||
### Running the Docker tests
|
||||
The Docker tests can be run locally. Before you run them for the first time, you need to download the test dependencies:
|
||||
|
||||
```
|
||||
make deps
|
||||
```
|
||||
|
||||
You can then run the tests, for example:
|
||||
|
||||
```
|
||||
make test-devserver
|
||||
@@ -31,7 +50,7 @@ or:
|
||||
make test-advancedserver
|
||||
```
|
||||
|
||||
### Running the tests with code coverage
|
||||
### Running the Docker tests with code coverage
|
||||
You can produce code coverage results from the Docker tests by running the following:
|
||||
|
||||
```
|
||||
|
||||
47
internal/command/command.go
Normal file
47
internal/command/command.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package command contains code to run external commands
|
||||
package command
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Run runs an OS command. On Linux it waits for the command to
|
||||
// complete and returns the exit status (return code).
|
||||
// Do not use this function to run shell built-ins (like "cd"), because
|
||||
// the error handling works differently
|
||||
func Run(name string, arg ...string) (string, int, error) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
// Run the command and wait for completion
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
// Assert that this is an ExitError
|
||||
exiterr, ok := err.(*exec.ExitError)
|
||||
// If the type assertion was correct, and we're on Linux
|
||||
if ok && runtime.GOOS == "linux" {
|
||||
status, ok := exiterr.Sys().(syscall.WaitStatus)
|
||||
if ok {
|
||||
return string(out), status.ExitStatus(), err
|
||||
}
|
||||
}
|
||||
return string(out), -1, err
|
||||
}
|
||||
return string(out), 0, nil
|
||||
}
|
||||
47
internal/command/command_test.go
Normal file
47
internal/command/command_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
© Copyright IBM Corporation 2017
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package command
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var commandTests = []struct {
|
||||
name string
|
||||
arg []string
|
||||
rc int
|
||||
}{
|
||||
{"ls", []string{}, 0},
|
||||
{"ls", []string{"madeup"}, 2},
|
||||
{"bash", []string{"-c", "exit 99"}, 99},
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("Skipping tests for package which only works on Linux")
|
||||
}
|
||||
for _, table := range commandTests {
|
||||
arg := table.arg
|
||||
_, rc, err := Run(table.name, arg...)
|
||||
if rc != table.rc {
|
||||
t.Errorf("Run(%v,%v) - expected %v, got %v", table.name, table.arg, table.rc, rc)
|
||||
}
|
||||
if rc != 0 && err == nil {
|
||||
t.Errorf("Run(%v,%v) - expected error for non-zero return code (rc=%v)", table.name, table.arg, rc)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,9 @@ package name
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
//log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// sanitizeQueueManagerName removes any invalid characters from a queue manager name
|
||||
// TODO: This is duplicate code
|
||||
func sanitizeQueueManagerName(name string) string {
|
||||
var re = regexp.MustCompile("[^a-zA-Z0-9._%/]")
|
||||
return re.ReplaceAllString(name, "")
|
||||
@@ -167,3 +167,55 @@ func TestNoVolumeWithRestart(t *testing.T) {
|
||||
startContainer(t, cli, id)
|
||||
waitForReady(t, cli, id)
|
||||
}
|
||||
|
||||
// Test the case where `crtmqm` will fail
|
||||
func TestCreateQueueManagerFail(t *testing.T) {
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
|
||||
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||
//ExposedPorts: ports,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
// Override the entrypoint to create the queue manager directory, but leave it empty.
|
||||
// This will cause `crtmqm` to return with an exit code of 2.
|
||||
Entrypoint: []string{"bash", "-c", "mkdir -p /mnt/mqm/data && mkdir -p /var/mqm/qmgrs/qm1 && exec " + oldEntrypoint},
|
||||
}
|
||||
id := runContainer(t, cli, &containerConfig)
|
||||
defer cleanContainer(t, cli, id)
|
||||
rc := waitForContainer(t, cli, id, 10)
|
||||
if rc != 1 {
|
||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||
}
|
||||
}
|
||||
|
||||
// Test the case where `strmqm` will fail
|
||||
func TestStartQueueManagerFail(t *testing.T) {
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img, _, err := cli.ImageInspectWithRaw(context.Background(), imageName())
|
||||
oldEntrypoint := strings.Join(img.Config.Entrypoint, " ")
|
||||
containerConfig := container.Config{
|
||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||
//ExposedPorts: ports,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"1414/tcp": struct{}{},
|
||||
},
|
||||
// Override the entrypoint to replace `crtmqm` with a no-op script.
|
||||
// This will cause `strmqm` to return with an exit code of 16.
|
||||
Entrypoint: []string{"bash", "-c", "echo '#!/bin/bash\n' > /opt/mqm/bin/crtmqm && exec " + oldEntrypoint},
|
||||
}
|
||||
id := runContainer(t, cli, &containerConfig)
|
||||
defer cleanContainer(t, cli, id)
|
||||
rc := waitForContainer(t, cli, id, 10)
|
||||
if rc != 1 {
|
||||
t.Errorf("Expected rc=1, got rc=%v", rc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -61,13 +62,15 @@ func cleanContainer(t *testing.T, cli *client.Client, ID string) {
|
||||
// Log the results and continue
|
||||
t.Logf("Inspected container %v: %#v", ID, i)
|
||||
}
|
||||
t.Logf("Killing container: %v", ID)
|
||||
// Kill the container. This allows the coverage output to be generated.
|
||||
err = cli.ContainerKill(context.Background(), ID, "SIGTERM")
|
||||
t.Logf("Stopping container: %v", ID)
|
||||
timeout := 10 * time.Second
|
||||
// Stop the container. This allows the coverage output to be generated.
|
||||
err = cli.ContainerStop(context.Background(), ID, &timeout)
|
||||
if err != nil {
|
||||
// Just log the error and continue
|
||||
t.Log(err)
|
||||
}
|
||||
t.Log("Container stopped")
|
||||
// If a code coverage file has been generated, then rename it to match the test name
|
||||
os.Rename(filepath.Join(coverageDir(t), "container.cov"), filepath.Join(coverageDir(t), t.Name()+".cov"))
|
||||
// Log the container output for any container we're about to delete
|
||||
@@ -134,11 +137,40 @@ func stopContainer(t *testing.T, cli *client.Client, ID string) {
|
||||
}
|
||||
}
|
||||
|
||||
func getCoverageExitCode(t *testing.T, orig int64) int64 {
|
||||
f := filepath.Join(coverageDir(t), "exitCode")
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return orig
|
||||
}
|
||||
// Remove the file, ready for the next test
|
||||
//defer os.Remove(f)
|
||||
buf, err := ioutil.ReadFile(f)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return orig
|
||||
}
|
||||
rc, err := strconv.Atoi(string(buf))
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return orig
|
||||
}
|
||||
t.Logf("Retrieved exit code %v from file", rc)
|
||||
return int64(rc)
|
||||
}
|
||||
|
||||
// waitForContainer waits until a container has exited
|
||||
func waitForContainer(t *testing.T, cli *client.Client, ID string, timeout int64) int64 {
|
||||
//ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
//defer cancel()
|
||||
rc, err := cli.ContainerWait(context.Background(), ID)
|
||||
|
||||
// COVERAGE: When running coverage, the exit code is written to a file,
|
||||
// to allow the coverage to be generated (which doesn't happen for non-zero
|
||||
// exit codes)
|
||||
rc = getCoverageExitCode(t, rc)
|
||||
|
||||
// err := <-errC
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
Reference in New Issue
Block a user