Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio
- **Github Runner Scaler**: Improve URL construction and error handling ([#7495](https://github.com/kedacore/keda/pull/7495))
- **Github Runner Scaler**: Limit HTTP error response logging ([#7469](https://github.com/kedacore/keda/pull/7469))
- **Loki Scaler**: Limit HTTP error response logging ([#7469](https://github.com/kedacore/keda/pull/7469))
- **Loki Scaler**: `serverAddress` now appends `/loki/api/v1/query` to the end of existing path instead of overriding ([#7648](https://github.com/kedacore/keda/pull/7648))
- **Metrics API Scaler**: Fix `aggregateFromKubeServiceEndpoints` using empty label selector that matched all EndpointSlices in the namespace instead of only the target service's ([#7641](https://github.com/kedacore/keda/issues/7641))
- **NATS JetStream Scaler**: URL-encode user input in monitoring URL construction ([#7483](https://github.com/kedacore/keda/pull/7483))
- **Prometheus Scaler**: Handle NaN results in the same manner as Inf ([#7475](https://github.com/kedacore/keda/issues/7475))
Expand Down
28 changes: 26 additions & 2 deletions pkg/scalers/loki_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (
"io"
"net/http"
"net/url"
"path"
"strconv"
"strings"

"github.com/go-logr/logr"
v2 "k8s.io/api/autoscaling/v2"
Expand Down Expand Up @@ -115,11 +117,10 @@ func (s *lokiScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec {
}

func (s *lokiScaler) ExecuteLokiQuery(ctx context.Context) (float64, error) {
u, err := url.ParseRequestURI(s.metadata.ServerAddress)
u, err := getServerAddress(&s.metadata)
if err != nil {
return -1, err
}
u.Path = "/loki/api/v1/query"
u.RawQuery = url.Values{"query": []string{s.metadata.Query}}.Encode()

req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
Expand Down Expand Up @@ -218,3 +219,26 @@ func (s *lokiScaler) GetMetricsAndActivity(ctx context.Context, metricName strin
metric := GenerateMetricInMili(metricName, val)
return []external_metrics.ExternalMetricValue{metric}, val > s.metadata.ActivationThreshold, nil
}

func getServerAddress(metadata *lokiMetadata) (url.URL, error) {
const lokiPath = "/loki/api/v1/query"
u, err := url.ParseRequestURI(metadata.ServerAddress)
if err != nil {
return url.URL{}, err
}

u.Path = strings.TrimRight(u.Path, "/")

if u.Path == lokiPath {
return *u, nil
}

if strings.HasPrefix(lokiPath, u.Path+"/") {
remaining := strings.TrimPrefix(lokiPath, u.Path)
u.Path = path.Join(u.Path, remaining)
} else {
u.Path = path.Join(u.Path, lokiPath)
}
Comment thread
pawan-regoti marked this conversation as resolved.
Outdated

return *u, nil
}
78 changes: 78 additions & 0 deletions pkg/scalers/loki_scaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,81 @@ func TestLokiScalerTenantHeader(t *testing.T) {
_, err := scaler.ExecuteLokiQuery(context.TODO())
assert.NoError(t, err)
}

type getServerAddressTestData struct {
name string
serverAddress string
expectedPath string
isError bool
}

var testGetServerAddressData = []getServerAddressTestData{
{
name: "no path in URL",
serverAddress: "http://localhost:3100",
expectedPath: "/loki/api/v1/query",
isError: false,
},
{
name: "URL with trailing slash",
serverAddress: "http://localhost:3100/",
expectedPath: "/loki/api/v1/query",
isError: false,
},
{
name: "URL with partial loki path",
serverAddress: "http://localhost:3100/loki",
expectedPath: "/loki/api/v1/query",
isError: false,
},
{
name: "URL with longer partial loki path",
serverAddress: "http://localhost:3100/loki/api/v1",
expectedPath: "/loki/api/v1/query",
isError: false,
},
{
name: "URL with full loki path already present",
serverAddress: "http://localhost:3100/loki/api/v1/query",
expectedPath: "/loki/api/v1/query",
isError: false,
},
{
name: "URL with full loki path and trailing slash",
serverAddress: "http://localhost:3100/loki/api/v1/query/",
expectedPath: "/loki/api/v1/query",
isError: false,
},
{
name: "URL with custom prefix",
serverAddress: "http://localhost:3100/custom",
expectedPath: "/custom/loki/api/v1/query",
isError: false,
},
{
name: "URL with partial loki path not on segment boundary",
serverAddress: "http://localhost:3100/lo",
expectedPath: "/lo/loki/api/v1/query",
isError: false,
},
Comment thread
pawan-regoti marked this conversation as resolved.
{
name: "invalid URL",
serverAddress: "not-a-url",
isError: true,
},
}

func TestGetServerAddress(t *testing.T) {
for _, testData := range testGetServerAddressData {
t.Run(testData.name, func(t *testing.T) {
meta := &lokiMetadata{ServerAddress: testData.serverAddress}
u, err := getServerAddress(meta)
if testData.isError {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, testData.expectedPath, u.Path)
})
}
}
Loading