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

     1  // Copyright 2020 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 srvcfg provides service-wide configs.
    16  package srvcfg
    17  
    18  import (
    19  	"context"
    20  	"regexp"
    21  
    22  	"go.chromium.org/luci/common/errors"
    23  	"go.chromium.org/luci/config"
    24  	"go.chromium.org/luci/config/server/cfgcache"
    25  
    26  	listenerpb "go.chromium.org/luci/cv/settings/listener"
    27  )
    28  
    29  var (
    30  	cachedListenerCfg = cfgcache.Register(&cfgcache.Entry{
    31  		Path: "listener-settings.cfg",
    32  		Type: (*listenerpb.Settings)(nil),
    33  	})
    34  )
    35  
    36  // ImportConfig is called from a cron to import and cache all the configs.
    37  func ImportConfig(ctx context.Context) error {
    38  	_, err := cachedListenerCfg.Update(ctx, nil)
    39  	return err
    40  }
    41  
    42  // GetListenerConfig loads cached Listener config.
    43  //
    44  // If meta is not nil, it will be updated with the meta of the loaded config.
    45  func GetListenerConfig(ctx context.Context, meta *config.Meta) (*listenerpb.Settings, error) {
    46  	switch v, err := cachedListenerCfg.Get(ctx, meta); {
    47  	case err != nil:
    48  		return nil, err
    49  	default:
    50  		return v.(*listenerpb.Settings), nil
    51  	}
    52  }
    53  
    54  // SetTestListenerConfig is used in tests only.
    55  func SetTestListenerConfig(ctx context.Context, ls *listenerpb.Settings, m *config.Meta) error {
    56  	return cachedListenerCfg.Set(ctx, ls, m)
    57  }
    58  
    59  // MakeListenerProjectChecker returns a function that checks if a given project
    60  // is enabled in the Listener config.
    61  func MakeListenerProjectChecker(ls *listenerpb.Settings) (isEnabled func(string) bool, err error) {
    62  	res, err := anchorRegexps(ls.GetDisabledProjectRegexps())
    63  	if err != nil {
    64  		// Must be a bug in the validator.
    65  		return nil, errors.Annotate(err, "invalid disabled_project_regexps").Err()
    66  	}
    67  	return func(prj string) bool {
    68  		for _, re := range res {
    69  			if re.Match([]byte(prj)) {
    70  				return false
    71  			}
    72  		}
    73  		return true
    74  	}, nil
    75  }
    76  
    77  // anchorRegexps converts partial match regexs to full matches.
    78  //
    79  // Returns compiled regexps of them.
    80  func anchorRegexps(partials []string) ([]*regexp.Regexp, error) {
    81  	var me errors.MultiError
    82  	var res []*regexp.Regexp
    83  	for _, p := range partials {
    84  		re, err := regexp.Compile("^" + p + "$")
    85  		me.MaybeAdd(err)
    86  		res = append(res, re)
    87  	}
    88  	if me.AsError() == nil {
    89  		return res, nil
    90  	}
    91  	return nil, me
    92  }
    93  
    94  // IsProjectEnabledInListener returns true if a given project is enabled
    95  // in the cached Listener config.
    96  func IsProjectEnabledInListener(ctx context.Context, project string) (bool, error) {
    97  	cfg, err := GetListenerConfig(ctx, nil)
    98  	if err != nil {
    99  		return false, err
   100  	}
   101  	chk, err := MakeListenerProjectChecker(cfg)
   102  	if err != nil {
   103  		return false, err
   104  	}
   105  	return chk(project), nil
   106  }