From 412b6a0591a1fd5feb5c3751edb4ed1e64248ac9 Mon Sep 17 00:00:00 2001 From: Witek Bedyk Date: Sat, 4 Dec 2021 21:14:47 +0100 Subject: [PATCH] Fix Uyuni SD initialization (#9924) * Fix Uyuni SD initialization The change prevents null pointer exception during SD initialization. Signed-off-by: Witek Bedyk --- config/config_test.go | 7 ++- config/testdata/uyuni_no_server.bad.yml | 4 ++ discovery/uyuni/uyuni.go | 12 ++--- discovery/uyuni/uyuni_test.go | 58 +++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 config/testdata/uyuni_no_server.bad.yml create mode 100644 discovery/uyuni/uyuni_test.go diff --git a/config/config_test.go b/config/config_test.go index e8d52d4aa..695c0188a 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -227,7 +227,6 @@ var expectedConf = &Config{ }, }, { - JobName: "service-x", HonorTimestamps: true, @@ -954,7 +953,7 @@ var expectedConf = &Config{ Scheme: DefaultScrapeConfig.Scheme, ServiceDiscoveryConfigs: discovery.Configs{ &uyuni.SDConfig{ - Server: kubernetesSDHostURL(), + Server: "https://localhost:1234", Username: "gopher", Password: "hole", Entitlement: "monitoring_entitled", @@ -1434,6 +1433,10 @@ var expectedErrors = []struct { filename: "empty_scrape_config_action.bad.yml", errMsg: "relabel action cannot be empty", }, + { + filename: "uyuni_no_server.bad.yml", + errMsg: "Uyuni SD configuration requires server host", + }, } func TestBadConfigs(t *testing.T) { diff --git a/config/testdata/uyuni_no_server.bad.yml b/config/testdata/uyuni_no_server.bad.yml new file mode 100644 index 000000000..4576be88d --- /dev/null +++ b/config/testdata/uyuni_no_server.bad.yml @@ -0,0 +1,4 @@ +scrape_configs: + - job_name: uyuni + uyuni_sd_configs: + - server: diff --git a/discovery/uyuni/uyuni.go b/discovery/uyuni/uyuni.go index df8efeeaf..c48cf2e6c 100644 --- a/discovery/uyuni/uyuni.go +++ b/discovery/uyuni/uyuni.go @@ -62,7 +62,7 @@ func init() { // SDConfig is the configuration for Uyuni based service discovery. type SDConfig struct { - Server config.URL `yaml:"server"` + Server string `yaml:"server"` Username string `yaml:"username"` Password config.Secret `yaml:"password"` HTTPClientConfig config.HTTPClientConfig `yaml:",inline"` @@ -122,11 +122,11 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { if err != nil { return err } - if c.Server.URL == nil { + if c.Server == "" { return errors.New("Uyuni SD configuration requires server host") } - _, err = url.Parse(c.Server.String()) + _, err = url.Parse(c.Server) if err != nil { return errors.Wrap(err, "Uyuni Server URL is not valid") } @@ -199,8 +199,10 @@ func getEndpointInfoForSystems( // NewDiscovery returns a uyuni discovery for the given configuration. func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) { - var apiURL *url.URL - *apiURL = *conf.Server.URL + apiURL, err := url.Parse(conf.Server) + if err != nil { + return nil, err + } apiURL.Path = path.Join(apiURL.Path, uyuniXMLRPCAPIPath) rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "uyuni_sd") diff --git a/discovery/uyuni/uyuni_test.go b/discovery/uyuni/uyuni_test.go new file mode 100644 index 000000000..9178c986b --- /dev/null +++ b/discovery/uyuni/uyuni_test.go @@ -0,0 +1,58 @@ +// Copyright 2020 The Prometheus Authors +// Licensed 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. + +package uyuni + +import ( + "context" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/prometheus/prometheus/discovery/targetgroup" +) + +func testUpdateServices(respHandler http.HandlerFunc) ([]*targetgroup.Group, error) { + // Create a test server with mock HTTP handler. + ts := httptest.NewServer(respHandler) + defer ts.Close() + + conf := SDConfig{ + Server: ts.URL, + } + + md, err := NewDiscovery(&conf, nil) + if err != nil { + return nil, err + } + + return md.refresh(context.Background()) +} + +func TestUyuniSDHandleError(t *testing.T) { + var ( + errTesting = "unable to login to Uyuni API: request error: bad status code - 500" + respHandler = func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + w.Header().Set("Content-Type", "application/xml") + io.WriteString(w, ``) + } + ) + tgs, err := testUpdateServices(respHandler) + + require.EqualError(t, err, errTesting) + require.Equal(t, len(tgs), 0) +}