Skip to content

Commit fdc3ca4

Browse files
committed
🌱 Update bm server cache, when a server was not found by name.
1 parent cf1c07d commit fdc3ca4

3 files changed

Lines changed: 8 additions & 130 deletions

File tree

hcloud/instances.go

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package hcloud
1919
import (
2020
"context"
2121
"fmt"
22-
"sync"
2322

2423
"github.com/hetznercloud/hcloud-go/v2/hcloud"
2524
"github.com/syself/hetzner-cloud-controller-manager/internal/legacydatacenter"
@@ -45,21 +44,16 @@ type instances struct {
4544
robotClient robotclient.Client
4645
addressFamily addressFamily
4746
networkID int64
48-
49-
robotMissMu sync.Mutex
50-
// robotMissByName counts repeated misses for young bare-metal nodes by name.
51-
robotMissByName map[string]int
5247
}
5348

5449
var errServerNotFound = fmt.Errorf("server not found")
5550

5651
func newInstances(client *hcloud.Client, robotClient robotclient.Client, addressFamily addressFamily, networkID int64) *instances {
5752
return &instances{
58-
client: client,
59-
robotClient: robotClient,
60-
addressFamily: addressFamily,
61-
networkID: networkID,
62-
robotMissByName: make(map[string]int),
53+
client: client,
54+
robotClient: robotClient,
55+
addressFamily: addressFamily,
56+
networkID: networkID,
6357
}
6458
}
6559

@@ -106,33 +100,11 @@ func (i *instances) lookupServer(
106100
if err != nil {
107101
return nil, nil, false, fmt.Errorf("failed to get robot server %q: %w", string(node.Name), err)
108102
}
109-
i.trackRobotServerByNameMiss(node, bmServer)
110103
}
111104
}
112105
return hcloudServer, bmServer, isHCloudServer, nil
113106
}
114107

115-
// trackRobotServerByNameMiss remembers repeated misses for young bare-metal nodes and
116-
// emits a warning on the second miss to surface unexpected stale-cache behavior.
117-
func (i *instances) trackRobotServerByNameMiss(node *corev1.Node, bmServer *models.Server) {
118-
if node == nil || node.Name == "" {
119-
return
120-
}
121-
122-
i.robotMissMu.Lock()
123-
defer i.robotMissMu.Unlock()
124-
125-
if bmServer != nil || !isYoungNode(node) {
126-
delete(i.robotMissByName, string(node.Name))
127-
return
128-
}
129-
130-
i.robotMissByName[string(node.Name)]++
131-
if i.robotMissByName[string(node.Name)] == 2 {
132-
klog.Warningf("young node %q still missing in robot after %d lookup misses", node.Name, i.robotMissByName[string(node.Name)])
133-
}
134-
}
135-
136108
func (i *instances) InstanceExists(ctx context.Context, node *corev1.Node) (bool, error) {
137109
const op = "hcloud/instancesv2.InstanceExists"
138110
metrics.OperationCalled.WithLabelValues(op).Inc()

hcloud/instances_test.go

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,12 @@ limitations under the License.
1717
package hcloud
1818

1919
import (
20-
"bytes"
2120
"context"
2221
"encoding/json"
2322
"net"
2423
"net/http"
2524
"reflect"
26-
"strings"
2725
"testing"
28-
"time"
2926

3027
"github.com/hetznercloud/hcloud-go/v2/hcloud"
3128
"github.com/hetznercloud/hcloud-go/v2/hcloud/schema"
@@ -34,7 +31,6 @@ import (
3431
corev1 "k8s.io/api/core/v1"
3532
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3633
cloudprovider "k8s.io/cloud-provider"
37-
"k8s.io/klog/v2"
3834
)
3935

4036
// TestInstances_InstanceExists also tests [lookupServer]. The other tests
@@ -211,15 +207,10 @@ func TestInstances_InstanceExistsRobotServerCreatedAfterCacheFill(t *testing.T)
211207
}
212208

213209
instances := newInstances(env.Client, robotClient, AddressFamilyIPv4, 0)
214-
// creationTime keeps the test nodes inside the young-node refresh window.
215-
creationTime := metav1.NewTime(time.Now())
216210

217211
// Warm the cache while bm-new does not exist yet.
218212
exists, err := instances.InstanceExists(context.TODO(), &corev1.Node{
219-
ObjectMeta: metav1.ObjectMeta{
220-
Name: "bm-existing",
221-
CreationTimestamp: creationTime,
222-
},
213+
ObjectMeta: metav1.ObjectMeta{Name: "bm-existing"},
223214
})
224215
if err != nil {
225216
t.Fatalf("Unexpected error warming cache: %v", err)
@@ -236,10 +227,7 @@ func TestInstances_InstanceExistsRobotServerCreatedAfterCacheFill(t *testing.T)
236227
})
237228

238229
exists, err = instances.InstanceExists(context.TODO(), &corev1.Node{
239-
ObjectMeta: metav1.ObjectMeta{
240-
Name: "bm-new",
241-
CreationTimestamp: creationTime,
242-
},
230+
ObjectMeta: metav1.ObjectMeta{Name: "bm-new"},
243231
})
244232
if err != nil {
245233
t.Fatalf("Unexpected error for bm-new: %v", err)
@@ -249,76 +237,6 @@ func TestInstances_InstanceExistsRobotServerCreatedAfterCacheFill(t *testing.T)
249237
}
250238
}
251239

