go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/scheduler/appengine/messages/config.proto (about)

     1  // Copyright 2015 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  syntax = "proto3";
    16  
    17  package scheduler.config;
    18  
    19  option go_package = "go.chromium.org/luci/scheduler/appengine/messages";
    20  
    21  import "go.chromium.org/luci/common/proto/options.proto";
    22  import "google/protobuf/duration.proto";
    23  
    24  option (luci.file_metadata) = {
    25    doc_url: "https://config.luci.app/schemas/projects:luci-scheduler.cfg";
    26  };
    27  
    28  
    29  // ProjectConfig defines a schema for a config file that describe jobs belonging
    30  // to some project.
    31  message ProjectConfig {
    32    reserved 4;
    33    reserved "security_options";
    34  
    35    // Job is a set of jobs defined in the project.
    36    repeated Job job = 1;
    37    // Trigger is a set of triggering jobs defined in the project.
    38    repeated Trigger trigger = 2;
    39    // Deprecated and unused. Use realms permissions instead.
    40    repeated AclSet acl_sets = 3 [deprecated = true];
    41  }
    42  
    43  
    44  // Deprecated in favor of LUCI Realms. This proto is totally unused now, exists
    45  // only to not break older configs that still may have deprecated fields
    46  // populated.
    47  message Acl {
    48    enum Role {
    49      READER = 0;
    50      TRIGGERER = 2;
    51      OWNER = 1;
    52    }
    53    Role role = 1 [deprecated = true];
    54    string granted_to = 2 [deprecated = true];
    55  }
    56  
    57  
    58  // Deprecated in favor of LUCI Realms. This proto is totally unused now, exists
    59  // only to not break older configs that still may have deprecated fields
    60  // populated.
    61  message AclSet {
    62    string name = 1 [deprecated = true];
    63    repeated Acl acls = 2 [deprecated = true];
    64  }
    65  
    66  
    67  // TriggeringPolicy defines a function that decides when and how to launch a
    68  // job invocation, given the job's current state and a set of pending triggers.
    69  message TriggeringPolicy {
    70    enum Kind {
    71      // A placeholder for unrecognized policy kind.
    72      UNDEFINED = 0;
    73  
    74      // A greedy triggering function that takes all pending triggers (up to
    75      // max_batch_size limit) and collapses them into one new invocation,
    76      // deriving its properties from the most recent trigger alone. It doesn't
    77      // wait for a full batch, nor tries to batch evenly.
    78      GREEDY_BATCHING = 1;
    79  
    80      // A logarithmic triggering function that takes floor(log(base,N)) pending
    81      // triggers (at least 1 and up to max_batch_size limit) and collapses them
    82      // into one new invocation, deriving its properties from the most recent
    83      // trigger alone, where N is the total number of pending triggers and k is
    84      // specified by the log_base field below.
    85      LOGARITHMIC_BATCHING = 2;
    86  
    87      // A triggering function that prioritizes the most recent pending triggers.
    88      // Triggers stay pending until they either become the most recent pending
    89      // trigger or expire. The timeout for pending triggers is specified by the
    90      // pending_timeout field below.
    91      NEWEST_FIRST = 3;
    92    }
    93  
    94    // Defines an algorithm to use for the triggering decisions.
    95    //
    96    // See comments for Kind enum field.
    97    //
    98    // Default is GREEDY_BATCHING.
    99    Kind kind = 1;
   100  
   101    // Limits number of job invocations running at the same time.
   102    //
   103    // If the number of current active invocations is more or equal to this
   104    // setting, the triggering function will be skipped completely, since it isn't
   105    // allowed to trigger anything anyway.
   106    //
   107    // Default is 1.
   108    int64 max_concurrent_invocations = 2;
   109  
   110    // Limits how many triggers can be put into one invocation request.
   111    //
   112    // For example, setting this to 1 will make each trigger launch its own
   113    // invocation. This value is ignore dby NEWEST_FIRST, since batching
   114    // isn't well-defined in that policy kind.
   115    //
   116    // Default is 1000 (which is ~= unlimited).
   117    int64 max_batch_size = 3;
   118  
   119    // Base of the logarithm operation during logarithmic batching.
   120    //
   121    // For example, setting this to 2, will cause 3 out of 8 pending triggers to
   122    // be combined into a single invocation with LOGARITHMIC_BATCHING kind. This
   123    // value is ignored by other policy kinds. Must be larger or equal to 1.0001
   124    // for numerical stability reasons.
   125    //
   126    // Required.
   127    float log_base = 4;
   128  
   129    // How long until a pending trigger is discarded.
   130    //
   131    // For example, setting this to 1 day will cause triggers that stay pending
   132    // for at least 1 day to be removed from consideration. This value is ignored
   133    // by policy kinds other than NEWEST_FIRST, which can starve old triggers and
   134    // cause the pending triggers list to grow without bound.
   135    //
   136    // Default is 7 days.
   137    google.protobuf.Duration pending_timeout = 5;
   138  }
   139  
   140  
   141  // Job specifies a single regular job belonging to a project.
   142  //
   143  // Such jobs runs on a schedule or can be triggered by some trigger.
   144  message Job {
   145    reserved 4;
   146    reserved 102;
   147  
   148    // Id is a name of the job (unique for the project).
   149    //
   150    // Must match '^[0-9A-Za-z_\-\. \)\(]{1,100}$'.
   151    string id = 1;
   152  
   153    // Realm is a name of a LUCI realm within the project to use for ACLs.
   154    //
   155    // Must match `^[a-z0-9_\.\-/]{1,400}$` or be literals "@root" or "@legacy".
   156    // If not set, defaults to "@legacy".
   157    //
   158    // ACLs associated with a realm are defined separately in realms.cfg file.
   159    // That way they can be shared by multiple services.
   160    string realm = 8;
   161  
   162    // Schedule describes when to run the job.
   163    //
   164    // A job with a schedule can still be triggered by other triggering jobs
   165    // and via "Trigger" button in UI.
   166    //
   167    // Supported kinds of schedules (illustrated by examples):
   168    //   - "* 0 * * * *": cron-like expression, in a syntax supported by
   169    //     https://github.com/gorhill/cronexpr (see its docs for full reference).
   170    //     The cron engine will attempt to start a job at specified moments in
   171    //     time (based on UTC clock). If when triggering a job, previous
   172    //     invocation is still running, an overrun will be recorded (and next
   173    //     attempt to start a job happens based on the schedule, not when the
   174    //     previous invocation finishes). Some examples:
   175    //       "0 */3 * * * *" - each 3 hours: at 12:00 AM UTC, 3:00 AM UTC, ...
   176    //       "0 */3 * * *" - exact same thing (last field is optional)
   177    //       "0 1/3 * * *" - each 3 hours but starting 1:00 AM UTC
   178    //       "0 2,10,18 * * *" - at 2 AM UTC, 10 AM UTC, 6 PM UTC
   179    //       "0 7 * * *" - at 7 AM UTC, once a day.
   180    //   - "with 10s interval": runs invocations in a loop, waiting 10s after
   181    //     finishing invocation before starting a new one. Overruns are not
   182    //     possible.
   183    //   - "continuously" is alias for "with 0s interval", meaning the job will
   184    //     run in a loop without any pauses.
   185    //   - "triggered" schedule indicates that job is only started via a trigger.
   186    //
   187    // Default is "triggered".
   188    string schedule = 2;
   189  
   190    // Disabled is true to disable this job.
   191    //
   192    // Disabled job is equivalent to a deleted job: it can't be triggered, it
   193    // can't be referenced by other jobs and it doesn't show up in UI or API.
   194    //
   195    // Use this instead of commenting out the definition in case you want to
   196    // temporarily git rid of the job.
   197    bool disabled = 3;
   198  
   199    // Deprecated and unused. Use realms permissions instead.
   200    repeated Acl acls = 5 [deprecated = true];
   201    // Deprecated and unused. Use realms permissions instead.
   202    repeated string acl_sets = 6 [deprecated = true];
   203  
   204    // TriggeringPolicy defines how job handles incoming triggering events.
   205    //
   206    // If not specified defaults to GREEDY_BATCHING with 1 max concurrent
   207    // invocation. See comments in TriggeringPolicy for more details.
   208    TriggeringPolicy triggering_policy = 7;
   209  
   210    // One and only one field below must be set. It defines what this job does.
   211  
   212    // Noop is used for testing. It is "do nothing" task.
   213    NoopTask noop = 100;
   214    // UrlFetch can be used to make a simple HTTP call.
   215    UrlFetchTask url_fetch = 101;
   216    // BuildbucketTask can be used to schedule buildbucket job.
   217    BuildbucketTask buildbucket = 103;
   218  }
   219  
   220  
   221  // Trigger specifies a job that triggers other jobs.
   222  //
   223  // It is a special kind of a job that periodically checks the state of the world
   224  // and triggers other jobs.
   225  message Trigger {
   226    // Id is a name of the job (unique for the project).
   227    //
   228    // Must match '^[0-9A-Za-z_\-\. \)\(]{1,100}$'. It's in the same namespace as
   229    // regular jobs.
   230    string id = 1;
   231  
   232    // Realm is a name of a LUCI realm within the project to use for ACLs.
   233    //
   234    // Must match `^[a-z0-9_\.\-/]{1,400}$` or be literals "@root" or "@legacy".
   235    // If not set, defaults to "@legacy".
   236    //
   237    // ACLs associated with a realm are defined separately in realms.cfg file.
   238    // That way they can be shared by multiple services.
   239    string realm = 7;
   240  
   241    // Schedule describes when to run this triggering job.
   242    //
   243    // See Job.schedule for more info. Default is "with 30s interval".
   244    string schedule = 2;
   245  
   246    // Disabled is true to disable this job.
   247    //
   248    // Se Job.disabled for more info.
   249    bool disabled = 3;
   250  
   251    // Deprecated and unused. Use realms permissions instead.
   252    repeated Acl acls = 4 [deprecated = true];
   253    // Deprecated and unused. Use realms permissions instead.
   254    repeated string acl_sets = 5 [deprecated = true];
   255  
   256    // TriggeringPolicy defines how job handles incoming triggering events.
   257    //
   258    // It is rare for a trigger itself to have a non-default triggering policy,
   259    // so most likely you should not touch this field.
   260    TriggeringPolicy triggering_policy = 6;
   261  
   262    // Triggers are IDs of jobs triggered by this trigger.
   263    repeated string triggers = 200;
   264  
   265    // One and only one field below must be set. It defines what this trigger
   266    // polls.
   267  
   268    // Noop is used for testing. It is "do nothing" trigger.
   269    NoopTask noop = 100;
   270    // Gitiles is used to trigger jobs for new commits on Gitiles.
   271    GitilesTask gitiles = 101;
   272  }
   273  
   274  
   275  // NoopTask is used for testing. It is a "do nothing" task that can emit fake
   276  // triggers.
   277  message NoopTask {
   278    int64 sleep_ms = 1;
   279    int64 triggers_count = 2;
   280  }
   281  
   282  
   283  // GitilesTask specifies parameters of what repo and which refs to watch for new
   284  // commits.
   285  //
   286  // GitilesTask will trigger other jobs if either:
   287  //   * ref's tip has changed (e.g. new commit landed on a ref),
   288  //   * a ref has just been created from Scheduler point of view, which is
   289  //     treated as a single new commit.
   290  //     For example, if you configure new GitilesTask or add a ref not previously
   291  //     watched to the existing GitilesTask, then Scheduler will "discover" this
   292  //     ref as newly created and emit exactly 1 trigger for the ref's current
   293  //     tip.
   294  //
   295  //
   296  // LIMITATIONS:
   297  //
   298  //  1. Per each fast-forward ref's tip change as observed by scheduler,
   299  //     no more than 50 latest (according to gitiles default ordering) commits
   300  //     will result in emitted triggers.
   301  //     This is a safeguard against mistaken or deliberate but unusual git push
   302  //     actions, which typically don't have intent of triggering a build for each
   303  //     such commit.
   304  //     If you absolutely need to act on every new commit even in such cases,
   305  //     you will need to roll your own implementation, though you may still find
   306  //     Scheduler GitilesTask useful to trigger your code on new changes.
   307  //
   308  //  2. No hard latency guarantee. A single invocation of GitilesTask may not be
   309  //     able to process all the backlog. This is particularly true after a config
   310  //     change changes the set of watched ref. However, GitilesTask is designed
   311  //     to make continuous progress with each invocation.
   312  message GitilesTask {
   313    // Repo is the URL of the Gitiles repository.
   314    string repo = 1;
   315  
   316    // Refs is a list of Git references to track.
   317    //
   318    // Each ref can be either:
   319    //   * a fully qualified ref like "refs/heads/master" or "refs/tags/v1.2.3"
   320    //   * a regular expression with "regexp:" prefix to match multiple refs, e.g.
   321    //     "regexp:refs/heads/[^/]+" or "regexp:refs/branch-heads/\d+\.\d+", but
   322    //     the regular expression should have a literal prefix with at least two
   323    //     slashes present, e.g. "refs/release-\d+/foobar" is not allowed, because
   324    //     the literal prefix "refs/release-" contains only one slash. The regexp
   325    //     should not start with ^ or end with $ as they will be added
   326    //     automatically.
   327    //
   328    // Each tracked ref, either fully qualified or regexp, must match at least 1
   329    // ref in gitiles output.
   330    repeated string refs = 2;
   331  
   332    // Optional path_regexps and path_regexps_exclude are lists of regular
   333    // expressions limiting emitted triggers only to commits whose tree diff
   334    // touches relevant files.
   335    //
   336    // If neither path_regexps nor path_regexps_exclude is specified (default),
   337    // emits triggers for any commit.
   338    // Specifying just path_regexps_exclude is not allowed.
   339    //
   340    // path_regexps and path_regexps_exclude rules apply on each individual commit
   341    // independently. For each commit, a set of all filepaths referenced in Git
   342    // commit diff is used for matching.  On top of simple file additions and file
   343    // modifications, this also includes: file removals, file moves (old and new
   344    // path is considered), and changing of file metadata (e.g., chmod +x). This
   345    // doesn't include directories (git doesn't track them explicitly).
   346    //
   347    // Triggers are emitted for a commit if only if at least 1 touched filepath
   348    //  1. is not matched by any path_regexps_exclude,
   349    //  2. AND is matched at least 1 path_regexps
   350    // **subject to caveats below** for exceptional cases.
   351    //
   352    // Each path_regexps and path_regexps_exclude is a regular expression
   353    // "a/b/c/.+". It should not start with ^ or end with $ as they will be added
   354    // automatically.
   355    //
   356    // CAVEATS:
   357    //  1. path_regexps: ".+"
   358    //     will NOT match commits which modify no files (aka empty commits) and
   359    //     as such differs from default case of not specifying any `path_regexps`.
   360    //  2. Per GitilesTask doc, if a ref fast-forwards >=50 commits, only the last
   361    //     50 commits are checked. If none of them matches any path specified here,
   362    //     no trigger is emitted, even if there is an unexamined commit which
   363    //     matches the path.
   364    //     TODO(tandrii): it's possible to improve this by examining diff
   365    //     between ref's last and new tips, but one has to worry about gitiles
   366    //     taking potentially very long time to compute it.
   367    //
   368    repeated string path_regexps = 3;
   369    repeated string path_regexps_exclude = 4;
   370  }
   371  
   372  
   373  // UrlFetchTask specifies parameters for simple HTTP call.
   374  message UrlFetchTask {
   375    // Method is HTTP method to use, such as "GET" or "POST". Default is "GET".
   376    string method = 1;
   377    // Url to send the request to.
   378    string url = 2;
   379    // Timeout is how long to wait for request to complete. Default is 60 sec.
   380    int32 timeout_sec = 3;
   381    // TODO: add more.
   382  }
   383  
   384  
   385  // BuildbucketTask specifies parameters of Buildbucket-based jobs.
   386  message BuildbucketTask {
   387    // Server is hostname of the buildbucket service to use.
   388    //
   389    // Typically, "cr-buildbucket.appspot.com".
   390    string server = 1;
   391  
   392    // Bucket defines what bucket to add the task to.
   393    //
   394    // Supported formats are:
   395    //    * "<bucket>" - for a bucket in the current project.
   396    //    * "<project>:<bucket>" - for a bucket in another project.
   397    //    * "luci.<project>.<bucket>" - legacy v1 bucket name.
   398    //
   399    // If empty, defaults to `realm` field in the parent Job message.
   400    string bucket = 2;
   401  
   402    // Builder defines what builder within the bucket to launch.
   403    string builder = 3;
   404  
   405    // Properties is arbitrary "key:value" pairs describing the task.
   406    // TODO(tandrii): which properties will be overridden if triggered?
   407    repeated string properties = 4;
   408  
   409    // Tags is a list of tags (as "key:value" pairs) to assign to the task.
   410    repeated string tags = 5;
   411  }
   412  
   413  
   414  ////////////////////////////////////////////////////////////////////////////////
   415  // Internal stuff.
   416  
   417  // TaskDefWrapper is a union type of all possible tasks known to the scheduler.
   418  //
   419  // It is used internally when storing jobs in the datastore.
   420  message TaskDefWrapper {
   421    reserved 3;
   422  
   423    NoopTask noop = 1;
   424    UrlFetchTask url_fetch = 2;
   425    BuildbucketTask buildbucket = 4;
   426    GitilesTask gitiles = 5;
   427  }