Fixes for tests on RHEL and test log output

This commit is contained in:
Arthur Barr
2019-02-27 14:27:12 +00:00
committed by Arthur Barr
parent a194545f08
commit c441de7d26
5 changed files with 122 additions and 53 deletions

View File

@@ -181,7 +181,7 @@ build-mqgolang-sdk: check-prereqs downloads/$(MQ_SDK_ARCHIVE)
.PHONY: build-go-programs .PHONY: build-go-programs
build-go-programs: check-prereqs downloads/$(MQ_SDK_ARCHIVE) build-mqgolang-sdk build-go-programs: check-prereqs downloads/$(MQ_SDK_ARCHIVE) build-mqgolang-sdk
$(info $(SPACER)$(shell printf $(TITLE)"Build go programs"$(END))) $(info $(SPACER)$(shell printf $(TITLE)"Build go programs"$(END)))
IMAGE_REVISION=$(IMAGE_REVISION) IMAGE_SOURCE=$(IMAGE_SOURCE) sudo mq-advanced-server-rhel/go-buildah.sh "$(MQ_IMAGE_GOLANG_SDK)" "$(MQDEV)" IMAGE_REVISION=$(IMAGE_REVISION) IMAGE_SOURCE=$(IMAGE_SOURCE) sudo --preserve-env mq-advanced-server-rhel/go-buildah.sh "$(MQ_IMAGE_GOLANG_SDK)" "$(MQDEV)"
.PHONY: build-devjmstest .PHONY: build-devjmstest
build-devjmstest: check-test-prereqs build-devjmstest: check-test-prereqs

View File

@@ -46,12 +46,17 @@ func logContainerDetails() {
} }
} }
caps, err := containerruntime.GetCapabilities() caps, err := containerruntime.GetCapabilities()
capLogged := false
if err == nil { if err == nil {
for k, v := range caps { for k, v := range caps {
if len(v) > 0 { if len(v) > 0 {
log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ",")) log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ","))
capLogged = true
} }
} }
if !capLogged {
log.Print("Capabilities: none")
}
} else { } else {
log.Errorf("Error getting capabilities: %v", err) log.Errorf("Error getting capabilities: %v", err)
} }

View File

