Merge pull request #23019 from vdemeester/more-daemon-horn-moving
Moving some more methods away from daemon.go
This commit is contained in:
commit
c050102536
6 changed files with 208 additions and 214 deletions
13
daemon/auth.go
Normal file
13
daemon/auth.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/engine-api/types"
|
||||
)
|
||||
|
||||
// AuthenticateToRegistry checks the validity of credentials in authConfig
|
||||
func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error) {
|
||||
return daemon.RegistryService.Auth(ctx, authConfig, dockerversion.DockerUserAgent(ctx))
|
||||
}
|
|
@ -3,14 +3,19 @@ package daemon
|
|||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/truncindex"
|
||||
containertypes "github.com/docker/engine-api/types/container"
|
||||
"github.com/docker/engine-api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
// GetContainer looks for a container using the provided information, which could be
|
||||
|
@ -143,3 +148,108 @@ func (daemon *Daemon) GetByName(name string) (*container.Container, error) {
|
|||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// newBaseContainer creates a new container with its initial
|
||||
// configuration based on the root storage from the daemon.
|
||||
func (daemon *Daemon) newBaseContainer(id string) *container.Container {
|
||||
return container.NewBaseContainer(id, daemon.containerRoot(id))
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint strslice.StrSlice, configCmd strslice.StrSlice) (string, []string) {
|
||||
if len(configEntrypoint) != 0 {
|
||||
return configEntrypoint[0], append(configEntrypoint[1:], configCmd...)
|
||||
}
|
||||
return configCmd[0], configCmd[1:]
|
||||
}
|
||||
|
||||
func (daemon *Daemon) generateHostname(id string, config *containertypes.Config) {
|
||||
// Generate default hostname
|
||||
if config.Hostname == "" {
|
||||
config.Hostname = id[:12]
|
||||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setSecurityOptions(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
return parseSecurityOpt(container, hostConfig)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
||||
// Do not lock while creating volumes since this could be calling out to external plugins
|
||||
// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
|
||||
if err := daemon.registerMountPoints(container, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
// Register any links from the host config before starting the container
|
||||
if err := daemon.registerLinks(container, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// make sure links is not nil
|
||||
// this ensures that on the next daemon restart we don't try to migrate from legacy sqlite links
|
||||
if hostConfig.Links == nil {
|
||||
hostConfig.Links = []string{}
|
||||
}
|
||||
|
||||
container.HostConfig = hostConfig
|
||||
return container.ToDisk()
|
||||
}
|
||||
|
||||
// verifyContainerSettings performs validation of the hostconfig and config
|
||||
// structures.
|
||||
func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
||||
|
||||
// First perform verification of settings common across all platforms.
|
||||
if config != nil {
|
||||
if config.WorkingDir != "" {
|
||||
config.WorkingDir = filepath.FromSlash(config.WorkingDir) // Ensure in platform semantics
|
||||
if !system.IsAbs(config.WorkingDir) {
|
||||
return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path", config.WorkingDir)
|
||||
}
|
||||
}
|
||||
|
||||
if len(config.StopSignal) > 0 {
|
||||
_, err := signal.ParseSignal(config.StopSignal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Validate if the given hostname is RFC 1123 (https://tools.ietf.org/html/rfc1123) compliant.
|
||||
if len(config.Hostname) > 0 {
|
||||
// RFC1123 specifies that 63 bytes is the maximium length
|
||||
// Windows has the limitation of 63 bytes in length
|
||||
// Linux hostname is limited to HOST_NAME_MAX=64, not not including the terminating null byte.
|
||||
// We limit the length to 63 bytes here to match RFC1035 and RFC1123.
|
||||
matched, _ := regexp.MatchString("^(([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])\\.)*([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])$", config.Hostname)
|
||||
if len(config.Hostname) > 63 || !matched {
|
||||
return nil, fmt.Errorf("invalid hostname format: %s", config.Hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hostConfig == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for port := range hostConfig.PortBindings {
|
||||
_, portStr := nat.SplitProtoPort(string(port))
|
||||
if _, err := nat.ParsePort(portStr); err != nil {
|
||||
return nil, fmt.Errorf("Invalid port specification: %q", portStr)
|
||||
}
|
||||
for _, pb := range hostConfig.PortBindings[port] {
|
||||
_, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid port specification: %q", pb.HostPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now do platform-specific verification
|
||||
return verifyPlatformContainerSettings(daemon, hostConfig, config, update)
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ package daemon
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
|
@ -234,3 +236,16 @@ func (daemon *Daemon) mergeAndVerifyConfig(config *containertypes.Config, img *i
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if the client set configurations for more than one network while creating a container
|
||||
func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingConfig) error {
|
||||
if nwConfig == nil || len(nwConfig.EndpointsConfig) <= 1 {
|
||||
return nil
|
||||
}
|
||||
l := make([]string, 0, len(nwConfig.EndpointsConfig))
|
||||
for k := range nwConfig.EndpointsConfig {
|
||||
l = append(l, k)
|
||||
}
|
||||
err := fmt.Errorf("Container cannot be connected to network endpoints: %s", strings.Join(l, ", "))
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
|
214
daemon/daemon.go
214
daemon/daemon.go
|
@ -14,7 +14,6 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -27,16 +26,12 @@ import (
|
|||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/events"
|
||||
"github.com/docker/docker/daemon/exec"
|
||||
"github.com/docker/docker/errors"
|
||||
"github.com/docker/engine-api/types"
|
||||
containertypes "github.com/docker/engine-api/types/container"
|
||||
networktypes "github.com/docker/engine-api/types/network"
|
||||
"github.com/docker/engine-api/types/strslice"
|
||||
// register graph drivers
|
||||
_ "github.com/docker/docker/daemon/graphdriver/register"
|
||||
dmetadata "github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
|
@ -58,11 +53,9 @@ import (
|
|||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
"github.com/docker/docker/volume/local"
|
||||
"github.com/docker/docker/volume/store"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/libnetwork"
|
||||
nwconfig "github.com/docker/libnetwork/config"
|
||||
"github.com/docker/libtrust"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -317,35 +310,6 @@ func (daemon *Daemon) waitForNetworks(c *container.Container) {
|
|||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) generateHostname(id string, config *containertypes.Config) {
|
||||
// Generate default hostname
|
||||
if config.Hostname == "" {
|
||||
config.Hostname = id[:12]
|
||||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint strslice.StrSlice, configCmd strslice.StrSlice) (string, []string) {
|
||||
if len(configEntrypoint) != 0 {
|
||||
return configEntrypoint[0], append(configEntrypoint[1:], configCmd...)
|
||||
}
|
||||
return configCmd[0], configCmd[1:]
|
||||
}
|
||||
|
||||
// GetLabels for a container or image id
|
||||
func (daemon *Daemon) GetLabels(id string) map[string]string {
|
||||
// TODO: TestCase
|
||||
container := daemon.containers.Get(id)
|
||||
if container != nil {
|
||||
return container.Config.Labels
|
||||
}
|
||||
|
||||
img, err := daemon.GetImage(id)
|
||||
if err == nil {
|
||||
return img.ContainerConfig.Labels
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) children(c *container.Container) map[string]*container.Container {
|
||||
return daemon.linkIndex.children(c)
|
||||
}
|
||||
|
@ -762,37 +726,6 @@ func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
|
|||
return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setSecurityOptions(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
return parseSecurityOpt(container, hostConfig)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
||||
// Do not lock while creating volumes since this could be calling out to external plugins
|
||||
// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
|
||||
if err := daemon.registerMountPoints(container, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
// Register any links from the host config before starting the container
|
||||
if err := daemon.registerLinks(container, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// make sure links is not nil
|
||||
// this ensures that on the next daemon restart we don't try to migrate from legacy sqlite links
|
||||
if hostConfig.Links == nil {
|
||||
hostConfig.Links = []string{}
|
||||
}
|
||||
|
||||
container.HostConfig = hostConfig
|
||||
return container.ToDisk()
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setupInitLayer(initPath string) error {
|
||||
rootUID, rootGID := daemon.GetRemappedUIDGID()
|
||||
return setupInitLayer(initPath, rootUID, rootGID)
|
||||
|
@ -806,73 +739,6 @@ func setDefaultMtu(config *Config) {
|
|||
config.Mtu = defaultNetworkMtu
|
||||
}
|
||||
|
||||
// verifyContainerSettings performs validation of the hostconfig and config
|
||||
// structures.
|
||||
func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
||||
|
||||
// First perform verification of settings common across all platforms.
|
||||
if config != nil {
|
||||
if config.WorkingDir != "" {
|
||||
config.WorkingDir = filepath.FromSlash(config.WorkingDir) // Ensure in platform semantics
|
||||
if !system.IsAbs(config.WorkingDir) {
|
||||
return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path", config.WorkingDir)
|
||||
}
|
||||
}
|
||||
|
||||
if len(config.StopSignal) > 0 {
|
||||
_, err := signal.ParseSignal(config.StopSignal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Validate if the given hostname is RFC 1123 (https://tools.ietf.org/html/rfc1123) compliant.
|
||||
if len(config.Hostname) > 0 {
|
||||
// RFC1123 specifies that 63 bytes is the maximium length
|
||||
// Windows has the limitation of 63 bytes in length
|
||||
// Linux hostname is limited to HOST_NAME_MAX=64, not not including the terminating null byte.
|
||||
// We limit the length to 63 bytes here to match RFC1035 and RFC1123.
|
||||
matched, _ := regexp.MatchString("^(([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])\\.)*([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])$", config.Hostname)
|
||||
if len(config.Hostname) > 63 || !matched {
|
||||
return nil, fmt.Errorf("invalid hostname format: %s", config.Hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hostConfig == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for port := range hostConfig.PortBindings {
|
||||
_, portStr := nat.SplitProtoPort(string(port))
|
||||
if _, err := nat.ParsePort(portStr); err != nil {
|
||||
return nil, fmt.Errorf("Invalid port specification: %q", portStr)
|
||||
}
|
||||
for _, pb := range hostConfig.PortBindings[port] {
|
||||
_, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid port specification: %q", pb.HostPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now do platform-specific verification
|
||||
return verifyPlatformContainerSettings(daemon, hostConfig, config, update)
|
||||
}
|
||||
|
||||
// Checks if the client set configurations for more than one network while creating a container
|
||||
func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingConfig) error {
|
||||
if nwConfig == nil || len(nwConfig.EndpointsConfig) <= 1 {
|
||||
return nil
|
||||
}
|
||||
l := make([]string, 0, len(nwConfig.EndpointsConfig))
|
||||
for k := range nwConfig.EndpointsConfig {
|
||||
l = append(l, k)
|
||||
}
|
||||
err := fmt.Errorf("Container cannot be connected to network endpoints: %s", strings.Join(l, ", "))
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore, error) {
|
||||
volumesDriver, err := local.New(config.Root, rootUID, rootGID)
|
||||
if err != nil {
|
||||
|
@ -883,84 +749,11 @@ func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore,
|
|||
return store.New(config.Root)
|
||||
}
|
||||
|
||||
// AuthenticateToRegistry checks the validity of credentials in authConfig
|
||||
func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error) {
|
||||
return daemon.RegistryService.Auth(ctx, authConfig, dockerversion.DockerUserAgent(ctx))
|
||||
}
|
||||
|
||||
// IsShuttingDown tells whether the daemon is shutting down or not
|
||||
func (daemon *Daemon) IsShuttingDown() bool {
|
||||
return daemon.shutdown
|
||||
}
|
||||
|
||||
// GetContainerStats collects all the stats published by a container
|
||||
func (daemon *Daemon) GetContainerStats(container *container.Container) (*types.StatsJSON, error) {
|
||||
stats, err := daemon.stats(container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stats.Networks, err = daemon.getNetworkStats(container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// Resolve Network SandboxID in case the container reuse another container's network stack
|
||||
func (daemon *Daemon) getNetworkSandboxID(c *container.Container) (string, error) {
|
||||
curr := c
|
||||
for curr.HostConfig.NetworkMode.IsContainer() {
|
||||
containerID := curr.HostConfig.NetworkMode.ConnectedContainer()
|
||||
connected, err := daemon.GetContainer(containerID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Could not get container for %s", containerID)
|
||||
}
|
||||
curr = connected
|
||||
}
|
||||
return curr.NetworkSettings.SandboxID, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getNetworkStats(c *container.Container) (map[string]types.NetworkStats, error) {
|
||||
sandboxID, err := daemon.getNetworkSandboxID(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sb, err := daemon.netController.SandboxByID(sandboxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lnstats, err := sb.Statistics()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := make(map[string]types.NetworkStats)
|
||||
// Convert libnetwork nw stats into engine-api stats
|
||||
for ifName, ifStats := range lnstats {
|
||||
stats[ifName] = types.NetworkStats{
|
||||
RxBytes: ifStats.RxBytes,
|
||||
RxPackets: ifStats.RxPackets,
|
||||
RxErrors: ifStats.RxErrors,
|
||||
RxDropped: ifStats.RxDropped,
|
||||
TxBytes: ifStats.TxBytes,
|
||||
TxPackets: ifStats.TxPackets,
|
||||
TxErrors: ifStats.TxErrors,
|
||||
TxDropped: ifStats.TxDropped,
|
||||
}
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// newBaseContainer creates a new container with its initial
|
||||
// configuration based on the root storage from the daemon.
|
||||
func (daemon *Daemon) newBaseContainer(id string) *container.Container {
|
||||
return container.NewBaseContainer(id, daemon.containerRoot(id))
|
||||
}
|
||||
|
||||
// initDiscovery initializes the discovery watcher for this daemon.
|
||||
func (daemon *Daemon) initDiscovery(config *Config) error {
|
||||
advertise, err := parseClusterAdvertiseSettings(config.ClusterStore, config.ClusterAdvertise)
|
||||
|
@ -1112,13 +905,6 @@ func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func validateID(id string) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("Invalid empty id")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBridgeNetworkDisabled(config *Config) bool {
|
||||
return config.bridgeConfig.Iface == disableNetworkBridge
|
||||
}
|
||||
|
|
|
@ -106,3 +106,10 @@ func (daemon *Daemon) generateNewName(id string) (string, error) {
|
|||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func validateID(id string) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("Invalid empty id")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package daemon
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
@ -130,3 +131,65 @@ func (daemon *Daemon) subscribeToContainerStats(c *container.Container) chan int
|
|||
func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch chan interface{}) {
|
||||
daemon.statsCollector.unsubscribe(c, ch)
|
||||
}
|
||||
|
||||
// GetContainerStats collects all the stats published by a container
|
||||
func (daemon *Daemon) GetContainerStats(container *container.Container) (*types.StatsJSON, error) {
|
||||
stats, err := daemon.stats(container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stats.Networks, err = daemon.getNetworkStats(container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// Resolve Network SandboxID in case the container reuse another container's network stack
|
||||
func (daemon *Daemon) getNetworkSandboxID(c *container.Container) (string, error) {
|
||||
curr := c
|
||||
for curr.HostConfig.NetworkMode.IsContainer() {
|
||||
containerID := curr.HostConfig.NetworkMode.ConnectedContainer()
|
||||
connected, err := daemon.GetContainer(containerID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Could not get container for %s", containerID)
|
||||
}
|
||||
curr = connected
|
||||
}
|
||||
return curr.NetworkSettings.SandboxID, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getNetworkStats(c *container.Container) (map[string]types.NetworkStats, error) {
|
||||
sandboxID, err := daemon.getNetworkSandboxID(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sb, err := daemon.netController.SandboxByID(sandboxID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lnstats, err := sb.Statistics()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := make(map[string]types.NetworkStats)
|
||||
// Convert libnetwork nw stats into engine-api stats
|
||||
for ifName, ifStats := range lnstats {
|
||||
stats[ifName] = types.NetworkStats{
|
||||
RxBytes: ifStats.RxBytes,
|
||||
RxPackets: ifStats.RxPackets,
|
||||
RxErrors: ifStats.RxErrors,
|
||||
RxDropped: ifStats.RxDropped,
|
||||
TxBytes: ifStats.TxBytes,
|
||||
TxPackets: ifStats.TxPackets,
|
||||
TxErrors: ifStats.TxErrors,
|
||||
TxDropped: ifStats.TxDropped,
|
||||
}
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue