blob: 11973d31fe03a92375026b3607ce38945168566d [file] [log] [blame]
// Copyright 2015 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package scheduler.config;
option go_package = "go.chromium.org/luci/scheduler/appengine/messages";
import "go.chromium.org/luci/common/proto/options.proto";
option (luci.file_metadata) = {
doc_url: "https://luci-config.appspot.com/schemas/projects:luci-scheduler.cfg";
};
// ProjectConfig defines a schema for a config file that describe jobs belonging
// to some project.
message ProjectConfig {
reserved 4;
reserved "security_options";
// Job is a set of jobs defined in the project.
repeated Job job = 1;
// Trigger is a set of triggering jobs defined in the project.
repeated Trigger trigger = 2;
// Deprecated and unused. Use realms permissions instead.
repeated AclSet acl_sets = 3 [deprecated = true];
}
// Deprecated in favor of LUCI Realms. This proto is totally unused now, exists
// only to not break older configs that still may have deprecated fields
// populated.
message Acl {
enum Role {
READER = 0;
TRIGGERER = 2;
OWNER = 1;
}
Role role = 1 [deprecated = true];
string granted_to = 2 [deprecated = true];
}
// Deprecated in favor of LUCI Realms. This proto is totally unused now, exists
// only to not break older configs that still may have deprecated fields
// populated.
message AclSet {
string name = 1 [deprecated = true];
repeated Acl acls = 2 [deprecated = true];
}
// TriggeringPolicy defines a function that decides when and how to launch a
// job invocation, given the job's current state and a set of pending triggers.
message TriggeringPolicy {
enum Kind {
// A placeholder for unrecognized policy kind.
UNDEFINED = 0;
// A greedy triggering function that takes all pending triggers (up to
// max_batch_size limit) and collapses them into one new invocation,
// deriving its properties from the most recent trigger alone. It doesn't
// wait for a full batch, nor tries to batch evenly.
GREEDY_BATCHING = 1;
// A logarithmic triggering function that takes floor(log(base,N)) pending
// triggers (at least 1 and up to max_batch_size limit) and collapses them
// into one new invocation, deriving its properties from the most recent
// trigger alone, where N is the total number of pending triggers and k is
// specified by the log_base field below.
LOGARITHMIC_BATCHING = 2;
}
// Defines an algorithm to use for the triggering decisions.
//
// See comments for Kind enum field.
//
// Default is GREEDY_BATCHING.
Kind kind = 1;
// Limits number of job invocations running at the same time.
//
// If the number of current active invocations is more or equal to this
// setting, the triggering function will be skipped completely, since it isn't
// allowed to trigger anything anyway.
//
// Default is 1.
int64 max_concurrent_invocations = 2;
// Limits how many triggers can be put into one invocation request.
//
// For example, setting this to 1 will make each trigger launch its own
// invocation.
//
// Default is 1000 (which is ~= unlimited).
int64 max_batch_size = 3;
// Base of the logarithm operation during logarithmic batching.
//
// For example, setting this to 2, will cause 3 out of 8 pending triggers to
// be combined into a single invocation with LOGARITHMIC_BATCHING kind. This
// value is ignored by other policy kinds. Must be larger or equal to 1.0001
// for numerical stability reasons.
//
// Required.
float log_base = 4;
}
// Job specifies a single regular job belonging to a project.
//
// Such jobs runs on a schedule or can be triggered by some trigger.
message Job {
reserved 4;
reserved 102;
// Id is a name of the job (unique for the project).
//
// Must match '^[0-9A-Za-z_\-\. \)\(]{1,100}$'.
string id = 1;
// Realm is a name of a LUCI realm within the project to use for ACLs.
//
// Must match `^[a-z0-9_\.\-/]{1,400}$` or be literals "@root" or "@legacy".
// If not set, defaults to "@legacy".
//
// ACLs associated with a realm are defined separately in realms.cfg file.
// That way they can be shared by multiple services.
string realm = 8;
// Schedule describes when to run the job.
//
// A job with a schedule can still be triggered by other triggering jobs
// and via "Trigger" button in UI.
//
// Supported kinds of schedules (illustrated by examples):
// - "* 0 * * * *": cron-like expression, in a syntax supported by
// https://github.com/gorhill/cronexpr (see its docs for full reference).
// The cron engine will attempt to start a job at specified moments in
// time (based on UTC clock). If when triggering a job, previous
// invocation is still running, an overrun will be recorded (and next
// attempt to start a job happens based on the schedule, not when the
// previous invocation finishes). Some examples:
// "0 */3 * * * *" - each 3 hours: at 12:00 AM UTC, 3:00 AM UTC, ...
// "0 */3 * * *" - exact same thing (last field is optional)
// "0 1/3 * * *" - each 3 hours but starting 1:00 AM UTC
// "0 2,10,18 * * *" - at 2 AM UTC, 10 AM UTC, 6 PM UTC
// "0 7 * * *" - at 7 AM UTC, once a day.
// - "with 10s interval": runs invocations in a loop, waiting 10s after
// finishing invocation before starting a new one. Overruns are not
// possible.
// - "continuously" is alias for "with 0s interval", meaning the job will
// run in a loop without any pauses.
// - "triggered" schedule indicates that job is only started via a trigger.
//
// Default is "triggered".
string schedule = 2;
// Disabled is true to disable this job.
//
// Disabled job is equivalent to a deleted job: it can't be triggered, it
// can't be referenced by other jobs and it doesn't show up in UI or API.
//
// Use this instead of commenting out the definition in case you want to
// temporarily git rid of the job.
bool disabled = 3;
// Deprecated and unused. Use realms permissions instead.
repeated Acl acls = 5 [deprecated = true];
// Deprecated and unused. Use realms permissions instead.
repeated string acl_sets = 6 [deprecated = true];
// TriggeringPolicy defines how job handles incoming triggering events.
//
// If not specified defaults to GREEDY_BATCHING with 1 max concurrent
// invocation. See comments in TriggeringPolicy for more details.
TriggeringPolicy triggering_policy = 7;
// One and only one field below must be set. It defines what this job does.
// Noop is used for testing. It is "do nothing" task.
NoopTask noop = 100;
// UrlFetch can be used to make a simple HTTP call.
UrlFetchTask url_fetch = 101;
// BuildbucketTask can be used to schedule buildbucket job.
BuildbucketTask buildbucket = 103;
}
// Trigger specifies a job that triggers other jobs.
//
// It is a special kind of a job that periodically checks the state of the world
// and triggers other jobs.
message Trigger {
// Id is a name of the job (unique for the project).
//
// Must match '^[0-9A-Za-z_\-\. \)\(]{1,100}$'. It's in the same namespace as
// regular jobs.
string id = 1;
// Realm is a name of a LUCI realm within the project to use for ACLs.
//
// Must match `^[a-z0-9_\.\-/]{1,400}$` or be literals "@root" or "@legacy".
// If not set, defaults to "@legacy".
//
// ACLs associated with a realm are defined separately in realms.cfg file.
// That way they can be shared by multiple services.
string realm = 7;
// Schedule describes when to run this triggering job.
//
// See Job.schedule for more info. Default is "with 30s interval".
string schedule = 2;
// Disabled is true to disable this job.
//
// Se Job.disabled for more info.
bool disabled = 3;
// Deprecated and unused. Use realms permissions instead.
repeated Acl acls = 4 [deprecated = true];
// Deprecated and unused. Use realms permissions instead.
repeated string acl_sets = 5 [deprecated = true];
// TriggeringPolicy defines how job handles incoming triggering events.
//
// It is rare for a trigger itself to have a non-default triggering policy,
// so most likely you should not touch this field.
TriggeringPolicy triggering_policy = 6;
// Triggers are IDs of jobs triggered by this trigger.
repeated string triggers = 200;
// One and only one field below must be set. It defines what this trigger
// polls.
// Noop is used for testing. It is "do nothing" trigger.
NoopTask noop = 100;
// Gitiles is used to trigger jobs for new commits on Gitiles.
GitilesTask gitiles = 101;
}
// NoopTask is used for testing. It is a "do nothing" task that can emit fake
// triggers.
message NoopTask {
int64 sleep_ms = 1;
int64 triggers_count = 2;
}
// GitilesTask specifies parameters of what repo and which refs to watch for new
// commits.
//
// GitilesTask will trigger other jobs if either:
// * ref's tip has changed (e.g. new commit landed on a ref),
// * a ref has just been created from Scheduler point of view, which is
// treated as a single new commit.
// For example, if you configure new GitilesTask or add a ref not previously
// watched to the existing GitilesTask, then Scheduler will "discover" this
// ref as newly created and emit exactly 1 trigger for the ref's current
// tip.
//
//
// LIMITATIONS:
//
// 1. Per each fast-forward ref's tip change as observed by scheduler,
// no more than 50 latest (according to gitiles default ordering) commits
// will result in emitted triggers.
// This is a safeguard against mistaken or deliberate but unusual git push
// actions, which typically don't have intent of triggering a build for each
// such commit.
// If you absolutely need to act on every new commit even in such cases,
// you will need to roll your own implementation, though you may still find
// Scheduler GitilesTask useful to trigger your code on new changes.
//
// 2. No hard latency guarantee. A single invocation of GitilesTask may not be
// able to process all the backlog. This is particularly true after a config
// change changes the set of watched ref. However, GitilesTask is designed
// to make continuous progress with each invocation.
message GitilesTask {
// Repo is the URL of the Gitiles repository.
string repo = 1;
// Refs is a list of Git references to track.
//
// Each ref can be either:
// * a fully qualified ref like "refs/heads/master" or "refs/tags/v1.2.3"
// * a regular expression with "regexp:" prefix to match multiple refs, e.g.
// "regexp:refs/heads/[^/]+" or "regexp:refs/branch-heads/\d+\.\d+", but
// the regular expression should have a literal prefix with at least two
// slashes present, e.g. "refs/release-\d+/foobar" is not allowed, because
// the literal prefix "refs/release-" contains only one slash. The regexp
// should not start with ^ or end with $ as they will be added
// automatically.
//
// Each tracked ref, either fully qualified or regexp, must match at least 1
// ref in gitiles output.
repeated string refs = 2;
// Optional path_regexps and path_regexps_exclude are lists of regular
// expressions limiting emitted triggers only to commits whose tree diff
// touches relevant files.
//
// If neither path_regexps nor path_regexps_exclude is specified (default),
// emits triggers for any commit.
// Specifying just path_regexps_exclude is not allowed.
//
// path_regexps and path_regexps_exclude rules apply on each individual commit
// independently. For each commit, a set of all filepaths referenced in Git
// commit diff is used for matching. On top of simple file additions and file
// modifications, this also includes: file removals, file moves (old and new
// path is considered), and changing of file metadata (e.g., chmod +x). This
// doesn't include directories (git doesn't track them explicitly).
//
// Triggers are emitted for a commit if only if at least 1 touched filepath
// 1. is not matched by any path_regexps_exclude,
// 2. AND is matched at least 1 path_regexps
// **subject to caveats below** for exceptional cases.
//
// Each path_regexps and path_regexps_exclude is a regular expression
// "a/b/c/.+". It should not start with ^ or end with $ as they will be added
// automatically.
//
// CAVEATS:
// 1. path_regexps: ".+"
// will NOT match commits which modify no files (aka empty commits) and
// as such differs from default case of not specifying any `path_regexps`.
// 2. Per GitilesTask doc, if a ref fast-forwards >=50 commits, only the last
// 50 commits are checked. If none of them matches any path specified here,
// no trigger is emitted, even if there is an unexamined commit which
// matches the path.
// TODO(tandrii): it's possible to improve this by examining diff
// between ref's last and new tips, but one has to worry about gitiles
// taking potentially very long time to compute it.
repeated string path_regexps = 3;
repeated string path_regexps_exclude = 4;
}
// UrlFetchTask specifies parameters for simple HTTP call.
message UrlFetchTask {
// Method is HTTP method to use, such as "GET" or "POST". Default is "GET".
string method = 1;
// Url to send the request to.
string url = 2;
// Timeout is how long to wait for request to complete. Default is 60 sec.
int32 timeout_sec = 3;
// TODO: add more.
}
// BuildbucketTask specifies parameters of Buildbucket-based jobs.
message BuildbucketTask {
// Server is hostname of the buildbucket service to use.
//
// Typically, "cr-buildbucket.appspot.com".
string server = 1;
// Bucket defines what bucket to add the task to.
//
// Supported formats are:
// * "<bucket>" - for a bucket in the current project.
// * "<project>:<bucket>" - for a bucket in another project.
// * "luci.<project>.<bucket>" - legacy v1 bucket name.
//
// If empty, defaults to `realm` field in the parent Job message.
string bucket = 2;
// Builder defines what builder within the bucket to launch.
string builder = 3;
// Properties is arbitrary "key:value" pairs describing the task.
// TODO(tandrii): which properties will be overridden if triggered?
repeated string properties = 4;
// Tags is a list of tags (as "key:value" pairs) to assign to the task.
repeated string tags = 5;
}
////////////////////////////////////////////////////////////////////////////////
// Internal stuff.
// TaskDefWrapper is a union type of all possible tasks known to the scheduler.
//
// It is used internally when storing jobs in the datastore.
message TaskDefWrapper {
reserved 3;
NoopTask noop = 1;
UrlFetchTask url_fetch = 2;
BuildbucketTask buildbucket = 4;
GitilesTask gitiles = 5;
}