Add logic to set custom Log File Page number (#371)
* Add logic to set custom Log File Page number Signed-off-by: Nicholas-Daffern <Nicholas.Daffern@ibm.com>
This commit is contained in:
committed by
GitHub Enterprise
parent
862427306b
commit
ed618dc6f6
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2022
|
© Copyright IBM Corporation 2017, 2023
|
||||||
|
|
||||||
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.
|
||||||
@@ -55,23 +55,36 @@ func createDirStructure() error {
|
|||||||
func createQueueManager(name string, devMode bool) (bool, error) {
|
func createQueueManager(name string, devMode bool) (bool, error) {
|
||||||
log.Printf("Creating queue manager %v", name)
|
log.Printf("Creating queue manager %v", name)
|
||||||
|
|
||||||
// Run 'dspmqinf' to check if 'mqs.ini' configuration file exists
|
|
||||||
// If command succeeds, the queue manager (or standby queue manager) has already been created
|
|
||||||
_, _, err := command.Run("dspmqinf", name)
|
|
||||||
if err == nil {
|
|
||||||
log.Printf("Detected existing queue manager %v", name)
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
mounts, err := containerruntime.GetMounts()
|
mounts, err := containerruntime.GetMounts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error getting mounts for queue manager")
|
log.Printf("Error getting mounts for queue manager")
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dataDir := getQueueManagerDataDir(mounts, name)
|
||||||
|
|
||||||
|
// Run 'dspmqinf' to check if 'mqs.ini' configuration file exists
|
||||||
|
// If command succeeds, the queue manager (or standby queue manager) has already been created
|
||||||
|
_, _, err = command.Run("dspmqinf", name)
|
||||||
|
if err == nil {
|
||||||
|
log.Printf("Detected existing queue manager %v", name)
|
||||||
|
// Check if MQ_QMGR_LOG_FILE_PAGES matches the value set in qm.ini
|
||||||
|
lfp := os.Getenv("MQ_QMGR_LOG_FILE_PAGES")
|
||||||
|
if lfp != "" {
|
||||||
|
qmIniBytes, err := readQMIni(dataDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error reading qm.ini : %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !validateLogFilePageSetting(qmIniBytes, lfp) {
|
||||||
|
log.Println("Warning: the value of MQ_QMGR_LOG_FILE_PAGES does not match the value of 'LogFilePages' in the qm.ini. This setting cannot be altered after Queue Manager creation.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Check if 'qm.ini' configuration file exists for the queue manager
|
// Check if 'qm.ini' configuration file exists for the queue manager
|
||||||
// TODO : handle possible race condition - use a file lock?
|
// TODO : handle possible race condition - use a file lock?
|
||||||
dataDir := getQueueManagerDataDir(mounts, name)
|
|
||||||
_, err = os.Stat(filepath.Join(dataDir, "qm.ini"))
|
_, err = os.Stat(filepath.Join(dataDir, "qm.ini"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If 'qm.ini' is not found - run 'crtmqm' to create a new queue manager
|
// If 'qm.ini' is not found - run 'crtmqm' to create a new queue manager
|
||||||
@@ -96,6 +109,25 @@ func createQueueManager(name string, devMode bool) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//readQMIni reads the qm.ini file and returns it as a byte array
|
||||||
|
//This function is specific to comply with the nosec.
|
||||||
|
func readQMIni(dataDir string) ([]byte, error) {
|
||||||
|
qmgrDir := filepath.Join(dataDir, "qm.ini")
|
||||||
|
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
|
||||||
|
iniFileBytes, err := ioutil.ReadFile(qmgrDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return iniFileBytes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//validateLogFilePageSetting validates if the specified logFilePage number is equal to the existing value in the qm.ini
|
||||||
|
func validateLogFilePageSetting(iniFileBytes []byte, logFilePages string) bool {
|
||||||
|
lfpString := "LogFilePages=" + logFilePages
|
||||||
|
qminiConfigStr := string(iniFileBytes)
|
||||||
|
return strings.Contains(qminiConfigStr, lfpString)
|
||||||
|
}
|
||||||
|
|
||||||
func updateCommandLevel() error {
|
func updateCommandLevel() error {
|
||||||
level, ok := os.LookupEnv("MQ_CMDLEVEL")
|
level, ok := os.LookupEnv("MQ_CMDLEVEL")
|
||||||
if ok && level != "" {
|
if ok && level != "" {
|
||||||
@@ -238,6 +270,14 @@ func getCreateQueueManagerArgs(mounts map[string]string, name string, devMode bo
|
|||||||
if _, ok := mounts["/mnt/mqm-data"]; ok {
|
if _, ok := mounts["/mnt/mqm-data"]; ok {
|
||||||
args = append(args, "-md", "/mnt/mqm-data/qmgrs")
|
args = append(args, "-md", "/mnt/mqm-data/qmgrs")
|
||||||
}
|
}
|
||||||
|
if os.Getenv("MQ_QMGR_LOG_FILE_PAGES") != "" {
|
||||||
|
_, err = strconv.Atoi(os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error processing MQ_QMGR_LOG_FILE_PAGES, the default value for LogFilePages will be used. Err: %v", err)
|
||||||
|
} else {
|
||||||
|
args = append(args, "-lf", os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
|
||||||
|
}
|
||||||
|
}
|
||||||
args = append(args, name)
|
args = append(args, name)
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|||||||
86
cmd/runmqserver/qmgr_test.go
Normal file
86
cmd/runmqserver/qmgr_test.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2023
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_validateLogFilePageSetting(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
iniFilePath string
|
||||||
|
isValid bool
|
||||||
|
logFilePagesValue string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "TestLogFilePages1",
|
||||||
|
args: args{
|
||||||
|
iniFilePath: "./test-files/testvalidateLogFilePages_1.ini",
|
||||||
|
isValid: true,
|
||||||
|
logFilePagesValue: "1235",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TestLogFilePages2",
|
||||||
|
args: args{
|
||||||
|
iniFilePath: "./test-files/testvalidateLogFilePages_2.ini",
|
||||||
|
isValid: true,
|
||||||
|
logFilePagesValue: "2224",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TestLogFilePages3",
|
||||||
|
args: args{
|
||||||
|
iniFilePath: "./test-files/testvalidateLogFilePages_3.ini",
|
||||||
|
isValid: false,
|
||||||
|
logFilePagesValue: "1235",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TestLogFilePages4",
|
||||||
|
args: args{
|
||||||
|
iniFilePath: "./test-files/testvalidateLogFilePages_4.ini",
|
||||||
|
isValid: false,
|
||||||
|
logFilePagesValue: "1235",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TestLogFilePages5",
|
||||||
|
args: args{
|
||||||
|
iniFilePath: "./test-files/testvalidateLogFilePages_5.ini",
|
||||||
|
isValid: false,
|
||||||
|
logFilePagesValue: "1235",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
iniFileBytes, err := ioutil.ReadFile(tt.args.iniFilePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
validate := validateLogFilePageSetting(iniFileBytes, tt.args.logFilePagesValue)
|
||||||
|
if validate != tt.args.isValid {
|
||||||
|
t.Fatalf("Expected ini file validation output to be %v got %v", tt.args.isValid, validate)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
ExitPath:
|
||||||
|
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||||
|
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||||
|
Log:
|
||||||
|
LogPrimaryFiles=3
|
||||||
|
LogSecondaryFiles=2
|
||||||
|
LogFilePages=1235
|
||||||
|
LogBufferPages=0
|
||||||
|
LogWriteIntegrity=TripleWrite
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
ExitPath:
|
||||||
|
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||||
|
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||||
|
Log:
|
||||||
|
LogPrimaryFiles=3
|
||||||
|
LogSecondaryFiles=2
|
||||||
|
LogFilePages=2224
|
||||||
|
LogBufferPages=0
|
||||||
|
LogWriteIntegrity=TripleWrite
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
ExitPath:
|
||||||
|
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||||
|
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||||
|
Log:
|
||||||
|
LogPrimaryFiles=3
|
||||||
|
LogSecondaryFiles=2
|
||||||
|
LogFilePages=6002
|
||||||
|
LogBufferPages=0
|
||||||
|
LogWriteIntegrity=TripleWrite
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
ExitPath:
|
||||||
|
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||||
|
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||||
|
Log:
|
||||||
|
LogPrimaryFiles=3
|
||||||
|
LogSecondaryFiles=2
|
||||||
|
LogBufferPages=0
|
||||||
|
LogWriteIntegrity=TripleWrite
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
ExitPath:
|
||||||
|
ExitsDefaultPath=/mnt/mqm/data/exits
|
||||||
|
ExitsDefaultPath64=/mnt/mqm/data/exits64
|
||||||
|
Log:
|
||||||
|
LogPrimaryFiles=3
|
||||||
|
LogSecondaryFiles=2
|
||||||
|
LogBufferPages=1235
|
||||||
|
LogWriteIntegrity=TripleWrite
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2022
|
© Copyright IBM Corporation 2017, 2023
|
||||||
|
|
||||||
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.
|
||||||
@@ -77,45 +77,20 @@ func TestLicenseView(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a container with qm grace set to x seconds
|
|
||||||
// Check that when the container is stopped that the command endmqm has option -tp and x
|
|
||||||
func TestEndMQMOpts(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
containerConfig := container.Config{
|
|
||||||
Env: []string{"LICENSE=accept", "MQ_GRACE_PERIOD=27"},
|
|
||||||
}
|
|
||||||
|
|
||||||
id := runContainer(t, cli, &containerConfig)
|
|
||||||
defer cleanContainer(t, cli, id)
|
|
||||||
waitForReady(t, cli, id)
|
|
||||||
killContainer(t, cli, id, "SIGTERM")
|
|
||||||
_, out := execContainer(t, cli, id, "", []string{"bash", "-c", "ps -ef | grep 'endmqm -w -r -tp 27'"})
|
|
||||||
t.Log(out)
|
|
||||||
if !strings.Contains(out, "endmqm -w -r -tp 27") {
|
|
||||||
t.Errorf("Expected endmqm options endmqm -w -r -tp 27; got \"%v\"", out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGoldenPath starts a queue manager successfully when metrics are enabled
|
// TestGoldenPath starts a queue manager successfully when metrics are enabled
|
||||||
func TestGoldenPathWithMetrics(t *testing.T) {
|
func TestGoldenPathWithMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
goldenPath(t, true)
|
goldenPath(t, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestGoldenPath starts a queue manager successfully when metrics are disabled
|
// TestGoldenPath starts a queue manager successfully when metrics are disabled
|
||||||
func TestGoldenPathNoMetrics(t *testing.T) {
|
func TestGoldenPathNoMetrics(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
goldenPath(t, false)
|
goldenPath(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual test function for TestGoldenPathNoMetrics & TestGoldenPathWithMetrics
|
// Actual test function for TestGoldenPathNoMetrics & TestGoldenPathWithMetrics
|
||||||
func goldenPath(t *testing.T, metric bool) {
|
func goldenPath(t *testing.T, metrics bool) {
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -123,13 +98,17 @@ func goldenPath(t *testing.T, metric bool) {
|
|||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
|
||||||
}
|
}
|
||||||
if metric {
|
if metrics {
|
||||||
containerConfig.Env = append(containerConfig.Env, "MQ_ENABLE_METRICS=true")
|
containerConfig.Env = append(containerConfig.Env, "MQ_ENABLE_METRICS=true")
|
||||||
}
|
}
|
||||||
|
|
||||||
id := runContainer(t, cli, &containerConfig)
|
id := runContainer(t, cli, &containerConfig)
|
||||||
defer cleanContainer(t, cli, id)
|
defer cleanContainer(t, cli, id)
|
||||||
waitForReady(t, cli, id)
|
waitForReady(t, cli, id)
|
||||||
|
|
||||||
|
t.Run("Validate Default LogFilePages", func(t *testing.T) {
|
||||||
|
testLogFilePages(t, cli, id, "qm1", "4096")
|
||||||
|
})
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
}
|
}
|
||||||
@@ -1482,3 +1461,45 @@ func TestStartedCheckWithNoNewPrivileges(t *testing.T) {
|
|||||||
func TestStartedCheckWithNewPrivileges(t *testing.T) {
|
func TestStartedCheckWithNewPrivileges(t *testing.T) {
|
||||||
utilTestStartedCheck(t, false)
|
utilTestStartedCheck(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start a container with qm grace set to x seconds
|
||||||
|
// Check that when the container is stopped that the command endmqm has option -tp and x
|
||||||
|
func TestEndMQMOpts(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{"LICENSE=accept", "MQ_GRACE_PERIOD=27"},
|
||||||
|
}
|
||||||
|
|
||||||
|
id := runContainer(t, cli, &containerConfig)
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
waitForReady(t, cli, id)
|
||||||
|
killContainer(t, cli, id, "SIGTERM")
|
||||||
|
_, out := execContainer(t, cli, id, "", []string{"bash", "-c", "ps -ef | grep 'endmqm -w -r -tp 27'"})
|
||||||
|
t.Log(out)
|
||||||
|
if !strings.Contains(out, "endmqm -w -r -tp 27") {
|
||||||
|
t.Errorf("Expected endmqm options endmqm -w -r -tp 27; got \"%v\"", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TestCustomLogFilePages starts a qmgr with a custom number of logfilepages set.
|
||||||
|
//Check that the number of logfilepages matches.
|
||||||
|
func TestCustomLogFilePages(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{"LICENSE=accept", "MQ_QMGR_LOG_FILE_PAGES=8192", "MQ_QMGR_NAME=qmlfp"},
|
||||||
|
}
|
||||||
|
|
||||||
|
id := runContainer(t, cli, &containerConfig)
|
||||||
|
defer cleanContainer(t, cli, id)
|
||||||
|
waitForReady(t, cli, id)
|
||||||
|
|
||||||
|
testLogFilePages(t, cli, id, "qmlfp", "8192")
|
||||||
|
}
|
||||||
|
|||||||
@@ -928,3 +928,13 @@ func startContainerError(t *testing.T, cli *client.Client, ID string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//testLogFilePages validates that the specified number of logFilePages is present in the qm.ini file.
|
||||||
|
func testLogFilePages(t *testing.T, cli *client.Client, id string, qmName string, expectedLogFilePages string) {
|
||||||
|
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/" + qmName + "/qm.ini")
|
||||||
|
_, iniContent := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand})
|
||||||
|
|
||||||
|
if !strings.Contains(iniContent, "LogFilePages="+expectedLogFilePages) {
|
||||||
|
t.Errorf("Expected qm.ini to contain LogFilePages="+expectedLogFilePages+"; got qm.ini \"%v\"", iniContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user