/
centerliazed_log.go
241 lines (196 loc) · 8.64 KB
/
centerliazed_log.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
package main
import (
"bytes"
"fmt"
dc "github.com/chef/automate/api/config/deployment"
"github.com/chef/automate/api/config/shared"
config "github.com/chef/automate/api/config/shared"
"github.com/chef/toml"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"io/ioutil"
)
const (
rsyslogConfigFile = "/etc/rsyslog.d/automate.conf"
logRotateConfigFile = "/etc/logrotate.d/automate"
postgresLogConfig = "/hab/a2_deploy_workspace/postgres_log.toml"
opensearchConfig = "/hab/a2_deploy_workspace/opensearch_log.toml"
restartSyslogService = "sudo systemctl restart rsyslog.service"
)
// enableCentralizedLogConfigForHA checks for requested and existing configuration for logging
func enableCentralizedLogConfigForHA(args []string, remoteType string, sshUtil SSHUtil, remoteIp []string) error {
reqConfig, err := getConfigForArgsLogs(args, remoteType)
if err != nil {
return err
}
//Returning if there is no config set for logging
if reqConfig.GetGlobal().GetV1().GetLog() == nil {
return nil
}
existConfig, err := getPostgresOrOpenSearchExistingLogConfig(remoteType)
if err != nil {
return err
}
err = enableCentralizedLogging(reqConfig, existConfig, sshUtil, remoteIp, remoteType)
if err != nil {
return err
}
return nil
}
// enableCentralizedLogging gets commands for rsyslog ang logrotate
func enableCentralizedLogging(reqConfig *dc.AutomateConfig, existConfig *dc.AutomateConfig, sshUtil SSHUtil, remoteIp []string, remoteType string) error {
scriptCommands := getScriptCommandsForLogging(reqConfig, existConfig)
if scriptCommands == "" {
//if there are no script commands do nothing
return nil
}
err := createRsyslogAndLogRotateConfig(sshUtil, remoteIp, scriptCommands, remoteType)
if err != nil {
return err
}
if remoteType == "postgresql" {
_, err := createTomlFileFromConfig(&reqConfig, postgresLogConfig)
if err != nil {
writer.Errorf("Unable to created toml file for postgresql toml %v", err)
}
} else {
_, err := createTomlFileFromConfig(&reqConfig, opensearchConfig)
if err != nil {
writer.Errorf("Unable to created toml file for postgresql toml %v", err)
}
}
return nil
}
// getScriptCommandsForLogging gets the commands to be executed for logging
func getScriptCommandsForLogging(reqConfig *dc.AutomateConfig, existConfig *dc.AutomateConfig) string {
var scriptCommands string
if existConfig.GetGlobal().GetV1().GetLog() != nil {
merged := &dc.AutomateConfig{}
//Merging both the config into the requested config for comparing
config.Merge(existConfig, reqConfig, merged)
*reqConfig = *merged
//If config changed reapplying the config accordingly
if isConfigChanged(reqConfig.GetGlobal().GetV1().GetLog(), existConfig.GetGlobal().GetV1().GetLog()) {
scriptCommands = getScriptCommandsForConfigChangedLogging(reqConfig, existConfig)
} else {
//if config in unchanged do nothing and returns
return ""
}
} else if existConfig.GetGlobal().GetV1().GetLog() == nil && reqConfig.GetGlobal().GetV1().GetLog().GetRedirectSysLog().GetValue() == true {
reqConfig.GetGlobal().ValidateReDirectSysLogConfig()
scriptCommands = createScriptCommandsForCentralizedLog(reqConfig)
}
return scriptCommands
}
// getScriptCommandsForConfigChangedLogging gets the script commands where only some values are changed
func getScriptCommandsForConfigChangedLogging(reqConfig *dc.AutomateConfig, existConfig *dc.AutomateConfig) string {
var scriptCommands string
//Disable the centralized logging if requested
// if only logrotate policies are requested and there is no change in the file path created
// if file path changes are requested
if reqConfig.GetGlobal().GetV1().GetLog().GetRedirectSysLog().GetValue() == false &&
existConfig.GetGlobal().GetV1().GetLog().GetRedirectSysLog().GetValue() == true {
scriptCommands = rollBackCentralized()
} else if reqConfig.GetGlobal().GetV1().GetLog().GetRedirectLogFilePath().GetValue() == existConfig.GetGlobal().GetV1().GetLog().GetRedirectLogFilePath().GetValue() {
logrotateFileCommand := fmt.Sprintf("echo \"%s\" > %s", configLogrotate(reqConfig.GetGlobal().GetV1().GetLog()), logRotateConfigFile)
return fmt.Sprintf("sudo sh -c '%s'", logrotateFileCommand)
} else {
scriptCommands = createScriptCommandsForCentralizedLog(reqConfig)
}
return scriptCommands
}
// configLogrotate Adds a config file for logrotate as /etc/logrotate.d/automate
// it handles all the config for rotating logs.
func configLogrotate(req *shared.Log) string {
var logRotateConfigContent string
if req.GetCompressRotatedLogs().GetValue() == true {
logRotateConfigContent = LogRotateConf(getLogFileName(req.GetRedirectLogFilePath().GetValue()),
getConcatStringFromConfig("size", req.GetMaxSizeRotateLogs().GetValue()), getConcatStringFromConfig("rotate", req.GetMaxNumberRotatedLogs().GetValue()), "missingok", "copytruncate", "compress", "dateext")
} else {
logRotateConfigContent = LogRotateConf(getLogFileName(req.GetRedirectLogFilePath().GetValue()),
getConcatStringFromConfig("size", req.GetMaxSizeRotateLogs().GetValue()), getConcatStringFromConfig("rotate", req.GetMaxNumberRotatedLogs().GetValue()), "missingok", "copytruncate", "dateext")
}
// Write the byteSlice to file
logrus.Infof("log rotated file content created")
return logRotateConfigContent
}
// createConfigFileForAutomateSysLog created a config file as /etc/rsyslog.d/automate.conf
// which redirects the logs to the specified location
func createConfigFileForAutomateSysLog(pathForLog string) string {
return fmt.Sprintf(`if \$programname == \"bash\" then %s
& stop`, getLogFileName(pathForLog))
}
// LogRotateConf gets the log rotate configuration using the values from config
func LogRotateConf(path string, params ...string) string {
if len(params) < 1 {
return ""
}
var buffer bytes.Buffer
buffer.WriteString(path + " {" + "\n")
for _, param := range params {
buffer.WriteString("\t" + param + "\n")
}
buffer.WriteString("}" + "\n")
return buffer.String()
}
// getLogFileName gets the log file name based on the path provided
func getLogFileName(path string) string {
if string(path[len(path)-1]) == "/" {
return fmt.Sprintf("%sautomate.log", path)
} else {
return fmt.Sprintf("%s/automate.log", path)
}
}
func getConcatStringFromConfig(constant string, variable interface{}) string {
return fmt.Sprintf("%s %v", constant, variable)
}
// decodeLogConfig decodes the log config from the log string from file
func decodeLogConfig(logConfig string) (*dc.AutomateConfig, error) {
var src dc.AutomateConfig
if _, err := toml.Decode(logConfig, &src); err != nil {
return nil, err
}
return &src, nil
}
// getConfigForArgsLogs get the requested config from the patched file
func getConfigForArgsLogs(args []string, remoteService string) (*dc.AutomateConfig, error) {
pemBytes, err := ioutil.ReadFile(args[0]) // nosemgrep
if err != nil {
return nil, err
}
destString := string(pemBytes)
dest1, err := decodeLogConfig(destString)
if err != nil {
return nil, errors.Errorf("Config file must be a valid %s config", remoteService)
}
return dest1, nil
}
// //rollBackCentralized removed the logrotate file and rsyslog file
func rollBackCentralized() string {
rsyslogFileRemove := fmt.Sprintf("sudo rm %s", rsyslogConfigFile)
logRotateFileRemove := fmt.Sprintf("sudo rm %s", logRotateConfigFile)
return fmt.Sprintf(" %s; %s; %s", rsyslogFileRemove, logRotateFileRemove, restartSyslogService)
}
// setConfigForCentralizedLog sets config for rsyslog and logrotate
func createScriptCommandsForCentralizedLog(reqConfig *dc.AutomateConfig) string {
contentForRsyslogConfig := createConfigFileForAutomateSysLog(reqConfig.GetGlobal().GetV1().GetLog().GetRedirectLogFilePath().GetValue())
//creating a file and adding content in the file
rsysCreateFileCommand := fmt.Sprintf("echo \"%s\" > %s", contentForRsyslogConfig, rsyslogConfigFile)
//rsyslog command for creating and added the content
logrotateFileCommand := fmt.Sprintf("echo \"%s\" > %s", configLogrotate(reqConfig.GetGlobal().GetV1().GetLog()), logRotateConfigFile)
return fmt.Sprintf("sudo sh -c '%s'; \n sudo sh -c '%s'; \n %s;", rsysCreateFileCommand, logrotateFileCommand, restartSyslogService)
}
// createRsyslogAndLogRotateConfig patching the config into the remote database servers
func createRsyslogAndLogRotateConfig(sshUtil SSHUtil, remoteIp []string, scriptCommands string, remoteService string) error {
for i := 0; i < len(remoteIp); i++ {
sshUtil.getSSHConfig().hostIP = remoteIp[i]
output, err := sshUtil.connectAndExecuteCommandOnRemote(scriptCommands, true)
if err != nil {
writer.Errorf("%v", err)
return err
}
writer.Printf(output)
writer.Success("Patching is completed on " + remoteService + " node : " + remoteIp[i] + "\n")
}
return nil
}