Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Conditionals to Resource Creation #49

Closed
vtereso opened this issue Jul 30, 2019 · 24 comments
Closed

Add Conditionals to Resource Creation #49

vtereso opened this issue Jul 30, 2019 · 24 comments
Assignees
Labels
kind/design Categorizes issue or PR as related to design. maybe-next-milestone
Milestone

Comments

@vtereso
Copy link

vtereso commented Jul 30, 2019

Expected Behavior

Users should be able to specify a Conditional against event payload values to ensure that resources are generated dependent on the payload data. For context, webhook POST data from GitHub specifies the source organization/repository/branch. Users will want to make TriggerBindings that execute against particular branches, etc.

Actual Behavior

Currently, this is no conditional creation.

Additional Info

Add Conditionals to the TriggerBindingSpec. Values should be interpolated from the event into the fields being asserted. Documentation should be included.

@vincent-pli
Copy link
Member

So, the Condition means general Condition, not the Condition in tekton pipeline?

@vtereso
Copy link
Author

vtereso commented Aug 1, 2019

So, the Condition means general Condition, not the Condition in tekton pipeline?

I believe we should be using Tekton pipeline Conditions for this.

@vincent-pli
Copy link
Member

I feel it's a little heavy, Conditions in pipeline will launch container to do the comparing.
Image that, when received a event, we need create pod only for string comparison...

@vtereso
Copy link
Author

vtereso commented Aug 1, 2019

I feel it's a little heavy, Conditions in pipeline will launch container to do the comparing.
Image that, when received a event, we need create pod only for string comparison...

@vincent-pli That's true. I made a point in counter argument to the Conditionals initially because I can't really see much besides string comparison to be done, especially here. Tekton is probably better served to used Conditions because the work has already been kicked off and the time it takes the Condition to complete is minuscule in comparison to the entire workload. Where as here, many events are likely to come in and we don't want to get bottle-necked this way. I see both sides because maybe the the payload has some special value that has to be computed upon/set somewhere and only providing some internal string match might not be sufficient.

@vtereso
Copy link
Author

vtereso commented Aug 1, 2019

This work is still blocked, but I think discussion in the issues like this is great. Opinions? @bobcatfish @ncskier @iancoffey @EliZucker

@dlorenc
Copy link
Contributor

dlorenc commented Aug 8, 2019

So to clarify, today we have something like:

http:
  headerMatch:
    foo=bar

We could extend this to support more advanced filtering with something like:

http:
  headerMatch:
    foo=bar
  bodyMatch:
    a.b.c=foo

Where a.b.c is a nested json field.

Other questions:

  • What type of matching?
  • Do we need regex?
  • Not equals? Equals?

@vtereso
Copy link
Author

vtereso commented Aug 8, 2019

The header match field is sort of a contrived way of allowing access to the headers without having to introduce a new interpolation variable (like ${header}) since ${event} extracts from the payload (no access to headers currently). This was the delineation between headers and conditionals in a way. If we were to introduce direct/interpolation access to the headers, maybe conditions/conditonals could encapsulate headers? Maybe having an explicit headers field is still favorable?

@ghost
Copy link

ghost commented Aug 8, 2019

Adding a usecase here in support of regex: On a previous team we used a regex branch match to determine whether a CI pipeline should run in response to a push event or not. I forget the exact pattern but it was something relatively simple/naive like "ignore branches named master, qa, and dev": ^((?!(master|qa|dev)).*)$

@bobcatfish
Copy link
Collaborator

bobcatfish commented Aug 13, 2019

I made a point in counter argument to the Conditionals initially because I can't really see much besides string comparison to be done, especially here.

I have a feeling that no matter what we do, people are going to want to express more complex Conditions eventually.

Here's an example of some slightly more complicated logic a person might want to use: https://github.com/wlynch/cel-playground/tree/get-commit#example-expressions

