-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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 Ports field to app spec #47706
base: master
Are you sure you want to change the base?
Add Ports field to app spec #47706
Conversation
return nil | ||
} | ||
|
||
func (a *App) checkPorts() error { |
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 like the fact that this is just a copy of what's already in api/types/app.go
. But I also noticed that we already duplicate a bunch of stuff between those two locations.
Should I instead create api/types.ValidateAppPorts
and create an interface with GetPort
and GetEndPort
so that I can reuse a single function between api/types
and lib/service/servicecfg
?
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 would move it to somewhere else and re-use it.
Eg api/utils/net.ValidatePortRange(port, portEnd int) error
uint32 Port = 1 [(gogoproto.jsontag) = "port"]; | ||
// EndPort describes the end of the range, inclusive. It must be between 2-65535 and be greater | ||
// than Port when describing a port range. When describing a single port, it must be set to 0. | ||
uint32 EndPort = 2 [(gogoproto.jsontag) = "end_port,omitempty"]; |
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.
maybe transforming this field into optional field?
I wonder if we shouldn't have
- Port
- StartPort
- EndPort
We validate so you can't specify Port and any of StartPort/Endport as it reads far easier or transform this into a oneof Port vs Range.
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.
maybe transforming this field into optional field?
How exactly? My impression was that this field is already optional, as when describing a single port you can omit it. I should change the comment though to spell that out loud explicitly.
Regarding StartPort
, I don't think Port
& EndPort
reads that terribly to warrant using one of the other two options. With three fields in a single struct, there's more invalid states that can be represented. With a oneof, as far as I understand, we'd lose some simplicity in lib/config
& lib/service/servicecfg
mirroring the structures defined in api/types
. oneof in protos necessitates a wrapper struct which we'd have to replicate in those two packages.
Or I guess it could be something like this:
type PortSpec struct {
Port Port
PortRange PortRange
}
…or some variation of it. But then again we'd have more stuff to validate and those three packages would no longer mirror their data structures in this specific case. Which I'm not sure how worthy of a goal it is to strive for, but it seems to me like a trait worth having.
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.
How exactly? My impression was that this field is already optional, as when describing a single port you can omit it. I should change the comment though to spell that out loud explicitly.
Proto3 recently introduced the optional keyword that transforms the field into *fieldType. It's just a simpler way to say it out loud that it's not mandatory.
My idea is to keep it as simple as possible and be able to evolve independently. I don't think it reads bad, I just wonder if we want to evolve them in the future separately but if we don't want to do it, that's fine.
A brief history, network policies already exist in Kubernetes for ~4y when they added support for ranges, so to keep the compatibility, they kept the port and introduced the endPort
287c0a5
to
aaf0c25
Compare
@espadolini @marcoandredinis Ping. |
return nil | ||
} | ||
|
||
func (a *App) checkPorts() error { |
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 would move it to somewhere else and re-use it.
Eg api/utils/net.ValidatePortRange(port, portEnd int) error
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.
LGTM after Marco's comments are addressed.
We should probably add a compatibility notice to the docs with regards to the behavior of multi-port TCP apps and older agents.
🤖 Vercel preview here: https://docs-84qfg2ra5-goteleport.vercel.app/docs/ver/preview |
// ValidatePortRange checks if the given port range is within bounds. If endPort is not zero, it | ||
// also checks if it's bigger than port. A port range with zero as endPort is assumed to describe a | ||
// single port. | ||
func ValidatePortRange(port, endPort int) error { |
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.
@marcoandredinis Could you take a look at c931742 which extracts port range validation to api/utils/net.ValidatePortRange
? I want to be sure that whatever I'm pushing to api looks perfect.
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 would just simplify the endPort
validation, but up to you 👍
if endPort != 0 { | ||
if endPort < minPort+1 || endPort > maxPort { | ||
return trace.BadParameter("end port must be between %d and %d, but got %d", minPort+1, maxPort, endPort) | ||
} | ||
|
||
if endPort <= port { | ||
return trace.BadParameter("end port must be greater than port (%d vs %d)", endPort, port) | ||
} | ||
} |
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.
if endPort != 0 { | |
if endPort < minPort+1 || endPort > maxPort { | |
return trace.BadParameter("end port must be between %d and %d, but got %d", minPort+1, maxPort, endPort) | |
} | |
if endPort <= port { | |
return trace.BadParameter("end port must be greater than port (%d vs %d)", endPort, port) | |
} | |
} | |
if endPort != 0 { | |
if endPort <= port || endPort > maxPort { | |
return trace.BadParameter("end port must be between %d and %d, but got %d", port+1, maxPort, endPort) | |
} | |
} |
This PR makes it possible to configure multi-port TCP apps. This is in accordance with RFD 182. The goal is to be able to define an app with multiple ports like this:
This PR adds
Ports
and relevant validation to bothapi/types
andlib/config
. The new field is validated no matter if someone attempts to add a dynamic app or include an app in an instance config.This specific format was chosen after a brief discussion (#46169 (comment)) base on prior art of network policies in Kubernetes.
I'll wait with merging this PR until I have the backend implementation ready.