diff --git a/cloud/linode/client/client.go b/cloud/linode/client/client.go index ca2efe2d..c97f6762 100644 --- a/cloud/linode/client/client.go +++ b/cloud/linode/client/client.go @@ -39,6 +39,7 @@ type Client interface { GetVPCSubnet(context.Context, int, int) (*linodego.VPCSubnet, error) ListVPCs(context.Context, *linodego.ListOptions) ([]linodego.VPC, error) ListVPCIPAddresses(context.Context, int, *linodego.ListOptions) ([]linodego.VPCIP, error) + ListVPCIPv6Addresses(context.Context, int, *linodego.ListOptions) ([]linodego.VPCIP, error) ListVPCSubnets(context.Context, int, *linodego.ListOptions) ([]linodego.VPCSubnet, error) CreateNodeBalancer(context.Context, linodego.NodeBalancerCreateOptions) (*linodego.NodeBalancer, error) diff --git a/cloud/linode/client/client_with_metrics.go b/cloud/linode/client/client_with_metrics.go index e20e746c..ba03e509 100644 --- a/cloud/linode/client/client_with_metrics.go +++ b/cloud/linode/client/client_with_metrics.go @@ -371,6 +371,19 @@ func (_d ClientWithPrometheus) ListVPCIPAddresses(ctx context.Context, i1 int, l return _d.base.ListVPCIPAddresses(ctx, i1, lp1) } +// ListVPCIPv6Addresses implements Client +func (_d ClientWithPrometheus) ListVPCIPv6Addresses(ctx context.Context, i1 int, lp1 *linodego.ListOptions) (va1 []linodego.VPCIP, err error) { + defer func() { + result := "ok" + if err != nil { + result = "error" + } + + ClientMethodCounterVec.WithLabelValues("ListVPCIPv6Addresses", result).Inc() + }() + return _d.base.ListVPCIPv6Addresses(ctx, i1, lp1) +} + // ListVPCSubnets implements Client func (_d ClientWithPrometheus) ListVPCSubnets(ctx context.Context, i1 int, lp1 *linodego.ListOptions) (va1 []linodego.VPCSubnet, err error) { defer func() { diff --git a/cloud/linode/client/mocks/mock_client.go b/cloud/linode/client/mocks/mock_client.go index d672ab8e..dad737ae 100644 --- a/cloud/linode/client/mocks/mock_client.go +++ b/cloud/linode/client/mocks/mock_client.go @@ -420,6 +420,21 @@ func (mr *MockClientMockRecorder) ListVPCIPAddresses(arg0, arg1, arg2 interface{ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListVPCIPAddresses", reflect.TypeOf((*MockClient)(nil).ListVPCIPAddresses), arg0, arg1, arg2) } +// ListVPCIPv6Addresses mocks base method. +func (m *MockClient) ListVPCIPv6Addresses(arg0 context.Context, arg1 int, arg2 *linodego.ListOptions) ([]linodego.VPCIP, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListVPCIPv6Addresses", arg0, arg1, arg2) + ret0, _ := ret[0].([]linodego.VPCIP) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListVPCIPv6Addresses indicates an expected call of ListVPCIPv6Addresses. +func (mr *MockClientMockRecorder) ListVPCIPv6Addresses(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListVPCIPv6Addresses", reflect.TypeOf((*MockClient)(nil).ListVPCIPv6Addresses), arg0, arg1, arg2) +} + // ListVPCSubnets mocks base method. func (m *MockClient) ListVPCSubnets(arg0 context.Context, arg1 int, arg2 *linodego.ListOptions) ([]linodego.VPCSubnet, error) { m.ctrl.T.Helper() diff --git a/cloud/linode/instances.go b/cloud/linode/instances.go index 1be51ccd..1a44a5a6 100644 --- a/cloud/linode/instances.go +++ b/cloud/linode/instances.go @@ -39,12 +39,22 @@ type nodeCache struct { } // getInstanceAddresses returns all addresses configured on a linode. -func (nc *nodeCache) getInstanceAddresses(instance linodego.Instance, vpcips []string) []nodeIP { +func (nc *nodeCache) getInstanceAddresses(instance linodego.Instance, vpcips []string, vpcIPv6AddrTypes map[string]v1.NodeAddressType) []nodeIP { ips := []nodeIP{} + // We store vpc IPv6 addrs separately so that we can list them after IPv4 addresses. + // Ordering matters in k8s, first address marked as externalIP will be used as external IP for node. + // We prefer to use IPv4 address as external IP if possible, so we list them first. + vpcIPv6Addrs := []nodeIP{} + // If vpc ips are present, list them first for _, ip := range vpcips { ipType := v1.NodeInternalIP + if _, ok := vpcIPv6AddrTypes[ip]; ok { + ipType = vpcIPv6AddrTypes[ip] + vpcIPv6Addrs = append(vpcIPv6Addrs, nodeIP{ip: ip, ipType: ipType}) + continue + } ips = append(ips, nodeIP{ip: ip, ipType: ipType}) } @@ -56,6 +66,9 @@ func (nc *nodeCache) getInstanceAddresses(instance linodego.Instance, vpcips []s ips = append(ips, nodeIP{ip: ip.String(), ipType: ipType}) } + // Add vpc IPv6 addresses after IPv4 addresses + ips = append(ips, vpcIPv6Addrs...) + if instance.IPv6 != "" { ips = append(ips, nodeIP{ip: strings.TrimSuffix(instance.IPv6, "/128"), ipType: v1.NodeExternalIP}) } @@ -80,6 +93,7 @@ func (nc *nodeCache) refreshInstances(ctx context.Context, client client.Client) // If running within VPC, find instances and store their ips vpcNodes := map[int][]string{} + vpcIPv6AddrTypes := map[string]v1.NodeAddressType{} for _, name := range Options.VPCNames { vpcName := strings.TrimSpace(name) if vpcName == "" { @@ -90,11 +104,30 @@ func (nc *nodeCache) refreshInstances(ctx context.Context, client client.Client) klog.Errorf("failed updating instances cache for VPC %s. Error: %s", vpcName, err.Error()) continue } - for _, r := range resp { - if r.Address == nil { + for _, vpcip := range resp { + if vpcip.Address == nil { + continue + } + vpcNodes[vpcip.LinodeID] = append(vpcNodes[vpcip.LinodeID], *vpcip.Address) + } + + resp, err = GetVPCIPv6Addresses(ctx, client, vpcName) + if err != nil { + klog.Errorf("failed updating instances cache for VPC %s. Error: %s", vpcName, err.Error()) + continue + } + for _, vpcip := range resp { + if len(vpcip.IPv6Addresses) == 0 { continue } - vpcNodes[r.LinodeID] = append(vpcNodes[r.LinodeID], *r.Address) + vpcIPv6AddrType := v1.NodeInternalIP + if vpcip.IPv6IsPublic != nil && *vpcip.IPv6IsPublic { + vpcIPv6AddrType = v1.NodeExternalIP + } + for _, ipv6 := range vpcip.IPv6Addresses { + vpcNodes[vpcip.LinodeID] = append(vpcNodes[vpcip.LinodeID], ipv6.SLAACAddress) + vpcIPv6AddrTypes[ipv6.SLAACAddress] = vpcIPv6AddrType + } } } @@ -106,7 +139,7 @@ func (nc *nodeCache) refreshInstances(ctx context.Context, client client.Client) } node := linodeInstance{ instance: &instances[index], - ips: nc.getInstanceAddresses(instance, vpcNodes[instance.ID]), + ips: nc.getInstanceAddresses(instance, vpcNodes[instance.ID], vpcIPv6AddrTypes), } newNodes[instance.ID] = node } diff --git a/cloud/linode/instances_test.go b/cloud/linode/instances_test.go index 4cedfff5..3c17b0d5 100644 --- a/cloud/linode/instances_test.go +++ b/cloud/linode/instances_test.go @@ -200,6 +200,7 @@ func TestMetadataRetrieval(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{instance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), vpcIDs["test"], gomock.Any()).Return(routesInVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), vpcIDs["test"], gomock.Any()).Return([]linodego.VPCIP{}, nil) meta, err := instances.InstanceMetadata(ctx, node) require.NoError(t, err) diff --git a/cloud/linode/route_controller_test.go b/cloud/linode/route_controller_test.go index ef727b25..83073ed2 100644 --- a/cloud/linode/route_controller_test.go +++ b/cloud/linode/route_controller_test.go @@ -52,6 +52,7 @@ func TestListRoutes(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), gomock.Any()).Times(1).Return([]linodego.Instance{}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return([]linodego.VPCIP{}, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) routes, err := routeController.ListRoutes(ctx, "test") require.NoError(t, err) assert.Empty(t, routes) @@ -76,6 +77,7 @@ func TestListRoutes(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return([]linodego.VPCIP{}, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) routes, err := routeController.ListRoutes(ctx, "test") require.NoError(t, err) assert.Empty(t, routes) @@ -103,6 +105,7 @@ func TestListRoutes(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(4).Return(noRoutesInVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) routes, err := routeController.ListRoutes(ctx, "test") require.NoError(t, err) assert.Empty(t, routes) @@ -151,6 +154,7 @@ func TestListRoutes(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(4).Return(routesInVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) routes, err := routeController.ListRoutes(ctx, "test") require.NoError(t, err) assert.NotEmpty(t, routes) @@ -199,6 +203,7 @@ func TestListRoutes(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(4).Return(routesInDifferentVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) routes, err := routeController.ListRoutes(ctx, "test") require.NoError(t, err) assert.Empty(t, routes) @@ -297,6 +302,7 @@ func TestListRoutes(t *testing.T) { c2 := client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).After(c1).Times(1).Return(routesInVPC2, nil) c3 := client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).After(c2).Times(1).Return(routesInVPC, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).After(c3).Times(1).Return(routesInVPC2, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) routes, err := routeController.ListRoutes(ctx, "test") require.NoError(t, err) assert.NotEmpty(t, routes) @@ -378,6 +384,7 @@ func TestCreateRoute(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(noRoutesInVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) client.EXPECT().UpdateInstanceConfigInterface(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&instanceConfigIntfWithVPCAndRoute, nil) err = routeController.CreateRoute(ctx, "dummy", "dummy", route) assert.NoError(t, err) @@ -445,6 +452,7 @@ func TestCreateRoute(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(routesInVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) err = routeController.CreateRoute(ctx, "dummy", "dummy", route) assert.NoError(t, err) }) @@ -459,6 +467,7 @@ func TestCreateRoute(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return([]linodego.VPCIP{}, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) err = routeController.CreateRoute(ctx, "dummy", "dummy", route) assert.Error(t, err) }) @@ -502,6 +511,7 @@ func TestDeleteRoute(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return([]linodego.VPCIP{}, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) err = routeController.DeleteRoute(ctx, "dummy", route) assert.Error(t, err) }) @@ -533,6 +543,7 @@ func TestDeleteRoute(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(noRoutesInVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) client.EXPECT().UpdateInstanceConfigInterface(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&instanceConfigIntfWithVPCAndNoRoute, nil) err = routeController.DeleteRoute(ctx, "dummy", route) assert.NoError(t, err) @@ -565,6 +576,7 @@ func TestDeleteRoute(t *testing.T) { client.EXPECT().ListInstances(gomock.Any(), nil).Times(1).Return([]linodego.Instance{validInstance}, nil) client.EXPECT().ListVPCIPAddresses(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).Return(routesInVPC, nil) + client.EXPECT().ListVPCIPv6Addresses(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return([]linodego.VPCIP{}, nil) client.EXPECT().UpdateInstanceConfigInterface(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(&instanceConfigIntfWithVPCAndNoRoute, nil) err = routeController.DeleteRoute(ctx, "dummy", route) assert.NoError(t, err) diff --git a/cloud/linode/vpc.go b/cloud/linode/vpc.go index 62d282f2..ea7a235c 100644 --- a/cloud/linode/vpc.go +++ b/cloud/linode/vpc.go @@ -100,11 +100,11 @@ func GetSubnetID(ctx context.Context, client client.Client, vpcID int, subnetNam return 0, subnetLookupError{subnetName} } -// GetVPCIPAddresses returns vpc ip's for given VPC label -func GetVPCIPAddresses(ctx context.Context, client client.Client, vpcName string) ([]linodego.VPCIP, error) { +// getVPCIDAndFilter returns the VPC ID and a resultFilter for subnet names (if any) +func getVPCIDAndFilter(ctx context.Context, client client.Client, vpcName string) (int, string, error) { vpcID, err := GetVPCID(ctx, client, strings.TrimSpace(vpcName)) if err != nil { - return nil, err + return 0, "", err } resultFilter := "" @@ -133,20 +133,49 @@ func GetVPCIPAddresses(ctx context.Context, client client.Client, vpcName string filter, err = json.Marshal(subnetFilter{SubnetID: strings.Join(subnetIDList, ",")}) if err != nil { klog.Error("could not create JSON filter for subnet_id") + } else { + resultFilter = string(filter) } - resultFilter = string(filter) + } + + return vpcID, resultFilter, nil +} + +// handleNotFoundError checks if the error is a '404 Not Found error' and deletes the entry from the cache. +func handleNotFoundError(err error, vpcName string) error { + if linodego.ErrHasStatus(err, http.StatusNotFound) { + Mu.Lock() + defer Mu.Unlock() + klog.Errorf("vpc %s not found. Deleting entry from cache", vpcName) + delete(vpcIDs, vpcName) + } + return err +} + +// GetVPCIPAddresses returns vpc ip's for given VPC label +func GetVPCIPAddresses(ctx context.Context, client client.Client, vpcName string) ([]linodego.VPCIP, error) { + vpcID, resultFilter, err := getVPCIDAndFilter(ctx, client, vpcName) + if err != nil { + return nil, err } resp, err := client.ListVPCIPAddresses(ctx, vpcID, linodego.NewListOptions(0, resultFilter)) if err != nil { - if linodego.ErrHasStatus(err, http.StatusNotFound) { - Mu.Lock() - defer Mu.Unlock() - klog.Errorf("vpc %s not found. Deleting entry from cache", vpcName) - delete(vpcIDs, vpcName) - } + return nil, handleNotFoundError(err, vpcName) + } + return resp, nil +} + +func GetVPCIPv6Addresses(ctx context.Context, client client.Client, vpcName string) ([]linodego.VPCIP, error) { + vpcID, resultFilter, err := getVPCIDAndFilter(ctx, client, vpcName) + if err != nil { return nil, err } + + resp, err := client.ListVPCIPv6Addresses(ctx, vpcID, linodego.NewListOptions(0, resultFilter)) + if err != nil { + return nil, handleNotFoundError(err, vpcName) + } return resp, nil } diff --git a/go.mod b/go.mod index f519d76f..d3b2bdb3 100644 --- a/go.mod +++ b/go.mod @@ -141,16 +141,16 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.39.0 // indirect + golang.org/x/crypto v0.40.0 // indirect golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.33.0 // indirect + golang.org/x/tools v0.34.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect google.golang.org/grpc v1.72.1 // indirect @@ -193,3 +193,5 @@ replace ( k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.33.0 k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.33.0 ) + +replace github.com/linode/linodego => github.com/rahulait/linodego v1.50.1-0.20250805021045-93a6855d693c diff --git a/go.sum b/go.sum index 3f232c98..459ba98c 100644 --- a/go.sum +++ b/go.sum @@ -202,8 +202,6 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/linode/linodego v1.53.1-0.20250709175023-9b152d30578c h1:WlZm+YNHBuphycMZG2s2+F04hx2wx1ShuOwPAIInjP8= -github.com/linode/linodego v1.53.1-0.20250709175023-9b152d30578c/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA= github.com/mackerelio/go-osstat v0.2.5 h1:+MqTbZUhoIt4m8qzkVoXUJg1EuifwlAJSk4Yl2GXh+o= github.com/mackerelio/go-osstat v0.2.5/go.mod h1:atxwWF+POUZcdtR1wnsUcQxTytoHG4uhl2AKKzrOajY= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= @@ -271,6 +269,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rahulait/linodego v1.50.1-0.20250805021045-93a6855d693c h1:DQ9iQF4vS6Rtz5gsfea9Wsp+h8hd+Sg/9DQKYgDi8bs= +github.com/rahulait/linodego v1.50.1-0.20250805021045-93a6855d693c/go.mod h1:VHlFAbhj18634Cd7B7L5D723kFKFQMOxzIutSMcWsB4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -391,8 +391,8 @@ golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -406,16 +406,16 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -427,15 +427,15 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -444,8 +444,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=