Skip to content

Commit

Permalink
runtimecfg node-ip: allow running without VIPs
Browse files Browse the repository at this point in the history
Allow running "runtimecfg node-ip" with no Virtual IP arguments, to
select an IP based on the default route. This will be used for bare
metal UPI environments, where kubelet may not pick the default node IP
correctly, but there is no apiserver VIP to use as a hint.
  • Loading branch information
danwinship committed Sep 27, 2020
1 parent 42224f8 commit 1cd2a95
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 11 deletions.
23 changes: 15 additions & 8 deletions cmd/runtimecfg/node-ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ var nodeIPCmd = &cobra.Command{
Use: "node-ip",
DisableFlagsInUseLine: true,
Short: "Node IP tools",
Long: "Node IP has tools that aid in the configuration of nodes in platforms that use Virtual IPs",
Long: "Node IP has tools that aid in the configuration of the default node IP",
}

var nodeIPShowCmd = &cobra.Command{
Use: "show [Virtual IP]",
Use: "show [Virtual IP...]",
DisableFlagsInUseLine: true,
Short: "Show a configured IP address that directly routes to the given Virtual IPs",
Args: cobra.MinimumNArgs(1),
Short: "Show a configured IP address that directly routes to the given Virtual IPs. If no Virtual IPs are provided it will pick an IP associated with the default route.",
Args: cobra.MinimumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
err := show(cmd, args)
if err != nil {
Expand All @@ -42,10 +42,10 @@ var nodeIPShowCmd = &cobra.Command{
}

var nodeIPSetCmd = &cobra.Command{
Use: "set [Virtual IP]",
Use: "set [Virtual IP...]",
DisableFlagsInUseLine: true,
Short: "Sets container runtime services to bind to a configured IP address that directly routes to the given virtual IPs",
Args: cobra.MinimumNArgs(1),
Short: "Sets container runtime services to bind to a configured IP address that directly routes to the given virtual IPs. If no Virtual IPs are provided it will pick an IP associated with the default route.",
Args: cobra.MinimumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
err := set(cmd, args)
if err != nil {
Expand Down Expand Up @@ -134,7 +134,14 @@ func set(cmd *cobra.Command, args []string) error {

func getSuitableIP(retry bool, vips []net.IP) (chosen net.IP, err error) {
for {
nodeAddrs, err := utils.AddressesRouting(vips, utils.NonDeprecatedAddress)
var nodeAddrs []net.IP
var err error

if len(vips) > 0 {
nodeAddrs, err = utils.AddressesRouting(vips, utils.ValidNodeAddress)
} else {
nodeAddrs, err = utils.AddressesDefault(utils.ValidNodeAddress)
}
if err != nil {
return nil, err
}
Expand Down
45 changes: 42 additions & 3 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,19 @@ func getRouteMap(filter RouteFilter) (routeMap map[int][]netlink.Route, err erro
return routeMap, nil
}

// NonDeprecatedAddress returns true if the address is IPv6 and has a preferred lifetime of 0
func NonDeprecatedAddress(address netlink.Addr) bool {
return !(net.IPv6len == len(address.IP) && address.PreferedLft == 0)
// ValidNodeAddress returns true if the address is suitable for a node's primary IP
func ValidNodeAddress(address netlink.Addr) bool {
// Ignore link-local addresses
if address.IP.IsLinkLocalUnicast() {
return false
}

// Ignore deprecated IPv6 addresses
if net.IPv6len == len(address.IP) && address.PreferedLft == 0 {
return false
}

return true
}

// usableIPv6Route returns true if the passed route is acceptable for AddressesRouting
Expand Down Expand Up @@ -274,3 +284,32 @@ func AddressesRouting(vips []net.IP, af AddressFilter) ([]net.IP, error) {
}
return matches, nil
}

// defaultRoute returns true if the passed route is a default route
func defaultRoute(route netlink.Route) bool {
return route.Dst == nil
}

// AddressesDefault and returns a slice of configured addresses in the current network namespace associated with default routes. You can optionally pass an AddressFilter to further filter down which addresses are considered
func AddressesDefault(af AddressFilter) ([]net.IP, error) {
addrMap, err := getAddrs(af)
if err != nil {
return nil, err
}
routeMap, err := getRouteMap(defaultRoute)
if err != nil {
return nil, err
}

matches := make([]net.IP, 0)
for link, addresses := range addrMap {
if routeMap[link.Attrs().Index] == nil {
continue
}
for _, address := range addresses {
log.Infof("Address %s is on interface %s with default route", address, link.Attrs().Name)
matches = append(matches, address.IP)
}
}
return matches, nil
}

0 comments on commit 1cd2a95

Please sign in to comment.