mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2015 The Kubernetes Authors All rights reserved.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
// Package chaosclient makes it easy to simulate network latency, misbehaving
 | 
						|
// servers, and random errors from servers. It is intended to stress test components
 | 
						|
// under failure conditions and expose weaknesses in the error handling logic
 | 
						|
// of the codebase.
 | 
						|
package chaosclient
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"log"
 | 
						|
	"math/rand"
 | 
						|
	"net/http"
 | 
						|
	"reflect"
 | 
						|
	"runtime"
 | 
						|
 | 
						|
	"k8s.io/kubernetes/pkg/util/net"
 | 
						|
)
 | 
						|
 | 
						|
// chaosrt provides the ability to perform simulations of HTTP client failures
 | 
						|
// under the Golang http.Transport interface.
 | 
						|
type chaosrt struct {
 | 
						|
	rt     http.RoundTripper
 | 
						|
	notify ChaosNotifier
 | 
						|
	c      []Chaos
 | 
						|
}
 | 
						|
 | 
						|
// Chaos intercepts requests to a remote HTTP endpoint and can inject arbitrary
 | 
						|
// failures.
 | 
						|
type Chaos interface {
 | 
						|
	// Intercept should return true if the normal flow should be skipped, and the
 | 
						|
	// return response and error used instead. Modifications to the request will
 | 
						|
	// be ignored, but may be used to make decisions about types of failures.
 | 
						|
	Intercept(req *http.Request) (bool, *http.Response, error)
 | 
						|
}
 | 
						|
 | 
						|
// ChaosNotifier notifies another component that the ChaosRoundTripper has simulated
 | 
						|
// a failure.
 | 
						|
type ChaosNotifier interface {
 | 
						|
	// OnChaos is invoked when a chaotic outcome was triggered. fn is the
 | 
						|
	// source of Chaos and req was the outgoing request
 | 
						|
	OnChaos(req *http.Request, c Chaos)
 | 
						|
}
 | 
						|
 | 
						|
// ChaosFunc takes an http.Request and decides whether to alter the response. It
 | 
						|
// returns true if it wishes to mutate the response, with a http.Response or
 | 
						|
// error.
 | 
						|
type ChaosFunc func(req *http.Request) (bool, *http.Response, error)
 | 
						|
 | 
						|
func (fn ChaosFunc) Intercept(req *http.Request) (bool, *http.Response, error) {
 | 
						|
	return fn.Intercept(req)
 | 
						|
}
 | 
						|
func (fn ChaosFunc) String() string {
 | 
						|
	return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
 | 
						|
}
 | 
						|
 | 
						|
// NewChaosRoundTripper creates an http.RoundTripper that will intercept requests
 | 
						|
// based on the provided Chaos functions. The notifier is invoked when a Chaos
 | 
						|
// Intercept is fired.
 | 
						|
func NewChaosRoundTripper(rt http.RoundTripper, notify ChaosNotifier, c ...Chaos) http.RoundTripper {
 | 
						|
	return &chaosrt{rt, notify, c}
 | 
						|
}
 | 
						|
 | 
						|
// RoundTrip gives each ChaosFunc an opportunity to intercept the request. The first
 | 
						|
// interceptor wins.
 | 
						|
func (rt *chaosrt) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
						|
	for _, c := range rt.c {
 | 
						|
		if intercept, resp, err := c.Intercept(req); intercept {
 | 
						|
			rt.notify.OnChaos(req, c)
 | 
						|
			return resp, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return rt.rt.RoundTrip(req)
 | 
						|
}
 | 
						|
 | 
						|
var _ = net.RoundTripperWrapper(&chaosrt{})
 | 
						|
 | 
						|
func (rt *chaosrt) WrappedRoundTripper() http.RoundTripper {
 | 
						|
	return rt.rt
 | 
						|
}
 | 
						|
 | 
						|
// Seed represents a consistent stream of chaos.
 | 
						|
type Seed struct {
 | 
						|
	*rand.Rand
 | 
						|
}
 | 
						|
 | 
						|
// NewSeed creates an object that assists in generating random chaotic events
 | 
						|
// based on a deterministic seed.
 | 
						|
func NewSeed(seed int64) Seed {
 | 
						|
	return Seed{rand.New(rand.NewSource(seed))}
 | 
						|
}
 | 
						|
 | 
						|
type pIntercept struct {
 | 
						|
	Chaos
 | 
						|
	s Seed
 | 
						|
	p float64
 | 
						|
}
 | 
						|
 | 
						|
// P returns a ChaosFunc that fires with a probability of p (p between 0.0
 | 
						|
// and 1.0 with 0.0 meaning never and 1.0 meaning always).
 | 
						|
func (s Seed) P(p float64, c Chaos) Chaos {
 | 
						|
	return pIntercept{c, s, p}
 | 
						|
}
 | 
						|
 | 
						|
// Intercept intercepts requests with the provided probability p.
 | 
						|
func (c pIntercept) Intercept(req *http.Request) (bool, *http.Response, error) {
 | 
						|
	if c.s.Float64() < c.p {
 | 
						|
		return c.Chaos.Intercept(req)
 | 
						|
	}
 | 
						|
	return false, nil, nil
 | 
						|
}
 | 
						|
 | 
						|
func (c pIntercept) String() string {
 | 
						|
	return fmt.Sprintf("P{%f %s}", c.p, c.Chaos)
 | 
						|
}
 | 
						|
 | 
						|
// ErrSimulatedConnectionResetByPeer emulates the golang net error when a connection
 | 
						|
// is reset by a peer.
 | 
						|
// TODO: make this more accurate
 | 
						|
// TODO: add other error types
 | 
						|
// TODO: add a helper for returning multiple errors randomly.
 | 
						|
var ErrSimulatedConnectionResetByPeer = Error{errors.New("connection reset by peer")}
 | 
						|
 | 
						|
// Error returns the nested error when C() is invoked.
 | 
						|
type Error struct {
 | 
						|
	error
 | 
						|
}
 | 
						|
 | 
						|
// C returns the nested error
 | 
						|
func (e Error) Intercept(_ *http.Request) (bool, *http.Response, error) {
 | 
						|
	return true, nil, e.error
 | 
						|
}
 | 
						|
 | 
						|
// LogChaos is the default ChaosNotifier and writes a message to the Golang log.
 | 
						|
var LogChaos = ChaosNotifier(logChaos{})
 | 
						|
 | 
						|
type logChaos struct{}
 | 
						|
 | 
						|
func (logChaos) OnChaos(req *http.Request, c Chaos) {
 | 
						|
	log.Printf("Triggered chaotic behavior for %s %s: %v", req.Method, req.URL.String(), c)
 | 
						|
}
 |