-
Notifications
You must be signed in to change notification settings - Fork 306
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
Generate composite types #729
Generate composite types #729
Conversation
Hi @spencerhance. Thanks for your PR. I'm waiting for a kubernetes 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. |
/ok-to-test |
3a05935
to
fc9b446
Compare
6e63d4c
to
c815bb0
Compare
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.
First round of comments: Nice usage of the JSON spec! I never thought of that as an approach but it seems a bit nicer than using reflection.
One general comment: Do you mind doing a diff of (HEAD, PR) of the composite.go and composite_test.go for just the BackendService? I want to make sure there is no difference so the possibility we introduce a subtle bug is as close to zero as possible.
pkg/backends/backends.go
Outdated
@@ -74,7 +74,7 @@ func (b *Backends) Create(sp utils.ServicePort, hcLink string) (*composite.Backe | |||
HealthChecks: []string{hcLink}, | |||
} | |||
ensureDescription(be, &sp) | |||
if err := composite.CreateBackendService(be, b.cloud); err != nil { | |||
if err := composite.CreateBackendService(be, b.cloud, meta.GlobalKey(be.Name)); err != nil { |
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.
Because we wan't to silo your changes for L7 ILB as much as possible to keep the code base stable, I would suggest not introducing the key parameter in this PR. That way these function calls do not change and there is no real chance for a bug to be introduced.
I would leave a TODO in the composite generator code that states this should be added in a follow up.
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.
Done. Also good call, the only major change this PR is introducing is bypassing the first cloud-provider layer and calling the CRUD functions directly
(e.g cloud.Compute().AlphaBackendServices().Insert(meta.GlobalKey())
instead of cloud.CreateAlphaGlobalBackendService()
.)
With this change, we would be losing metrics until some replacement is implemented.
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.
The reason for that was to try to make it simpler to use global and regional resources with less switches (and easier code generation logic), but I'm definitely open to suggestions.
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.
The only other change I see in the diff is making the TestToX() functions simpler since I don't use known Alpha/Beta fields anymore. It's possible to add those in by doing a diff in the generate code but it would definitely add a bunch more complexity.
pkg/composite/gen/main.go
Outdated
gofmt = "gofmt" | ||
|
||
// This assumes that alpha contains a superset of all struct fields | ||
apiFilePath = "../../vendor/google.golang.org/api/compute/v0.alpha/compute-api.json" |
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 should be okay for now I think. Once we migrate to go modules, its possible we may have to do something different. My understanding of go modules is that they remove the need for vendor/ but you can still use it if you want. Anyways, we can cross that bridge when we get there.
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.
hmm good point. Will look into modules.
return nil, fmt.Errorf("error unmarshalling {{$type.Name}} JSON to compute {{$lower}} type: %v", err) | ||
} | ||
|
||
{{- if eq $type.Name "BackendService"}} |
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.
We will have to think of a better solution for this. It may be fine to just add all fields to ForceSendFields but for now I think this is fine.
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.
Agreed, do you remember why those ForceSendFields for BackendService were added originally?
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.
They were needed because of some subtle behavior with how the GCE API's work. Specifically, if you there is a boolean field (like "IncludeHost") and you are trying to set the field to false, GCE will not recognize that false setting unless you add the field to the ForceSendFields list.
From GCE docs: "By default, fields with empty values are omitted from API requests." (https://godoc.org/google.golang.org/api/compute/v1).
I'm trying to remember why though I needed to add this here rather than have callers set those fields...
c815bb0
to
f4c706f
Compare
@rramkumar1 Thanks! There's also an additional approach which uses the parsing code found in k8s-cloud-provider, but that would have to be heavily modified or copy-pasted into ingress-gce which seemed worse than not having any dependencies. Also ready for another round of review |
return nil, fmt.Errorf("error unmarshalling {{$type.Name}} JSON to compute {{$lower}} type: %v", err) | ||
} | ||
|
||
{{- if eq $type.Name "BackendService"}} |
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.
They were needed because of some subtle behavior with how the GCE API's work. Specifically, if you there is a boolean field (like "IncludeHost") and you are trying to set the field to false, GCE will not recognize that false setting unless you add the field to the ForceSendFields list.
From GCE docs: "By default, fields with empty values are omitted from API requests." (https://godoc.org/google.golang.org/api/compute/v1).
I'm trying to remember why though I needed to add this here rather than have callers set those fields...
return err | ||
} | ||
klog.V(3).Infof("Creating alpha backend service %v", alpha.Name) | ||
return cloud.CreateAlphaGlobalBackendService(alpha) |
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.
My feeling is that we should not remove the usage of the wrapper until we have a solution for keeping the metrics around.
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.
So the two main reasons for removing the wrapper are that it doesn't follow a consistent formula like the generated wrapper, and it's in k/k so it would be potentially harder for me to change it for the PR. https://github.com/kubernetes/kubernetes/tree/master/pkg/cloudprovider/providers/gce.
That being said, I could just limit this PR to doing a drop-in replacement of BackendService and leave the other composite types for another PR once I have a replacement for metrics.
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.
I don't mind that idea. That way, we don't have to block this necessarily on the metrics stuff.
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.
Done
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.
side note, do you know offhand if anything uses those metrics?
@rramkumar1 Ready for another round |
pkg/composite/gen/main.go
Outdated
// The other types that are discovered as dependencies will simply be wrapped with a composite struct | ||
// The format of the map is ServiceName -> k8s-cloud-provider wrapper name | ||
// TODO: (shance) Add the commented services and remove dependency on first cloud-provider layer | ||
var MainServices = map[string]string{ |
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.
Can you extract this and all the other types and methods below into a separate package?
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.
Done
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.
I'm starting to wonder if it would make sense for all of this stuff to be moved into k8s-cloud-provider 🙃 . Maybe not at first though.
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.
Yeah I've thought about that. Reason I hesitate right now is that its pretty specific to us. If someone else finds a need for this, then definitely it should go there.
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.
makes sense. It would allow us to refactor the parsing code a bit too which would be nice eventually.
pkg/composite/gen/main.go
Outdated
} | ||
} | ||
|
||
func init() { |
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 init can also be moved to a separate package when you move the other stuff.
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.
Done
@rramkumar1 Ready for another review |
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.
@@ -0,0 +1,476 @@ | |||
/* | |||
Copyright 2019 The Kubernetes Authors. |
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.
Need the proper line breaks for the copyright. You can look at some other file for reference.
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.
Done
pkg/composite/gen/main.go
Outdated
"fmt" | ||
"io" | ||
"io/ioutil" | ||
compositemeta "k8s.io/ingress-gce/pkg/composite/meta" |
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.
Typically standard library imports (like bytes or strings) are first (and in alphabetical order) and the stuff imported from elsewhere is next (after a empty line). Example:
"bytes"
"fmt"
"io"
...
compositemeta "k8s.io...."
Can you make sure the imports for other files is fixed as well?
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.
Done
pkg/composite/gen/main.go
Outdated
) | ||
|
||
// gofmtContent runs "gofmt" on the given contents. | ||
// Duplicate of the function in k8s-cloud-provider |
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 function is pretty trivial so no need to mention that its a dup.
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.
Done
pkg/composite/gen/main.go
Outdated
fmt.Fprintf(wr, "\n\n") | ||
} | ||
|
||
// genTypes() generates all of the struct definitions |
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.
Nit: genTypes() generates all of the composite structs.
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.
Done
pkg/composite/gen/main.go
Outdated
} | ||
} | ||
|
||
// genFuncs() generates all of the struct methods |
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.
Nit: genFuncs() generates helper methods attached to composite structs.
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.
Done
pkg/composite/gen/main.go
Outdated
} | ||
|
||
// genTests() generates all of the tests | ||
// TODO: (shance) figure out a better way to test the toGA(), toAlpha(), and toBeta() functions |
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.
Can remove TODO since you addressed it I think.
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.
Done
pkg/composite/meta/meta.go
Outdated
"GA": "", | ||
} | ||
|
||
// ApiService is a struct to hold all of the relevant data for generating a composite service |
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.
Nit: ApiService holds relevant data for generating a composite type + helper methods for a single API service.
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.
Done
json.Unmarshal([]byte(byteValue), &result) | ||
|
||
// Queue of ApiService names for BFS | ||
typesQueue := []string{} |
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 the extra spaces between here and line 136.
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.
Done
52f071e
to
7cf766f
Compare
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: rramkumar1, spencerhance 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 |
This PR adds generated composite types for many of the services from k8s-cloud-provider using the API spec json. This auto-generates the existing BackendService composite type as well.
The next step will to be to remove the first cloud-provider layer so that all types can be easily generated. That will also depend on: GoogleCloudPlatform/k8s-cloud-provider#9