Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libnetwork: add NetworkInfo() for get network information #1460

Merged
merged 1 commit into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least for dnsname you can get the version from the binary as well:

$ /usr/libexec/cni/dnsname --version
CNI dnsname plugin
version: 1.3.1
commit: unknown

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a wrapper function ProgramVersionDnsname() to get the dnsname information.
AFAICS, dnsname --version returns the information to stdErr.

# /usr/libexec/cni/dnsname --version > /dev/null
CNI dnsname plugin
version: 1.3.1
commit: unknown

# /usr/libexec/cni/dnsname > /dev/null
CNI dnsname plugin
version: 1.3.1
commit: unknown


# /usr/libexec/cni/dnsname --version 2> /dev/null

# /usr/libexec/cni/dnsname 2> /dev/null

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 {
sstosh marked this conversation as resolved.
Show resolved Hide resolved
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