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 16, 2023
1 parent 2758e27 commit 6595ffb
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 1 deletion.
38 changes: 38 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,43 @@ 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 != cutil.UnknownPackage {
path = p
packageVersion = ver
break
}
}

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

dnsPath := filepath.Join(path, "dnsname")
dnsPackage := cutil.PackageVersion(dnsPath)
dnsProgram, err := cutil.ProgramVersionDnsname(dnsPath)
if err != nil {
logrus.Infof("Failed to get the dnsname plugin version: %v", err)
}
if _, err := os.Stat(dnsPath); err == nil {
info.DNS = types.DNSNetworkInfo{
Path: dnsPath,
Package: dnsPackage,
Version: dnsProgram,
}
}

return info
}

func (n *cniNetwork) Network(nameOrID string) (*types.Network, error) {
network, err := n.getNetwork(nameOrID)
if err != nil {
Expand Down
32 changes: 32 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,37 @@ 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.Infof("Failed to get the netavark version: %v", err)
}
info := types.NetworkInfo{
Backend: types.Netavark,
Version: programVersion,
Package: packageVersion,
Path: path,
}

dnsPath := n.aardvarkBinary
dnsPackage := cutil.PackageVersion(dnsPath)
dnsProgram, err := cutil.ProgramVersion(dnsPath)
if err != nil {
logrus.Infof("Failed to get the aardvark version: %v", err)
}
info.DNS = types.DNSNetworkInfo{
Package: dnsPackage,
Path: dnsPath,
Version: dnsProgram,
}

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 NetworkBackend `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
90 changes: 89 additions & 1 deletion pkg/util/util.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,94 @@
package util

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

const (
UnknownPackage = "Unknown"
)

// Note: This function is copied from containers/podman libpod/util.go
// Please see https://github.com/containers/common/pull/1460
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")
}

// Note: This function is copied from containers/podman libpod/util.go
// Please see https://github.com/containers/common/pull/1460
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
}

// Note: This function is copied from containers/podman libpod/util.go
// Please see https://github.com/containers/common/pull/1460
func ProgramVersion(program string) (string, error) {
return programVersion(program, false)
}

func ProgramVersionDnsname(program string) (string, error) {
return programVersion(program, true)
}

func programVersion(program string, dnsname bool) (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)
}

output := strings.TrimSuffix(stdout.String(), "\n")
// dnsname --version returns the information to stderr
if dnsname {
output = strings.TrimSuffix(stderr.String(), "\n")
}

return output, 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 6595ffb

Please sign in to comment.