<commit_before>package victims

import (
	"fmt"
	"math"
	"math/rand"
	"time"

	"github.com/golang/glog"

	"github.com/asobti/kube-monkey/config"

	kube "k8s.io/client-go/kubernetes"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/selection"
	"k8s.io/apimachinery/pkg/util/sets"
)

type Victim interface {
	VictimBaseTemplate
	VictimSpecificAPICalls
	VictimKillNumberGenerator
}

type VictimBaseTemplate interface {
	// Get value methods
	Kind() string
	Name() string
	Namespace() string
	Identifier() string
	Mtbf() int

	VictimAPICalls
}

type VictimSpecificAPICalls interface {
	// Depends on which version i.e. apps/v1 or extensions/v1beta2
	IsEnrolled(kube.Interface) (bool, error) // Get updated enroll status
	KillType(kube.Interface) (string, error) // Get updated kill config type
	KillValue(kube.Interface) (int, error)   // Get updated kill config value
}

type VictimAPICalls interface {
	// Exposed Api Calls
	RunningPods(kube.Interface) ([]v1.Pod, error)
	Pods(kube.Interface) ([]v1.Pod, error)
	DeletePod(kube.Interface, string) error
	DeleteRandomPod(kube.Interface) error // Deprecated, but faster than DeleteRandomPods for single pod termination
	DeleteRandomPods(kube.Interface, int) error
	IsBlacklisted() bool
	IsWhitelisted() bool
}

type VictimKillNumberGenerator interface {
	KillNumberForMaxPercentage(kube.Interface, int) int
	KillNumberForKillingAll(kube.Interface, int) int
	KillNumberForFixedPercentage(kube.Interface, int) int
}

type VictimBase struct {
	kind       string
	name       string
	namespace  string
	identifier string
	mtbf       int

	VictimBaseTemplate
}

func New(kind, name, namespace, identifier string, mtbf int) *VictimBase {
	return &VictimBase{kind: kind, name: name, namespace: namespace, identifier: identifier, mtbf: mtbf}
}

func (v *VictimBase) Kind() string {
	return v.kind
}

func (v *VictimBase) Name() string {
	return v.name
}

func (v *VictimBase) Namespace() string {
	return v.namespace
}

func (v *VictimBase) Identifier() string {
	return v.identifier
}

func (v *VictimBase) Mtbf() int {
	return v.mtbf
}

// Returns a list of running pods for the victim
func (v *VictimBase) RunningPods(clientset kube.Interface) (runningPods []v1.Pod, err error) {
	pods, err := v.Pods(clientset)
	if err != nil {
		return nil, err
	}

	for _, pod := range pods {
		if pod.Status.Phase == v1.PodRunning {
			runningPods = append(runningPods, pod)
		}
	}

	return runningPods, nil
}

// Returns a list of pods under the victim
func (v *VictimBase) Pods(clientset kube.Interface) ([]v1.Pod, error) {
	labelSelector, err := labelFilterForPods(v.identifier)
	if err != nil {
		return nil, err
	}

	podlist, err := clientset.CoreV1().Pods(v.namespace).List(*labelSelector)
	if err != nil {
		return nil, err
	}
	return podlist.Items, nil
}

// Removes specified pod for victim
func (v *VictimBase) DeletePod(clientset kube.Interface, podName string) error {
	if config.DryRun() {
		glog.Infof("[DryRun Mode] Terminated pod %s for %s/%s", podName, v.namespace, v.name)
		return nil
	}

	deleteopts := &metav1.DeleteOptions{
		GracePeriodSeconds: config.GracePeriodSeconds(),
	}

	return clientset.CoreV1().Pods(v.namespace).Delete(podName, deleteopts)
}

