Skip to content

Commit f67455c

Browse files
ajohnson1NDaffernIBM
authored andcommitted
Add logic to set custom Log File Page number (back port from #371) (#443)
* Add logic to set custom Log File Page number Signed-off-by: Nicholas-Daffern <[email protected] Co-authored-by: Nicholas Daffern <[email protected]>
1 parent 9946434 commit f67455c

File tree

9 files changed

+214
-14
lines changed

9 files changed

+214
-14
lines changed

cmd/runmqserver/qmgr.go

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
© Copyright IBM Corporation 2017, 2020
2+
© Copyright IBM Corporation 2017, 2023
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -54,23 +54,36 @@ func createDirStructure() error {
5454
func createQueueManager(name string, devMode bool) (bool, error) {
5555
log.Printf("Creating queue manager %v", name)
5656

57+
mounts, err := containerruntime.GetMounts()
58+
if err != nil {
59+
log.Printf("Error getting mounts for queue manager")
60+
return false, err
61+
}
62+
63+
dataDir := getQueueManagerDataDir(mounts, name)
64+
5765
// Run 'dspmqinf' to check if 'mqs.ini' configuration file exists
5866
// If command succeeds, the queue manager (or standby queue manager) has already been created
59-
_, _, err := command.Run("dspmqinf", name)
67+
_, _, err = command.Run("dspmqinf", name)
6068
if err == nil {
6169
log.Printf("Detected existing queue manager %v", name)
70+
// Check if MQ_QMGR_LOG_FILE_PAGES matches the value set in qm.ini
71+
lfp := os.Getenv("MQ_QMGR_LOG_FILE_PAGES")
72+
if lfp != "" {
73+
qmIniBytes, err := readQMIni(dataDir)
74+
if err != nil {
75+
log.Printf("Error reading qm.ini : %v", err)
76+
return false, err
77+
}
78+
if !validateLogFilePageSetting(qmIniBytes, lfp) {
79+
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.")
80+
}
81+
}
6282
return false, nil
6383
}
6484

65-
mounts, err := containerruntime.GetMounts()
66-
if err != nil {
67-
log.Printf("Error getting mounts for queue manager")
68-
return false, err
69-
}
70-
7185
// Check if 'qm.ini' configuration file exists for the queue manager
7286
// TODO : handle possible race condition - use a file lock?
73-
dataDir := getQueueManagerDataDir(mounts, name)
7487
_, err = os.Stat(filepath.Join(dataDir, "qm.ini"))
7588
if err != nil {
7689
// If 'qm.ini' is not found - run 'crtmqm' to create a new queue manager
@@ -95,6 +108,25 @@ func createQueueManager(name string, devMode bool) (bool, error) {
95108
return true, nil
96109
}
97110

111+
//readQMIni reads the qm.ini file and returns it as a byte array
112+
//This function is specific to comply with the nosec.
113+
func readQMIni(dataDir string) ([]byte, error) {
114+
qmgrDir := filepath.Join(dataDir, "qm.ini")
115+
// #nosec G304 - qmgrDir filepath is derived from dspmqinf
116+
iniFileBytes, err := ioutil.ReadFile(qmgrDir)
117+
if err != nil {
118+
return nil, err
119+
}
120+
return iniFileBytes, err
121+
}
122+
123+
//validateLogFilePageSetting validates if the specified logFilePage number is equal to the existing value in the qm.ini
124+
func validateLogFilePageSetting(iniFileBytes []byte, logFilePages string) bool {
125+
lfpString := "LogFilePages=" + logFilePages
126+
qminiConfigStr := string(iniFileBytes)
127+
return strings.Contains(qminiConfigStr, lfpString)
128+
}
129+
98130
func updateCommandLevel() error {
99131
level, ok := os.LookupEnv("MQ_CMDLEVEL")
100132
if ok && level != "" {
@@ -237,6 +269,14 @@ func getCreateQueueManagerArgs(mounts map[string]string, name string, devMode bo
237269
if _, ok := mounts["/mnt/mqm-data"]; ok {
238270
args = append(args, "-md", "/mnt/mqm-data/qmgrs")
239271
}
272+
if os.Getenv("MQ_QMGR_LOG_FILE_PAGES") != "" {
273+
_, err = strconv.Atoi(os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
274+
if err != nil {
275+
log.Printf("Error processing MQ_QMGR_LOG_FILE_PAGES, the default value for LogFilePages will be used. Err: %v", err)
276+
} else {
277+
args = append(args, "-lf", os.Getenv("MQ_QMGR_LOG_FILE_PAGES"))
278+
}
279+
}
240280
args = append(args, name)
241281
return args
242282
}

cmd/runmqserver/qmgr_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
© Copyright IBM Corporation 2023
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package main
17+
18+
import (
19+
"io/ioutil"
20+
"testing"
21+
)
22+
23+
func Test_validateLogFilePageSetting(t *testing.T) {
24+
type args struct {
25+
iniFilePath string
26+
isValid bool
27+
logFilePagesValue string
28+
}
29+
tests := []struct {
30+
name string
31+
args args
32+
}{
33+
{
34+
name: "TestLogFilePages1",
35+
args: args{
36+
iniFilePath: "./test-files/testvalidateLogFilePages_1.ini",
37+
isValid: true,
38+
logFilePagesValue: "1235",
39+
},
40+
},
41+
{
42+
name: "TestLogFilePages2",
43+
args: args{
44+
iniFilePath: "./test-files/testvalidateLogFilePages_2.ini",
45+
isValid: true,
46+
logFilePagesValue: "2224",
47+
},
48+
},
49+
{
50+
name: "TestLogFilePages3",
51+
args: args{
52+
iniFilePath: "./test-files/testvalidateLogFilePages_3.ini",
53+
isValid: false,
54+
logFilePagesValue: "1235",
55+
},
56+
},
57+
{
58+
name: "TestLogFilePages4",
59+
args: args{
60+
iniFilePath: "./test-files/testvalidateLogFilePages_4.ini",
61+
isValid: false,
62+
logFilePagesValue: "1235",
63+
},
64+
},
65+
{
66+
name: "TestLogFilePages5",
67+
args: args{
68+
iniFilePath: "./test-files/testvalidateLogFilePages_5.ini",
69+
isValid: false,
70+
logFilePagesValue: "1235",
71+
},
72+
},
73+
}
74+
for _, tt := range tests {
75+
t.Run(tt.name, func(t *testing.T) {
76+
iniFileBytes, err := ioutil.ReadFile(tt.args.iniFilePath)
77+
if err != nil {
78+
t.Fatal(err)
79+
}
80+
validate := validateLogFilePageSetting(iniFileBytes, tt.args.logFilePagesValue)
81+
if validate != tt.args.isValid {
82+
t.Fatalf("Expected ini file validation output to be %v got %v", tt.args.isValid, validate)
83+
}
84+
})
85+
}
86+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ExitPath:
2+
ExitsDefaultPath=/mnt/mqm/data/exits
3+
ExitsDefaultPath64=/mnt/mqm/data/exits64
4+
Log:
5+
LogPrimaryFiles=3
6+
LogSecondaryFiles=2
7+
LogFilePages=1235
8+
LogBufferPages=0
9+
LogWriteIntegrity=TripleWrite
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ExitPath:
2+
ExitsDefaultPath=/mnt/mqm/data/exits
3+
ExitsDefaultPath64=/mnt/mqm/data/exits64
4+
Log:
5+
LogPrimaryFiles=3
6+
LogSecondaryFiles=2
7+
LogFilePages=2224
8+
LogBufferPages=0
9+
LogWriteIntegrity=TripleWrite
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ExitPath:
2+
ExitsDefaultPath=/mnt/mqm/data/exits
3+
ExitsDefaultPath64=/mnt/mqm/data/exits64
4+
Log:
5+
LogPrimaryFiles=3
6+
LogSecondaryFiles=2
7+
LogFilePages=6002
8+
LogBufferPages=0
9+
LogWriteIntegrity=TripleWrite
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ExitPath:
2+
ExitsDefaultPath=/mnt/mqm/data/exits
3+
ExitsDefaultPath64=/mnt/mqm/data/exits64
4+
Log:
5+
LogPrimaryFiles=3
6+
LogSecondaryFiles=2
7+
LogBufferPages=0
8+
LogWriteIntegrity=TripleWrite
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ExitPath:
2+
ExitsDefaultPath=/mnt/mqm/data/exits
3+
ExitsDefaultPath64=/mnt/mqm/data/exits64
4+
Log:
5+
LogPrimaryFiles=3
6+
LogSecondaryFiles=2
7+
LogBufferPages=1235
8+
LogWriteIntegrity=TripleWrite

test/docker/docker_api_test.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
© Copyright IBM Corporation 2017, 2022
2+
© Copyright IBM Corporation 2017, 2023
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -101,33 +101,35 @@ func TestEndMQMOpts(t *testing.T) {
101101
// TestGoldenPath starts a queue manager successfully when metrics are enabled
102102
func TestGoldenPathWithMetrics(t *testing.T) {
103103
t.Parallel()
104-
105104
goldenPath(t, true)
106105
}
107106

108107
// TestGoldenPath starts a queue manager successfully when metrics are disabled
109108
func TestGoldenPathNoMetrics(t *testing.T) {
110109
t.Parallel()
111-
112110
goldenPath(t, false)
113111
}
114112

115113
// Actual test function for TestGoldenPathNoMetrics & TestGoldenPathWithMetrics
116-
func goldenPath(t *testing.T, metric bool) {
114+
func goldenPath(t *testing.T, metrics bool) {
117115
cli, err := client.NewClientWithOpts(client.FromEnv)
118116
if err != nil {
119117
t.Fatal(err)
120118
}
121119
containerConfig := container.Config{
122120
Env: []string{"LICENSE=accept", "MQ_QMGR_NAME=qm1"},
123121
}
124-
if metric {
122+
if metrics {
125123
containerConfig.Env = append(containerConfig.Env, "MQ_ENABLE_METRICS=true")
126124
}
127125

128126
id := runContainer(t, cli, &containerConfig)
129127
defer cleanContainer(t, cli, id)
130128
waitForReady(t, cli, id)
129+
130+
t.Run("Validate Default LogFilePages", func(t *testing.T) {
131+
testLogFilePages(t, cli, id, "qm1", "4096")
132+
})
131133
// Stop the container cleanly
132134
stopContainer(t, cli, id)
133135
}
@@ -1516,3 +1518,22 @@ func TestStartedCheckWithNoNewPrivileges(t *testing.T) {
15161518
func TestStartedCheckWithNewPrivileges(t *testing.T) {
15171519
utilTestStartedCheck(t, false)
15181520
}
1521+
1522+
//TestCustomLogFilePages starts a qmgr with a custom number of logfilepages set.
1523+
//Check that the number of logfilepages matches.
1524+
func TestCustomLogFilePages(t *testing.T) {
1525+
t.Parallel()
1526+
cli, err := client.NewClientWithOpts(client.FromEnv)
1527+
if err != nil {
1528+
t.Fatal(err)
1529+
}
1530+
containerConfig := container.Config{
1531+
Env: []string{"LICENSE=accept", "MQ_QMGR_LOG_FILE_PAGES=8192", "MQ_QMGR_NAME=qmlfp"},
1532+
}
1533+
1534+
id := runContainer(t, cli, &containerConfig)
1535+
defer cleanContainer(t, cli, id)
1536+
waitForReady(t, cli, id)
1537+
1538+
testLogFilePages(t, cli, id, "qmlfp", "8192")
1539+
}

test/docker/docker_api_test_util.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,3 +889,13 @@ func getMQVersion(t *testing.T, cli *client.Client) (string, error) {
889889
version := inspect.ContainerConfig.Labels["version"]
890890
return version, nil
891891
}
892+
893+
//testLogFilePages validates that the specified number of logFilePages is present in the qm.ini file.
894+
func testLogFilePages(t *testing.T, cli *client.Client, id string, qmName string, expectedLogFilePages string) {
895+
catIniFileCommand := fmt.Sprintf("cat /var/mqm/qmgrs/" + qmName + "/qm.ini")
896+
_, iniContent := execContainer(t, cli, id, "", []string{"bash", "-c", catIniFileCommand})
897+
898+
if !strings.Contains(iniContent, "LogFilePages="+expectedLogFilePages) {
899+
t.Errorf("Expected qm.ini to contain LogFilePages="+expectedLogFilePages+"; got qm.ini \"%v\"", iniContent)
900+
}
901+
}

0 commit comments

Comments
 (0)