Files
my-rook-config/pkg/daemon/multus/util.go
T
Blaine Gardner 0f6e7ee921 test: add multus validation test routine to rook binary
Add a more involved multus validation test to the Rook binary. Because
this is intended to be end-user runnable, make sure operator-only
commands are hidden.

Build this into the rook binary instead of creating a separate binary
for ease, and because any binary built with the kube api becomes 40+
megabytes. We save quite a bit of space by including this in the Rook
binary, which is good for keeping container layers as small as possible.

Signed-off-by: Blaine Gardner <blaine.gardner@redhat.com>
2023-05-02 10:23:00 -06:00

130 lines
4.2 KiB
Go

package multus
import (
"fmt"
"os"
nadutils "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils"
core "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)
// Logger defines the log types that this library will use for outputting status information to the
// user. Because this library may be called interactively by a user or programmatically by another
// application, we allow the calling application to make a very simple Logger type that will be
// compatible with this library.
type Logger interface {
Infof(format string, args ...interface{})
Debugf(format string, args ...interface{})
Warningf(format string, args ...interface{})
}
type SimpleStderrLogger struct{}
func (*SimpleStderrLogger) Infof(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, " INFO: "+format+"\n", args...)
}
func (*SimpleStderrLogger) Debugf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "DEBUG: "+format+"\n", args...)
}
func (*SimpleStderrLogger) Warningf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, " WARN: "+format+"\n", args...)
}
func getNetworksFromPod(
pod *core.Pod,
desiredPublicNet, desiredClusterNet *types.NamespacedName,
) (
publicAddr, clusterAddr string, suggestions []string, err error,
) {
nets, err := nadutils.GetNetworkStatus(pod)
if err != nil {
return "", "", unableToProvideAddressSuggestions,
fmt.Errorf("pod has no network status yet: %w", err)
}
if len(nets) == 0 {
return "", "", unableToProvideAddressSuggestions,
fmt.Errorf("pod has no attached networks yet")
}
// if the pod has networks attached, parse all of them, and report any debugging suggestions
// associated for each one
publicAddr, clusterAddr = "", ""
suggestions = []string{}
for _, net := range nets {
nsName, err := networkNamespacedName(net.Name, pod.Namespace)
if err != nil {
suggestions = append(suggestions,
fmt.Sprintf("pod has an attached network with an un-parse-able network name [%s]; "+
"not sure what to do; this is unlikely to resolve", net.Name),
)
}
if len(net.IPs) == 0 {
suggestions = append(suggestions,
fmt.Sprintf("pod has an attached network [%s] with no IP; "+
"could this be an IPAM issue?", net.Name))
}
ip := net.IPs[0] // any IP should work
if desiredPublicNet != nil && nsName == *desiredPublicNet {
// FOUND DESIRED PUBLIC ADDR
publicAddr = ip
}
if desiredClusterNet != nil && nsName == *desiredClusterNet {
// FOUND DESIRED CLUSTER ADDR
clusterAddr = ip
}
}
if desiredPublicNet != nil && publicAddr == "" {
suggestions = append(suggestions, "pod does not have a public network attachment")
}
if desiredClusterNet != nil && clusterAddr == "" {
suggestions = append(suggestions, "pod does not have a cluster network attachment")
}
// if there are any suggestions, something isn't right
if len(suggestions) > 0 {
suggestions = append(suggestions, unableToProvideAddressSuggestions...)
return publicAddr, clusterAddr, suggestions, fmt.Errorf("did not find all desired networks")
}
// found what we were looking for
return publicAddr, clusterAddr, []string{}, nil
}
func podIsRunning(pod core.Pod) bool {
return pod.Status.Phase == core.PodRunning
}
func podIsReady(pod core.Pod) bool {
for _, c := range pod.Status.Conditions {
if c.Type == core.PodReady {
return c.Status == core.ConditionTrue
}
}
return false
}
func networkNamespacedName(netName, podNamespace string) (types.NamespacedName, error) {
nsName := types.NamespacedName{}
// what we really want is the result of parsePodNetworkObjectText(), a private method.
// because the network name is in the same format as network annotations, we can at
// at least use ParseNetworkAnnotation() to parse the network name
netSelections, err := nadutils.ParseNetworkAnnotation(netName, podNamespace)
if err != nil {
return nsName, fmt.Errorf("failed to parse network name %q into namespaced name: %w", netName, err)
}
if len(netSelections) != 1 {
return nsName, fmt.Errorf("failed to parse network name %q into a single namespaced network name, instead: %v", netName, netSelections)
}
net := netSelections[0]
nsName.Namespace = net.Namespace
nsName.Name = net.Name
return nsName, nil
}