-
Notifications
You must be signed in to change notification settings - Fork 339
/
recordsdotconfig.go
226 lines (188 loc) · 8 KB
/
recordsdotconfig.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
package atscfg
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import (
"os/exec"
"strings"
"github.com/apache/trafficcontrol/lib/go-tc"
)
const RecordsSeparator = " "
const RecordsFileName = "records.config"
const ContentTypeRecordsDotConfig = ContentTypeTextASCII
const LineCommentRecordsDotConfig = LineCommentHash
type RecordsConfigOpts struct {
// ReleaseViaStr is whether or not we replace the via and server strings in ATS
// responses to be the Release value from the rpm package. This can be a user
// defined build hash (or whatever the user wants) type value to give more
// specific info as well as obfuscating the real ATS version from prying eyes
ReleaseViaStr bool
// DNSLocalBindServiceAddr is whether to set the server's service addresses
// as the records.config proxy.config.dns.local_ipv* settings.
DNSLocalBindServiceAddr bool
// HdrComment is the header comment to include at the beginning of the file.
// This should be the text desired, without comment syntax (like # or //). The file's comment syntax will be added.
// To omit the header comment, pass the empty string.
HdrComment string
// NoOutgoingIP is whether to omit adding a records.config entry for
// proxy.local.outgoing_ip_to_bind set to the server's IP addresses (V4 and V6).
// By default, this entry is added, unless it already exists in records.config
// (probably from a Parameter).
//
// The default, setting the IP to bind, is usually the right solution, unless
// the server's addresses are unusual or not public, such as NAT.
NoOutgoingIP bool
}
func MakeRecordsDotConfig(
server *Server,
serverParams []tc.Parameter,
opt *RecordsConfigOpts,
) (Cfg, error) {
if opt == nil {
opt = &RecordsConfigOpts{}
}
warnings := []string{}
if len(server.ProfileNames) == 0 {
return Cfg{}, makeErr(warnings, "server missing profiles")
}
params, paramWarns := paramsToMap(filterParams(serverParams, RecordsFileName, "", "", "location"))
warnings = append(warnings, paramWarns...)
hdr := makeHdrComment(opt.HdrComment)
txt := genericProfileConfig(params, RecordsSeparator)
if txt == "" {
txt = "\n" // If no params exist, don't send "not found," but an empty file. We know the profile exists.
}
txt = replaceLineSuffixes(txt, "STRING __HOSTNAME__", "STRING __FULL_HOSTNAME__")
txt = hdr + txt
txt, overrideWarns := addRecordsDotConfigOverrides(txt, server, opt)
warnings = append(warnings, overrideWarns...)
return Cfg{
Text: txt,
ContentType: ContentTypeRecordsDotConfig,
LineComment: LineCommentRecordsDotConfig,
Warnings: warnings,
}, nil
}
// addRecordsDotConfigOverrides modifies the records.config text and adds any overrides.
// Returns the modified text and any warnings.
func addRecordsDotConfigOverrides(txt string, server *Server, opt *RecordsConfigOpts) (string, []string) {
warnings := []string{}
if !opt.NoOutgoingIP {
ipWarns := []string{}
txt, ipWarns = addRecordsDotConfigOutgoingIP(txt, server)
warnings = append(warnings, ipWarns...)
}
if opt.ReleaseViaStr {
viaWarns := []string{}
txt, viaWarns = addRecordsDotConfigViaStr(txt)
warnings = append(warnings, viaWarns...)
}
if opt.DNSLocalBindServiceAddr {
dnsWarns := []string{}
txt, dnsWarns = addRecordsDotConfigDNSLocal(txt, server)
warnings = append(warnings, dnsWarns...)
}
return txt, warnings
}
// addRecordsDotConfigOutgoingIP returns the outgoing IP added to the config text, and any warnings.
func addRecordsDotConfigOutgoingIP(txt string, server *Server) (string, []string) {
warnings := []string{}
outgoingIPConfig := `proxy.local.outgoing_ip_to_bind`
if strings.Contains(txt, outgoingIPConfig) {
warnings = append(warnings, "records.config had a proxy.local.outgoing_ip_to_bind Parameter! Using Parameter, not setting Outgoing IP from Server")
return txt, warnings
}
v4, v6 := getServiceAddresses(server)
if v4 == nil {
warnings = append(warnings, "server had no IPv4 service address, cannot set "+outgoingIPConfig+"!")
return txt, warnings
}
txt = txt + `LOCAL ` + outgoingIPConfig + ` STRING ` + v4.String()
if v6 != nil {
txt += ` [` + v6.String() + `]`
}
txt += "\n"
return txt, warnings
}
// addRecordsDotConfigViaStr returns the request, response, and response server via strings with the current Release (a.k.a. build version and not ATS version), and any warnings.
func addRecordsDotConfigViaStr(txt string) (string, []string) {
warnings := []string{}
requestViaStr := `proxy.config.http.request_via_str`
responseViaStr := `proxy.config.http.response_via_str`
responseServerStr := `proxy.config.http.response_server_str`
cmd := "yum info installed trafficserver | grep Release"
yumOutput, err := exec.Command("sh", "-c", cmd).Output()
if err != nil {
warnings = append(warnings, "could not read trafficserver release information from yum! Not setting via strings")
return txt, warnings
}
releaseVerSlice := strings.Split(string(yumOutput), " ")
releaseVer := releaseVerSlice[len(releaseVerSlice)-1]
if strings.Contains(txt, requestViaStr) {
warnings = append(warnings, "records.config had a proxy.config.http.request_via_str Parameter! Using Parameter, not setting request via string")
} else {
txt = txt + `CONFIG ` + requestViaStr + ` STRING ` + releaseVer
txt += "\n"
}
if strings.Contains(txt, responseViaStr) {
warnings = append(warnings, "records.config had a proxy.config.http.response_via_str Parameter! Using Parameter, not setting response via string")
} else {
txt = txt + `CONFIG ` + responseViaStr + ` STRING ` + releaseVer
txt += "\n"
}
if strings.Contains(txt, responseServerStr) {
warnings = append(warnings, "records.config had a proxy.config.http.response_server_str Parameter! Using Parameter, not setting response server string")
} else {
txt = txt + `CONFIG ` + responseServerStr + ` STRING ` + releaseVer
txt += "\n"
}
return txt, warnings
}
func addRecordsDotConfigDNSLocal(txt string, server *Server) (string, []string) {
warnings := []string{}
const dnsLocalV4 = `proxy.config.dns.local_ipv4`
const dnsLocalV6 = `proxy.config.dns.local_ipv6`
v4, v6 := getServiceAddresses(server)
if v4 == nil {
warnings = append(warnings, "server had no IPv4 Service Address, not setting records.config dns v4 local bind addr!")
} else if strings.Contains(txt, dnsLocalV4) {
warnings = append(warnings, "dns local option was set, but proxy.config.dns.local_ipv4 was already in records.config, not overriding! Check the server's Parameters.")
} else {
txt += `CONFIG ` + dnsLocalV4 + ` STRING ` + v4.String() + "\n"
}
if v6 == nil {
warnings = append(warnings, "server had no IPv6 Service Address, not setting records.config dns v6 local bind addr!")
} else if strings.Contains(txt, dnsLocalV6) {
warnings = append(warnings, "dns local option was set, but proxy.config.dns.local_ipv6 was already in records.config, not overriding! Check the server's Parameters!")
} else {
txt += `CONFIG ` + dnsLocalV6 + ` STRING [` + v6.String() + `]` + "\n"
}
return txt, warnings
}
func replaceLineSuffixes(txt string, suffix string, newSuffix string) string {
lines := strings.Split(txt, "\n")
newLines := make([]string, 0, len(lines))
for _, line := range lines {
if strings.HasSuffix(line, suffix) {
line = line[:len(line)-len(suffix)]
line += newSuffix
}
newLines = append(newLines, line)
}
return strings.Join(newLines, "\n")
}