ce.type == "com.github.pull_request.create"
ce.source == "foo"
ce.source != "foo" && ce.type != "bar"
ce.source.matches("com\\.github\\..*") # backslash must be escaped

That's using a language called CEL and it's conceivable that folks will very quickly want to:

  1. Choose the language they can use for expressing this type of thing (e.g. maybe you want to use Rego instead https://www.openpolicyagent.org/docs/latest/policy-language/)
  2. Want to be able to reuse conditions, e.g. they wouldn't want to copy + paste the above for all their trigger setups - and related to this comment Enable TriggerBindings to validate requests (e.g. GitHub) #45 (comment) if we're gonna use something like headersMatch for security ( + @dlorenc ) then I think folks will want to have a reusuable chunk of logic they can easily apply to all their trigger setups
  3. Folks are going to need to do even more complicated stuff, for example @wlynch has pointed out that in some cases you'll actually need to make requests back to GitHub for further information before determining whether to trigger or not (e.g. 'is the user that created this PR is such and such org')

I feel it's a little heavy, Conditions in pipeline will launch container to do the comparing.
Image that, when received a event, we need create pod only for string comparison...

I think we can find ways to optimize this, for example I think @dibyom has proposed in Pipelines having ways to more easily express common operations. And I'm not against having a regex type of Condition that maybe gets executed in some optimized way.

Are we certain that this is too heavy? I'd be interested to see what the startup time is for a pod that does nothing but run a very tiny container, e.g. a regex container.

@vtereso
Copy link
Author

vtereso commented Aug 13, 2019

Are we certain that this is too heavy?

Definitely not, but it was my main/only consideration in opposition to utilizing containers.

I think providing some optimized conditional checks down the line (should they be necessary) is a great point. Also, it wouldn't be very secure to match some potentially secret authentication header in plaintext. Using a container, a secret or such could be mounted. If nothing else than the sake of simplicity (rather than engineering matching piece meal), I think containers are the way to go 👍

@dibyom
Copy link
Member

dibyom commented Aug 27, 2019

Some relevant discussion here as well: #45 (comment)

@ncskier ncskier added the kind/design Categorizes issue or PR as related to design. label Sep 9, 2019
@vtereso
Copy link
Author

vtereso commented Sep 17, 2019

Current status from WG: We have already integrated validation of Triggers using tasks, which validates the event source. This issue should create a separate conditions (plural) field for the event trigger for the following reasons:

  • In order to allow for reusable components, we wouldn't want to combine validation with potentially multiple conditions
  • If there is any validation, this should happen prior to conditions
  • It is advantageous to log these differently
  • Easily distinguish the optional validation from optional conditions (makes validating a single validation task easier as well)

@vtereso
Copy link
Author

vtereso commented Sep 17, 2019

Whoever picks this up should also add the test builder(s) for the validation task fields within the EventListener. It seem to be agreed on that OR conditions should be resolved internally so that all conditions are additive booleans and short circuit Trigger actuation on failure.

@khrm
Copy link
Contributor

khrm commented Sep 19, 2019

/assign

I am taking this task. Will send pr for #117 and then work on this. According to discussion, it's schedule for 0.2 release but may be we can push for it to be release with 0.1. Will see.

@ncskier
Copy link
Member

ncskier commented Oct 29, 2019

We should be wary of the Pod proliferation problem discussed in issue #125 which led to the creation of the interceptors.

@kav
Copy link

kav commented Oct 30, 2019

Might be worth considering using JsonPath here as well as (#178). I'm definitely for lightweight conditional filtering without making more pods. As a user though whichever language is used to navigate and select object properties should likely also be used for conditionals if that functionality is available.

@vtereso
Copy link
Author

vtereso commented Oct 30, 2019

@kav Regarding this, allowing conditional filters also allows the potential for people to use them as validators, which was the reason we replaced them with interceptors.

@kav
Copy link

kav commented Oct 30, 2019

That makes sense to a degree but when I looked at interceptors as an option they felt a bit heavy when all I really wanted was a bit of string equality comparison on a property or two, though I'll admit it does seem like a pretty robust solution to validation, filtering, and any clean up or data conversion

@vtereso
Copy link
Author

vtereso commented Oct 30, 2019

I meant to specify conditional filters as containers, my apologies for any confusion. I have been back and forth on the container issue, but in consideration for the security, I have come back to my skepticism. I agree interceptors might be too heavy weight in many circumstances and we could add string comparisons (and maybe regex), which might handle most cases. This has been discussed since the initial MVP so I don't entirely consider this "extra behavior" for Triggers, but ideally, I would keep Triggers as slim as possible so as not to reinvent the wheel.

@vtereso
Copy link
Author

vtereso commented Nov 12, 2019

As per the design document, we will be using CEL to satisfy this conditional/filter request so that interceptors are reusable. This should also enable people to get away with simple validation as well outside of VCS like GitHub, GitLab, etc.

@bigkevmcd
Copy link
Member

@dibyom I had a very rough go at this last week

https://github.com/bigkevmcd/triggers/tree/master/pkg/interceptors/cel

@dibyom
Copy link
Member

dibyom commented Dec 3, 2019

Awesome! @wlynch mentioned that we could consider a "core" CEL interceptor as an alternative to a top level filters field

@dibyom dibyom mentioned this issue Jan 6, 2020
3 tasks
bigkevmcd added a commit to bigkevmcd/triggers that referenced this issue Jan 6, 2020
This adds a cel interceptor, that uses a a CEL expression to filter request bodies.

This addresses issue tektoncd#49.
bigkevmcd added a commit to bigkevmcd/triggers that referenced this issue Jan 6, 2020
This adds a cel interceptor, that uses a a CEL expression to filter request bodies.

This implements issue tektoncd#49.
bigkevmcd added a commit to bigkevmcd/triggers that referenced this issue Jan 7, 2020
This adds a cel interceptor, that uses a a CEL expression to filter request bodies.

This implements issue tektoncd#49.
bigkevmcd added a commit to bigkevmcd/triggers that referenced this issue Jan 7, 2020
This adds a cel interceptor, that uses a a CEL expression to filter request bodies.

This implements issue tektoncd#49.
tekton-robot pushed a commit that referenced this issue Jan 7, 2020
This adds a cel interceptor, that uses a a CEL expression to filter request bodies.

This implements issue #49.
@bigkevmcd
Copy link
Member

Now that CEL interceptor is in there, I'd like to see if we can't agree on how to do CEL munging, i.e. the original values implementation in early days of that branch.

  triggers:
    - name: cel-trig
      interceptor:
        cel:
          filter: "headers.match('X-GitHub-Event', 'pull_request')"
          values:
            "pr.url": body.pull_request.url
            "pr.short_sha": truncate(body.head.sha, 7)

I'd propose something similar, I don't have a better name than values, but I think it should be a list of key/values, with "key" and "expression" as the keys for each thing to update.

so...

triggers:
- name: cel-trig
  interceptor:
  cel:
    filter: "headers.match('X-GitHub-Event', 'pull_request')"
    values:
      - key: pr.url
        expression: body.pull_request.url
      - key: pr.short_sha
        expression: truncate(body.head.sha, 7)

This would be used in the same way as the original values implementation, i.e. if the filter was successful, using sjson to set the keys in the body to the values returned by the expressions.

This allows an interceptor to add custom keys to the body, or, modify existing ones if it wants to.

@dibyom
Copy link
Member

dibyom commented Jan 9, 2020

Yeah, using to modify body will be an interesting feature though I think we should track it in its own issue. I'll close this and open a new one for that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/design Categorizes issue or PR as related to design. maybe-next-milestone
Projects
None yet
Development

No branches or pull requests

9 participants