Documentation ¶
Overview ¶
Package policy contains implementation of Policy parsing and querying.
Policies are configs fetched from LUCI Config and used from Token Server RPCs for various decisions. Each policy is defined by one or more config files, all fetched at a single revision (for consistency) and cached in single datastore entity (for faster fetches).
The defining properties of policy configs are:
- They are global (i.e they are service configs, not per-project ones).
- The content is mostly static.
- They are queried from performance critical RPC handlers.
This suggests to heavily cache policies in local instance memory in a form most suitable for querying.
Thus policies have 3 representations:
- Text protos: that's how they are stored in LUCI Config.
- Binary protos: that's how Token Server stores them in the datastore.
- Queryable state: that's how Token Server keeps them in the local memory.
Index ¶
Constants ¶
This section is empty.
Variables ¶
ErrNoPolicy is returned by Queryable(...) if a policy is not yet available.
This happens when the service is deployed for the first time and policy configs aren't fetched yet. This error will not show up if ImportConfigs succeeded at least once.
Functions ¶
This section is empty.
Types ¶
type ConfigBundle ¶
ConfigBundle is a bunch of related parsed text proto files.
For example, it may be a main top-level config and a bunch of include files it references.
Keys are paths, values are corresponding proto messages. Users are supposed to know themselves what concrete proto types correspond to what paths.
type ConfigFetcher ¶
type ConfigFetcher interface { // FetchTextProto fetches text-serialized protobuf message at a given path. // // The path is relative to the token server config set root in LUCI config. // // On success returns nil and fills in 'out' (which should be a pointer to // a concrete proto message class). May return transient error (e.g timeouts) // and fatal ones (e.g bad proto file). FetchTextProto(c context.Context, path string, out proto.Message) error }
ConfigFetcher hides details of interaction with LUCI Config.
Passed to Fetch callback.
type Policy ¶
type Policy struct { // Name defines the name of the policy, e.g. "delegation rules". // // It is used in datastore IDs and for logging. Name string // Fetch fetches and parses all relevant text proto files. // // This is a user-supplied callback. // // Called from cron when ingesting new configs. It must return either a non // empty bundle with configs or an error. Fetch func(c context.Context, f ConfigFetcher) (ConfigBundle, error) // Validate verifies the fetched config files are semantically valid. // // This is a user-supplied callback. Must be a pure function. // // Reports all errors through the given validation.Context object. The config // is considered valid if there are no errors reported. A valid config must be // accepted by Prepare without errors. // // Called from cron when ingesting new configs. Validate func(cfg ConfigBundle, v *validation.Context) // Prepare converts validated configs into an optimized queryable form. // // This is a user-supplied callback. Must be a pure function. // // The result of the processing is cached in local instance memory for 1 min. // It is supposed to be a read-only object, optimized for performing queries // over it. // // Users of Policy should type-cast it to an appropriate type. Prepare func(cfg ConfigBundle, revision string) (Queryable, error) // contains filtered or unexported fields }
Policy describes how to fetch, store and parse policy documents.
This is a singleton-like object that should be shared by multiple requests.
Each instance corresponds to one kind of a policy and it keeps a Queryable form if the corresponding policy cached in local memory, occasionally updating it based on the configs stored in the datastore (that are in turn periodically updated from a cron).
func (*Policy) ImportConfigs ¶
ImportConfigs updates configs stored in the datastore.
Is should be periodically called from a cron.
Returns the revision of the configs that are now in the datastore. It's either the imported revision, if configs change, or a previously known revision, if configs at HEAD are same.
Validation errors are returned as *validation.Error struct. Use type cast to sniff them, if necessary.
func (*Policy) Queryable ¶
Queryable returns a form of the policy document optimized for queries.
This is hot function called from each RPC handler. It uses local in-memory cache to store the configs, synchronizing it with the state stored in the datastore once a minute.
Returns ErrNoPolicy if the policy config wasn't imported yet.
type Queryable ¶
type Queryable interface { // ConfigRevision returns the revision passed to Policy.Prepare. // // It is a revision of configs used to construct this object. Used for // logging. ConfigRevision() string }
Queryable is validated and parsed configs in a form optimized for queries.
This object is shared between multiple requests and kept in memory for as long as it still matches the current config.