azure-container-networking/platform/os_linux.go

242 строки
6.7 KiB
Go

// Copyright 2017 Microsoft. All rights reserved.
// MIT License
package platform
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"
"github.com/Azure/azure-container-networking/log"
"github.com/pkg/errors"
"go.uber.org/zap"
)
const (
// CNMRuntimePath is the path where CNM state files are stored.
CNMRuntimePath = "/var/lib/azure-network/"
// CNIRuntimePath is the path where CNI state files are stored.
CNIRuntimePath = "/var/run/"
// CNILockPath is the path where CNI lock files are stored.
CNILockPath = "/var/run/azure-vnet/"
// CNIStateFilePath is the path to the CNI state file
CNIStateFilePath = "/var/run/azure-vnet.json"
// CNIIpamStatePath is the name of IPAM state file
CNIIpamStatePath = "/var/run/azure-vnet-ipam.json"
// CNIBinaryPath is the path to the CNI binary
CNIBinaryPath = "/opt/cni/bin/azure-vnet"
// CNSRuntimePath is the path where CNS state files are stored.
CNSRuntimePath = "/var/run/"
// CNI runtime path on a Kubernetes cluster
K8SCNIRuntimePath = "/opt/cni/bin"
// Network configuration file path on a Kubernetes cluster
K8SNetConfigPath = "/etc/cni/net.d"
// NPMRuntimePath is the path where NPM logging files are stored.
NPMRuntimePath = "/var/run/"
// DNCRuntimePath is the path where DNC logging files are stored.
DNCRuntimePath = "/var/run/"
// This file contains OS details
osReleaseFile = "/etc/os-release"
)
// GetOSInfo returns OS version information.
func GetOSInfo() string {
info, err := os.ReadFile("/proc/version")
if err != nil {
return "unknown"
}
return string(info)
}
func GetProcessSupport() error {
p := NewExecClient(nil)
cmd := fmt.Sprintf("ps -p %v -o comm=", os.Getpid())
_, err := p.ExecuteRawCommand(cmd)
return err
}
// GetLastRebootTime returns the last time the system rebooted.
func (p *execClient) GetLastRebootTime() (time.Time, error) {
// Query last reboot time.
out, err := exec.Command("uptime", "-s").Output()
if err != nil {
if p.logger != nil {
p.logger.Error("Failed to query uptime", zap.Error(err))
} else {
log.Printf("Failed to query uptime, err:%v", err)
}
return time.Time{}.UTC(), err
}
// Parse the output.
layout := "2006-01-02 15:04:05"
rebootTime, err := time.ParseInLocation(layout, string(out[:len(out)-1]), time.Local)
if err != nil {
if p.logger != nil {
p.logger.Error("Failed to parse uptime", zap.Error(err))
} else {
log.Printf("Failed to parse uptime, err:%v", err)
}
return time.Time{}.UTC(), err
}
return rebootTime.UTC(), nil
}
// Deprecated: ExecuteRawCommand is deprecated, it is recommended to use ExecuteCommand when possible
func (p *execClient) ExecuteRawCommand(command string) (string, error) {
if p.logger != nil {
p.logger.Info("[Azure-Utils]", zap.String("command", command))
} else {
log.Printf("[Azure-Utils] %s", command)
}
var stderr bytes.Buffer
var out bytes.Buffer
// Create a new context and add a timeout to it
ctx, cancel := context.WithTimeout(context.Background(), p.Timeout)
defer cancel() // The cancel should be deferred so resources are cleaned up
cmd := exec.CommandContext(ctx, "sh", "-c", command)
cmd.Stderr = &stderr
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return "", fmt.Errorf("%s:%s", err.Error(), stderr.String())
}
return out.String(), nil
}
// ExecuteCommand passes its parameters to an exec.CommandContext, runs the command, and returns its output, or an error if the command fails or times out
func (p *execClient) ExecuteCommand(ctx context.Context, command string, args ...string) (string, error) {
if p.logger != nil {
p.logger.Info("[Azure-Utils]", zap.String("command", command), zap.Strings("args", args))
} else {
log.Printf("[Azure-Utils] %s %v", command, args)
}
var stderr bytes.Buffer
var out bytes.Buffer
// Create a new context and add a timeout to it
derivedCtx, cancel := context.WithTimeout(ctx, p.Timeout)
defer cancel() // The cancel should be deferred so resources are cleaned up
cmd := exec.CommandContext(derivedCtx, command, args...)
cmd.Stderr = &stderr
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return "", errors.Wrapf(err, "%s:%s", err.Error(), stderr.String())
}
return out.String(), nil
}
func SetOutboundSNAT(subnet string) error {
p := NewExecClient(nil)
cmd := fmt.Sprintf("iptables -t nat -A POSTROUTING -m iprange ! --dst-range 168.63.129.16 -m addrtype ! --dst-type local ! -d %v -j MASQUERADE",
subnet)
_, err := p.ExecuteRawCommand(cmd)
if err != nil {
log.Printf("SNAT Iptable rule was not set")
return err
}
return nil
}
// ClearNetworkConfiguration clears the azure-vnet.json contents.
// This will be called only when reboot is detected - This is windows specific
func (p *execClient) ClearNetworkConfiguration() (bool, error) {
return false, nil
}
// not supported on linux
func (p *execClient) ExecutePowershellCommand(_ string) (string, error) {
return "", nil
}
// not supported on linux
func (p *execClient) ExecutePowershellCommandWithContext(_ context.Context, _ string) (string, error) {
return "", nil
}
func (p *execClient) KillProcessByName(processName string) error {
cmd := fmt.Sprintf("pkill -f %v", processName)
_, err := p.ExecuteRawCommand(cmd)
return err
}
// SetSdnRemoteArpMacAddress sets the regkey for SDNRemoteArpMacAddress needed for multitenancy
// This operation is specific to windows OS
func SetSdnRemoteArpMacAddress(_ ExecClient) error {
return nil
}
func GetOSDetails() (map[string]string, error) {
linesArr, err := ReadFileByLines(osReleaseFile)
if err != nil || len(linesArr) <= 0 {
return nil, err
}
osInfoArr := make(map[string]string)
for i := range linesArr {
s := strings.Split(linesArr[i], "=")
if len(s) == 2 {
osInfoArr[s[0]] = strings.TrimSuffix(s[1], "\n")
}
}
return osInfoArr, nil
}
func GetProcessNameByID(pidstr string) (string, error) {
p := NewExecClient(nil)
pidstr = strings.Trim(pidstr, "\n")
cmd := fmt.Sprintf("ps -p %s -o comm=", pidstr)
out, err := p.ExecuteRawCommand(cmd)
if err != nil {
log.Printf("GetProcessNameByID returned error: %v", err)
return "", err
}
out = strings.Trim(out, "\n")
out = strings.TrimSpace(out)
return out, nil
}
func PrintDependencyPackageDetails() {
p := NewExecClient(nil)
out, err := p.ExecuteRawCommand("iptables --version")
out = strings.TrimSuffix(out, "\n")
log.Printf("[cni-net] iptable version:%s, err:%v", out, err)
}
func ReplaceFile(source, destination string) error {
return os.Rename(source, destination)
}
// Mellanox adapter not applicable for linux
func HasMellanoxAdapter() bool {
return false
}
// Not needed for Linux
func MonitorAndSetMellanoxRegKeyPriorityVLANTag(_ context.Context, _ int) {}
func FetchMacAddressPnpIDMapping(_ context.Context, _ ExecClient) (map[string]string, error) {
return nil, nil
}