[LogCLI] Load tenant-specific schema config file when using `--remote-schema` (#8413)

Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
pull/8421/head
Christian Haudum 2 years ago committed by GitHub
parent 5447541e2e
commit 2139dbf55f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      CHANGELOG.md
  2. 3
      docs/sources/tools/logcli.md
  3. 54
      pkg/logcli/query/query.go
  4. 17
      pkg/logcli/query/query_test.go

@ -65,6 +65,12 @@
##### Changes ##### Changes
#### LogCLI
##### Enhancement
* [8413](https://github.com/grafana/loki/pull/8413) **chaudum**: Try to load tenant-specific `schemaconfig-{orgID}.yaml` when using `--remote-schema` argument and fallback to global `schemaconfig.yaml`.
#### Fluent Bit #### Fluent Bit
#### Loki Canary #### Loki Canary

@ -372,9 +372,6 @@ Flags:
--remote-schema Execute the current query using a remote schema --remote-schema Execute the current query using a remote schema
retrieved using the configured storage in the retrieved using the configured storage in the
given Loki configuration file. given Loki configuration file.
--remote-schema Execute the current query using a remote schema
retrieved using the configured storage in the given
Loki configuration file.
--colored-output Show output with colored labels --colored-output Show output with colored labels
-t, --tail Tail the logs -t, --tail Tail the logs
-f, --follow Alias for --tail -f, --follow Alias for --tail

@ -18,6 +18,7 @@ import (
"github.com/weaveworks/common/user" "github.com/weaveworks/common/user"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/grafana/dskit/multierror"
"github.com/grafana/loki/pkg/logcli/client" "github.com/grafana/loki/pkg/logcli/client"
"github.com/grafana/loki/pkg/logcli/output" "github.com/grafana/loki/pkg/logcli/output"
"github.com/grafana/loki/pkg/loghttp" "github.com/grafana/loki/pkg/loghttp"
@ -36,7 +37,7 @@ import (
"github.com/grafana/loki/pkg/validation" "github.com/grafana/loki/pkg/validation"
) )
const SchemaConfigFilename = "schemaconfig.yaml" const schemaConfigFilename = "schemaconfig"
type streamEntryPair struct { type streamEntryPair struct {
entry loghttp.Entry entry loghttp.Entry
@ -197,7 +198,11 @@ func (q *Query) DoLocalQuery(out output.LogOutput, statistics bool, orgID string
return err return err
} }
loadedSchema, err := LoadSchemaUsingObjectClient(client, SchemaConfigFilename) objects := []string{
fmt.Sprintf("%s-%s.yaml", orgID, schemaConfigFilename), // schemaconfig-tenant.yaml
fmt.Sprintf("%s.yaml", schemaConfigFilename), // schemaconfig.yaml for backwards compatibility
}
loadedSchema, err := LoadSchemaUsingObjectClient(client, objects...)
if err != nil { if err != nil {
return err return err
} }
@ -284,24 +289,37 @@ type schemaConfigSection struct {
config.SchemaConfig `yaml:"schema_config"` config.SchemaConfig `yaml:"schema_config"`
} }
func LoadSchemaUsingObjectClient(oc chunk.ObjectClient, name string) (*config.SchemaConfig, error) { // LoadSchemaUsingObjectClient returns the loaded schema from the first found object
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second)) func LoadSchemaUsingObjectClient(oc chunk.ObjectClient, names ...string) (*config.SchemaConfig, error) {
defer cancel() errors := multierror.New()
rdr, _, err := oc.GetObject(ctx, name) for _, name := range names {
if err != nil { schema, err := func(name string) (*config.SchemaConfig, error) {
return nil, err ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
} defer cancel()
defer rdr.Close() rdr, _, err := oc.GetObject(ctx, name)
if err != nil {
return nil, err
}
defer rdr.Close()
decoder := yaml.NewDecoder(rdr) decoder := yaml.NewDecoder(rdr)
decoder.SetStrict(true) decoder.SetStrict(true)
section := schemaConfigSection{} section := schemaConfigSection{}
err = decoder.Decode(&section) err = decoder.Decode(&section)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &section.SchemaConfig, nil
}(name)
return &section.SchemaConfig, nil if err != nil {
errors = append(errors, err)
continue
}
return schema, nil
}
return nil, errors.Err()
} }
// SetInstant makes the Query an instant type // SetInstant makes the Query an instant type

@ -614,19 +614,28 @@ func TestLoadFromURL(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, client) require.NotNil(t, client)
// Missing schema.config file should error filename := "schemaconfig.yaml"
schemaConfig, err := LoadSchemaUsingObjectClient(client, SchemaConfigFilename)
// Missing schemaconfig.yaml file should error
schemaConfig, err := LoadSchemaUsingObjectClient(client, filename)
require.Error(t, err) require.Error(t, err)
require.Nil(t, schemaConfig) require.Nil(t, schemaConfig)
err = os.WriteFile( err = os.WriteFile(
filepath.Join(tmpDir, SchemaConfigFilename), filepath.Join(tmpDir, filename),
[]byte(schemaConfigContents), []byte(schemaConfigContents),
0666, 0666,
) )
require.NoError(t, err) require.NoError(t, err)
schemaConfig, err = LoadSchemaUsingObjectClient(client, SchemaConfigFilename) // Load single schemaconfig.yaml
schemaConfig, err = LoadSchemaUsingObjectClient(client, filename)
require.NoError(t, err)
require.NotNil(t, schemaConfig)
// Load multiple schemaconfig files
schemaConfig, err = LoadSchemaUsingObjectClient(client, "foo.yaml", filename, "bar.yaml")
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, schemaConfig) require.NotNil(t, schemaConfig)

Loading…
Cancel
Save