github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/ruler/registry_test.go (about)

     1  package ruler
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/url"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/go-kit/log"
    12  	promConfig "github.com/prometheus/common/config"
    13  	"github.com/prometheus/common/model"
    14  	"github.com/prometheus/common/sigv4"
    15  	"github.com/prometheus/prometheus/config"
    16  	"github.com/prometheus/prometheus/model/relabel"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  	"github.com/weaveworks/common/user"
    20  
    21  	"github.com/grafana/loki/pkg/ruler/storage/instance"
    22  	"github.com/grafana/loki/pkg/ruler/util"
    23  	"github.com/grafana/loki/pkg/util/test"
    24  	"github.com/grafana/loki/pkg/validation"
    25  )
    26  
    27  const enabledRWTenant = "enabled"
    28  const disabledRWTenant = "disabled"
    29  const additionalHeadersRWTenant = "additional-headers"
    30  const noHeadersRWTenant = "no-headers"
    31  const customRelabelsTenant = "custom-relabels"
    32  const badRelabelsTenant = "bad-relabels"
    33  const nilRelabelsTenant = "nil-relabels"
    34  const emptySliceRelabelsTenant = "empty-slice-relabels"
    35  const sigV4ConfigTenant = "sigv4"
    36  const sigV4GlobalRegion = "us-east-1"
    37  const sigV4TenantRegion = "us-east-2"
    38  
    39  const defaultCapacity = 1000
    40  
    41  func newFakeLimits() fakeLimits {
    42  	return fakeLimits{
    43  		limits: map[string]*validation.Limits{
    44  			enabledRWTenant: {
    45  				RulerRemoteWriteQueueCapacity: 987,
    46  			},
    47  			disabledRWTenant: {
    48  				RulerRemoteWriteDisabled: true,
    49  			},
    50  			additionalHeadersRWTenant: {
    51  				RulerRemoteWriteHeaders: validation.NewOverwriteMarshalingStringMap(map[string]string{
    52  					user.OrgIDHeaderName:                         "overridden",
    53  					fmt.Sprintf("   %s  ", user.OrgIDHeaderName): "overridden",
    54  					strings.ToLower(user.OrgIDHeaderName):        "overridden-lower",
    55  					strings.ToUpper(user.OrgIDHeaderName):        "overridden-upper",
    56  					"Additional":                                 "Header",
    57  				}),
    58  			},
    59  			noHeadersRWTenant: {
    60  				RulerRemoteWriteHeaders: validation.NewOverwriteMarshalingStringMap(map[string]string{}),
    61  			},
    62  			customRelabelsTenant: {
    63  				RulerRemoteWriteRelabelConfigs: []*util.RelabelConfig{
    64  					{
    65  						Regex:        ".+:.+",
    66  						SourceLabels: []string{"__name__"},
    67  						Action:       "drop",
    68  					},
    69  					{
    70  						Regex:  "__cluster__",
    71  						Action: "labeldrop",
    72  					},
    73  				},
    74  			},
    75  			nilRelabelsTenant: {},
    76  			emptySliceRelabelsTenant: {
    77  				RulerRemoteWriteRelabelConfigs: []*util.RelabelConfig{},
    78  			},
    79  			badRelabelsTenant: {
    80  				RulerRemoteWriteRelabelConfigs: []*util.RelabelConfig{
    81  					{
    82  						SourceLabels: []string{"__cluster__"},
    83  						Action:       "labeldrop",
    84  					},
    85  				},
    86  			},
    87  			sigV4ConfigTenant: {
    88  				RulerRemoteWriteSigV4Config: &sigv4.SigV4Config{
    89  					Region: sigV4TenantRegion,
    90  				},
    91  			},
    92  		},
    93  	}
    94  }
    95  
    96  func setupRegistry(t *testing.T) *walRegistry {
    97  	// TempDir adds RemoveAll to c.Cleanup
    98  	walDir := t.TempDir()
    99  	u, _ := url.Parse("http://remote-write")
   100  
   101  	cfg := Config{
   102  		RemoteWrite: RemoteWriteConfig{
   103  			Client: config.RemoteWriteConfig{
   104  				URL: &promConfig.URL{URL: u},
   105  				QueueConfig: config.QueueConfig{
   106  					Capacity: defaultCapacity,
   107  				},
   108  				HTTPClientConfig: promConfig.HTTPClientConfig{
   109  					BasicAuth: &promConfig.BasicAuth{
   110  						Password: "bar",
   111  						Username: "foo",
   112  					},
   113  				},
   114  				Headers: map[string]string{
   115  					"Base": "value",
   116  				},
   117  				WriteRelabelConfigs: []*relabel.Config{
   118  					{
   119  						SourceLabels: []model.LabelName{"__name__"},
   120  						Regex:        relabel.MustNewRegexp("ALERTS.*"),
   121  						Action:       "drop",
   122  						Separator:    ";",
   123  						Replacement:  "$1",
   124  					},
   125  				},
   126  			},
   127  			Enabled:             true,
   128  			ConfigRefreshPeriod: 5 * time.Second,
   129  		},
   130  		WAL: instance.Config{
   131  			Dir: walDir,
   132  		},
   133  	}
   134  
   135  	overrides, err := validation.NewOverrides(validation.Limits{}, newFakeLimits())
   136  	require.NoError(t, err)
   137  
   138  	reg := newWALRegistry(log.NewNopLogger(), nil, cfg, overrides)
   139  	require.NoError(t, err)
   140  
   141  	//stops the registry before the directory is cleaned up
   142  	t.Cleanup(reg.stop)
   143  	return reg.(*walRegistry)
   144  }
   145  
   146  func setupSigV4Registry(t *testing.T) *walRegistry {
   147  	// Get the global config and override it
   148  	reg := setupRegistry(t)
   149  
   150  	// Remove the basic auth config and replace with sigv4
   151  	reg.config.RemoteWrite.Client.HTTPClientConfig.BasicAuth = nil
   152  	reg.config.RemoteWrite.Client.SigV4Config = &sigv4.SigV4Config{
   153  		Region: sigV4GlobalRegion,
   154  	}
   155  
   156  	return reg
   157  }
   158  
   159  func TestTenantRemoteWriteConfigWithOverride(t *testing.T) {
   160  	reg := setupRegistry(t)
   161  
   162  	tenantCfg, err := reg.getTenantConfig(enabledRWTenant)
   163  	require.NoError(t, err)
   164  
   165  	// tenant has not disable remote-write so will inherit the global one
   166  	assert.Len(t, tenantCfg.RemoteWrite, 1)
   167  	// but the tenant has an override for the queue capacity
   168  	assert.Equal(t, tenantCfg.RemoteWrite[0].QueueConfig.Capacity, 987)
   169  }
   170  
   171  func TestTenantRemoteWriteConfigWithoutOverride(t *testing.T) {
   172  	reg := setupRegistry(t)
   173  
   174  	// this tenant has no overrides, so will get defaults
   175  	tenantCfg, err := reg.getTenantConfig("unknown")
   176  	require.NoError(t, err)
   177  
   178  	// tenant has not disable remote-write so will inherit the global one
   179  	assert.Len(t, tenantCfg.RemoteWrite, 1)
   180  	// but the tenant has an override for the queue capacity
   181  	assert.Equal(t, tenantCfg.RemoteWrite[0].QueueConfig.Capacity, defaultCapacity)
   182  }
   183  
   184  func TestRulerRemoteWriteSigV4ConfigWithOverrides(t *testing.T) {
   185  	reg := setupSigV4Registry(t)
   186  
   187  	tenantCfg, err := reg.getTenantConfig(sigV4ConfigTenant)
   188  	require.NoError(t, err)
   189  
   190  	// tenant has not disable remote-write so will inherit the global one
   191  	assert.Len(t, tenantCfg.RemoteWrite, 1)
   192  	// ensure sigv4 config is not nil and overwritten
   193  	if assert.NotNil(t, tenantCfg.RemoteWrite[0].SigV4Config) {
   194  		assert.Equal(t, tenantCfg.RemoteWrite[0].SigV4Config.Region, sigV4TenantRegion)
   195  	}
   196  }
   197  
   198  func TestRulerRemoteWriteSigV4ConfigWithoutOverrides(t *testing.T) {
   199  	reg := setupSigV4Registry(t)
   200  
   201  	// this tenant has no overrides, so will get defaults
   202  	tenantCfg, err := reg.getTenantConfig("unknown")
   203  	require.NoError(t, err)
   204  
   205  	// tenant has not disable remote-write so will inherit the global one
   206  	assert.Len(t, tenantCfg.RemoteWrite, 1)
   207  	// ensure sigv4 config is not nil and the global value
   208  	if assert.NotNil(t, tenantCfg.RemoteWrite[0].SigV4Config) {
   209  		assert.Equal(t, tenantCfg.RemoteWrite[0].SigV4Config.Region, sigV4GlobalRegion)
   210  	}
   211  }
   212  
   213  func TestTenantRemoteWriteConfigDisabled(t *testing.T) {
   214  	reg := setupRegistry(t)
   215  
   216  	tenantCfg, err := reg.getTenantConfig(disabledRWTenant)
   217  	require.NoError(t, err)
   218  
   219  	// this tenant has remote-write disabled
   220  	assert.Len(t, tenantCfg.RemoteWrite, 0)
   221  }
   222  
   223  func TestTenantRemoteWriteHTTPConfigMaintained(t *testing.T) {
   224  	reg := setupRegistry(t)
   225  
   226  	tenantCfg, err := reg.getTenantConfig(enabledRWTenant)
   227  	require.NoError(t, err)
   228  
   229  	// HTTP client config is not currently overrideable, all tenants' configs should inherit base
   230  	assert.Equal(t, tenantCfg.RemoteWrite[0].HTTPClientConfig.BasicAuth.Username, "foo")
   231  	assert.Equal(t, tenantCfg.RemoteWrite[0].HTTPClientConfig.BasicAuth.Password, promConfig.Secret("bar"))
   232  }
   233  
   234  func TestTenantRemoteWriteHeaderOverride(t *testing.T) {
   235  	reg := setupRegistry(t)
   236  
   237  	tenantCfg, err := reg.getTenantConfig(additionalHeadersRWTenant)
   238  	require.NoError(t, err)
   239  
   240  	assert.Len(t, tenantCfg.RemoteWrite[0].Headers, 2)
   241  	// ensure that tenant cannot override X-Scope-OrgId header
   242  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers[user.OrgIDHeaderName], additionalHeadersRWTenant)
   243  	// but that the additional header defined is set
   244  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers["Additional"], "Header")
   245  	// the original header must be removed
   246  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers["Base"], "")
   247  
   248  	tenantCfg, err = reg.getTenantConfig(enabledRWTenant)
   249  	require.NoError(t, err)
   250  
   251  	// and a user who didn't set any header overrides still gets the X-Scope-OrgId header
   252  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers[user.OrgIDHeaderName], enabledRWTenant)
   253  }
   254  
   255  func TestTenantRemoteWriteHeadersReset(t *testing.T) {
   256  	reg := setupRegistry(t)
   257  
   258  	tenantCfg, err := reg.getTenantConfig(noHeadersRWTenant)
   259  	require.NoError(t, err)
   260  
   261  	assert.Len(t, tenantCfg.RemoteWrite[0].Headers, 1)
   262  	// ensure that tenant cannot override X-Scope-OrgId header
   263  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers[user.OrgIDHeaderName], noHeadersRWTenant)
   264  	// the original header must be removed
   265  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers["Base"], "")
   266  }
   267  
   268  func TestTenantRemoteWriteHeadersNoOverride(t *testing.T) {
   269  	reg := setupRegistry(t)
   270  
   271  	tenantCfg, err := reg.getTenantConfig(enabledRWTenant)
   272  	require.NoError(t, err)
   273  
   274  	assert.Len(t, tenantCfg.RemoteWrite[0].Headers, 2)
   275  	// ensure that tenant cannot override X-Scope-OrgId header
   276  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers[user.OrgIDHeaderName], enabledRWTenant)
   277  	// the original header must be present
   278  	assert.Equal(t, tenantCfg.RemoteWrite[0].Headers["Base"], "value")
   279  }
   280  
   281  func TestRelabelConfigOverrides(t *testing.T) {
   282  	reg := setupRegistry(t)
   283  
   284  	tenantCfg, err := reg.getTenantConfig(customRelabelsTenant)
   285  	require.NoError(t, err)
   286  
   287  	// it should also override the default label configs
   288  	assert.Len(t, tenantCfg.RemoteWrite[0].WriteRelabelConfigs, 2)
   289  }
   290  
   291  func TestRelabelConfigOverridesNilWriteRelabels(t *testing.T) {
   292  	reg := setupRegistry(t)
   293  
   294  	tenantCfg, err := reg.getTenantConfig(nilRelabelsTenant)
   295  	require.NoError(t, err)
   296  
   297  	// if there are no relabel configs defined for the tenant, it should not override
   298  	assert.Equal(t, tenantCfg.RemoteWrite[0].WriteRelabelConfigs, reg.config.RemoteWrite.Client.WriteRelabelConfigs)
   299  }
   300  
   301  func TestRelabelConfigOverridesEmptySliceWriteRelabels(t *testing.T) {
   302  	reg := setupRegistry(t)
   303  
   304  	tenantCfg, err := reg.getTenantConfig(emptySliceRelabelsTenant)
   305  	require.NoError(t, err)
   306  
   307  	// if there is an empty slice of relabel configs, it should clear existing relabel configs
   308  	assert.Len(t, tenantCfg.RemoteWrite[0].WriteRelabelConfigs, 0)
   309  }
   310  
   311  func TestRelabelConfigOverridesWithErrors(t *testing.T) {
   312  	reg := setupRegistry(t)
   313  
   314  	_, err := reg.getTenantConfig(badRelabelsTenant)
   315  
   316  	// ensure that relabel validation is being applied
   317  	require.EqualError(t, err, "failed to parse relabel configs: labeldrop action requires only 'regex', and no other fields")
   318  }
   319  
   320  func TestWALRegistryCreation(t *testing.T) {
   321  	overrides, err := validation.NewOverrides(validation.Limits{}, nil)
   322  	require.NoError(t, err)
   323  
   324  	regEnabled := newWALRegistry(log.NewNopLogger(), nil, Config{
   325  		RemoteWrite: RemoteWriteConfig{
   326  			Enabled: true,
   327  		},
   328  	}, overrides)
   329  
   330  	_, ok := regEnabled.(*walRegistry)
   331  	assert.Truef(t, ok, "instance is not of expected type")
   332  
   333  	// if remote-write is disabled, setup a null registry
   334  	regDisabled := newWALRegistry(log.NewNopLogger(), nil, Config{
   335  		RemoteWrite: RemoteWriteConfig{
   336  			Enabled: false,
   337  		},
   338  	}, overrides)
   339  
   340  	_, ok = regDisabled.(nullRegistry)
   341  	assert.Truef(t, ok, "instance is not of expected type")
   342  }
   343  
   344  func TestStorageSetup(t *testing.T) {
   345  	reg := setupRegistry(t)
   346  
   347  	// once the registry is setup and we configure the tenant storage, we should be able
   348  	// to acquire an appender for the WAL storage
   349  	reg.configureTenantStorage(enabledRWTenant)
   350  
   351  	test.Poll(t, 2*time.Second, true, func() interface{} {
   352  		return reg.isReady(enabledRWTenant)
   353  	})
   354  
   355  	app := reg.Appender(user.InjectOrgID(context.Background(), enabledRWTenant))
   356  	assert.Equalf(t, "*storage.fanoutAppender", fmt.Sprintf("%T", app), "instance is not of expected type")
   357  }
   358  
   359  func TestStorageSetupWithRemoteWriteDisabled(t *testing.T) {
   360  	reg := setupRegistry(t)
   361  
   362  	// once the registry is setup and we configure the tenant storage, we should be able
   363  	// to acquire an appender for the WAL storage
   364  	reg.configureTenantStorage(disabledRWTenant)
   365  
   366  	// if remote-write is disabled, we use a discardingAppender to not write to the WAL
   367  	app := reg.Appender(user.InjectOrgID(context.Background(), disabledRWTenant))
   368  	_, ok := app.(discardingAppender)
   369  	assert.Truef(t, ok, "instance is not of expected type")
   370  }
   371  
   372  type fakeLimits struct {
   373  	limits map[string]*validation.Limits
   374  }
   375  
   376  func (f fakeLimits) TenantLimits(userID string) *validation.Limits {
   377  	limits, ok := f.limits[userID]
   378  	if !ok {
   379  		return &validation.Limits{}
   380  	}
   381  
   382  	return limits
   383  }
   384  
   385  func (f fakeLimits) AllByUserID() map[string]*validation.Limits {
   386  	return f.limits
   387  }