252-
func TestInstances_InstanceExistsRobotServerLogsSecondYoungNodeMiss(t *testing.T) {
253-
env := newTestEnv()
254-
defer env.Teardown()
255-
256-
resetEnv := Setenv(t,
257-
"ROBOT_USER_NAME", "user",
258-
"ROBOT_PASSWORD", "pass",
259-
"CACHE_TIMEOUT", "1h",
260-
)
261-
defer resetEnv()
262-
263-
env.Mux.HandleFunc("/robot/server", func(w http.ResponseWriter, _ *http.Request) {
264-
json.NewEncoder(w).Encode([]models.ServerResponse{
265-
{
266-
Server: models.Server{
267-
ServerIP: "123.123.123.123",
268-
ServerIPv6Net: "2a01:f48:111:4221::",
269-
ServerNumber: 321,
270-
Name: "bm-existing",
271-
},
272-
},
273-
})
274-
})
275-
276-
robotClient, err := cache.NewCachedRobotClient(t.TempDir(), env.Server.Client(), env.Server.URL+"/robot")
277-
if err != nil {
278-
t.Fatalf("Unexpected error creating cached robot client: %v", err)
279-
}
280-
281-
instances := newInstances(env.Client, robotClient, AddressFamilyIPv4, 0)
282-
node := &corev1.Node{
283-
ObjectMeta: metav1.ObjectMeta{
284-
Name: "bm-new",
285-
CreationTimestamp: metav1.NewTime(time.Now()),
286-
},
287-
}
288-
289-
state := klog.CaptureState()
290-
defer state.Restore()
291-
292-
// logs captures klog output so the warning can be asserted directly.
293-
var logs bytes.Buffer
294-
klog.LogToStderr(false)
295-
klog.SetOutput(&logs)
296-
297-
exists, err := instances.InstanceExists(context.TODO(), node)
298-
if err != nil {
299-
t.Fatalf("Unexpected error on first miss: %v", err)
300-
}
301-
if exists {
302-
t.Fatal("Expected bm-new to be missing on first lookup")
303-
}
304-
klog.Flush()
305-
if strings.Contains(logs.String(), "still missing in robot") {
306-
t.Fatal("Did not expect warning log on first miss")
307-
}
308-
309-
exists, err = instances.InstanceExists(context.TODO(), node)
310-
if err != nil {
311-
t.Fatalf("Unexpected error on second miss: %v", err)
312-
}
313-
if exists {
314-
t.Fatal("Expected bm-new to be missing on second lookup")
315-
}
316-
klog.Flush()
317-
if !strings.Contains(logs.String(), `young node "bm-new" still missing in robot after 2 lookup misses`) {
318-
t.Fatalf("Expected warning log after second miss, got %q", logs.String())
319-
}
320-
}
321-
322240
func TestInstances_InstanceShutdown(t *testing.T) {
323241
env := newTestEnv()
324242
defer env.Teardown()

hcloud/util.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"fmt"
2222
"regexp"
2323
"strings"
24-
"time"
2524

2625
"github.com/hetznercloud/hcloud-go/v2/hcloud"
2726
"github.com/syself/hetzner-cloud-controller-manager/internal/hcops"
@@ -31,9 +30,6 @@ import (
3130
corev1 "k8s.io/api/core/v1"
3231
)
3332

34-
// youngRobotServerLookupWindow limits forced Robot refreshes to newly created nodes.
35-
var youngRobotServerLookupWindow = 10 * time.Minute
36-
3733
func getHCloudServerByName(ctx context.Context, c *hcloud.Client, name string) (*hcloud.Server, error) {
3834
const op = "hcloud/getServerByName"
3935
metrics.OperationCalled.WithLabelValues(op).Inc()
@@ -76,14 +72,14 @@ func getRobotServerByName(c robotclient.Client, node *corev1.Node) (server *mode
7672
}
7773

7874
server = findRobotServerByName(serverList, string(node.Name))
79-
if server != nil || !isYoungNode(node) {
75+
if server != nil {
8076
return server, nil
8177
}
8278

8379
serverList, err = c.ServerGetListForceRefresh()
8480
if err != nil {
8581
hcops.HandleRateLimitExceededError(err, node)
86-
return nil, fmt.Errorf("%s: refresh for young node: %w", op, err)
82+
return nil, fmt.Errorf("%s: force refresh after cache miss: %w", op, err)
8783
}
8884

8985
return findRobotServerByName(serverList, string(node.Name)), nil
@@ -134,14 +130,6 @@ func findRobotServerByName(serverList []models.Server, name string) *models.Serv
134130
return nil
135131
}
136132

137-
func isYoungNode(node *corev1.Node) bool {
138-
if node == nil || node.CreationTimestamp.IsZero() {
139-
return false
140-
}
141-
142-
return time.Since(node.CreationTimestamp.Time) <= youngRobotServerLookupWindow
143-
}
144-
145133
func isHCloudServerByName(name string) bool {
146134
return !strings.HasPrefix(name, hostNamePrefixRobot)
147135
}

0 commit comments

Comments
 (0)