github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/old/bandwidth_manager/bandwidth_manager.go (about)

     1  package bandwidth_manager
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os/exec"
     7  	"path"
     8  	"regexp"
     9  	"strconv"
    10  
    11  	"github.com/cloudfoundry-incubator/garden"
    12  	"github.com/cloudfoundry-incubator/garden-linux/old/logging"
    13  	"github.com/cloudfoundry/gunk/command_runner"
    14  	"github.com/pivotal-golang/lager"
    15  )
    16  
    17  var IN_RATE_PATTERN = regexp.MustCompile(`qdisc tbf [0-9a-f]+: root refcnt \d+ rate (\d+)([KMG]?)bit burst (\d+)([KMG]?)b`)
    18  var OUT_RATE_PATTERN = regexp.MustCompile(`police 0x[0-9a-f]+ rate (\d+)([KMG]?)bit burst (\d+)([KMG]?)b`)
    19  
    20  type BandwidthManager interface {
    21  	SetLimits(lager.Logger, garden.BandwidthLimits) error
    22  	GetLimits(lager.Logger) (garden.ContainerBandwidthStat, error)
    23  }
    24  
    25  type ContainerBandwidthManager struct {
    26  	containerPath string
    27  	containerID   string
    28  
    29  	runner command_runner.CommandRunner
    30  }
    31  
    32  func New(containerPath, containerID string, runner command_runner.CommandRunner) *ContainerBandwidthManager {
    33  	return &ContainerBandwidthManager{
    34  		containerPath: containerPath,
    35  		containerID:   containerID,
    36  
    37  		runner: runner,
    38  	}
    39  }
    40  
    41  func (m *ContainerBandwidthManager) SetLimits(
    42  	logger lager.Logger,
    43  	limits garden.BandwidthLimits,
    44  ) error {
    45  	runner := logging.Runner{
    46  		CommandRunner: m.runner,
    47  		Logger:        logger,
    48  	}
    49  
    50  	setRate := exec.Command(path.Join(m.containerPath, "net_rate.sh"))
    51  	setRate.Env = []string{
    52  		fmt.Sprintf("BURST=%d", limits.BurstRateInBytesPerSecond),
    53  		fmt.Sprintf("RATE=%d", limits.RateInBytesPerSecond*8),
    54  	}
    55  
    56  	return runner.Run(setRate)
    57  }
    58  
    59  func (m *ContainerBandwidthManager) GetLimits(logger lager.Logger) (garden.ContainerBandwidthStat, error) {
    60  	limits := garden.ContainerBandwidthStat{}
    61  
    62  	runner := logging.Runner{
    63  		CommandRunner: m.runner,
    64  		Logger:        logger,
    65  	}
    66  
    67  	egressOut := new(bytes.Buffer)
    68  
    69  	egress := exec.Command(path.Join(m.containerPath, "net.sh"), "get_egress_info")
    70  	egress.Env = []string{"ID=" + m.containerID}
    71  	egress.Stdout = egressOut
    72  
    73  	err := runner.Run(egress)
    74  	if err != nil {
    75  		return limits, err
    76  	}
    77  
    78  	matches := IN_RATE_PATTERN.FindStringSubmatch(string(egressOut.Bytes()))
    79  	if matches != nil {
    80  		inRate, err := strconv.ParseUint(matches[1], 10, 0)
    81  		if err != nil {
    82  			return limits, err
    83  		}
    84  
    85  		inBurst, err := strconv.ParseUint(matches[3], 10, 0)
    86  		if err != nil {
    87  			return limits, err
    88  		}
    89  
    90  		inRateUnit := matches[2]
    91  		inBurstUnit := matches[4]
    92  
    93  		limits.InRate = convertUnits(inRate, inRateUnit) / 8
    94  		limits.InBurst = convertUnits(inBurst, inBurstUnit)
    95  	}
    96  
    97  	ingressOut := new(bytes.Buffer)
    98  
    99  	ingress := exec.Command(path.Join(m.containerPath, "net.sh"), "get_ingress_info")
   100  	ingress.Env = []string{"ID=" + m.containerID}
   101  	ingress.Stdout = ingressOut
   102  
   103  	err = runner.Run(ingress)
   104  	if err != nil {
   105  		return limits, err
   106  	}
   107  
   108  	matches = OUT_RATE_PATTERN.FindStringSubmatch(string(ingressOut.Bytes()))
   109  	if matches != nil {
   110  		outRate, err := strconv.ParseUint(matches[1], 10, 0)
   111  		if err != nil {
   112  			return limits, err
   113  		}
   114  
   115  		outBurst, err := strconv.ParseUint(matches[3], 10, 0)
   116  		if err != nil {
   117  			return limits, err
   118  		}
   119  
   120  		outRateUnit := matches[2]
   121  		outBurstUnit := matches[4]
   122  
   123  		limits.OutRate = convertUnits(outRate, outRateUnit) / 8
   124  		limits.OutBurst = convertUnits(outBurst, outBurstUnit)
   125  	}
   126  
   127  	return limits, err
   128  }
   129  
   130  func convertUnits(num uint64, unit string) uint64 {
   131  	switch unit {
   132  	case "K":
   133  		return num * 1024
   134  	case "M":
   135  		return num * (1024 ^ 2)
   136  	case "G":
   137  		return num * (1024 ^ 3)
   138  	default:
   139  		return num
   140  	}
   141  }