Skip to content

mixer: add header operation templates #612

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

Merged
merged 5 commits into from
Aug 17, 2018

Conversation

kyessenov
Copy link
Contributor

This is a minimal addition to expose routing features from Mixer.
I've put the combinatorial expression problem out of scope for now, and only added the header template and action name.
With these two, we have a way to propagate adapter attributes out to the client. Header operations are easy to combine, so that is also orthogonal to the check rule combination discussion.

/assign @geeknoid
/assign @mandarjog

Signed-off-by: Kuat Yessenov [email protected]

Signed-off-by: Kuat Yessenov <[email protected]>
@googlebot googlebot added the cla: yes Set by the Google CLA bot to indicate the author of a PR has signed the Google CLA. label Aug 16, 2018
Copy link
Contributor

@geeknoid geeknoid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You say this is merging is easy, but what's the ordering semantics if multiple adapters request header mutations?

enum Operation {
REPLACE = 0; // replaces the header with the given name
REMOVE = 1; // removes the header with the given name (the value is ignored)
APPEND = 2; // appends the value to the header value, or sets it if not present
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this context, I don't quite understand the difference in semantics between REPLACE and APPEND. Can you elaborate? Also, the command says "appeands the value to the header value", and I'm not sure what "appends" means here. String concatenation?

Copy link
Contributor Author

@kyessenov kyessenov Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP header pairs can be repeated. For example, the following is correct in the protocol:

x-forwarded-for: 10.0.0.1
x-forwarded-for: 10.0.0.2
...

It is usually up to the client to decide what to do with multiple values for a header. Typically, the values are comma-concatenated, e.g. the client would receive x-forwarded-for: 10.0.0.1, 10.0.0.2. Append operation corresponds to inserting a new pair into the request headers, without regard whether a value is present or not for the same header.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so then what is the semantic of REPLACE and REMOVE given that there can be multiple headers with the same name? Do they remove all headers with the given name? What if you want to remove only the second instance of a particular named header?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Operations are executed one by one. Semantically, there is just one header with the given name, but it can be represented on the wire as several "key: value" pairs. That means removing is really removing all pairs on the wire, yet appending is fast, since you can just add one more pair.

Removing a second value in a list is simply not supported (not in envoy, nor any other proxy I know of). Usually you want to append a header value, or to replace it entirely. Replacing is more intuitive, so I made it the default.

There are a few examples here: https://github.com/istio/istio/blob/master/mixer/test/client/route_directive/route_directive_test.go#L95

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to keep harping on this...

What you say here makes sense. So in this context, each header is thus a name with an array of values. In that context, I think the value field should be a []string instead of just a single string. Thus:

REMOVE. Remove a header with all its value
REPLACE. Replace a header and all its values with the new array of values
APPEND: Appends an array of values to a header's values.

Copy link
Contributor Author

@kyessenov kyessenov Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intent was to optimize for the common case, which is just a single header key-value pair. If you insist we can change the value to be an array type. I am just worried this might confuse the user, since we would need to explain the semantics of HTTP headers again.

In terms of implementation, the two are interchangeable:

REMOVE_ARRAY(key, _) = REMOVE(key, _)
REPLACE_ARRAY(key, {"value1", "value2"}) = REPLACE(key, "value1, value2")
APPEND_ARRAY(key, {"value1", "value2"}) = APPEND(key, value1); APPEND(key, value2)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the patterns are isomorphic. I just find it confusing that the model is one header to multiple values, but the API just deals in terms of a single value like that's all there is.

Ultimately, it boils down to the syntax operators will use to manipulate this stuff. Do you have an idea how this would look in config?

Copy link
Contributor Author

@kyessenov kyessenov Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an example from the doc:

actions:
    - name: authorizer
      handler: authorizer
      instances: [“cookie”]
requestHeaderOperations:
    - name: user-info
      value: $authorizer.user

APPEND = 2; // appends the value to the header value, or sets it if not present
}

// Optional. Header operation type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional? What's the behavior when not present?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default value is 0, which is REPLACE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then let's add a comment about the default behavior when not specified

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -146,6 +174,9 @@ message Action {
// Referenced instances are evaluated by resolving the attributes/literals for all the fields.
// The constructed objects are then passed to the `handler` referenced within this action.
repeated string instances = 3;

// Optional. A handle to refer to the results of the action application.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "application"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Signed-off-by: Kuat Yessenov <[email protected]>
@kyessenov
Copy link
Contributor Author

kyessenov commented Aug 16, 2018

@geeknoid I think it is reasonable to expect no overlap between header operations for multiple rules for the same header keys. We can under-specify what happens if two rules apply operations on the same key. Mixer runtime may only need to guarantee a deterministic ordering of rule evaluation.

Signed-off-by: Kuat Yessenov <[email protected]>
Signed-off-by: Kuat Yessenov <[email protected]>
@geeknoid
Copy link
Contributor

geeknoid commented Aug 16, 2018 via email

Signed-off-by: Kuat Yessenov <[email protected]>
@kyessenov
Copy link
Contributor Author

kyessenov commented Aug 17, 2018

Fair enough. Here is an updated example:

actions:
    - name: authorizer
      handler: authorizer
      instances: [“cookie”]
requestHeaderOperations:
    - name: user-info
      values: 
      - $authorizer.user

@geeknoid
Copy link
Contributor

Thanks.

/lgtm
/approve

@istio-testing
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: geeknoid

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@istio-testing istio-testing merged commit 864a733 into istio:master Aug 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Set by the Google CLA bot to indicate the author of a PR has signed the Google CLA.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants