Skip to content

Commit 101f642

Browse files
committed
update script now calls api to fetch prom and puppetserver url
1 parent 783f029 commit 101f642

8 files changed

Lines changed: 291 additions & 35 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ rpmbuild
77

88
# Ignore the linuxaid tool binaries
99
/linuxaid-cli
10-
/linuxaid-install
10+
/linuxaid-install
11+
12+
# Claude Code
13+
/.claude

cmd/linuxaid-cli/run-openvox.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,21 @@ func runOpenvoxAgent() error {
6262
func RunOpenvox() {
6363
helper.LoadPuppetEnv()
6464

65-
allAPIReachable := checkconnectivity.CheckTCPConnection()
65+
obmondoAPI := api.NewObmondoClient(api.GetObmondoURL(), false)
66+
67+
certname := helper.GetCertname()
68+
prometheusHost, puppetServerHost := resolveCustomerURLs(obmondoAPI, certname)
69+
slog.Info("resolved customer URLs",
70+
slog.String("prometheus", prometheusHost),
71+
slog.String("puppet_server", puppetServerHost))
72+
73+
allAPIReachable := checkconnectivity.CheckTCPConnection(prometheusHost, puppetServerHost)
6674
if !allAPIReachable {
67-
slog.Error("unable to connect to obmondo api, aborting", slog.String("error", "api not accessible"))
75+
slog.Error("unable to connect to required hosts, aborting",
76+
slog.String("prometheus", prometheusHost),
77+
slog.String("puppet_server", puppetServerHost))
6878
return
6979
}
70-
obmondoAPI := api.NewObmondoClient(api.GetObmondoURL(), false)
7180

7281
// nolint:errcheck
7382
obmondoAPI.ServerPing()

cmd/linuxaid-cli/system-update.go

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"log/slog"
6+
"net/url"
67
"os"
78
"slices"
89
"strings"
@@ -45,7 +46,7 @@ var systemUpdateCmd = &cobra.Command{
4546

4647
func cleanup(puppetService *puppet.Service) {
4748
if err := puppetService.EnableAgent(); err != nil {
48-
slog.Error("unable to remove agent disable file and enable puppet agent")
49+
slog.Error("unable to remove agent disable file and enable puppet agent", slog.Any("error", err))
4950
}
5051

5152
slog.Info("ending system-update")
@@ -64,7 +65,7 @@ func UpdateSystem(distribution string) error {
6465
case "centos", "rhel":
6566
return updateRedHat()
6667
default:
67-
slog.Error("unknown distribution")
68+
slog.Error("unknown distribution", slog.String("distribution", distribution))
6869
return nil
6970
}
7071
}
@@ -90,7 +91,7 @@ func updateDebian() error {
9091
exitStatus := pipe.ExitStatus()
9192
if exitStatus != 0 {
9293
slog.Error("exiting, apt update failed")
93-
return fmt.Errorf(" apt-get update and upgrade failed: exit status %d", exitStatus)
94+
return fmt.Errorf("apt-get update and upgrade failed: exit status %d", exitStatus)
9495
}
9596

9697
pipe = script.Exec("apt-get autoremove -y")
@@ -237,6 +238,70 @@ func buildPostUpdateComment(exporter security.SecurityExporter) string {
237238
}
238239
}
239240

241+
const defaultPrometheusHost = "prometheus.obmondo.com"
242+
243+
// extractHostname parses a URL and returns just the hostname.
244+
// Returns empty string if parsing fails.
245+
func extractHostname(rawURL string) string {
246+
parsed, err := url.Parse(rawURL)
247+
if err == nil && parsed.Hostname() != "" {
248+
return parsed.Hostname()
249+
}
250+
return ""
251+
}
252+
253+
// resolveCustomerURLs fetches customer settings and returns resolved prometheus
254+
// and puppet server hostnames. Falls back to defaults if customer has not
255+
// configured them or if the API call fails.
256+
func resolveCustomerURLs(obmondoAPI api.ObmondoClient, certname string) (prometheusHost, puppetServerHost string) {
257+
defaultPuppetServer := constant.DefaultPuppetServerCustomerID + constant.DefaultPuppetServerDomainSuffix
258+
prometheusHost = defaultPrometheusHost
259+
puppetServerHost = defaultPuppetServer
260+
261+
customerID := helper.GetCustomerID(certname)
262+
if customerID == "" {
263+
slog.Warn("could not determine customer ID from certname, using defaults",
264+
slog.String("certname", certname))
265+
return
266+
}
267+
268+
settings, err := obmondoAPI.GetCustomerSettings(customerID)
269+
if err != nil {
270+
slog.Warn("failed to fetch customer settings, using defaults", slog.Any("error", err))
271+
return
272+
}
273+
274+
if settings.LinuxAid == nil {
275+
slog.Info("no linuxaid settings configured for customer, using defaults",
276+
slog.String("customer_id", customerID))
277+
return
278+
}
279+
280+
if settings.LinuxAid.PrometheusURL != "" {
281+
h := extractHostname(settings.LinuxAid.PrometheusURL)
282+
if h == "" {
283+
slog.Warn("could not extract hostname from prometheus_url, using default",
284+
slog.String("prometheus_url", settings.LinuxAid.PrometheusURL))
285+
}
286+
if h != "" {
287+
prometheusHost = h
288+
}
289+
}
290+
291+
if settings.LinuxAid.PuppetserverURL != "" {
292+
h := extractHostname(settings.LinuxAid.PuppetserverURL)
293+
if h == "" {
294+
slog.Warn("could not extract hostname from puppetserver_url, using default",
295+
slog.String("puppetserver_url", settings.LinuxAid.PuppetserverURL))
296+
}
297+
if h != "" {
298+
puppetServerHost = h
299+
}
300+
}
301+
302+
return
303+
}
304+
240305
// ------------------------------------------------
241306
// ------------------------------------------------
242307

@@ -245,7 +310,7 @@ func SystemUpdate() {
245310

246311
envErr := os.Setenv("PATH", constant.PuppetPath)
247312
if envErr != nil {
248-
slog.Error("failed to set the PATH env, exiting")
313+
slog.Error("failed to set the PATH env, exiting", slog.Any("error", envErr))
249314
os.Exit(1)
250315
}
251316

@@ -263,7 +328,7 @@ func SystemUpdate() {
263328
openvoxInitiallyEnabled := true
264329
if _, err := os.Stat(agentDisabledFile); err == nil {
265330
openvoxInitiallyEnabled = false
266-
slog.Warn("openvox agent was disabled before system-update, will skip opnvox operations")
331+
slog.Warn("openvox agent was disabled before system-update, will skip openvox operations")
267332
}
268333

269334
obmondoAPIURL := api.GetObmondoURL()
@@ -293,6 +358,13 @@ func SystemUpdate() {
293358
os.Exit(1)
294359
}
295360

361+
certname := helper.GetCertname()
362+
prometheusHost, puppetServer := resolveCustomerURLs(obmondoAPI, certname)
363+
config.GetViperInstance().Set(constant.CobraFlagOpenvoxServer, puppetServer)
364+
slog.Info("resolved customer URLs",
365+
slog.String("prometheus", prometheusHost),
366+
slog.String("puppet_server", puppetServer))
367+
296368
puppetService := puppet.NewService(obmondoAPI, webtee.NewWebtee(obmondoAPI))
297369

298370
if openvoxInitiallyEnabled && !config.ShouldSkipOpenvox() {

cmd/linuxaid-cli/system-update_test.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package main
22

33
import (
4+
"errors"
45
"path/filepath"
56
"testing"
67
"time"
78

9+
"gitea.obmondo.com/EnableIT/linuxaid-cli/constant"
810
"gitea.obmondo.com/EnableIT/linuxaid-cli/helper"
911
"gitea.obmondo.com/EnableIT/linuxaid-cli/mock"
12+
api "gitea.obmondo.com/EnableIT/linuxaid-cli/pkg/obmondo"
1013
)
1114

1215
func TestGetCustomerID(t *testing.T) {
@@ -65,3 +68,151 @@ func TestGetInstalledKernel(t *testing.T) {
6568
}
6669

6770
// Need tests for 204 and 208 and a failed scenario as well
71+
72+
func TestExtractHostname(t *testing.T) {
73+
tests := []struct {
74+
name string
75+
rawURL string
76+
expected string
77+
}{
78+
{"https URL", "https://prom-test.obmondo.com", "prom-test.obmondo.com"},
79+
{"https URL with port", "https://prom-test.obmondo.com:9090", "prom-test.obmondo.com"},
80+
{"https URL with path", "https://prom-test.obmondo.com/api/v1", "prom-test.obmondo.com"},
81+
{"http URL", "http://prometheus.local:9090", "prometheus.local"},
82+
{"empty string", "", ""},
83+
{"bare hostname (no scheme)", "prom-test.obmondo.com", ""},
84+
}
85+
86+
for _, tt := range tests {
87+
t.Run(tt.name, func(t *testing.T) {
88+
got := extractHostname(tt.rawURL)
89+
if got != tt.expected {
90+
t.Errorf("extractHostname(%q) = %q, want %q", tt.rawURL, got, tt.expected)
91+
}
92+
})
93+
}
94+
}
95+
96+
// mockSettingsClient is a mock that returns configurable customer settings.
97+
type mockSettingsClient struct {
98+
mock.MockObmondoClient
99+
settings *api.CustomerSettings
100+
err error
101+
}
102+
103+
func (m *mockSettingsClient) GetCustomerSettings(_ string) (*api.CustomerSettings, error) {
104+
return m.settings, m.err
105+
}
106+
107+
func TestResolveCustomerURLs(t *testing.T) {
108+
defaultPuppetServer := constant.DefaultPuppetServerCustomerID + constant.DefaultPuppetServerDomainSuffix
109+
110+
t.Run("returns custom URLs when settings exist", func(t *testing.T) {
111+
client := &mockSettingsClient{
112+
settings: &api.CustomerSettings{
113+
CustomerID: "enableit",
114+
LinuxAid: &api.LinuxAidSettings{
115+
PrometheusURL: "https://prom-test.obmondo.com",
116+
PuppetserverURL: "https://enableit.puppet.obmondo.com",
117+
},
118+
},
119+
}
120+
t.Setenv("CERTNAME", "testserver.enableit")
121+
122+
promHost, puppetHost := resolveCustomerURLs(client, "testserver.enableit")
123+
if promHost != "prom-test.obmondo.com" {
124+
t.Errorf("prometheus host = %q, want %q", promHost, "prom-test.obmondo.com")
125+
}
126+
if puppetHost != "enableit.puppet.obmondo.com" {
127+
t.Errorf("puppet server host = %q, want %q", puppetHost, "enableit.puppet.obmondo.com")
128+
}
129+
})
130+
131+
t.Run("returns defaults when linuxaid settings are nil", func(t *testing.T) {
132+
client := &mockSettingsClient{
133+
settings: &api.CustomerSettings{
134+
CustomerID: "enableit",
135+
LinuxAid: nil,
136+
},
137+
}
138+
t.Setenv("CERTNAME", "testserver.enableit")
139+
140+
promHost, puppetHost := resolveCustomerURLs(client, "testserver.enableit")
141+
if promHost != defaultPrometheusHost {
142+
t.Errorf("prometheus host = %q, want default %q", promHost, defaultPrometheusHost)
143+
}
144+
if puppetHost != defaultPuppetServer {
145+
t.Errorf("puppet server host = %q, want default %q", puppetHost, defaultPuppetServer)
146+
}
147+
})
148+
149+
t.Run("returns defaults when API call fails", func(t *testing.T) {
150+
client := &mockSettingsClient{
151+
settings: nil,
152+
err: errors.New("connection refused"),
153+
}
154+
t.Setenv("CERTNAME", "testserver.enableit")
155+
156+
promHost, puppetHost := resolveCustomerURLs(client, "testserver.enableit")
157+
if promHost != defaultPrometheusHost {
158+
t.Errorf("prometheus host = %q, want default %q", promHost, defaultPrometheusHost)
159+
}
160+
if puppetHost != defaultPuppetServer {
161+
t.Errorf("puppet server host = %q, want default %q", puppetHost, defaultPuppetServer)
162+
}
163+
})
164+
165+
t.Run("returns defaults when certname has no customer ID", func(t *testing.T) {
166+
client := &mockSettingsClient{
167+
settings: &api.CustomerSettings{},
168+
}
169+
170+
promHost, puppetHost := resolveCustomerURLs(client, "")
171+
if promHost != defaultPrometheusHost {
172+
t.Errorf("prometheus host = %q, want default %q", promHost, defaultPrometheusHost)
173+
}
174+
if puppetHost != defaultPuppetServer {
175+
t.Errorf("puppet server host = %q, want default %q", puppetHost, defaultPuppetServer)
176+
}
177+
})
178+
179+
t.Run("uses default for prometheus when only puppetserver is set", func(t *testing.T) {
180+
client := &mockSettingsClient{
181+
settings: &api.CustomerSettings{
182+
CustomerID: "enableit",
183+
LinuxAid: &api.LinuxAidSettings{
184+
PuppetserverURL: "https://custom.puppet.server.com",
185+
},
186+
},
187+
}
188+
t.Setenv("CERTNAME", "testserver.enableit")
189+
190+
promHost, puppetHost := resolveCustomerURLs(client, "testserver.enableit")
191+
if promHost != defaultPrometheusHost {
192+
t.Errorf("prometheus host = %q, want default %q", promHost, defaultPrometheusHost)
193+
}
194+
if puppetHost != "custom.puppet.server.com" {
195+
t.Errorf("puppet server host = %q, want %q", puppetHost, "custom.puppet.server.com")
196+
}
197+
})
198+
199+
t.Run("uses default for puppetserver when only prometheus is set", func(t *testing.T) {
200+
client := &mockSettingsClient{
201+
settings: &api.CustomerSettings{
202+
CustomerID: "enableit",
203+
LinuxAid: &api.LinuxAidSettings{
204+
PrometheusURL: "https://custom-prom.example.com:9090",
205+
},
206+
},
207+
}
208+
t.Setenv("CERTNAME", "testserver.enableit")
209+
210+
promHost, puppetHost := resolveCustomerURLs(client, "testserver.enableit")
211+
if promHost != "custom-prom.example.com" {
212+
t.Errorf("prometheus host = %q, want %q", promHost, "custom-prom.example.com")
213+
}
214+
if puppetHost != defaultPuppetServer {
215+
t.Errorf("puppet server host = %q, want default %q", puppetHost, defaultPuppetServer)
216+
}
217+
})
218+
}

mock/api.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ func (*MockObmondoClient) UpdatePuppetLastRunReport() error {
3232
return nil
3333
}
3434

35+
func (*MockObmondoClient) GetCustomerSettings(_ string) (*api.CustomerSettings, error) {
36+
return &api.CustomerSettings{}, nil
37+
}
38+
3539
func (*MockObmondoClient) FetchServiceWindowStatus() (*http.Response, error) {
3640
data := map[string]interface{}{
3741
"status": http.StatusOK,

0 commit comments

Comments
 (0)