-
Notifications
You must be signed in to change notification settings - Fork 642
CASSGO-45 ConnectAddress() should not panic and HostInfo should not be created with invalid connect address #1858
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
CASSGO-45 ConnectAddress() should not panic and HostInfo should not be created with invalid connect address #1858
Conversation
6f8773a to
8aae39b
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.
Left some comments. The host selection / load balancing policies need some changes, we shouldn't assume the address is always valid on those implementations.
cassandra_test.go
Outdated
| if hi.host.ConnectAddress().String() == host { | ||
| connAddr, err := hi.host.ConnectAddress() | ||
| if err != nil { | ||
| t.Error(err) |
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 this should be t.Fatal so the behavior of this test is consistent after the change?
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.
Agree, fixed
control.go
Outdated
| for _, host := range hosts { | ||
| connAddr, err := host.ConnectAddress() | ||
| if err != nil { | ||
| c.session.logger.Printf("gocql: %v\n", err) |
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.
Usually we add a message for this error before we add the actual error string so something like:
c.session.logger.Printf("gocql: unable to use host for control connection, skipping it: %v\n", err)
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.
Fixed
control.go
Outdated
| for _, host := range hosts { | ||
| connAddr, err := host.ConnectAddress() | ||
| if err != nil { | ||
| c.session.logger.Printf("gocql: %v\n", err) |
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.
same as comment above
control_test.go
Outdated
| t.Errorf("expected ip %v got %v for addr %q", test.ip, host.ConnectAddress(), test.addr) | ||
| connAddr, err := host.ConnectAddress() | ||
| if err != nil { | ||
| t.Errorf("%d: %v", i, err) |
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.
t.Errorf("could not get connect address of host %q to compare with expected: %v", test.addr, err)
filters.go
Outdated
| m := make(map[string]bool, len(hostInfos)) | ||
| for _, host := range hostInfos { | ||
| m[host.ConnectAddress().String()] = true | ||
| connAddr, _ := host.ConnectAddress() |
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 err != nil I don't think it should be whitelisted, it should just continue
policies.go
Outdated
| } | ||
|
|
||
| func (d *dcAwareRR) RemoveHost(host *HostInfo) { | ||
| connAddr, _ := host.ConnectAddress() |
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.
just return if unable to get conn addr but also need to add a check for this in AddHost so hosts with invalid connect addresses are not added
policies.go
Outdated
| dist := d.HostTier(host) | ||
| d.hosts[dist].remove(host.ConnectAddress()) | ||
| connAddr, _ := host.ConnectAddress() | ||
| d.hosts[dist].remove(connAddr) |
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.
same as above, check in AddHost so we don't add hosts with invalid addresses and then we can just return here when unable to get connAddr
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
session.go
Outdated
| buf := bytes.NewBufferString("Session.ring:") | ||
| for _, h := range hosts { | ||
| buf.WriteString("[" + h.ConnectAddress().String() + ":" + h.State().String() + "]") | ||
| connAddr, _ := h.ConnectAddress() |
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 shouldn't really ignore these errors, it's better to handle them than assuming that connAddr is always valid, just continue if unable to get connAddr
session.go
Outdated
| func (qm *queryMetrics) hostMetricsLocked(host *HostInfo) *hostMetrics { | ||
| metrics, exists := qm.m[host.ConnectAddress().String()] | ||
| connAddr, _ := host.ConnectAddress() | ||
| metrics, exists := qm.m[connAddr.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.
We definitely should not be creating metrics objects for hosts with invalid connect addresses since they won't be used anyway.
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.
Agree, fixed
token.go
Outdated
| buf.WriteString(th.token.String()) | ||
| buf.WriteString(":") | ||
| buf.WriteString(th.host.ConnectAddress().String()) | ||
| buf.WriteString(connAddr.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.
Will this print an empty string if err != nil ? Printing empty string on the address part could be fine but we could also print nil instead
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.
As I have checked, it will print a nil
|
Also can you create a JIRA for this? |
Of course, currently working on refactoring. |
8aae39b to
c884b90
Compare
|
I just had a realization that we are probably going about this the wrong way. Instead of changing Sorry for not realizing this earlier, I know you already worked a bit on this approach but I really think we should change the approach here. First step is to find all occurences of straight |
|
Understood, I will work on it. |
I don't clearly understand how we can use the logic from the I think it is better to create raw structure here as it is now, and add the validation inside of the or validate it inside of |
You would have those IPs as parameters of the function instead for example.
This can also work, as long as we guarantee that we don't have |
c884b90 to
ffe9660
Compare
|
@joao-r-reis I've made an update. I decided to add validation into |
joao-r-reis
left a comment
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.
Added a comment about existing HostInfo struct initialization references in the codebase
host_source.go
Outdated
|
|
||
| ip, port := s.cfg.translateAddressPort(host.ConnectAddress(), host.port) | ||
| if !validIpAddr(ip) { | ||
| return nil, errors.New("invalid connect address") |
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.
hostAddr := host.ConnectAddress()
return nil, fmt.Errorf("invalid connect address after translating %v:%v", hostAddr.String(), host.port)
conn.go
Outdated
|
|
||
| for _, row := range rows { | ||
| host, err := c.session.hostInfoFromMap(row, &HostInfo{connectAddress: c.host.ConnectAddress(), port: c.session.cfg.Port}) | ||
| h, err := newHostInfo(c.host.connectAddress, c.session.cfg.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.
c.host.ConnectAdress()
ffe9660 to
9e7fbd5
Compare
host_source.go
Outdated
|
|
||
| func (h *HostInfo) SetConnectAddress(address net.IP) *HostInfo { | ||
| // TODO(zariel): should this not be exported? | ||
| func (h *HostInfo) SetConnectAddress(address net.IP) (*HostInfo, 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 honestly think we should just remove this method, what do you think @jameshartig ? Allowing users to just modify the connect address on a host is weird, there's already an AddressTranslator interface for this.
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 I'd like to go through a version or so of it being deprecated but since we're about to cut a major release I think it makes sense to remove it and we can always add it back if there's a reason to.
joao-r-reis
left a comment
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.
Couple of comments
host_source.go
Outdated
|
|
||
| ip, port := s.cfg.translateAddressPort(host.ConnectAddress(), host.port) | ||
| if !validIpAddr(ip) { | ||
| return nil, fmt.Errorf("invalid connect address after translating %v:%v", ip.String(), host.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.
Just realized this will be called even if there is no address translator so maybe changing this error message to be less confusing:
"invalid host address (before translation: %v:%v, after translation: %v:%v)", host.ConnectAddress(), host.port, ip.String(), 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.
Refactored
host_source.go
Outdated
| } else if h.preferredIP != nil { | ||
| return h.preferredIP, "preferred_ip" | ||
| } else if validIpAddr(h.broadcastAddress) { | ||
| } else if h.broadcastAddress != 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.
We should keep the validIpAddr check on all of these (except the last) so that the "fallback" priority still works otherwise this would be a behavior change and could cause bugs.
Just skip the check on the last one (h.peer), this will be checked either way in hostInfoFromMap before returning the host info object so we're good.
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.
Fixed
9e7fbd5 to
12406bf
Compare
jameshartig
left a comment
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.
Overall good, but I agree, let's remove SetConnectAddress
12406bf to
55525fe
Compare
|
Done. |
|
@joao-r-reis want to give your approval? |
55525fe to
ad5de46
Compare
HostInfo struct creation was refactored to create via constructor to make sure the connectAddress is valid. Panic in case of invalid connect address inside of ConnectAddress() method was removed. patch by Oleksandr Luzhniy; reviewed by João Reis, James Hartig, for CASSGO-45
ad5de46 to
744871b
Compare
|
@joao-r-reis I have updated the changelog and the commit message. |
Fix for the #1370
Panic from the
ConnectAddress()was removed.HostInfostruct creation was refactored to create via constructor to make sure the address is valid.