// Removes specified number of random pods for the victim
func (v *VictimBase) DeleteRandomPods(clientset kube.Interface, killNum int) error {<commit_msg>Use pod's termination grace period if defined and greater than configured grace period<commit_after>package victims

import (
	"fmt"
	"math"
	"math/rand"
	"time"

	"github.com/asobti/kube-monkey/config"
	"github.com/golang/glog"
	"github.com/pkg/errors"

	kube "k8s.io/client-go/kubernetes"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/selection"
	"k8s.io/apimachinery/pkg/util/sets"
)

type Victim interface {
	VictimBaseTemplate
	VictimSpecificAPICalls
	VictimKillNumberGenerator
}

type VictimBaseTemplate interface {
	// Get value methods
	Kind() string
	Name() string
	Namespace() string
	Identifier() string
	Mtbf() int

	VictimAPICalls
}

type VictimSpecificAPICalls interface {
	// Depends on which version i.e. apps/v1 or extensions/v1beta2
	IsEnrolled(kube.Interface) (bool, error) // Get updated enroll status
	KillType(kube.Interface) (string, error) // Get updated kill config type
	KillValue(kube.Interface) (int, error)   // Get updated kill config value
}

type VictimAPICalls interface {
	// Exposed Api Calls
	RunningPods(kube.Interface) ([]v1.Pod, error)
	Pods(kube.Interface) ([]v1.Pod, error)
	DeletePod(kube.Interface, string) error
	DeleteRandomPod(kube.Interface) error // Deprecated, but faster than DeleteRandomPods for single pod termination
	DeleteRandomPods(kube.Interface, int) error
	IsBlacklisted() bool
	IsWhitelisted() bool
}

type VictimKillNumberGenerator interface {
	KillNumberForMaxPercentage(kube.Interface, int) int
	KillNumberForKillingAll(kube.Interface, int) int
	KillNumberForFixedPercentage(kube.Interface, int) int
}

type VictimBase struct {
	kind       string
	name       string
	namespace  string
	identifier string
	mtbf       int

	VictimBaseTemplate
}

func New(kind, name, namespace, identifier string, mtbf int) *VictimBase {
	return &VictimBase{kind: kind, name: name, namespace: namespace, identifier: identifier, mtbf: mtbf}
}

func (v *VictimBase) Kind() string {
	return v.kind
}

func (v *VictimBase) Name() string {
	return v.name
}

func (v *VictimBase) Namespace() string {
	return v.namespace
}

func (v *VictimBase) Identifier() string {
	return v.identifier
}

func (v *VictimBase) Mtbf() int {
	return v.mtbf
}

// Returns a list of running pods for the victim
func (v *VictimBase) RunningPods(clientset kube.Interface) (runningPods []v1.Pod, err error) {
	pods, err := v.Pods(clientset)
	if err != nil {
		return nil, err
	}

	for _, pod := range pods {
		if pod.Status.Phase == v1.PodRunning {
			runningPods = append(runningPods, pod)
		}
	}

	return runningPods, nil
}

// Returns a list of pods under the victim
func (v *VictimBase) Pods(clientset kube.Interface) ([]v1.Pod, error) {
	labelSelector, err := labelFilterForPods(v.identifier)
	if err != nil {
		return nil, err
	}

	podlist, err := clientset.CoreV1().Pods(v.namespace).List(*labelSelector)
	if err != nil {
		return nil, err
	}
	return podlist.Items, nil
}

// Removes specified pod for victim
func (v *VictimBase) DeletePod(clientset kube.Interface, podName string) error {
	if config.DryRun() {
		glog.Infof("[DryRun Mode] Terminated pod %s for %s/%s", podName, v.namespace, v.name)
		return nil
	}

	pod, err := clientset.CoreV1().Pods(v.namespace).Get(podName, metav1.GetOptions{})
	if err != nil {
		return errors.Wrapf(err, "unable to get pod %s for %s/%s", podName, v.namespace, v.name)
	}

	gracePeriodSec := config.GracePeriodSeconds()
	if pod.Spec.TerminationGracePeriodSeconds != nil && *pod.Spec.TerminationGracePeriodSeconds > *gracePeriodSec {
		gracePeriodSec = pod.Spec.TerminationGracePeriodSeconds
	}

	deleteopts := &metav1.DeleteOptions{
		GracePeriodSeconds: gracePeriodSec,
	}

	return clientset.CoreV1().Pods(v.namespace).Delete(podName, deleteopts)
}

// Removes specified number of random pods for the victim
func (v *VictimBase) DeleteRandomPods(clientset kube.Interface, killNum int) error {
{'fraction_non_alphanumeric': 0.1127676877202494, 'fraction_numerical': 0.0056925996204933585, 'mean_word_length': 4.543951915852742, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1312119', 'n_tokens_mistral': 2698, 'n_tokens_neox': 2626, 'n_words': 671}