github.com/sequix/cortex@v1.1.6/pkg/chunk/storage/factory.go (about)

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/go-kit/kit/log/level"
    11  	"github.com/pkg/errors"
    12  	"github.com/sequix/cortex/pkg/chunk"
    13  	"github.com/sequix/cortex/pkg/chunk/aws"
    14  	"github.com/sequix/cortex/pkg/chunk/baidu"
    15  	"github.com/sequix/cortex/pkg/chunk/cache"
    16  	"github.com/sequix/cortex/pkg/chunk/cassandra"
    17  	"github.com/sequix/cortex/pkg/chunk/gcp"
    18  	"github.com/sequix/cortex/pkg/chunk/local"
    19  	"github.com/sequix/cortex/pkg/chunk/ts"
    20  	"github.com/sequix/cortex/pkg/util"
    21  	"github.com/sequix/cortex/pkg/util/validation"
    22  )
    23  
    24  // Config chooses which storage client to use.
    25  type Config struct {
    26  	AWSStorageConfig       aws.StorageConfig         `yaml:"aws"`
    27  	GCPStorageConfig       gcp.Config                `yaml:"bigtable"`
    28  	GCSConfig              gcp.GCSConfig             `yaml:"gcs"`
    29  	CassandraStorageConfig cassandra.Config          `yaml:"cassandra"`
    30  	BoltDBConfig           local.BoltDBConfig        `yaml:"boltdb"`
    31  	FSConfig               local.FSConfig            `yaml:"filesystem"`
    32  	BOSConfig              baidu.ObjectStorageConfig `yaml:"bos"`
    33  	TableStorageConfig     ts.Config                 `yaml:"table_storage"`
    34  
    35  	IndexCacheValidity time.Duration
    36  
    37  	IndexQueriesCacheConfig cache.Config `yaml:"index_queries_cache_config,omitempty"`
    38  }
    39  
    40  // RegisterFlags adds the flags required to configure this flag set.
    41  func (cfg *Config) RegisterFlags(f *flag.FlagSet) {
    42  	cfg.AWSStorageConfig.RegisterFlags(f)
    43  	cfg.GCPStorageConfig.RegisterFlags(f)
    44  	cfg.GCSConfig.RegisterFlags(f)
    45  	cfg.CassandraStorageConfig.RegisterFlags(f)
    46  	cfg.BoltDBConfig.RegisterFlags(f)
    47  	cfg.FSConfig.RegisterFlags(f)
    48  
    49  	cfg.IndexQueriesCacheConfig.RegisterFlagsWithPrefix("store.index-cache-read.", "Cache config for index entry reading. ", f)
    50  	f.DurationVar(&cfg.IndexCacheValidity, "store.index-cache-validity", 5*time.Minute, "Cache validity for active index entries. Should be no higher than -ingester.max-chunk-idle.")
    51  }
    52  
    53  // NewStore makes the storage clients based on the configuration.
    54  func NewStore(cfg Config, storeCfg chunk.StoreConfig, schemaCfg chunk.SchemaConfig, limits *validation.Overrides) (chunk.Store, error) {
    55  	tieredCache, err := cache.New(cfg.IndexQueriesCacheConfig)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	// Cache is shared by multiple stores, which means they will try and Stop
    61  	// it more than once.  Wrap in a StopOnce to prevent this.
    62  	tieredCache = cache.StopOnce(tieredCache)
    63  
    64  	err = schemaCfg.Load()
    65  	if err != nil {
    66  		return nil, errors.Wrap(err, "error loading schema config")
    67  	}
    68  	stores := chunk.NewCompositeStore()
    69  
    70  	for _, s := range schemaCfg.Configs {
    71  		index, err := NewIndexClient(s.IndexType, cfg, schemaCfg)
    72  		if err != nil {
    73  			return nil, errors.Wrap(err, "error creating index client")
    74  		}
    75  		index = newCachingIndexClient(index, tieredCache, cfg.IndexCacheValidity, limits)
    76  
    77  		objectStoreType := s.ObjectType
    78  		if objectStoreType == "" {
    79  			objectStoreType = s.IndexType
    80  		}
    81  		chunks, err := NewObjectClient(objectStoreType, cfg, schemaCfg)
    82  		if err != nil {
    83  			return nil, errors.Wrap(err, "error creating object client")
    84  		}
    85  
    86  		err = stores.AddPeriod(storeCfg, s, index, chunks, limits)
    87  		if err != nil {
    88  			return nil, err
    89  		}
    90  	}
    91  
    92  	return stores, nil
    93  }
    94  
    95  // NewIndexClient makes a new index client of the desired type.
    96  func NewIndexClient(name string, cfg Config, schemaCfg chunk.SchemaConfig) (chunk.IndexClient, error) {
    97  	switch name {
    98  	case "inmemory":
    99  		store := chunk.NewMockStorage()
   100  		return store, nil
   101  	case "aws", "aws-dynamo", "dynamo":
   102  		if cfg.AWSStorageConfig.DynamoDB.URL == nil {
   103  			return nil, fmt.Errorf("Must set -dynamodb.url in aws mode")
   104  		}
   105  		path := strings.TrimPrefix(cfg.AWSStorageConfig.DynamoDB.URL.Path, "/")
   106  		if len(path) > 0 {
   107  			level.Warn(util.Logger).Log("msg", "ignoring DynamoDB URL path", "path", path)
   108  		}
   109  		return aws.NewDynamoDBIndexClient(cfg.AWSStorageConfig.DynamoDBConfig, schemaCfg)
   110  	case "gcp":
   111  		return gcp.NewStorageClientV1(context.Background(), cfg.GCPStorageConfig, schemaCfg)
   112  	case "gcp-columnkey", "bigtable":
   113  		return gcp.NewStorageClientColumnKey(context.Background(), cfg.GCPStorageConfig, schemaCfg)
   114  	case "bigtable-hashed":
   115  		cfg.GCPStorageConfig.DistributeKeys = true
   116  		return gcp.NewStorageClientColumnKey(context.Background(), cfg.GCPStorageConfig, schemaCfg)
   117  	case "cassandra":
   118  		return cassandra.NewStorageClient(cfg.CassandraStorageConfig, schemaCfg)
   119  	case "boltdb":
   120  		return local.NewBoltDBIndexClient(cfg.BoltDBConfig)
   121  	default:
   122  		return nil, fmt.Errorf("Unrecognized storage client %v, choose one of: aws, cassandra, inmemory, gcp, bigtable, bigtable-hashed", name)
   123  	}
   124  }
   125  
   126  // NewObjectClient makes a new ObjectClient of the desired types.
   127  func NewObjectClient(name string, cfg Config, schemaCfg chunk.SchemaConfig) (chunk.ObjectClient, error) {
   128  	switch name {
   129  	case "inmemory":
   130  		store := chunk.NewMockStorage()
   131  		return store, nil
   132  	case "aws", "s3":
   133  		return aws.NewS3ObjectClient(cfg.AWSStorageConfig, schemaCfg)
   134  	case "aws-dynamo", "dynamo":
   135  		if cfg.AWSStorageConfig.DynamoDB.URL == nil {
   136  			return nil, fmt.Errorf("Must set -dynamodb.url in aws mode")
   137  		}
   138  		path := strings.TrimPrefix(cfg.AWSStorageConfig.DynamoDB.URL.Path, "/")
   139  		if len(path) > 0 {
   140  			level.Warn(util.Logger).Log("msg", "ignoring DynamoDB URL path", "path", path)
   141  		}
   142  		return aws.NewDynamoDBObjectClient(cfg.AWSStorageConfig.DynamoDBConfig, schemaCfg)
   143  	case "gcp":
   144  		return gcp.NewBigtableObjectClient(context.Background(), cfg.GCPStorageConfig, schemaCfg)
   145  	case "gcp-columnkey", "bigtable", "bigtable-hashed":
   146  		return gcp.NewBigtableObjectClient(context.Background(), cfg.GCPStorageConfig, schemaCfg)
   147  	case "gcs":
   148  		return gcp.NewGCSObjectClient(context.Background(), cfg.GCSConfig, schemaCfg)
   149  	case "cassandra":
   150  		return cassandra.NewStorageClient(cfg.CassandraStorageConfig, schemaCfg)
   151  	case "filesystem":
   152  		return local.NewFSObjectClient(cfg.FSConfig)
   153  	case "bos":
   154  		return baidu.New(cfg.BOSConfig)
   155  	case "table-storage":
   156  		return ts.New(cfg.TableStorageConfig)
   157  	default:
   158  		return nil, fmt.Errorf("Unrecognized storage client %v, choose one of: aws, cassandra, inmemory, gcp, bigtable, bigtable-hashed", name)
   159  	}
   160  }
   161  
   162  // NewTableClient makes a new table client based on the configuration.
   163  func NewTableClient(name string, cfg Config) (chunk.TableClient, error) {
   164  	switch name {
   165  	case "inmemory":
   166  		return chunk.NewMockStorage(), nil
   167  	case "aws", "aws-dynamo":
   168  		if cfg.AWSStorageConfig.DynamoDB.URL == nil {
   169  			return nil, fmt.Errorf("Must set -dynamodb.url in aws mode")
   170  		}
   171  		path := strings.TrimPrefix(cfg.AWSStorageConfig.DynamoDB.URL.Path, "/")
   172  		if len(path) > 0 {
   173  			level.Warn(util.Logger).Log("msg", "ignoring DynamoDB URL path", "path", path)
   174  		}
   175  		return aws.NewDynamoDBTableClient(cfg.AWSStorageConfig.DynamoDBConfig)
   176  	case "gcp", "gcp-columnkey", "bigtable", "bigtable-hashed":
   177  		return gcp.NewTableClient(context.Background(), cfg.GCPStorageConfig)
   178  	case "cassandra":
   179  		return cassandra.NewTableClient(context.Background(), cfg.CassandraStorageConfig)
   180  	case "boltdb":
   181  		return local.NewTableClient(cfg.BoltDBConfig.Directory)
   182  	default:
   183  		return nil, fmt.Errorf("Unrecognized storage client %v, choose one of: aws, cassandra, inmemory, gcp, bigtable, bigtable-hashed", name)
   184  	}
   185  }
   186  
   187  // NewBucketClient makes a new bucket client based on the configuration.
   188  func NewBucketClient(storageConfig Config) (chunk.BucketClient, error) {
   189  	if storageConfig.FSConfig.Directory != "" {
   190  		return local.NewFSObjectClient(storageConfig.FSConfig)
   191  	}
   192  
   193  	return nil, nil
   194  }