@@ -50,12 +50,19 @@ func logContainerDetails() error {
} }
} }
caps, err := containerruntime.GetCapabilities() caps, err := containerruntime.GetCapabilities()
capLogged := false
if err == nil { if err == nil {
for k, v := range caps { for k, v := range caps {
if len(v) > 0 { if len(v) > 0 {
log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ",")) log.Printf("Capabilities (%s set): %v", strings.ToLower(k), strings.Join(v, ","))
capLogged = true
} }
} }
if !capLogged {
log.Print("Capabilities: none")
}
} else {
log.Errorf("Error getting capabilities: %v", err)
} }
sc, err := containerruntime.GetSeccomp() sc, err := containerruntime.GetSeccomp()
if err == nil { if err == nil {

View File

@@ -43,6 +43,18 @@ import (
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
) )
type containerDetails struct {
ID string
Name string
Image string
Path string
Args []string
CapAdd []string
CapDrop []string
User string
Env []string
}
func imageName() string { func imageName() string {
image, ok := os.LookupEnv("TEST_IMAGE") image, ok := os.LookupEnv("TEST_IMAGE")
if !ok { if !ok {
@@ -59,8 +71,9 @@ func imageNameDevJMS() string {
return image return image
} }
// baseImage returns the ID of the underlying base image (e.g. "ubuntu" or "rhel")
func baseImage(t *testing.T, cli *client.Client) string { func baseImage(t *testing.T, cli *client.Client) string {
rc, out := runContainerOneShot(t, cli, "bash", "-c", "cat /etc/*release | grep \"^ID=\"") rc, out := runContainerOneShot(t, cli, "grep", "^ID=", "/etc/os-release")
if rc != 0 { if rc != 0 {
t.Fatal("Couldn't determine base image") t.Fatal("Couldn't determine base image")
} }
@@ -71,6 +84,16 @@ func baseImage(t *testing.T, cli *client.Client) string {
return s[1] return s[1]
} }
// devImage returns true if the image under test is a developer image,
// determined by use of the MQ_ADMIN_PASSWORD environment variable
func devImage(t *testing.T, cli *client.Client) bool {
rc, _ := runContainerOneShot(t, cli, "printenv", "MQ_ADMIN_PASSWORD")
if rc == 0 {
return true
}
return false
}
// isWSL return whether we are running in the Windows Subsystem for Linux // isWSL return whether we are running in the Windows Subsystem for Linux
func isWSL(t *testing.T) bool { func isWSL(t *testing.T) bool {
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
@@ -166,21 +189,49 @@ func expectTerminationMessage(t *testing.T, cli *client.Client, ID string) {
} }
} }
func cleanContainer(t *testing.T, cli *client.Client, ID string) { // logContainerDetails logs selected details about the container
func logContainerDetails(t *testing.T, cli *client.Client, ID string) {
i, err := cli.ContainerInspect(context.Background(), ID) i, err := cli.ContainerInspect(context.Background(), ID)
if err == nil { if err == nil {
// Log the results and continue d := containerDetails{
t.Logf("Inspected container %v: %#v", ID, i) ID: ID,
s, err := json.MarshalIndent(i, "", " ") Name: i.Name,
if err != nil { Image: i.Image,
t.Fatal(err) Path: i.Path,
Args: i.Args,
CapAdd: i.HostConfig.CapAdd,
CapDrop: i.HostConfig.CapDrop,
User: i.Config.User,
Env: i.Config.Env,
} }
t.Logf("Inspected container %v: %v", ID, string(s)) // If you need more details, you can always just run `json.MarshalIndent(i, "", " ")` to see everything.
t.Logf("Container details: %+v", d)
} }
}
func cleanContainerQuiet(t *testing.T, cli *client.Client, ID string) {
timeout := 10 * time.Second
err := cli.ContainerStop(context.Background(), ID, &timeout)
if err != nil {
// Just log the error and continue
t.Log(err)
}
opts := types.ContainerRemoveOptions{
RemoveVolumes: true,
Force: true,
}
err = cli.ContainerRemove(context.Background(), ID, opts)
if err != nil {
t.Error(err)
}
}
func cleanContainer(t *testing.T, cli *client.Client, ID string) {
logContainerDetails(t, cli, ID)
t.Logf("Stopping container: %v", ID) t.Logf("Stopping container: %v", ID)
timeout := 10 * time.Second timeout := 10 * time.Second
// Stop the container. This allows the coverage output to be generated. // Stop the container. This allows the coverage output to be generated.
err = cli.ContainerStop(context.Background(), ID, &timeout) err := cli.ContainerStop(context.Background(), ID, &timeout)
if err != nil { if err != nil {
// Just log the error and continue // Just log the error and continue
t.Log(err) t.Log(err)
@@ -208,22 +259,6 @@ func cleanContainer(t *testing.T, cli *client.Client, ID string) {
} }
} }
// devImage returns true if the specified image is a developer image,
// determined by use of the MQ_ADMIN_PASSWORD or MQ_APP_PASSWORD
// environment variables
func devImage(t *testing.T, cli *client.Client, imageID string) bool {
i, _, err := cli.ImageInspectWithRaw(context.Background(), imageID)
if err != nil {
t.Fatal(err)
}
for _, e := range i.ContainerConfig.Env {
if strings.HasPrefix(e, "MQ_ADMIN_PASSWORD") || strings.HasPrefix(e, "MQ_APP_PASSWORD") {
return true
}
}
return false
}
// runContainerWithPorts creates and starts a container, exposing the specified ports on the host. // runContainerWithPorts creates and starts a container, exposing the specified ports on the host.
// If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE // If no image is specified in the container config, then the image name is retrieved from the TEST_IMAGE
// environment variable. // environment variable.
@@ -247,7 +282,7 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co
"ALL", "ALL",
}, },
} }
if devImage(t, cli, containerConfig.Image) { if devImage(t, cli) {
t.Logf("Detected MQ Advanced for Developers image — adding extra Linux capabilities to container") t.Logf("Detected MQ Advanced for Developers image — adding extra Linux capabilities to container")
hostConfig.CapAdd = []string{ hostConfig.CapAdd = []string{
"CHOWN", "CHOWN",
@@ -259,6 +294,8 @@ func runContainerWithPorts(t *testing.T, cli *client.Client, containerConfig *co
if baseImage(t, cli) != "ubuntu" { if baseImage(t, cli) != "ubuntu" {
hostConfig.CapAdd = append(hostConfig.CapAdd, "DAC_OVERRIDE") hostConfig.CapAdd = append(hostConfig.CapAdd, "DAC_OVERRIDE")
} }
} else {
t.Logf("Detected MQ Advanced image - dropping all capabilities")
} }
for _, p := range ports { for _, p := range ports {
port := nat.Port(fmt.Sprintf("%v/tcp", p)) port := nat.Port(fmt.Sprintf("%v/tcp", p))
@@ -295,14 +332,21 @@ func runContainerOneShot(t *testing.T, cli *client.Client, command ...string) (i
} }
hostConfig := container.HostConfig{} hostConfig := container.HostConfig{}
networkingConfig := network.NetworkingConfig{} networkingConfig := network.NetworkingConfig{}
t.Logf("Running one shot container (%s)", containerConfig.Image) t.Logf("Running one shot container (%s): %v", containerConfig.Image, command)
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()) ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShot")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
startContainer(t, cli, ctr.ID) startOptions := types.ContainerStartOptions{}
defer cleanContainer(t, cli, ctr.ID) err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
return waitForContainer(t, cli, ctr.ID, 10*time.Second), inspectLogs(t, cli, ctr.ID) if err != nil {
t.Fatal(err)
}
defer cleanContainerQuiet(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 10*time.Second)
out := inspectLogs(t, cli, ctr.ID)
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
return rc, out
} }
// runContainerOneShot runs a container with a custom entrypoint, as the root // runContainerOneShot runs a container with a custom entrypoint, as the root
@@ -320,14 +364,20 @@ func runContainerOneShotWithVolume(t *testing.T, cli *client.Client, bind string
} }
networkingConfig := network.NetworkingConfig{} networkingConfig := network.NetworkingConfig{}
t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command) t.Logf("Running one shot container with volume (%s): %v", containerConfig.Image, command)
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()) ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()+"OneShotVolume")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Logf("One shot container ID: %v", ctr.ID) startOptions := types.ContainerStartOptions{}
startContainer(t, cli, ctr.ID) err = cli.ContainerStart(context.Background(), ctr.ID, startOptions)
defer cleanContainer(t, cli, ctr.ID) if err != nil {
return waitForContainer(t, cli, ctr.ID, 10*time.Second), inspectLogs(t, cli, ctr.ID) t.Fatal(err)
}
defer cleanContainerQuiet(t, cli, ctr.ID)
rc := waitForContainer(t, cli, ctr.ID, 10*time.Second)
out := inspectLogs(t, cli, ctr.ID)
t.Logf("One shot container finished with rc=%v, output=%v", rc, out)
return rc, out
} }
func startContainer(t *testing.T, cli *client.Client, ID string) { func startContainer(t *testing.T, cli *client.Client, ID string) {

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# © Copyright IBM Corporation 2018 # © Copyright IBM Corporation 2018, 2019
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -22,24 +22,34 @@ set -e
# Use a "scratch" container, so the resulting image has minimal files # Use a "scratch" container, so the resulting image has minimal files
# Resulting image won't have yum, for example # Resulting image won't have yum, for example
readonly ctr_mq=$(buildah from rhel7) readonly ctr_mq=$(buildah from rhel7-minimal)
readonly mnt_mq=$(buildah mount $ctr_mq) readonly mnt_mq=$(buildah mount $ctr_mq)
readonly imagename=$1 readonly imagename=$1
buildah run $ctr_mq -- yum install -y \ microdnf_opts="--nodocs"
java-1.7.0-openjdk-devel \ # Check whether the host is registered with Red Hat
java \ if subscription-manager status ; then
which \ # Host is subscribed, but the minimal image has no enabled repos
wget # Note that the "bc" package is the only one in "extras"
microdnf_opts="${microdnf_opts} --enablerepo=rhel-7-server-rpms --enablerepo=rhel-7-server-extras-rpms"
else
# Use the Yum repositories configured on the host
cp -R /etc/yum.repos.d/* ${mnt_mq}/etc/yum.repos.d/
fi
buildah run ${ctr_mq} -- microdnf ${microdnf_opts} install \
java-1.8.0-openjdk-devel \
java \
which \
wget
buildah run $ctr_mq -- sh -c "cd /tmp && wget http://mirror.olnevhost.net/pub/apache/maven/binaries/apache-maven-3.2.2-bin.tar.gz" buildah run $ctr_mq -- sh -c "cd /tmp && wget https://www-eu.apache.org/dist/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz"
tar xvf $mnt_mq/tmp/apache-maven-3.2.2-bin.tar.gz -C $mnt_mq/tmp/ tar xvf $mnt_mq/tmp/apache-maven-3.6.0-bin.tar.gz -C $mnt_mq/tmp/
mkdir -p $mnt_mq/usr/src/mymaven mkdir -p $mnt_mq/usr/src/mymaven
cp pom.xml $mnt_mq/usr/src/mymaven/ cp pom.xml $mnt_mq/usr/src/mymaven/
cp -R src $mnt_mq/usr/src/mymaven/src cp -R src $mnt_mq/usr/src/mymaven/src
buildah run $ctr_mq -- sh -c "cd /usr/src/mymaven && export M2_HOME=/tmp/apache-maven-3.2.2 && export M2=\$M2_HOME/bin && export PATH=\$M2:\$PATH && mvn --version && mvn dependency:go-offline install && mvn --offline install" buildah run $ctr_mq -- sh -c "cd /usr/src/mymaven && export M2_HOME=/tmp/apache-maven-3.6.0 && export M2=\$M2_HOME/bin && export PATH=\$M2:\$PATH && mvn --version && mvn dependency:go-offline install && mvn --offline install"
mkdir -p $mnt_mq/opt/app mkdir -p $mnt_mq/opt/app
@@ -53,13 +63,9 @@ cp $mnt_mq/usr/src/mymaven/target/lib/*.jar $mnt_mq/opt/app/
rm -rf $mnt_mq/tmp/* rm -rf $mnt_mq/tmp/*
rm -rf $mnt_mq/usr/src/mymaven rm -rf $mnt_mq/usr/src/mymaven
# We can't uninstall tar or gzip because they are required
buildah run $ctr_mq -- yum remove -y \
wget
# Clean up cached files # Clean up cached files
buildah run $ctr_mq -- yum clean all buildah run ${ctr_mq} -- microdnf ${microdnf_opts} clean all
rm -rf ${mnt_mq}/var/cache/yum/* rm -rf ${mnt_mq}/etc/yum.repos.d/*
############################################################################### ###############################################################################
# Contain image finalization # Contain image finalization
@@ -69,6 +75,7 @@ buildah config \
--os linux \ --os linux \
--label architecture=x86_64 \ --label architecture=x86_64 \
--label name="${imagename%:*}" \ --label name="${imagename%:*}" \
--cmd "" \
--entrypoint '["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]' \ --entrypoint '["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"]' \
$ctr_mq $ctr_mq
buildah unmount $ctr_mq buildah unmount $ctr_mq