...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/stresschaos/stresschaos.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/debug/stresschaos

     1  // Copyright 2019 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package stresschaos
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"regexp"
    20  	"strconv"
    21  	"strings"
    22  
    23  	"code.cloudfoundry.org/bytefmt"
    24  	"github.com/pkg/errors"
    25  	v1 "k8s.io/api/core/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  
    28  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    29  	cm "github.com/chaos-mesh/chaos-mesh/pkg/chaosctl/common"
    30  )
    31  
    32  // Debug get chaos debug information
    33  func Debug(ctx context.Context, chaos runtime.Object, c *cm.ClientSet, result *cm.ChaosResult) error {
    34  	stressChaos, ok := chaos.(*v1alpha1.StressChaos)
    35  	if !ok {
    36  		return fmt.Errorf("chaos is not stresschaos")
    37  	}
    38  	chaosStatus := stressChaos.Status.ChaosStatus
    39  	chaosSelector := stressChaos.Spec.Selector
    40  
    41  	pods, daemons, err := cm.GetPods(ctx, stressChaos.GetName(), chaosStatus, chaosSelector, c.CtrlCli)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	for i := range pods {
    47  		podName := pods[i].Name
    48  		podResult := cm.PodResult{Name: podName}
    49  		_ = debugEachPod(ctx, pods[i], daemons[i], stressChaos, c, &podResult)
    50  		result.Pods = append(result.Pods, podResult)
    51  		// TODO: V(4) log when err != nil, wait for #1433
    52  	}
    53  	return nil
    54  }
    55  
    56  func debugEachPod(ctx context.Context, pod v1.Pod, daemon v1.Pod, chaos *v1alpha1.StressChaos, c *cm.ClientSet, result *cm.PodResult) error {
    57  	// get process path
    58  	cmd := "cat /proc/cgroups"
    59  	out, err := cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli)
    60  	if err != nil {
    61  		return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
    62  	}
    63  	result.Items = append(result.Items, cm.ItemResult{Name: "cat /proc/cgroups", Value: string(out)})
    64  
    65  	cmd = "ps"
    66  	out, err = cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli)
    67  	if err != nil {
    68  		return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
    69  	}
    70  	result.Items = append(result.Items, cm.ItemResult{Name: "ps", Value: string(out)})
    71  	stressngLine := regexp.MustCompile("(.*)(stress-ng)").FindStringSubmatch(string(out))
    72  	if len(stressngLine) == 0 {
    73  		return fmt.Errorf("could not find stress-ng, StressChaos failed")
    74  	}
    75  
    76  	pids, commands, err := cm.GetPidFromPS(ctx, pod, daemon, c.KubeCli)
    77  	if err != nil {
    78  		return errors.Wrap(err, "get pid from ps failed")
    79  	}
    80  
    81  	for i := range pids {
    82  		cmd = fmt.Sprintf("cat /proc/%s/cgroup", pids[i])
    83  		out, err = cm.ExecBypass(ctx, pod, daemon, cmd, c.KubeCli)
    84  		if err != nil {
    85  			cm.L().WithName("stress-chaos").V(2).Info("failed to fetch cgroup ofr certain process",
    86  				"pod", fmt.Sprintf("%s/%s", pod.Namespace, pod.Name),
    87  				"pid", i,
    88  			)
    89  			result.Items = append(result.Items, cm.ItemResult{Name: fmt.Sprintf("/proc/%s/cgroup of %s", pids[i], commands[i]), Value: "No cgroup found"})
    90  		} else {
    91  			result.Items = append(result.Items, cm.ItemResult{Name: fmt.Sprintf("/proc/%s/cgroup of %s", pids[i], commands[i]), Value: string(out)})
    92  		}
    93  	}
    94  
    95  	// no more info for StressngStressors
    96  	if chaos.Spec.StressngStressors != "" {
    97  		return nil
    98  	}
    99  
   100  	isCPU := true
   101  	if cpuSpec := chaos.Spec.Stressors.CPUStressor; cpuSpec == nil {
   102  		isCPU = false
   103  	}
   104  
   105  	var expr, cpuMountType string
   106  	if isCPU {
   107  		if regexp.MustCompile("(cpu,cpuacct)").MatchString(string(out)) {
   108  			cpuMountType = "cpu,cpuacct"
   109  		} else {
   110  			cpuMountType = "cpu"
   111  		}
   112  		expr = "(?::" + cpuMountType + ":)(.*)"
   113  	} else {
   114  		expr = "(?::memory:)(.*)"
   115  	}
   116  	processPath := regexp.MustCompile(expr).FindStringSubmatch(string(out))[1]
   117  
   118  	// print out debug info
   119  	if isCPU {
   120  		cmd = fmt.Sprintf("cat /sys/fs/cgroup/%s/%s/cpu.cfs_quota_us", cpuMountType, processPath)
   121  		out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
   122  		if err != nil {
   123  			return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
   124  		}
   125  		result.Items = append(result.Items, cm.ItemResult{Name: "cpu.cfs_quota_us", Value: string(out)})
   126  		quota, err := strconv.Atoi(strings.TrimSuffix(string(out), "\n"))
   127  		if err != nil {
   128  			return errors.Wrap(err, "could not get cpu.cfs_quota_us")
   129  		}
   130  
   131  		cmd = fmt.Sprintf("cat /sys/fs/cgroup/%s/%s/cpu.cfs_period_us", cpuMountType, processPath)
   132  		out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
   133  		if err != nil {
   134  			return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
   135  		}
   136  		period, err := strconv.Atoi(strings.TrimSuffix(string(out), "\n"))
   137  		if err != nil {
   138  			return errors.Wrap(err, "could not get cpu.cfs_period_us")
   139  		}
   140  		itemResult := cm.ItemResult{Name: "cpu.cfs_period_us", Value: string(out)}
   141  
   142  		if quota == -1 {
   143  			itemResult.Status = cm.ItemFailure
   144  			itemResult.ErrInfo = "no cpu limit is set for now"
   145  		} else {
   146  			itemResult.Status = cm.ItemSuccess
   147  			itemResult.SucInfo = fmt.Sprintf("cpu limit is equals to %.2f", float64(quota)/float64(period))
   148  		}
   149  		result.Items = append(result.Items, itemResult)
   150  	} else {
   151  		cmd = fmt.Sprintf("cat /sys/fs/cgroup/memory/%s/memory.limit_in_bytes", processPath)
   152  		out, err = cm.Exec(ctx, daemon, cmd, c.KubeCli)
   153  		if err != nil {
   154  			return errors.Wrap(err, fmt.Sprintf("run command %s failed", cmd))
   155  		}
   156  		limit, err := strconv.ParseUint(strings.TrimSuffix(string(out), "\n"), 10, 64)
   157  		if err != nil {
   158  			return errors.Wrap(err, "could not get memory.limit_in_bytes")
   159  		}
   160  		result.Items = append(result.Items, cm.ItemResult{Name: "memory.limit_in_bytes", Value: bytefmt.ByteSize(limit) + "B"})
   161  	}
   162  	return nil
   163  }
   164