go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/internal/config/config.go (about)

     1  // Copyright 2024 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package config
    16  
    17  import (
    18  	"context"
    19  
    20  	"google.golang.org/protobuf/proto"
    21  
    22  	"go.chromium.org/luci/common/errors"
    23  	"go.chromium.org/luci/common/logging"
    24  	"go.chromium.org/luci/config"
    25  	"go.chromium.org/luci/config/server/cfgcache"
    26  	"go.chromium.org/luci/config/validation"
    27  	"go.chromium.org/luci/gae/service/datastore"
    28  
    29  	configpb "go.chromium.org/luci/resultdb/proto/config"
    30  )
    31  
    32  const serviceConfigFilename = "config.cfg"
    33  
    34  // Cached service-level config
    35  var cachedServiceCfg = cfgcache.Register(&cfgcache.Entry{
    36  	Path: serviceConfigFilename,
    37  	Type: (*configpb.Config)(nil),
    38  	Validator: func(ctx *validation.Context, msg proto.Message) error {
    39  		validateServiceConfig(ctx, msg.(*configpb.Config))
    40  		return nil
    41  	},
    42  })
    43  
    44  // UpdateConfig is called from a cron periodically; it fetches the latest
    45  // service-wide config and project config from the LUCI Config service
    46  // and caches them into the datastore
    47  func UpdateConfig(ctx context.Context) error {
    48  	var errs []error
    49  	err := UpdateProjects(ctx)
    50  	if err != nil {
    51  		errs = append(errs, errors.Annotate(err, "update project configs").Err())
    52  	}
    53  	err = UpdateServiceConfig(ctx)
    54  	if err != nil {
    55  		errs = append(errs, errors.Annotate(err, "update service configs").Err())
    56  	}
    57  	if len(errs) > 0 {
    58  		return errors.NewMultiError(errs...)
    59  	}
    60  	return nil
    61  
    62  }
    63  
    64  // UpdateServiceConfig fetches the latest service config and caches it in datastore.
    65  func UpdateServiceConfig(ctx context.Context) error {
    66  	_, err := cachedServiceCfg.Update(ctx, nil)
    67  	return err
    68  }
    69  
    70  // GetServiceConfig returns the cached service-level config
    71  func GetServiceConfig(ctx context.Context) (*configpb.Config, error) {
    72  	cfg, err := cachedServiceCfg.Get(ctx, nil)
    73  	if err != nil {
    74  		err = errors.Annotate(err, "failed to get cached config").Err()
    75  		logging.Errorf(ctx, "%s", err.Error())
    76  		return nil, err
    77  	}
    78  
    79  	return cfg.(*configpb.Config), nil
    80  }
    81  
    82  // SetServiceConfig installs the service into the context ctx.
    83  // This is only used for the purpose of testing.
    84  func SetServiceConfig(ctx context.Context, cfg *configpb.Config) error {
    85  	testable := datastore.GetTestable(ctx)
    86  	if testable == nil {
    87  		return errors.New("SetServiceConfig should only be used with testable datastore implementations")
    88  	}
    89  	err := cachedServiceCfg.Set(ctx, cfg, &config.Meta{})
    90  	if err != nil {
    91  		return err
    92  	}
    93  	testable.CatchupIndexes()
    94  	return nil
    95  }