Skip to content

Commit

Permalink
libnetwork: add NetworkInfo() for get network information
Browse files Browse the repository at this point in the history
NetworkInfo() return the network binary path, package version,
program version and DNS information.

Signed-off-by: Toshiki Sonoda <[email protected]>
  • Loading branch information
sstosh committed May 15, 2023
1 parent 2758e27 commit 0bde67d
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 1 deletion.
33 changes: 33 additions & 0 deletions libnetwork/cni/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/containernetworking/cni/libcni"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/config"
cutil "github.com/containers/common/pkg/util"
"github.com/containers/storage/pkg/lockfile"
"github.com/containers/storage/pkg/unshare"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -295,6 +296,38 @@ func (n *cniNetwork) DefaultInterfaceName() string {
return cniDeviceName
}

// NetworkInfo return the network information about binary path,
// package version and program version.
func (n *cniNetwork) NetworkInfo() types.NetworkInfo {
path := ""
packageVersion := ""
for _, p := range n.cniPluginDirs {
ver := cutil.PackageVersion(p)
if ver != "Unknown" {
path = p
packageVersion = ver
break
}
}

info := types.NetworkInfo{
Backend: "cni",
Package: packageVersion,
Path: path,
}

dnsPath := filepath.Join(path, "dnsname")
dnsPackage := cutil.PackageVersion(dnsPath)
if _, err := os.Stat(dnsPath); err == nil {
info.DNS = types.DNSNetworkInfo{
Path: dnsPath,
Package: dnsPackage,
}
}

return info
}

func (n *cniNetwork) Network(nameOrID string) (*types.Network, error) {
network, err := n.getNetwork(nameOrID)
if err != nil {
Expand Down
34 changes: 34 additions & 0 deletions libnetwork/netavark/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/containers/common/libnetwork/internal/util"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/config"
cutil "github.com/containers/common/pkg/util"
"github.com/containers/storage/pkg/lockfile"
"github.com/containers/storage/pkg/unshare"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -336,6 +337,39 @@ func (n *netavarkNetwork) DefaultInterfaceName() string {
return defaultBridgeName
}

// NetworkInfo return the network information about binary path,
// package version and program version.
func (n *netavarkNetwork) NetworkInfo() types.NetworkInfo {
path := n.netavarkBinary
packageVersion := cutil.PackageVersion(path)
programVersion, err := cutil.ProgramVersion(path)
if err != nil {
logrus.Warnf("Failed to get netavark version: %v", err)
}

info := types.NetworkInfo{
Backend: "netavark",
Version: programVersion,
Package: packageVersion,
Path: path,
}

dnsPath := n.aardvarkBinary
dnsPackage := cutil.PackageVersion(dnsPath)
dnsProgram, err := cutil.ProgramVersion(dnsPath)
if err != nil {
logrus.Warnf("Failed to get aardvark version: %v", err)
}

info.DNS = types.DNSNetworkInfo{
Version: dnsProgram,
Package: dnsPackage,
Path: dnsPath,
}

return info
}

func (n *netavarkNetwork) Network(nameOrID string) (*types.Network, error) {
network, err := n.getNetwork(nameOrID)
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions libnetwork/types/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ type ContainerNetwork interface {
// DefaultNetworkName will return the default network name
// for this interface.
DefaultNetworkName() string

// NetworkInfo return the network information about backend type,
// binary path, package version and so on.
NetworkInfo() NetworkInfo
}

// Network describes the Network attributes.
Expand Down Expand Up @@ -80,6 +84,22 @@ type NetworkUpdateOptions struct {
RemoveDNSServers []string `json:"remove_dns_servers,omitempty"`
}

// NetworkInfo contains the network information.
type NetworkInfo struct {
Backend string `json:"backend"`
Version string `json:"version,omitempty"`
Package string `json:"package,omitempty"`
Path string `json:"path,omitempty"`
DNS DNSNetworkInfo `json:"dns,omitempty"`
}

// NetworkInfo contains the DNS information.
type DNSNetworkInfo struct {
Version string `json:"version,omitempty"`
Package string `json:"package,omitempty"`
Path string `json:"path,omitempty"`
}

// IPNet is used as custom net.IPNet type to add Marshal/Unmarshal methods.
type IPNet struct {
net.IPNet
Expand Down
70 changes: 69 additions & 1 deletion pkg/util/util.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,74 @@
package util

import "regexp"
import (
"bytes"
"fmt"
"os/exec"
"regexp"
"strings"
)

const (
unknownPackage = "Unknown"
)

func queryPackageVersion(cmdArg ...string) string {
output := unknownPackage
if 1 < len(cmdArg) {
cmd := exec.Command(cmdArg[0], cmdArg[1:]...)
if outp, err := cmd.Output(); err == nil {
output = string(outp)
if cmdArg[0] == "/usr/bin/dpkg" {
r := strings.Split(output, ": ")
queryFormat := `${Package}_${Version}_${Architecture}`
cmd = exec.Command("/usr/bin/dpkg-query", "-f", queryFormat, "-W", r[0])
if outp, err := cmd.Output(); err == nil {
output = string(outp)
}
}
}
if cmdArg[0] == "/sbin/apk" {
prefix := cmdArg[len(cmdArg)-1] + " is owned by "
output = strings.Replace(output, prefix, "", 1)
}
}
return strings.Trim(output, "\n")
}

func PackageVersion(program string) string { // program is full path
packagers := [][]string{
{"/usr/bin/rpm", "-q", "-f"},
{"/usr/bin/dpkg", "-S"}, // Debian, Ubuntu
{"/usr/bin/pacman", "-Qo"}, // Arch
{"/usr/bin/qfile", "-qv"}, // Gentoo (quick)
{"/usr/bin/equery", "b"}, // Gentoo (slow)
{"/sbin/apk", "info", "-W"}, // Alpine
{"/usr/local/sbin/pkg", "which", "-q"}, // FreeBSD
}

for _, cmd := range packagers {
cmd = append(cmd, program)
if out := queryPackageVersion(cmd...); out != unknownPackage {
return out
}
}
return unknownPackage
}

func ProgramVersion(program string) (string, error) {
cmd := exec.Command(program, "--version")
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

err := cmd.Run()
if err != nil {
return "", fmt.Errorf("`%v --version` failed: %v %v (%v)", program, stderr.String(), stdout.String(), err)
}

return strings.TrimSuffix(stdout.String(), "\n"), nil
}

// StringInSlice determines if a string is in a string slice, returns bool
func StringInSlice(s string, sl []string) bool {
Expand Down

0 comments on commit 0bde67d

Please sign in to comment.