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 a configurable option to switch yaml parser between yaml and utilyaml #497
Conversation
Hi @nnmin-aws. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: nnmin-aws The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/hold |
/ok-to-test |
@nnmin-aws: Cannot trigger testing until a trusted user reviews the PR and leaves an In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/ok-to-test |
pkg/mapper/configmap/configmap.go
Outdated
@@ -115,15 +115,19 @@ func ParseMap(m map[string]string) (userMappings []config.UserMapping, roleMappi | |||
rawUserMappings := make([]config.UserMapping, 0) | |||
userMappings = make([]config.UserMapping, 0) | |||
if userData, ok := m["mapUsers"]; ok { | |||
userJson, err := utilyaml.ToJSON([]byte(userData)) | |||
if LenientYamlEKS { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO one improvement would be push this logic into a utility. We can have a pkg/config/yaml
which includes our own implementation of yaml.Unmarshal which makes this decision based on a struct variable. Then its set when the struct is initialized and we can do that once when authenticator starts up based on the flag value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO one improvement would be push this logic into a utility. We can have a
pkg/config/yaml
which includes our own implementation of yaml.Unmarshal which makes this decision based on a struct variable. Then its set when the struct is initialized and we can do that once when authenticator starts up based on the flag value.
thank you for the comments. this can be a future goal to build a pkg/config/yaml
if there are more changes about yaml parsing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it need to be a future change? Here is an example to give you an idea of what I was thinking:
In pkg/mapper/configmap/configmap.go
:
import (
"sigs.k8s.io/aws-iam-authenticator/pkg/yaml"
)
...
func ParseMap(m map[string]string) (userMappings []config.UserMapping, roleMappings []config.RoleMapping, awsAccounts []string, err error) {
...
if userData, ok := m["mapUsers"]; ok {
if err := yaml.Unmarshal([]byte(userData), &userMappings); err != nil {
errs = append(errs, err)
}
}
...
In pkg/yaml
:
// compatibilityMode enables specific yaml parsing behavior used by EKS.
var compatibilityMode = true
func Unmarshal(b []byte, obj interface{}) error {
if !compatibilityMode {
if s, err := utilyaml.ToJSON(b); err != nil {
return err
} else if err := json.Unmarshal(s, obj); err != nil {
return err
}
return nil
}
return yaml.Unmarshal(b, obj)
}
Note that I suggested to use a struct above, but I used a global variable and function in this example, which might be cleaner. I also think pkg/yaml
is fine for a location.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for this idea, also could make a case where any other need for it would just be able to import it from pkg as I believe we already do farther down this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only short term fix to solve certain case in EKS configmap parsing. We are working on long term solution for this. Given essentially it is a short-term fix, I'd like to constrain it only in configmap.go. Because if exposed in a new package, we can't control how the new package will be used potentially. It is harder to clean it up in future.
//use Lenient Yaml Parser | ||
err = yaml.Unmarshal([]byte(userData), &rawUserMappings) | ||
} else { | ||
//use Strict Yaml Parser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lenient/strict is not 100% accurate, the "lenient" parser is case insensitive, but it does not konw how to deal with username: {{SessionName}}
, it expects quotes likeusername: "{{SessionName}}"
can we have a test case for the {{SessionName}} issue, I'll try to find a link to it. But basically we are using {{ in the golang template sense, but {{ also has a meaning in the yaml sense https://yaml.org/spec/1.2.2/#flow-mappings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lenient/strict is not 100% accurate, the "lenient" parser is case insensitive, but it does not konw how to deal with
username: {{SessionName}}
, it expects quotes likeusername: "{{SessionName}}"
can we have a test case for the {{SessionName}} issue, I'll try to find a link to it. But basically we are using {{ in the golang template sense, but {{ also has a meaning in the yaml sense https://yaml.org/spec/1.2.2/#flow-mappings
thank you for the comments. there are test yamls https://github.com/kubernetes-sigs/aws-iam-authenticator/tree/master/pkg/mapper/configmap/yaml. do they cover the case you mentioned? this cr is to include #455 on master branch, it is only on release-0.5 branch now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With regards to the naming, I agree. I verified that sigs.k8s.io/yaml does a case insensitive key comparison ("lenient") but errors on an unquoted curly braces ("strict"). I think we should instead call the behavior "compatibility mode" with a comment explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do they cover the case you mentioned?
We don't currently have a test for the case mentioned. The test needs to include a mapping of key to value where the first letter of the value is a curly brace and the entire value is unquoted:
key: {{value}}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//use Lenient Yaml Parser | ||
err = yaml.Unmarshal([]byte(userData), &rawUserMappings) | ||
} else { | ||
//use Strict Yaml Parser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With regards to the naming, I agree. I verified that sigs.k8s.io/yaml does a case insensitive key comparison ("lenient") but errors on an unquoted curly braces ("strict"). I think we should instead call the behavior "compatibility mode" with a comment explanation.
//use Lenient Yaml Parser | ||
err = yaml.Unmarshal([]byte(userData), &rawUserMappings) | ||
} else { | ||
//use Strict Yaml Parser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do they cover the case you mentioned?
We don't currently have a test for the case mentioned. The test needs to include a mapping of key to value where the first letter of the value is a curly brace and the entire value is unquoted:
key: {{value}}
pkg/mapper/configmap/configmap.go
Outdated
@@ -115,15 +115,19 @@ func ParseMap(m map[string]string) (userMappings []config.UserMapping, roleMappi | |||
rawUserMappings := make([]config.UserMapping, 0) | |||
userMappings = make([]config.UserMapping, 0) | |||
if userData, ok := m["mapUsers"]; ok { | |||
userJson, err := utilyaml.ToJSON([]byte(userData)) | |||
if LenientYamlEKS { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it need to be a future change? Here is an example to give you an idea of what I was thinking:
In pkg/mapper/configmap/configmap.go
:
import (
"sigs.k8s.io/aws-iam-authenticator/pkg/yaml"
)
...
func ParseMap(m map[string]string) (userMappings []config.UserMapping, roleMappings []config.RoleMapping, awsAccounts []string, err error) {
...
if userData, ok := m["mapUsers"]; ok {
if err := yaml.Unmarshal([]byte(userData), &userMappings); err != nil {
errs = append(errs, err)
}
}
...
In pkg/yaml
:
// compatibilityMode enables specific yaml parsing behavior used by EKS.
var compatibilityMode = true
func Unmarshal(b []byte, obj interface{}) error {
if !compatibilityMode {
if s, err := utilyaml.ToJSON(b); err != nil {
return err
} else if err := json.Unmarshal(s, obj); err != nil {
return err
}
return nil
}
return yaml.Unmarshal(b, obj)
}
Note that I suggested to use a struct above, but I used a global variable and function in this example, which might be cleaner. I also think pkg/yaml
is fine for a location.
pkg/mapper/configmap/mapper.go
Outdated
@@ -13,7 +13,10 @@ type ConfigMapMapper struct { | |||
|
|||
var _ mapper.Mapper = &ConfigMapMapper{} | |||
|
|||
var LenientYamlEKS = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reasoning for this global exported variable here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is only meaningful in this file. it is a short term fix for EKS configmap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on making it unexportable then if it's only meaningful in this package?
bc69c3f
to
f5b6e04
Compare
@@ -115,15 +115,19 @@ func ParseMap(m map[string]string) (userMappings []config.UserMapping, roleMappi | |||
rawUserMappings := make([]config.UserMapping, 0) | |||
userMappings = make([]config.UserMapping, 0) | |||
if userData, ok := m["mapUsers"]; ok { | |||
userJson, err := utilyaml.ToJSON([]byte(userData)) | |||
if EKSYaml { | |||
//use Lenient Yaml Parser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove or update comments
/close |
@nckturner: Closed this PR. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Add a configurable option to switch yaml parser between yaml and utilyaml. refer to #455