Add initial support for INI file merging (#349)

This commit is contained in:
KiranDarbha
2019-08-06 13:47:28 +05:30
committed by Arthur Barr
parent b8a7167c4e
commit 97941bc87c
8 changed files with 497 additions and 1 deletions

View File

@@ -19,7 +19,12 @@ package mqini
import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/ibm-messaging/mq-container/internal/command"
@@ -34,6 +39,12 @@ type QueueManager struct {
InstallationName string
}
var qmgrDir string
var stanzasQMINI []string
var stanzasMQATINI []string
// getQueueManagerFromStanza parses a queue manager stanza
func getQueueManagerFromStanza(stanza string) (*QueueManager, error) {
scanner := bufio.NewScanner(strings.NewReader(stanza))
@@ -76,3 +87,242 @@ func GetErrorLogDirectory(qm *QueueManager) string {
}
return filepath.Join(qm.Prefix, "qmgrs", qm.Directory, "errors")
}
//AddStanzas Reads supplied mq ini configuration files and updates the stanzas
//into queue manager's ini configuration files.
func AddStanzas(qmname string) error {
//find the qmgr directory.
qm, err := GetQueueManager(qmname)
if err != nil {
return err
}
qmgrDir = filepath.Join(qm.Prefix, "qmgrs", qm.Directory)
//Find the users ini configuration file
files := getIniFileList()
if len(files) > 1 {
msg := fmt.Sprintf("[ %v ]", files)
return errors.New("Only a single ini file can be provided. Following ini files are found:" + msg)
}
if len(files) == 0 {
//no ini file update required.
return nil
}
iniFileBytes, err := ioutil.ReadFile(files[0])
if err != nil {
return err
}
userconfig := string(iniFileBytes)
if len(userconfig) == 0 {
return nil
}
//Prepare a list of all supported stanzas
PopulateAllAvailableStanzas()
//Update the qmgr ini file with user config.
qmConfig, atConfig, err := PrepareConfigStanzasToWrite(userconfig)
if err != nil {
return err
}
err = writeConfigStanzas(qmConfig, atConfig)
if err != nil {
return err
}
return nil
}
// PopulateAllAvailableStanzas initializes the ini stanzas prescribed by mq specification.
func PopulateAllAvailableStanzas() {
stanzasQMINI = []string{"ExitPath",
"Log",
"Service",
"ServiceComponent",
"Channels",
"TCP",
"ApiExitLocal",
"AccessMode",
"RestrictedMode",
"XAResourceManager",
"DefaultBindType",
"SSL",
"DiagnosticMessages",
"Filesystem",
"Security",
"TuningParameters",
"ExitPropertiesLocal",
"LU62",
"NETBIOS"}
stanzasMQATINI = []string{"AllActivityTrace", "ApplicationTrace"}
}
// getIniFileList Checks for the user supplied ini file in /etc/mqm directory.
func getIniFileList() []string {
fileList := []string{}
filepath.Walk("/etc/mqm", func(path string, f os.FileInfo, err error) error {
if strings.HasSuffix(path, ".ini") {
fileList = append(fileList, path)
}
return nil
})
return fileList
}
//PrepareConfigStanzasToWrite Reads through the user supplied ini config file and prepares list of
//updates to be written into corresponding mq ini files (qm.ini and/or mqat.ini files.)
func PrepareConfigStanzasToWrite(userconfig string) (string, string, error) {
var qminiConfigStr string
var mqatiniConfigStr string
//read the initial version.
iniFileBytes, err := ioutil.ReadFile(filepath.Join(qmgrDir, "qm.ini"))
if err != nil {
return "", "", err
}
qminiConfigStr = string(iniFileBytes)
iniFileBytes, err = ioutil.ReadFile(filepath.Join(qmgrDir, "mqat.ini"))
if err != nil {
return "", "", err
}
mqatiniConfigStr = string(iniFileBytes)
stanzaListMerge := make(map[string]strings.Builder)
stanzaListAppend := make(map[string]strings.Builder)
var sbAppend strings.Builder
var sbMerger strings.Builder
scanner := bufio.NewScanner(strings.NewReader(userconfig))
scanner.Split(bufio.ScanLines)
consumetoAppend := false
consumeToMerge := false
var stanza string
//read through the user file and prepare what we want.
for scanner.Scan() {
if strings.Contains(scanner.Text(), ":") {
consumetoAppend = false
consumeToMerge = false
stanza = scanner.Text()
//check if this stanza exists in the qm.ini/mqat.ini files
if strings.Contains(qminiConfigStr, stanza) ||
(strings.Contains(mqatiniConfigStr, stanza) && !(strings.Contains(stanza, "ApplicationTrace"))) {
consumeToMerge = true
sbMerger = strings.Builder{}
stanzaListMerge[stanza] = sbMerger
} else {
consumetoAppend = true
sbAppend = strings.Builder{}
stanzaListAppend[stanza] = sbAppend
}
} else {
if consumetoAppend {
sb := stanzaListAppend[stanza]
sb.WriteString(scanner.Text() + "\n")
stanzaListAppend[stanza] = sb
}
if consumeToMerge {
sb := stanzaListMerge[stanza]
sb.WriteString(scanner.Text() + "\n")
stanzaListMerge[stanza] = sb
}
}
}
//merge if stanza exits.
if len(stanzaListMerge) > 0 {
for key := range stanzaListMerge {
toWrite, filename := ValidateStanzaToWrite(key)
if toWrite {
attrList := stanzaListMerge[key]
switch filename {
case "qm.ini":
qminiConfigStr = prepareStanzasToMerge(key, attrList, qminiConfigStr)
case "mqat.ini":
mqatiniConfigStr = prepareStanzasToMerge(key, attrList, mqatiniConfigStr)
default:
}
}
}
}
//append new stanzas.
if len(stanzaListAppend) > 0 {
for key := range stanzaListAppend {
attrList := stanzaListAppend[key]
if strings.Contains(strings.Join(stanzasMQATINI, ", "), strings.TrimSuffix(strings.TrimSpace(key), ":")) {
mqatiniConfigStr = prepareStanzasToAppend(key, attrList, mqatiniConfigStr)
} else {
qminiConfigStr = prepareStanzasToAppend(key, attrList, qminiConfigStr)
}
}
}
return qminiConfigStr, mqatiniConfigStr, nil
}
//ValidateStanzaToWrite Validates stanza to be written and the file it belongs to.
func ValidateStanzaToWrite(stanza string) (bool, string) {
stanza = strings.TrimSpace(stanza)
if strings.Contains(stanza, ":") {
stanza = stanza[:len(stanza)-1]
}
if strings.Contains(strings.Join(stanzasQMINI, ", "), stanza) {
return true, "qm.ini"
} else if strings.Contains(strings.Join(stanzasMQATINI, ", "), stanza) {
return true, "mqat.ini"
} else {
return false, ""
}
}
//prepareStanzasToAppend Prepares list of stanzas that are to be appended into qm ini files(qm.ini/mqat.ini)
func prepareStanzasToAppend(key string, attrList strings.Builder, iniConfig string) string {
newVal := key + "\n" + attrList.String()
iniConfig = iniConfig + newVal
return iniConfig
}
//prepareStanzasToMerge Prepares list of stanzas that are to be updated into qm ini files(qm.ini/mqat.ini)
//These stanzas are already present in mq ini files and their values have to be updated with user supplied ini.
func prepareStanzasToMerge(key string, attrList strings.Builder, iniConfig string) string {
lineScanner := bufio.NewScanner(strings.NewReader(attrList.String()))
lineScanner.Split(bufio.ScanLines)
for lineScanner.Scan() {
attrLine := lineScanner.Text()
keyvalue := strings.Split(attrLine, "=")
//this line present in qm.ini, update value.
if strings.Contains(iniConfig, keyvalue[0]) {
re := regexp.MustCompile(keyvalue[0] + "=.*")
iniConfig = re.ReplaceAllString(iniConfig, attrLine)
} else { //this line not present in qm.ini file, add it.
re := regexp.MustCompile(key)
newVal := key + "\n" + attrLine
iniConfig = re.ReplaceAllString(iniConfig, newVal)
}
}
return iniConfig
}
//writeConfigStanzas Writes the ini file updates into corresponding mq ini files.
func writeConfigStanzas(qmConfig string, atConfig string) error {
err := ioutil.WriteFile(filepath.Join(qmgrDir, "qm.ini"), []byte(qmConfig), 0644)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(qmgrDir, "mqat.ini"), []byte(atConfig), 0644)
if err != nil {
return err
}
return nil
}