<commit_before>/* Copyright 2017 Google Inc.
 * https://github.com/NeilFraser/CodeCity
 *
 * 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 flatpack

import (
	"reflect"
	"testing"

	"CodeCity/server/testutil"
)

// Some user-declared types for testing:
type myBool bool
type myInt int
type myUint64 uint64
type myFloat64 float64
type myComplex64 complex64
type myString string

// All these should not be changed by flatten() or unflatten(), and in
// the former case nothing should be added to the flatpack.
var simpleCases = []interface{}{
	false,
	int(1),
	int8(2),
	int16(3),
	int32(4),
	int64(5),
	uint(6),
	uint8(7),
	uint16(8),
	uint32(9),
	uint64(10),
	uintptr(11),
	float32(12.0),
	float64(13.0),
	complex64(14 + 15i),
	complex128(16 + 17i),
	string("Eighteen"),

	myBool(false),
	myInt(19),
	myUint64(20),
	myFloat64(21.0),
	myComplex64(22 + 23i),
	myString("twenty-four"),

	[3]int{24, 25, 26},
	[]int{27, 28, 29},
	map[myString]myInt{
		"cpcallen": 2365779,
		"fraser":   7499832,
	},
}

func TestSimple(t *testing.T) {
	var f = New()
	for _, c := range simpleCases {
		typ := reflect.TypeOf(c)
		v := reflect.ValueOf(c)
		if r := f.flatten(v); !testutil.RecEqual(r.Interface(), c, true) {
			t.Errorf("f.flatten(reflect.ValueOf(%#v)).Interface() == %#v (expected %#v)", c, r, c)
		}
		if r := f.unflatten(typ, v); !testutil.RecEqual(r.Interface(), c, true) {
			t.Errorf("f.unflatten(%s, reflect.ValueOf(%#v)).Interface() == %#v (expected %#v)", typ, c, r, c)
		}
	}
	if len(f.Values) != 0 {
		t.Errorf("f.Values == %#v (expected empty slice)", f.Values)
	}
}

func TestFlattenStringMap(t *testing.T) {
	var a = [...]int{42, 69, 105}
	var m = map[myString]*int{
		"answer":  &a[0],
		"naughty": &a[1],
		"random":  &a[2],
	}
	var f = New()
	r := f.flatten(reflect.ValueOf(m))

	if r.Type() != flatType(reflect.TypeOf(m)) {
		t.Errorf("r.Type() == %s (expected %s)", r.Type(), flatType(reflect.TypeOf(m)))
	}
	if r.Len() != len(m) {
		t.Errorf("r.Len() == %d (expected %d)", r.Len(), len(m))
	}
	for k, v := range r.Interface().(map[myString]ref) {
		if *(m[k]) != f.Values[v].V {
			t.Errorf("*(m[%#v]) == %#v in input but %#v in output", k, *(m[k]), f.Values[v].V)
		}
		delete(m, k)
	}
	if len(m) > 0 {
		t.Errorf("%#v present in input but not in output", m)
	}
}

func TestFlattenNonStringMap(t *testing.T) {
	// Gratuitous use of interface{} to verify key and value types are
	// also (recursively) flattened.
	var m = map[interface{}]interface{}{
		[2]int{1914, 1918}: "WW I",
		[2]int{1939, 1945}: "WW II",
		[2]int{2026, 2053}: "WW III", // Citation: http://memory-alpha.wikia.com/wiki/World_War_III
	}
	var f = New()
	r := f.flatten(reflect.ValueOf(m))

	if r.Type() != flatType(reflect.TypeOf(m)) {
		t.Errorf("r.Type() == %s (expected %s)", r.Type(), flatType(reflect.TypeOf(m)))
	}
	if r.Len() != len(m) {
		t.Errorf("r.Len() == %d (expected %d)", r.Len(), len(m))
	}
	for i, l := 0, r.Len(); i < l; i++ {
		k := r.Index(i).Field(0).Interface().(tagged).V.([2]int)
		v := r.Index(i).Field(1).Interface().(tagged).V
		if m[k] != v {
			t.Errorf("m[%#v] == %#v in input but %#v in output", k, m[k], v)
		}
		delete(m, k)
	}
	if len(m) > 0 {
		t.Errorf("%#v present in input but not in output", m)
	}
}

func TestFlattenArrayPtr(t *testing.T) {
	// An array of four pointers to the same string should store one
	// copy in the flatpack an return an array of four refs:
	var s = "spam"
	var a = [5]*string{nil, &s, &s, &s, &s}

	var f = New()
	r := f.flatten(reflect.ValueOf(a))
	if r.Len() != len(a) {
		t.Errorf("r.Len() == %d (expected %d)", r.Len(), len(a))
	}

	if r0 := r.Index(0).Interface().(ref); r0 != -1 {
		t.Errorf("r[0] == %d (expected -1)", r0)
	}
	for i := 2; i < len(a); i++ {
		if r.Index(i).Interface() != r.Index(1).Interface() {
			t.Errorf("Flattening same pointer value should yield same ref")
		}
	}

	if len(f.Values) != 1 {
		t.Errorf("Flattening same pointer value multiple times should only store one copy of referant")
	}
	exp := tagged{tIDOf(reflect.TypeOf("")), s}
	if f.Values[0] != exp {
		t.Errorf("f.Values[0] == %#v (expected %#v)", f.Values[0], exp)
	}
}

func TestFlattenStructSliceInterface(t *testing.T) {
	// A struct containing an int and a slice of interface type should
	// come back as a struct containign an int and a slice of structs
	// containing a tID in addition to the original interface value.
	var s = struct {
		i  int
		sl []interface{}
	}{42, []interface{}{nil, 69, "Hello", true}}

	var f = New()
	r := f.flatten(reflect.ValueOf(s))

	if r.Type() != flatType(reflect.TypeOf(s)) {
		t.Errorf("r.Type() == %s (expected %s)", r.Type(), flatType(reflect.TypeOf(s)))
	}
	if ri := r.Field(0).Interface(); ri.(int) != s.i {
		t.Errorf("r.Field(0).Interface() == %#v (expected %#v)", ri, s.i)
	}
	rSlice := r.Field(1).Interface().([]tagged)
	for i := 0; i < len(s.sl); i++ {
		expType := tIDOf(reflect.TypeOf(s.sl[i]))
		if rSlice[i].T != expType {
			t.Errorf("rSlice[%d].T == %#v (expected %#v)", i, rSlice[i].T, expType)
		}
		if rSlice[i].V != s.sl[i] {
			t.Errorf("rSlice[%d].V == %#v (expected %#v)", i, rSlice[i].T, s.sl[i])
		}
	}
}

/********************************************************************/

func TestUnflattenStringMap(t *testing.T) {
	var f = Flatpack{
		Values: []tagged{{"int", 42}, {"int", 69}, {"int", 105}},
	}
	mapStrPtrIntType := reflect.TypeOf(map[string]*int{})
	var m = map[string]ref{
		"answer":  0,
		"naughty": 1,
		"random":  2,
	}
	r := f.unflatten(mapStrPtrIntType, reflect.ValueOf(m))
	if r.Len() != len(m) {
		t.Errorf("r.Len() == %d (expected %d)", r.Len(), len(m))
	}
	for k, v := range r.Interface().(map[string]*int) {
		if exp := f.Values[int(m[k])].V.(int); *v != exp {
			t.Errorf("*(m[%#v]) == %#v in input but %#v in output", k, *v, exp)
		}
		delete(m, k)
	}
	if len(m) > 0 {
		t.Errorf("%#v present in input but not in output", m)
	}
}

func TestUnflattenNonStringMap(t *testing.T) {
	var f = Flatpack{
		Values: []tagged{
			{T: "string", V: "WW I"},
			{T: "string", V: "WW II"},
			{T: "string", V: "WW III"},
		},
	}
	var sl = []struct {
		K [2]int `json:"k"`
		V ref    `json:"v"`
	}{
		{[2]int{1914, 1918}, ref(0)},
		{[2]int{1939, 1945}, ref(1)},
		{[2]int{2026, 2053}, ref(2)},
	}
	r := f.unflatten(reflect.TypeOf(map[[2]int]*string{}), reflect.ValueOf(sl))
	if r.Len() != len(sl) {
		t.Errorf("r.Len() == %d (expected %d)", r.Len(), len(sl))
	}
	for i := 0; i < len(sl); i++ {
		k := reflect.ValueOf(sl[i].K)
		exp := f.Values[sl[i].V].V
		if v := *(r.MapIndex(k).Interface().(*string)); v != exp {
			t.Errorf("key %#v maps to %#v in input but %#v in output", k, exp, v)
		}
		r.SetMapIndex(k, reflect.Value{}) // Delete index k
	}
	if r.Len() > 0 {
		//		t.Errorf("%#v present in output but not in input", r.Interface())
	}
}

func TestUnflattenArrayPtr(t *testing.T) {
	var f = Flatpack{
		Values: []tagged{{"string", "spam"}},
	}
	arr5PtrStrType := reflect.TypeOf([5]*string{})
	a := [5]ref{-1, 0, 0, 0, 0}
	r := f.unflatten(arr5PtrStrType, reflect.ValueOf(a))
	if rtyp := r.Type(); rtyp != arr5PtrStrType {
		t.Errorf("Type of r is %s (expected []*int)", rtyp)
	}
	if r.Len() != len(a) {
		t.Errorf("r.Len() == %d (expected %d)", r.Len(), len(a))
	}
	if r0 := r.Index(0).Interface().(*string); r0 != nil {
		t.Errorf("r[0] == %#v (expected nil)", r0)
	}
	for i := 2; i < len(a); i++ {
		if r.Index(i).Interface() != r.Index(1).Interface() {
			t.Errorf("Unflatting same ref should yield same pointer value")
		}
	}
}

func TestUnflattenStruct(t *testing.T) {
	type testStruct struct {
		n int
		p *testStruct
	}
	typ := reflect.TypeOf(testStruct{})
	RegisterType(typ)
	tid := tIDOf(typ)

	// A flatpack of two crosslinked testStructs.
	//
	// Unfortunately the flattened struct type can't be given a name,
	// because unflatten expects it to be anonymous.
	//
	// FIXME: use type aliases once once Go1.9 is available.
	var f = Flatpack{
		Values: []tagged{
			{
				T: tid,
				V: struct {
					F_n int `json:"n"` // Piss off, golint.
					F_p ref `json:"p"`
				}{42, 1},
			},
			{
				T: tid,
				V: struct {
					F_n int `json:"n"`
					F_p ref `json:"p"`
				}{69, 0},
			},
		},
	}
	r := f.unflatten(reflect.PtrTo(typ), reflect.ValueOf(ref(0)))

	// Cycle of two testStructs:
	exp := &testStruct{42, &testStruct{69, nil}}
	exp.p.p = exp

	if v := r.Interface().(*testStruct); !reflect.DeepEqual(v, exp) {
		t.Errorf("%#v != %#v", v, exp)
	} else if v.p.p != v { // Double check cycle length
		t.Errorf("v.p.p == %#v (expected %#v == v)", v.p.p, v)
	}
}

func TestUnflattenSliceInterface(t *testing.T) {
	var f Flatpack
	sl := []tagged{{nilTID, nil}, {"int", 69}, {"string", "Hello"}, {"bool", true}}
	exp := []interface{}{nil, 69, "Hello", true}
	typ := reflect.TypeOf(exp)
	r := f.unflatten(typ, reflect.ValueOf(sl))
	if r.Type() != typ {
		t.Errorf("r.Type() == %s (expected %s)", r.Type(), typ)
	} else if v := r.Interface().([]interface{}); !reflect.DeepEqual(v, exp) {
		t.Errorf("r == %#v (expected %#v)", v, exp)
	}
}

// init registers types for testing.
func init() {
	var examples = []interface{}{
		myBool(false),
		myInt(0),
		myUint64(0),
		myFloat64(0),
		myComplex64(0 + 0i),
		myString(""),
	}
	for _, val := range examples {
		RegisterTypeOf(val)
	}
}
<commit_msg>Combine complex tests into single table-driven round-trip test<commit_after>/* Copyright 2017 Google Inc.
 * https://github.com/NeilFraser/CodeCity
 *
 * 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 flatpack

import (
	"reflect"
	"testing"

	"CodeCity/server/testutil"
)

// Some user-declared types for testing:
type myBool bool
type myInt int
type myUint64 uint64
type myFloat64 float64
type myComplex64 complex64
type myString string

// All these should not be changed by flatten() or unflatten(), and in
// the former case nothing should be added to the flatpack.
var simpleCases = []interface{}{
	false,
	int(1),
	int8(2),
	int16(3),
	int32(4),
	int64(5),
	uint(6),
	uint8(7),
	uint16(8),
	uint32(9),
	uint64(10),
	uintptr(11),
	float32(12.0),
	float64(13.0),
	complex64(14 + 15i),
	complex128(16 + 17i),
	string("Eighteen"),

	myBool(false),
	myInt(19),
	myUint64(20),
	myFloat64(21.0),
	myComplex64(22 + 23i),
	myString("twenty-four"),

	[3]int{24, 25, 26},
	[]int{27, 28, 29},
	map[myString]myInt{
		"cpcallen": 2365779,
		"fraser":   7499832,
	},
}

func TestSimple(t *testing.T) {
	var f = New()
	for _, c := range simpleCases {
		typ := reflect.TypeOf(c)
		v := reflect.ValueOf(c)
		if r := f.flatten(v); !testutil.RecEqual(r.Interface(), c, true) {
			t.Errorf("f.flatten(reflect.ValueOf(%#v)).Interface() == %#v (expected %#v)", c, r, c)
		}
		if r := f.unflatten(typ, v); !testutil.RecEqual(r.Interface(), c, true) {
			t.Errorf("f.unflatten(%s, reflect.ValueOf(%#v)).Interface() == %#v (expected %#v)", typ, c, r, c)
		}
	}
	if len(f.Values) != 0 {
		t.Errorf("f.Values == %#v (expected empty slice)", f.Values)
	}
}

type complexCase struct {
	name       string      // Testcase name
	pre        interface{} // Value to flatten before test (as setup)
	orig, flat interface{} // Original and flattend value
	newVals    int         // How many items will be added to .Values()?
}

// Data used (by pointer) in some complex cases:

var ints = [...]int{42, 69, 105}
var spam = "spam"

// complexCases are the cases checked by TestComplex.
//
// N.B. TestComplex runs extra checks for certain named testcases.  Be
// careful if renaming testcases to make sure new name matches!
var complexCases = []complexCase{
	{
		name:    "TestFlattenArrayPtr",
		orig:    [...]*string{nil, &spam, &spam, &spam, &spam},
		flat:    [...]ref{-1, 0, 0, 0, 0},
		newVals: 1,
	}, {
		name: "StringMap",
		pre:  [...]*int{&ints[0], &ints[1]}, // Force ref order
		orig: map[myString]*int{
			"answer":  &ints[0],
			"naughty": &ints[1],
			"random":  &ints[2],
		},
		flat: map[myString]ref{
			"answer":  ref(0),
			"naughty": ref(1),
			"random":  ref(2),
		},
		newVals: 3,
	}, {
		name: "NonStringMap",
		orig: map[[2]int]string{
			[2]int{1914, 1918}: "WW I",
			[2]int{1939, 1945}: "WW II",
			[2]int{2026, 2053}: "WW III", // Citation: http://memory-alpha.wikia.com/wiki/World_War_III
		},
	}, {
		name: "NonStringMapRecursive",
		pre:  [...]*int{&ints[0], &ints[1]}, // Force ref order
		orig: map[interface{}]*int{
			nil:    &ints[0],
			"one":  &ints[1],
			2:      &ints[2],
			3 + 0i: &ints[2], // Check shared substructure
		},
		newVals: 3,
	}, {
		name: "TestFlattenStruct",
		orig: (struct {
			i  int
			sl []interface{}
		}{42, []interface{}{nil, 69, "Hello", true}}),
	},
}

// TestComplex does round-trip testing of more complex cases.
//
// N.B.: there are some extra checks for certain named testcases in
// the bottom section of the function.
func TestComplex(t *testing.T) {
	for _, c := range complexCases {
		t.Run(c.name, func(t *testing.T) {
			defer func() {
				if p := recover(); p != nil {
					t.Errorf("%s panicked: %s", c.name, p)
				}
			}()

			var f = New()
			if c.pre != nil {
				_ = f.flatten(reflect.ValueOf(c.pre))
			}
			typ := reflect.TypeOf(c.orig)
			v := reflect.ValueOf(c.orig)
			flat := f.flatten(v)
			unflat := f.unflatten(typ, flat)

			if ftyp := flat.Type(); ftyp != flatType(typ) {
				t.Errorf("f.Flatten(reflect.ValueOf(%#v)).Type() == %s (expected %s)", c.orig, ftyp, flatType(typ))
			}
			if c.flat != nil && !testutil.RecEqual(flat.Interface(), c.flat, true) {
				t.Errorf("f.flatten(reflect.ValueOf(%#v)).Interface() == %#v (expected %#v)", c.orig, flat, c.flat)
			}
			if !testutil.RecEqual(unflat.Interface(), c.orig, true) {
				t.Errorf("f.unflatten(%s, f.flatten(reflect.ValueOf(%#v))).Interface() == %#v (expected %#[2]v)", typ, c.orig, unflat)
			}
			if len(f.Values) != c.newVals {
				t.Errorf("len(f.Values) == %d (expected %d)", len(f.Values), c.newVals)
				t.Logf("f.Values == %#v", f.Values)
			}

			// Extra checks:
			switch c.name {
			case "StringMap":
				if ft := flat.Type().Kind(); ft != reflect.Map {
					t.Errorf("f.flatten(reflect.ValueOf(%#v)).Type() == %s (expected a map type)", c.orig, ft)
				}
			case "NonStringMap", "NonStringMapRecursive":
				if ft := flat.Type().Kind(); ft == reflect.Map {
					t.Errorf("f.flatten(reflect.ValueOf(%#v)).Type() == %s (expected a non-map type)", c.orig, ft)

				}
			}
		})
	}
}

// init registers types for testing.
func init() {
	var examples = []interface{}{
		myBool(false),
		myInt(0),
		myUint64(0),
		myFloat64(0),
		myComplex64(0 + 0i),
		myString(""),
	}
	for _, val := range examples {
		RegisterTypeOf(val)
	}
}
<|endoftext|>


<commit_before>package spot

type Artist struct {
	Href       string
	SpotId     string `json:"id"`
	Name       string
	Type       string
	Uri        string
	Genres     []string
	Popularity int
	Images     []Image
}

type ArtistResults struct {
	Href  string
	Items []Artist
	total int
}

func GetArtist(id string) (Artist, error) {
	var artist Artist
	err := fetchJson("artists/"+id, &artist)
	if err != nil {
		return artist, err
	}

	return artist, err
}
<commit_msg>adds followers to artist<commit_after>package spot

type Artist struct {
	Href       string
	SpotId     string `json:"id"`
	Name       string
	Type       string
	Uri        string
	Genres     []string
	Popularity int
	Images     []Image
	Followers  map[string]interface{}
}

type ArtistResults struct {
	Href  string
	Items []Artist
	total int
}

func GetArtist(id string) (Artist, error) {
	var artist Artist
	err := fetchJson("artists/"+id, &artist)
	if err != nil {
		return artist, err
	}

	return artist, err
}
<|endoftext|>


<commit_before>package certificates

import (
	"fmt"
	"reflect"
	"time"

	corev1 "k8s.io/api/core/v1"
	extv1beta1 "k8s.io/api/extensions/v1beta1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	corelisters "k8s.io/client-go/listers/core/v1"
	extlisters "k8s.io/client-go/listers/extensions/v1beta1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"

	"github.com/munnerz/cert-manager/pkg/apis/certmanager/v1alpha1"
	"github.com/munnerz/cert-manager/pkg/client"
	controllerpkg "github.com/munnerz/cert-manager/pkg/controller"
	"github.com/munnerz/cert-manager/pkg/informers/externalversions"
	cmlisters "github.com/munnerz/cert-manager/pkg/listers/certmanager/v1alpha1"
	"github.com/munnerz/cert-manager/pkg/log"
)

var _ controllerpkg.Constructor = New

var _ controllerpkg.Controller = &controller{}

type controller struct {
	client   kubernetes.Interface
	cmClient client.Interface

	// To allow injection for testing.
	syncHandler func(key string) error

	issuerInformerSynced cache.InformerSynced
	issuerLister         cmlisters.IssuerLister

	certificateInformerSynced cache.InformerSynced
	certificateLister         cmlisters.CertificateLister

	secretInformerSynced cache.InformerSynced
	secretLister         corelisters.SecretLister

	ingressInformerSynced cache.InformerSynced
	ingressLister         extlisters.IngressLister

	queue workqueue.RateLimitingInterface
}

// New returns a new Certificates controller. It sets up the informer handler
// functions for all the types it watches.
func New(client kubernetes.Interface,
	cmClient client.Interface,
	factory informers.SharedInformerFactory,
	cmFactory externalversions.SharedInformerFactory) (controllerpkg.Controller, error) {

	ctrl := &controller{client: client, cmClient: cmClient}
	ctrl.syncHandler = ctrl.processNextWorkItem
	ctrl.queue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "certificates")

	secretsInformer := factory.Core().V1().Secrets()
	ingressInformer := factory.Extensions().V1beta1().Ingresses()
	certificatesInformer := cmFactory.Certmanager().V1alpha1().Certificates()
	issuersInformer := cmFactory.Certmanager().V1alpha1().Issuers()

	certificatesInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc:    ctrl.certificateAdded,
		UpdateFunc: ctrl.certificateUpdated,
	})
	ctrl.certificateInformerSynced = certificatesInformer.Informer().HasSynced
	ctrl.certificateLister = certificatesInformer.Lister()

	secretsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		DeleteFunc: ctrl.secretDeleted,
	})
	ctrl.secretInformerSynced = secretsInformer.Informer().HasSynced
	ctrl.secretLister = secretsInformer.Lister()

	ctrl.issuerInformerSynced = issuersInformer.Informer().HasSynced
	ctrl.issuerLister = issuersInformer.Lister()

	ingressInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		DeleteFunc: ctrl.ingressDeleted,
	})
	ctrl.ingressInformerSynced = ingressInformer.Informer().HasSynced
	ctrl.ingressLister = ingressInformer.Lister()

	return ctrl, nil
}

func (c *controller) certificateAdded(obj interface{}) {
	var certificate *v1alpha1.Certificate
	var ok bool
	if certificate, ok = obj.(*v1alpha1.Certificate); !ok {
		runtime.HandleError(fmt.Errorf("expected *Certificate but got %T in work queue", obj))
		return
	}
	var key string
	var err error
	if key, err = keyFunc(certificate); err != nil {
		runtime.HandleError(err)
		return
	}
	c.queue.Add(key)
}

func (c *controller) certificateUpdated(prev, obj interface{}) {
	var certificate *v1alpha1.Certificate
	var ok bool
	if certificate, ok = obj.(*v1alpha1.Certificate); !ok {
		runtime.HandleError(fmt.Errorf("expected *Certificate but got %T in work queue", obj))
		return
	}
	if reflect.DeepEqual(prev, obj) {
		return
	}
	var key string
	var err error
	if key, err = keyFunc(certificate); err != nil {
		runtime.HandleError(err)
		return
	}
	c.queue.Add(key)
}

func (c *controller) secretDeleted(obj interface{}) {
	secret, ok := obj.(*corev1.Secret)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			runtime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
			return
		}
		secret, ok = tombstone.Obj.(*corev1.Secret)
		if !ok {
			runtime.HandleError(fmt.Errorf("Tombstone contained object that is not a Secret %#v", obj))
			return
		}
	}
	crts, err := c.certificatesForSecret(secret)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up certificates observing Secret: %s/%s", secret.Namespace, secret.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *controller) ingressDeleted(obj interface{}) {
	ingress, ok := obj.(*extv1beta1.Ingress)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			runtime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
			return
		}
		ingress, ok = tombstone.Obj.(*extv1beta1.Ingress)
		if !ok {
			runtime.HandleError(fmt.Errorf("Tombstone contained object that is not an Ingress %#v", obj))
			return
		}
	}
	crts, err := c.certificatesForIngress(ingress)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up certificates observing Ingress: %s/%s", ingress.Namespace, ingress.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *controller) Run(workers int, stopCh <-chan struct{}) {
	defer c.queue.ShutDown()

	log.Printf("Starting control loop")
	// wait for all the informer caches we depend on are synced
	if !cache.WaitForCacheSync(stopCh,
		c.issuerInformerSynced,
		c.secretInformerSynced,
		c.certificateInformerSynced,
		c.ingressInformerSynced) {
		log.Errorf("error waiting for informer caches to sync")
		return
	}

	for i := 0; i < workers; i++ {
		// TODO (@munnerz): make time.Second duration configurable
		go wait.Until(c.worker, time.Second, stopCh)
	}

	<-stopCh
	log.Printf("shutting down queue as workqueue signalled shutdown")
}

func (c *controller) worker() {
	log.Printf("starting worker")
	for {
		obj, shutdown := c.queue.Get()
		if shutdown {
			break
		}

		err := func(obj interface{}) error {
			defer c.queue.Done(obj)
			var key string
			var ok bool
			if key, ok = obj.(string); !ok {
				runtime.HandleError(fmt.Errorf("expected string in workqueue but got %T", obj))
				return nil
			}
			if err := c.processNextWorkItem(key); err != nil {
				return err
			}
			c.queue.Forget(obj)
			return nil
		}(obj)

		if err != nil {
			log.Printf("requeuing item due to error processing: %s", err.Error())
			c.queue.AddRateLimited(obj)
			continue
		}

		log.Printf("finished processing work item")
	}
	log.Printf("exiting worker loop")
}

func (c *controller) processNextWorkItem(key string) error {
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		runtime.HandleError(fmt.Errorf("invalid resource key: %s", key))
		return nil
	}

	crt, err := c.certificateLister.Certificates(namespace).Get(name)

	if err != nil {
		if k8sErrors.IsNotFound(err) {
			runtime.HandleError(fmt.Errorf("certificate '%s' in work queue no longer exists", key))
			return nil
		}

		return err
	}

	return c.sync(crt)
}

var keyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc

const (
	ControllerName = "certificates"
)

func init() {
	controllerpkg.SharedFactory().Register(ControllerName, New)
}
<commit_msg>Set up resyncPeriod of 5 minutes on Certificate control loop<commit_after>package certificates

import (
	"fmt"
	"reflect"
	"time"

	corev1 "k8s.io/api/core/v1"
	extv1beta1 "k8s.io/api/extensions/v1beta1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	corelisters "k8s.io/client-go/listers/core/v1"
	extlisters "k8s.io/client-go/listers/extensions/v1beta1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"

	"github.com/munnerz/cert-manager/pkg/apis/certmanager/v1alpha1"
	"github.com/munnerz/cert-manager/pkg/client"
	controllerpkg "github.com/munnerz/cert-manager/pkg/controller"
	"github.com/munnerz/cert-manager/pkg/informers/externalversions"
	cmlisters "github.com/munnerz/cert-manager/pkg/listers/certmanager/v1alpha1"
	"github.com/munnerz/cert-manager/pkg/log"
)

var _ controllerpkg.Constructor = New

var _ controllerpkg.Controller = &controller{}

type controller struct {
	client   kubernetes.Interface
	cmClient client.Interface

	// To allow injection for testing.
	syncHandler func(key string) error

	issuerInformerSynced cache.InformerSynced
	issuerLister         cmlisters.IssuerLister

	certificateInformerSynced cache.InformerSynced
	certificateLister         cmlisters.CertificateLister

	secretInformerSynced cache.InformerSynced
	secretLister         corelisters.SecretLister

	ingressInformerSynced cache.InformerSynced
	ingressLister         extlisters.IngressLister

	queue workqueue.RateLimitingInterface
}

// New returns a new Certificates controller. It sets up the informer handler
// functions for all the types it watches.
func New(client kubernetes.Interface,
	cmClient client.Interface,
	factory informers.SharedInformerFactory,
	cmFactory externalversions.SharedInformerFactory) (controllerpkg.Controller, error) {

	ctrl := &controller{client: client, cmClient: cmClient}
	ctrl.syncHandler = ctrl.processNextWorkItem
	ctrl.queue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "certificates")

	secretsInformer := factory.Core().V1().Secrets()
	ingressInformer := factory.Extensions().V1beta1().Ingresses()
	certificatesInformer := cmFactory.Certmanager().V1alpha1().Certificates()
	issuersInformer := cmFactory.Certmanager().V1alpha1().Issuers()

	certificatesInformer.Informer().AddEventHandlerWithResyncPeriod(cache.ResourceEventHandlerFuncs{
		AddFunc:    ctrl.certificateAdded,
		UpdateFunc: ctrl.certificateUpdated,
	}, time.Minute*5)
	ctrl.certificateInformerSynced = certificatesInformer.Informer().HasSynced
	ctrl.certificateLister = certificatesInformer.Lister()

	secretsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		DeleteFunc: ctrl.secretDeleted,
	})
	ctrl.secretInformerSynced = secretsInformer.Informer().HasSynced
	ctrl.secretLister = secretsInformer.Lister()

	ctrl.issuerInformerSynced = issuersInformer.Informer().HasSynced
	ctrl.issuerLister = issuersInformer.Lister()

	ingressInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		DeleteFunc: ctrl.ingressDeleted,
	})
	ctrl.ingressInformerSynced = ingressInformer.Informer().HasSynced
	ctrl.ingressLister = ingressInformer.Lister()

	return ctrl, nil
}

func (c *controller) certificateAdded(obj interface{}) {
	var certificate *v1alpha1.Certificate
	var ok bool
	if certificate, ok = obj.(*v1alpha1.Certificate); !ok {
		runtime.HandleError(fmt.Errorf("expected *Certificate but got %T in work queue", obj))
		return
	}
	var key string
	var err error
	if key, err = keyFunc(certificate); err != nil {
		runtime.HandleError(err)
		return
	}
	c.queue.Add(key)
}

func (c *controller) certificateUpdated(prev, obj interface{}) {
	var certificate *v1alpha1.Certificate
	var ok bool
	if certificate, ok = obj.(*v1alpha1.Certificate); !ok {
		runtime.HandleError(fmt.Errorf("expected *Certificate but got %T in work queue", obj))
		return
	}
	if reflect.DeepEqual(prev, obj) {
		return
	}
	var key string
	var err error
	if key, err = keyFunc(certificate); err != nil {
		runtime.HandleError(err)
		return
	}
	c.queue.Add(key)
}

func (c *controller) secretDeleted(obj interface{}) {
	secret, ok := obj.(*corev1.Secret)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			runtime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
			return
		}
		secret, ok = tombstone.Obj.(*corev1.Secret)
		if !ok {
			runtime.HandleError(fmt.Errorf("Tombstone contained object that is not a Secret %#v", obj))
			return
		}
	}
	crts, err := c.certificatesForSecret(secret)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up certificates observing Secret: %s/%s", secret.Namespace, secret.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *controller) ingressDeleted(obj interface{}) {
	ingress, ok := obj.(*extv1beta1.Ingress)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			runtime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj))
			return
		}
		ingress, ok = tombstone.Obj.(*extv1beta1.Ingress)
		if !ok {
			runtime.HandleError(fmt.Errorf("Tombstone contained object that is not an Ingress %#v", obj))
			return
		}
	}
	crts, err := c.certificatesForIngress(ingress)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up certificates observing Ingress: %s/%s", ingress.Namespace, ingress.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *controller) Run(workers int, stopCh <-chan struct{}) {
	defer c.queue.ShutDown()

	log.Printf("Starting control loop")
	// wait for all the informer caches we depend on are synced
	if !cache.WaitForCacheSync(stopCh,
		c.issuerInformerSynced,
		c.secretInformerSynced,
		c.certificateInformerSynced,
		c.ingressInformerSynced) {
		log.Errorf("error waiting for informer caches to sync")
		return
	}

	for i := 0; i < workers; i++ {
		// TODO (@munnerz): make time.Second duration configurable
		go wait.Until(c.worker, time.Second, stopCh)
	}

	<-stopCh
	log.Printf("shutting down queue as workqueue signalled shutdown")
}

func (c *controller) worker() {
	log.Printf("starting worker")
	for {
		obj, shutdown := c.queue.Get()
		if shutdown {
			break
		}

		err := func(obj interface{}) error {
			defer c.queue.Done(obj)
			var key string
			var ok bool
			if key, ok = obj.(string); !ok {
				runtime.HandleError(fmt.Errorf("expected string in workqueue but got %T", obj))
				return nil
			}
			if err := c.processNextWorkItem(key); err != nil {
				return err
			}
			c.queue.Forget(obj)
			return nil
		}(obj)

		if err != nil {
			log.Printf("requeuing item due to error processing: %s", err.Error())
			c.queue.AddRateLimited(obj)
			continue
		}

		log.Printf("finished processing work item")
	}
	log.Printf("exiting worker loop")
}

func (c *controller) processNextWorkItem(key string) error {
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		runtime.HandleError(fmt.Errorf("invalid resource key: %s", key))
		return nil
	}

	crt, err := c.certificateLister.Certificates(namespace).Get(name)

	if err != nil {
		if k8sErrors.IsNotFound(err) {
			runtime.HandleError(fmt.Errorf("certificate '%s' in work queue no longer exists", key))
			return nil
		}

		return err
	}

	return c.sync(crt)
}

var keyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc

const (
	ControllerName = "certificates"
)

func init() {
	controllerpkg.SharedFactory().Register(ControllerName, New)
}
<|endoftext|>


<commit_before>package anteater

import (
	"time"
	"runtime"
	"sort"
	"sync/atomic"
	"fmt"
)

var FiveSecondsCounters []*StateHttpCounters = make([]*StateHttpCounters, 60)
var FiveSecondsCursor int

type State struct {
	Main  *StateMain
	Files *StateFiles
	Counters *StateHttpCounters
	CountersLast5Seconds *StateHttpCounters
	CountersLastMinute   *StateHttpCounters
	CountersLast5Minutes *StateHttpCounters
	Alloc *StateAllocateCounters
}

type StateMain struct {
	Time          int64
	StartTime     int64
	Goroutines    int
	MemoryUsage   uint64
	LastDump      int64
	LastDumpTime  int64
	IndexFileSize int64
}

type StateFiles struct {
	ContainersCount int
	FilesCount      int64
	FilesSize       int64
	SpacesCount    int64
	SpacesSize     int64
}

type StateHttpCounters struct {
	Get      int64
	Add      int64
	Delete   int64
	NotFound int64
}

type StateAllocateCounters struct {
	ReplaceSpace int64
	AddToSpace   int64
	ToEnd        int64
}

func init() {
	FiveSecondsTick()
	go func() {
		ch := time.Tick(5 * time.Second)
		for _ = range ch {
			func () {
				FiveSecondsTick()
			}()
		}
	}()
}

func GetState() *State {
	ms := &runtime.MemStats{}
	runtime.ReadMemStats(ms)
	m := &StateMain{
		Time         : time.Now().Unix(),
		StartTime    : StartTime.Unix(),
		Goroutines   : runtime.NumGoroutine(),
		MemoryUsage  : ms.TotalAlloc,
		LastDump     : LastDump.Unix(),
		LastDumpTime : LastDumpTime,
		IndexFileSize: IndexFileSize,
	}

	GetFileLock.Lock()
	defer GetFileLock.Unlock()

	var ids []int = make([]int, 0)
	for _, cn := range(FileContainers) {
		ids = append(ids, int(cn.Id))
	}
	sort.Ints(ids)
	var cnt *Container

	var totalSize, totalFileSize, fileCount, spacesCount, spacesTotalSize int64

	for _, id := range(ids) {
		cnt = FileContainers[int32(id)]
		_, sc, st := cnt.Spaces.ToHtml(10, cnt.Size)
		totalSize += cnt.Size
		fileCount += cnt.Count
		spacesCount += sc
		spacesTotalSize += st
		allocated := cnt.Size - (cnt.Size - cnt.Offset) - st
		totalFileSize += allocated
	}

	f := &StateFiles{
		ContainersCount : len(ids),
		FilesCount      : fileCount,
		FilesSize       : totalFileSize,
		SpacesCount     : spacesCount,
		SpacesSize      : spacesTotalSize,
	}

	return &State{
		Main     : m,
		Files    : f,
		Counters : HttpCn,
		CountersLast5Seconds : GetHttpStateByPeriod(1),
		CountersLastMinute : GetHttpStateByPeriod(12),
		CountersLast5Minutes : GetHttpStateByPeriod(60),
		Alloc    : AllocCn,
	}
}

func FiveSecondsTick() {
	if FiveSecondsCursor == 60 {
		FiveSecondsCursor = 0
	}
	if FiveSecondsCounters[FiveSecondsCursor] == nil {
		FiveSecondsCounters[FiveSecondsCursor] = &StateHttpCounters{}
	}
	FiveSecondsCounters[FiveSecondsCursor].SetData(HttpCn)
	FiveSecondsCursor++
}

func GetHttpStateByPeriod(period int) (result *StateHttpCounters) {
	curCursor := FiveSecondsCursor - 1
	diffCursor := curCursor
	result = &StateHttpCounters{}
	i := 0
	for {
		diffCursor--
		i++
		if diffCursor == -1 {
			diffCursor = 59
		}
		if FiveSecondsCounters[diffCursor] == nil {
			diffCursor++
			if diffCursor == 60 {
				diffCursor = 0
			}
			break
		}
		if i >= period {
			break
		}
	}
	fmt.Println(period, curCursor, diffCursor)
	cur  := FiveSecondsCounters[curCursor]
	diff := FiveSecondsCounters[diffCursor]

	result.Add = cur.Add - diff.Add
	result.Get = cur.Get - diff.Add
	result.Delete = cur.Delete - diff.Delete
	result.NotFound = cur.NotFound - diff.NotFound
	return
}

func (s *StateHttpCounters) CGet() {
	atomic.AddInt64(&s.Get, 1)
}

func (s *StateHttpCounters) CAdd() {
	atomic.AddInt64(&s.Add, 1)
}

func (s *StateHttpCounters) CDelete() {
	atomic.AddInt64(&s.Delete, 1)
}

func (s *StateHttpCounters) CNotFound() {
	atomic.AddInt64(&s.NotFound, 1)
}

func (s *StateHttpCounters) SetData(otherS *StateHttpCounters) {
	s.Get = otherS.Get
	s.Add = otherS.Add
	s.Delete = otherS.Delete
	s.NotFound = otherS.NotFound
}

func (s *StateAllocateCounters) CTarget(target int) {
	switch target {
		case TARGET_SPACE_EQ:
			atomic.AddInt64(&s.ReplaceSpace, 1)
		case TARGET_SPACE_FREE:
			atomic.AddInt64(&s.AddToSpace, 1)
	 	case TARGET_NEW:
	 		atomic.AddInt64(&s.ToEnd, 1)
	}
}
<commit_msg>Debug<commit_after>package anteater

import (
	"time"
	"runtime"
	"sort"
	"sync/atomic"
	"fmt"
)

var FiveSecondsCounters []*StateHttpCounters = make([]*StateHttpCounters, 60)
var FiveSecondsCursor int

type State struct {
	Main  *StateMain
	Files *StateFiles
	Counters *StateHttpCounters
	CountersLast5Seconds *StateHttpCounters
	CountersLastMinute   *StateHttpCounters
	CountersLast5Minutes *StateHttpCounters
	Alloc *StateAllocateCounters
}

type StateMain struct {
	Time          int64
	StartTime     int64
	Goroutines    int
	MemoryUsage   uint64
	LastDump      int64
	LastDumpTime  int64
	IndexFileSize int64
}

type StateFiles struct {
	ContainersCount int
	FilesCount      int64
	FilesSize       int64
	SpacesCount    int64
	SpacesSize     int64
}

type StateHttpCounters struct {
	Get      int64
	Add      int64
	Delete   int64
	NotFound int64
}

type StateAllocateCounters struct {
	ReplaceSpace int64
	AddToSpace   int64
	ToEnd        int64
}

func init() {
	FiveSecondsTick()
	go func() {
		ch := time.Tick(5 * time.Second)
		for _ = range ch {
			func () {
				FiveSecondsTick()
			}()
		}
	}()
}

func GetState() *State {
	ms := &runtime.MemStats{}
	runtime.ReadMemStats(ms)
	m := &StateMain{
		Time         : time.Now().Unix(),
		StartTime    : StartTime.Unix(),
		Goroutines   : runtime.NumGoroutine(),
		MemoryUsage  : ms.TotalAlloc,
		LastDump     : LastDump.Unix(),
		LastDumpTime : LastDumpTime,
		IndexFileSize: IndexFileSize,
	}

	GetFileLock.Lock()
	defer GetFileLock.Unlock()

	var ids []int = make([]int, 0)
	for _, cn := range(FileContainers) {
		ids = append(ids, int(cn.Id))
	}
	sort.Ints(ids)
	var cnt *Container

	var totalSize, totalFileSize, fileCount, spacesCount, spacesTotalSize int64

	for _, id := range(ids) {
		cnt = FileContainers[int32(id)]
		_, sc, st := cnt.Spaces.ToHtml(10, cnt.Size)
		totalSize += cnt.Size
		fileCount += cnt.Count
		spacesCount += sc
		spacesTotalSize += st
		allocated := cnt.Size - (cnt.Size - cnt.Offset) - st
		totalFileSize += allocated
	}

	f := &StateFiles{
		ContainersCount : len(ids),
		FilesCount      : fileCount,
		FilesSize       : totalFileSize,
		SpacesCount     : spacesCount,
		SpacesSize      : spacesTotalSize,
	}

	return &State{
		Main     : m,
		Files    : f,
		Counters : HttpCn,
		CountersLast5Seconds : GetHttpStateByPeriod(1),
		CountersLastMinute : GetHttpStateByPeriod(12),
		CountersLast5Minutes : GetHttpStateByPeriod(60),
		Alloc    : AllocCn,
	}
}

func FiveSecondsTick() {
	if FiveSecondsCursor == 60 {
		FiveSecondsCursor = 0
	}
	if FiveSecondsCounters[FiveSecondsCursor] == nil {
		FiveSecondsCounters[FiveSecondsCursor] = &StateHttpCounters{}
	}
	FiveSecondsCounters[FiveSecondsCursor].SetData(HttpCn)
	FiveSecondsCursor++

	for k, v := range(FiveSecondsCounters) {
		fmt.Println(k, v)
	}
}

func GetHttpStateByPeriod(period int) (result *StateHttpCounters) {
	curCursor := FiveSecondsCursor - 1
	diffCursor := curCursor
	result = &StateHttpCounters{}
	i := 0
	for {
		diffCursor--
		i++
		if diffCursor == -1 {
			diffCursor = 59
		}
		if FiveSecondsCounters[diffCursor] == nil {
			diffCursor++
			if diffCursor == 60 {
				diffCursor = 0
			}
			break
		}
		if i >= period {
			break
		}
	}
	//fmt.Println(period, curCursor, diffCursor)
	cur  := FiveSecondsCounters[curCursor]
	diff := FiveSecondsCounters[diffCursor]

	result.Add = cur.Add - diff.Add
	result.Get = cur.Get - diff.Add
	result.Delete = cur.Delete - diff.Delete
	result.NotFound = cur.NotFound - diff.NotFound
	return
}

func (s *StateHttpCounters) CGet() {
	atomic.AddInt64(&s.Get, 1)
}

func (s *StateHttpCounters) CAdd() {
	atomic.AddInt64(&s.Add, 1)
}

func (s *StateHttpCounters) CDelete() {
	atomic.AddInt64(&s.Delete, 1)
}

func (s *StateHttpCounters) CNotFound() {
	atomic.AddInt64(&s.NotFound, 1)
}

func (s *StateHttpCounters) SetData(otherS *StateHttpCounters) {
	s.Get = otherS.Get
	s.Add = otherS.Add
	s.Delete = otherS.Delete
	s.NotFound = otherS.NotFound
}

func (s *StateAllocateCounters) CTarget(target int) {
	switch target {
		case TARGET_SPACE_EQ:
			atomic.AddInt64(&s.ReplaceSpace, 1)
		case TARGET_SPACE_FREE:
			atomic.AddInt64(&s.AddToSpace, 1)
	 	case TARGET_NEW:
	 		atomic.AddInt64(&s.ToEnd, 1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"libvsw"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usge: %s IP_address_of_livewedge\n", os.Args[0])
		os.Exit(1)
	}
	vsw := libvsw.NewVsw(os.Args[1])

	c := vsw.RequestSwitcherStatus()
	c2 := vsw.RequestAudioPeakStatus()
	for {
		vsw.HeartBeat()
		select {
		case ss := <-c:
			fmt.Printf("status0: %#v\n", ss)
		case ss := <-c2:
			fmt.Printf("status0: %#v\n", ss)
		}
	}
}
<commit_msg>status0: Send HeartBeat every 10 seconds<commit_after>package main

import (
	"fmt"
	"libvsw"
	"log"
	"os"
	"time"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usge: %s IP_address_of_livewedge\n", os.Args[0])
		os.Exit(1)
	}
	vsw := libvsw.NewVsw(os.Args[1])

	c := vsw.RequestSwitcherStatus()
	c2 := vsw.RequestAudioPeakStatus()
	tick := time.Tick(10 * time.Second)
	for {
		select {
		case <-tick:
			vsw.HeartBeat()
			log.Printf("status0: HeartBeat!\n")
		case ss := <-c:
			log.Printf("status0: %#v\n", ss)
		case ss := <-c2:
			log.Printf("status0: %#v\n", ss)
		}
	}
}
<|endoftext|>


<commit_before>// Title：员工相关服务
//
// Description:
//
// Author:Samurai
//
// Createtime:2013-09-24 13:04
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
package server

import (
	"github.com/hjqhezgh/lessgo"
	"github.com/hjqhezgh/commonlib"
)

func CheckPwd(username, password string) (bool, lessgo.Employee, string){

	var employee lessgo.Employee
	var dbPwd string

	db := lessgo.GetMySQL()
	defer db.Close()

	sql := "select user_id,username,password,really_name,department_id from employee where username=?"

	rows, err := db.Query(sql, username)
	if err != nil {
		lessgo.Log.Error(err.Error())
		return false, employee, " 数据库异常!"
	}

	if rows.Next() {
		err := rows.Scan(&employee.UserId, &employee.UserName,
						&dbPwd, &employee.ReallyName, &employee.DepartmentId)
		if err != nil {
			lessgo.Log.Error(err.Error())
			return false, employee, " 数据库异常!"
		}
	}

	if password != dbPwd {
		lessgo.Log.Warn("密码错误:", username, " : ", password)
		return false, employee, "密码错误"
	}

	return true, employee, ""
}

type Employee struct {
	UserId       string `json:"userId"`
	UserName     string `json:"userName"`
	ReallyName   string `json:"reallyName"`
	DepartmentId string `json:"departmentId"`
	CenterId 	 string `json:"centerId"`
}

//根据id获取员工信息
func FindEmployeeById(id int) (Employee,error) {

	var employee Employee

	db := lessgo.GetMySQL()
	defer db.Close()

	sql := "select user_id,username,really_name,department_id,center_id from employee where user_id=?"

	rows, err := db.Query(sql, id)
	if err != nil {
		lessgo.Log.Error(err.Error())
		return  employee, err
	}

	if rows.Next() {
		err := commonlib.PutRecord(rows,&employee.UserId, &employee.UserName,&employee.ReallyName, &employee.DepartmentId, &employee.CenterId)
		if err != nil {
			lessgo.Log.Error(err.Error())
			return  employee, err
		}
	}

	return employee , nil
}

<commit_msg>增加返回角色id<commit_after>// Title：员工相关服务
//
// Description:
//
// Author:Samurai
//
// Createtime:2013-09-24 13:04
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
package server

import (
	"github.com/hjqhezgh/lessgo"
	"github.com/hjqhezgh/commonlib"
)

func CheckPwd(username, password string) (bool, lessgo.Employee, string){

	var employee lessgo.Employee
	var dbPwd string

	db := lessgo.GetMySQL()
	defer db.Close()

	sql := "select user_id,username,password,really_name,department_id from employee where username=?"
	rows, err := db.Query(sql, username)
	if err != nil {
		lessgo.Log.Error(err.Error())
		return false, employee, " 数据库异常!"
	}
	if rows.Next() {
		err := rows.Scan(&employee.UserId, &employee.UserName,
						&dbPwd, &employee.ReallyName, &employee.DepartmentId)
		if err != nil {
			lessgo.Log.Error(err.Error())
			return false, employee, " 数据库异常!"
		}
	}

	if password != dbPwd {
		lessgo.Log.Warn("密码错误:", username, " : ", password)
		return false, employee, "密码错误"
	}

	sql = "select distinct(role_id) from employee_role where user_id=?"
	rows, err = db.Query(sql, employee.UserId)
	if err != nil {
		lessgo.Log.Error(err.Error())
		return false, employee, " 数据库异常!"
	}
	var tmp_id string
	for rows.Next() {
		err := rows.Scan(&tmp_id)
		if err != nil {
			lessgo.Log.Error(err.Error())
			return false, employee, " 数据库异常!"
		}
		employee.RoleId = employee.RoleId + tmp_id + ","
	}
	lessgo.Log.Info(employee)
	return true, employee, ""
}

type Employee struct {
	UserId       string `json:"userId"`
	UserName     string `json:"userName"`
	ReallyName   string `json:"reallyName"`
	DepartmentId string `json:"departmentId"`
	CenterId 	 string `json:"centerId"`
}

//根据id获取员工信息
func FindEmployeeById(id int) (Employee,error) {

	var employee Employee

	db := lessgo.GetMySQL()
	defer db.Close()

	sql := "select user_id,username,really_name,department_id,center_id from employee where user_id=?"

	rows, err := db.Query(sql, id)
	if err != nil {
		lessgo.Log.Error(err.Error())
		return  employee, err
	}

	if rows.Next() {
		err := commonlib.PutRecord(rows,&employee.UserId, &employee.UserName,&employee.ReallyName, &employee.DepartmentId, &employee.CenterId)
		if err != nil {
			lessgo.Log.Error(err.Error())
			return  employee, err
		}
	}

	return employee , nil
}

<|endoftext|>


<commit_before>// Copyright 2015 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/maruel/subcommands"

	"github.com/luci/luci-go/client/archiver"
	"github.com/luci/luci-go/client/isolate"
	"github.com/luci/luci-go/common/auth"
	"github.com/luci/luci-go/common/data/text/units"
	"github.com/luci/luci-go/common/isolated"
	"github.com/luci/luci-go/common/isolatedclient"
)

func cmdBatchArchive(defaultAuthOpts auth.Options) *subcommands.Command {
	return &subcommands.Command{
		UsageLine: "batcharchive <options> file1 file2 ...",
		ShortDesc: "archives multiple isolated trees at once.",
		LongDesc: `Archives multiple isolated trees at once.

Using single command instead of multiple sequential invocations allows to cut
redundant work when isolated trees share common files (e.g. file hashes are
checked only once, their presence on the server is checked only once, and
so on).

Takes a list of paths to *.isolated.gen.json files that describe what trees to
isolate. Format of files is:
{
  "version": 1,
  "dir": <absolute path to a directory all other paths are relative to>,
  "args": [list of command line arguments for single 'archive' command]
}`,
		CommandRun: func() subcommands.CommandRun {
			c := batchArchiveRun{}
			c.commonServerFlags.Init(defaultAuthOpts)
			c.Flags.StringVar(&c.dumpJSON, "dump-json", "",
				"Write isolated digests of archived trees to this file as JSON")
			return &c
		},
	}
}

type batchArchiveRun struct {
	commonServerFlags
	dumpJSON string
}

func (c *batchArchiveRun) Parse(a subcommands.Application, args []string) error {
	if err := c.commonServerFlags.Parse(); err != nil {
		return err
	}
	if len(args) == 0 {
		return errors.New("at least one isolate file required")
	}
	return nil
}

func parseArchiveCMD(args []string, cwd string) (*isolate.ArchiveOptions, error) {
	// Python isolate allows form "--XXXX-variable key value".
	// Golang flag pkg doesn't consider value to be part of --XXXX-variable flag.
	// Therefore, we convert all such "--XXXX-variable key value" to
	// "--XXXX-variable key --XXXX-variable value" form.
	// Note, that key doesn't have "=" in it in either case, but value might.
	// TODO(tandrii): eventually, we want to retire this hack.
	args = convertPyToGoArchiveCMDArgs(args)
	base := subcommands.CommandRunBase{}
	i := isolateFlags{}
	i.Init(&base.Flags)
	if err := base.GetFlags().Parse(args); err != nil {
		return nil, err
	}
	if err := i.Parse(cwd, RequireIsolatedFile); err != nil {
		return nil, err
	}
	if base.GetFlags().NArg() > 0 {
		return nil, fmt.Errorf("no positional arguments expected")
	}
	i.PostProcess(cwd)
	return &i.ArchiveOptions, nil
}

// convertPyToGoArchiveCMDArgs converts kv-args from old python isolate into go variants.
// Essentially converts "--X key value" into "--X key=value".
func convertPyToGoArchiveCMDArgs(args []string) []string {
	kvars := map[string]bool{
		"--path-variable": true, "--config-variable": true, "--extra-variable": true}
	newArgs := []string{}
	for i := 0; i < len(args); {
		newArgs = append(newArgs, args[i])
		kvar := args[i]
		i++
		if !kvars[kvar] {
			continue
		}
		if i >= len(args) {
			// Ignore unexpected behaviour, it'll be caught by flags.Parse() .
			break
		}
		appendArg := args[i]
		i++
		if !strings.Contains(appendArg, "=") && i < len(args) {
			// appendArg is key, and args[i] is value .
			appendArg = fmt.Sprintf("%s=%s", appendArg, args[i])
			i++
		}
		newArgs = append(newArgs, appendArg)
	}
	return newArgs
}

func (c *batchArchiveRun) main(a subcommands.Application, args []string) error {
	out := os.Stdout
	prefix := "\n"
	if c.defaultFlags.Quiet {
		prefix = ""
	}
	start := time.Now()
	client, err := c.createAuthClient()
	if err != nil {
		return err
	}
	ctx := c.defaultFlags.MakeLoggingContext(os.Stderr)
	arch := archiver.New(ctx, isolatedclient.New(nil, client, c.isolatedFlags.ServerURL, c.isolatedFlags.Namespace, nil, nil), out)
	CancelOnCtrlC(arch)

	type namedItem struct {
		*archiver.Item
		name string
	}
	items := make(chan *namedItem, len(args))
	var wg sync.WaitGroup
	for _, arg := range args {
		wg.Add(1)
		go func(genJSONPath string) {
			defer wg.Done()
			if opts, err := processGenJSON(genJSONPath); err != nil {
				arch.Cancel(err)
			} else {
				items <- &namedItem{
					isolate.Archive(arch, opts),
					strippedIsolatedName(opts.Isolated),
				}
			}
		}(arg)
	}
	go func() {
		wg.Wait()
		close(items)
	}()

	data := map[string]isolated.HexDigest{}
	for item := range items {
		item.WaitForHashed()
		if item.Error() == nil {
			data[item.name] = item.Digest()
			fmt.Printf("%s%s  %s\n", prefix, item.Digest(), item.name)
		} else {
			fmt.Fprintf(os.Stderr, "%s%s  %s\n", prefix, item.name, item.Error())
		}
	}
	err = arch.Close()
	duration := time.Since(start)
	// Only write the file once upload is confirmed.
	if err == nil && c.dumpJSON != "" {
		err = writeJSONDigestFile(c.dumpJSON, data)
	}
	if !c.defaultFlags.Quiet {
		stats := arch.Stats()
		fmt.Fprintf(os.Stderr, "Hits    : %5d (%s)\n", stats.TotalHits(), stats.TotalBytesHits())
		fmt.Fprintf(os.Stderr, "Misses  : %5d (%s)\n", stats.TotalMisses(), stats.TotalBytesPushed())
		fmt.Fprintf(os.Stderr, "Duration: %s\n", units.Round(duration, time.Millisecond))
	}
	return err
}

// processGenJSON validates a genJSON file and returns the contents.
func processGenJSON(genJSONPath string) (*isolate.ArchiveOptions, error) {
	f, err := os.Open(genJSONPath)
	if err != nil {
		return nil, fmt.Errorf("opening %s: %s", genJSONPath, err)
	}
	defer f.Close()

	opts, err := processGenJSONData(f)
	if err != nil {
		return nil, fmt.Errorf("processing %s: %s", genJSONPath, err)
	}
	return opts, nil
}

// processGenJSONData performs the function of processGenJSON, but operates on an io.Reader.
func processGenJSONData(r io.Reader) (*isolate.ArchiveOptions, error) {
	data := &struct {
		Args    []string
		Dir     string
		Version int
	}{}
	if err := json.NewDecoder(r).Decode(data); err != nil {
		return nil, fmt.Errorf("failed to decode: %s", err)
	}

	if data.Version != isolate.IsolatedGenJSONVersion {
		return nil, fmt.Errorf("invalid version %d", data.Version)
	}

	if fileInfo, err := os.Stat(data.Dir); err != nil || !fileInfo.IsDir() {
		return nil, fmt.Errorf("invalid dir %s", data.Dir)
	}

	opts, err := parseArchiveCMD(data.Args, data.Dir)
	if err != nil {
		return nil, fmt.Errorf("invalid archive command: %s", err)
	}
	return opts, nil
}

// strippedIsolatedName returns the base name of an isolated path, with the extension (if any) removed.
func strippedIsolatedName(isolated string) string {
	name := filepath.Base(isolated)
	// Strip the extension if there is one.
	if dotIndex := strings.LastIndex(name, "."); dotIndex != -1 {
		return name[0:dotIndex]
	}
	return name
}

func writeJSONDigestFile(filePath string, data map[string]isolated.HexDigest) error {
	digestBytes, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return fmt.Errorf("encoding digest JSON: %s", err)
	}
	return writeFile(filePath, digestBytes)
}

// writeFile writes data to filePath. File permission is set to user only.
func writeFile(filePath string, data []byte) error {
	f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return fmt.Errorf("opening %s: %s", filePath, err)
	}
	// NOTE: We don't defer f.Close here, because it may return an error.

	_, writeErr := f.Write(data)
	closeErr := f.Close()
	if writeErr != nil {
		return fmt.Errorf("writing %s: %s", filePath, writeErr)
	} else if closeErr != nil {
		return fmt.Errorf("closing %s: %s", filePath, closeErr)
	}
	return nil
}

func (c *batchArchiveRun) Run(a subcommands.Application, args []string, _ subcommands.Env) int {
	if err := c.Parse(a, args); err != nil {
		fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
		return 1
	}
	cl, err := c.defaultFlags.StartTracing()
	if err != nil {
		fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
		return 1
	}
	defer cl.Close()
	if err := c.main(a, args); err != nil {
		fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
		return 1
	}
	return 0
}
<commit_msg>Add eventlogging to batcharchive.<commit_after>// Copyright 2015 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/maruel/subcommands"

	"github.com/luci/luci-go/client/archiver"
	"github.com/luci/luci-go/client/isolate"
	"github.com/luci/luci-go/common/auth"
	"github.com/luci/luci-go/common/data/text/units"
	logpb "github.com/luci/luci-go/common/eventlog/proto"
	"github.com/luci/luci-go/common/isolated"
	"github.com/luci/luci-go/common/isolatedclient"
)

func cmdBatchArchive(defaultAuthOpts auth.Options) *subcommands.Command {
	return &subcommands.Command{
		UsageLine: "batcharchive <options> file1 file2 ...",
		ShortDesc: "archives multiple isolated trees at once.",
		LongDesc: `Archives multiple isolated trees at once.

Using single command instead of multiple sequential invocations allows to cut
redundant work when isolated trees share common files (e.g. file hashes are
checked only once, their presence on the server is checked only once, and
so on).

Takes a list of paths to *.isolated.gen.json files that describe what trees to
isolate. Format of files is:
{
  "version": 1,
  "dir": <absolute path to a directory all other paths are relative to>,
  "args": [list of command line arguments for single 'archive' command]
}`,
		CommandRun: func() subcommands.CommandRun {
			c := batchArchiveRun{}
			c.commonServerFlags.Init(defaultAuthOpts)
			c.loggingFlags.Init(&c.Flags)
			c.Flags.StringVar(&c.dumpJSON, "dump-json", "",
				"Write isolated digests of archived trees to this file as JSON")
			return &c
		},
	}
}

type batchArchiveRun struct {
	commonServerFlags
	loggingFlags loggingFlags
	dumpJSON     string
}

func (c *batchArchiveRun) Parse(a subcommands.Application, args []string) error {
	if err := c.commonServerFlags.Parse(); err != nil {
		return err
	}
	if len(args) == 0 {
		return errors.New("at least one isolate file required")
	}
	return nil
}

func parseArchiveCMD(args []string, cwd string) (*isolate.ArchiveOptions, error) {
	// Python isolate allows form "--XXXX-variable key value".
	// Golang flag pkg doesn't consider value to be part of --XXXX-variable flag.
	// Therefore, we convert all such "--XXXX-variable key value" to
	// "--XXXX-variable key --XXXX-variable value" form.
	// Note, that key doesn't have "=" in it in either case, but value might.
	// TODO(tandrii): eventually, we want to retire this hack.
	args = convertPyToGoArchiveCMDArgs(args)
	base := subcommands.CommandRunBase{}
	i := isolateFlags{}
	i.Init(&base.Flags)
	if err := base.GetFlags().Parse(args); err != nil {
		return nil, err
	}
	if err := i.Parse(cwd, RequireIsolatedFile); err != nil {
		return nil, err
	}
	if base.GetFlags().NArg() > 0 {
		return nil, fmt.Errorf("no positional arguments expected")
	}
	i.PostProcess(cwd)
	return &i.ArchiveOptions, nil
}

// convertPyToGoArchiveCMDArgs converts kv-args from old python isolate into go variants.
// Essentially converts "--X key value" into "--X key=value".
func convertPyToGoArchiveCMDArgs(args []string) []string {
	kvars := map[string]bool{
		"--path-variable": true, "--config-variable": true, "--extra-variable": true}
	newArgs := []string{}
	for i := 0; i < len(args); {
		newArgs = append(newArgs, args[i])
		kvar := args[i]
		i++
		if !kvars[kvar] {
			continue
		}
		if i >= len(args) {
			// Ignore unexpected behaviour, it'll be caught by flags.Parse() .
			break
		}
		appendArg := args[i]
		i++
		if !strings.Contains(appendArg, "=") && i < len(args) {
			// appendArg is key, and args[i] is value .
			appendArg = fmt.Sprintf("%s=%s", appendArg, args[i])
			i++
		}
		newArgs = append(newArgs, appendArg)
	}
	return newArgs
}

func (c *batchArchiveRun) main(a subcommands.Application, args []string) error {
	out := os.Stdout
	prefix := "\n"
	if c.defaultFlags.Quiet {
		prefix = ""
	}
	start := time.Now()
	client, err := c.createAuthClient()
	if err != nil {
		return err
	}
	ctx := c.defaultFlags.MakeLoggingContext(os.Stderr)
	arch := archiver.New(ctx, isolatedclient.New(nil, client, c.isolatedFlags.ServerURL, c.isolatedFlags.Namespace, nil, nil), out)
	CancelOnCtrlC(arch)

	type namedItem struct {
		*archiver.Item
		name string
	}
	items := make(chan *namedItem, len(args))
	var wg sync.WaitGroup
	for _, arg := range args {
		wg.Add(1)
		go func(genJSONPath string) {
			defer wg.Done()
			if opts, err := processGenJSON(genJSONPath); err != nil {
				arch.Cancel(err)
			} else {
				items <- &namedItem{
					isolate.Archive(arch, opts),
					strippedIsolatedName(opts.Isolated),
				}
			}
		}(arg)
	}
	go func() {
		wg.Wait()
		close(items)
	}()

	data := map[string]isolated.HexDigest{}
	var digests []string
	for item := range items {
		item.WaitForHashed()
		if item.Error() == nil {
			d := item.Digest()
			data[item.name] = d
			digests = append(digests, string(d))
			fmt.Printf("%s%s  %s\n", prefix, d, item.name)
		} else {
			fmt.Fprintf(os.Stderr, "%s%s  %s\n", prefix, item.name, item.Error())
		}
	}
	err = arch.Close()
	duration := time.Since(start)
	// Only write the file once upload is confirmed.
	if err == nil && c.dumpJSON != "" {
		err = writeJSONDigestFile(c.dumpJSON, data)
	}

	stats := arch.Stats()
	if !c.defaultFlags.Quiet {
		fmt.Fprintf(os.Stderr, "Hits    : %5d (%s)\n", stats.TotalHits(), stats.TotalBytesHits())
		fmt.Fprintf(os.Stderr, "Misses  : %5d (%s)\n", stats.TotalMisses(), stats.TotalBytesPushed())
		fmt.Fprintf(os.Stderr, "Duration: %s\n", units.Round(duration, time.Millisecond))
	}

	end := time.Now()
	archiveDetails := &logpb.IsolateClientEvent_ArchiveDetails{
		HitCount:    proto.Int64(int64(stats.TotalHits())),
		MissCount:   proto.Int64(int64(stats.TotalMisses())),
		HitBytes:    proto.Int64(int64(stats.TotalBytesHits())),
		MissBytes:   proto.Int64(int64(stats.TotalBytesPushed())),
		IsolateHash: digests,
	}

	eventlogger := NewLogger(ctx, c.loggingFlags.EventlogEndpoint)
	op := logpb.IsolateClientEvent_BATCH_ARCHIVE.Enum()
	if err := eventlogger.logStats(ctx, op, start, end, archiveDetails); err != nil {
		log.Printf("Failed to log to eventlog: %v", err)
	}

	return err
}

// processGenJSON validates a genJSON file and returns the contents.
func processGenJSON(genJSONPath string) (*isolate.ArchiveOptions, error) {
	f, err := os.Open(genJSONPath)
	if err != nil {
		return nil, fmt.Errorf("opening %s: %s", genJSONPath, err)
	}
	defer f.Close()

	opts, err := processGenJSONData(f)
	if err != nil {
		return nil, fmt.Errorf("processing %s: %s", genJSONPath, err)
	}
	return opts, nil
}

// processGenJSONData performs the function of processGenJSON, but operates on an io.Reader.
func processGenJSONData(r io.Reader) (*isolate.ArchiveOptions, error) {
	data := &struct {
		Args    []string
		Dir     string
		Version int
	}{}
	if err := json.NewDecoder(r).Decode(data); err != nil {
		return nil, fmt.Errorf("failed to decode: %s", err)
	}

	if data.Version != isolate.IsolatedGenJSONVersion {
		return nil, fmt.Errorf("invalid version %d", data.Version)
	}

	if fileInfo, err := os.Stat(data.Dir); err != nil || !fileInfo.IsDir() {
		return nil, fmt.Errorf("invalid dir %s", data.Dir)
	}

	opts, err := parseArchiveCMD(data.Args, data.Dir)
	if err != nil {
		return nil, fmt.Errorf("invalid archive command: %s", err)
	}
	return opts, nil
}

// strippedIsolatedName returns the base name of an isolated path, with the extension (if any) removed.
func strippedIsolatedName(isolated string) string {
	name := filepath.Base(isolated)
	// Strip the extension if there is one.
	if dotIndex := strings.LastIndex(name, "."); dotIndex != -1 {
		return name[0:dotIndex]
	}
	return name
}

func writeJSONDigestFile(filePath string, data map[string]isolated.HexDigest) error {
	digestBytes, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return fmt.Errorf("encoding digest JSON: %s", err)
	}
	return writeFile(filePath, digestBytes)
}

// writeFile writes data to filePath. File permission is set to user only.
func writeFile(filePath string, data []byte) error {
	f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return fmt.Errorf("opening %s: %s", filePath, err)
	}
	// NOTE: We don't defer f.Close here, because it may return an error.

	_, writeErr := f.Write(data)
	closeErr := f.Close()
	if writeErr != nil {
		return fmt.Errorf("writing %s: %s", filePath, writeErr)
	} else if closeErr != nil {
		return fmt.Errorf("closing %s: %s", filePath, closeErr)
	}
	return nil
}

func (c *batchArchiveRun) Run(a subcommands.Application, args []string, _ subcommands.Env) int {
	if err := c.Parse(a, args); err != nil {
		fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
		return 1
	}
	cl, err := c.defaultFlags.StartTracing()
	if err != nil {
		fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
		return 1
	}
	defer cl.Close()
	if err := c.main(a, args); err != nil {
		fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
		return 1
	}
	return 0
}
<|endoftext|>


<commit_before>package management

import (
	"fmt"
	"os"
	"reflect"
	"strings"

	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"

	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/types/config"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	Amazonec2driver    = "amazonec2"
	Azuredriver        = "azure"
	DigitalOceandriver = "digitalocean"
	ExoscaleDriver     = "exoscale"
	Linodedriver       = "linode"
	OCIDriver          = "oci"
	OTCDriver          = "otc"
	OpenstackDriver    = "openstack"
	PacketDriver       = "packet"
	RackspaceDriver    = "rackspace"
	SoftLayerDriver    = "softlayer"
	Vmwaredriver       = "vmwarevsphere"
)

var driverData = map[string]map[string][]string{
	Amazonec2driver:    {"publicCredentialFields": []string{"accessKey"}, "privateCredentialFields": []string{"secretKey"}},
	Azuredriver:        {"publicCredentialFields": []string{"clientId", "subscriptionId"}, "privateCredentialFields": []string{"clientSecret"}},
	DigitalOceandriver: {"privateCredentialFields": []string{"accessToken"}},
	ExoscaleDriver:     {"privateCredentialFields": []string{"apiSecretKey"}},
	Linodedriver:       {"privateCredentialFields": []string{"token"}, "passwordFields": []string{"rootPass"}},
	OCIDriver:          {"publicCredentialFields": []string{"tenancyId", "userId", "fingerprint"}, "privateCredentialFields": []string{"privateKeyContents"}, "passwordFields": []string{"privateKeyPassphrase"}},
	OTCDriver:          {"privateCredentialFields": []string{"accessKeySecret"}},
	OpenstackDriver:    {"privateCredentialFields": []string{"password"}},
	PacketDriver:       {"privateCredentialFields": []string{"apiKey"}},
	RackspaceDriver:    {"privateCredentialFields": []string{"apiKey"}},
	SoftLayerDriver:    {"privateCredentialFields": []string{"apiKey"}},
	Vmwaredriver:       {"publicCredentialFields": []string{"username", "vcenter", "vcenterPort"}, "privateCredentialFields": []string{"password"}},
}

var driverDefaults = map[string]map[string]string{
	Vmwaredriver: {"vcenterPort": "443"},
}

type machineDriverCompare struct {
	builtin     bool
	url         string
	uiURL       string
	checksum    string
	name        string
	whitelist   []string
	annotations map[string]string
}

func addMachineDrivers(management *config.ManagementContext) error {
	if err := addMachineDriver("pinganyunecs", "https://drivers.rancher.cn/node-driver-pinganyun/0.3.0/docker-machine-driver-pinganyunecs-linux.tgz",
		"https://drivers.rancher.cn/node-driver-pinganyun/0.3.0/component.js", "f84ccec11c2c1970d76d30150916933efe8ca49fe4c422c8954fc37f71273bb5",
		[]string{"drivers.rancher.cn"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver("aliyunecs", "https://drivers.rancher.cn/node-driver-aliyun/1.0.4/docker-machine-driver-aliyunecs.tgz",
		"", "5990d40d71c421a85563df9caf069466f300cd75723effe4581751b0de9a6a0e", []string{"ecs.aliyuncs.com"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(Amazonec2driver, "local://", "", "",
		[]string{"iam.amazonaws.com", "iam.%.amazonaws.com.cn", "ec2.%.amazonaws.com", "ec2.%.amazonaws.com.cn", "eks.%.amazonaws.com", "kms.%.amazonaws.com"},
		true, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(Azuredriver, "local://", "", "", nil, true, true, management); err != nil {
		return err
	}
	if err := addMachineDriver("cloudca", "https://github.com/cloud-ca/docker-machine-driver-cloudca/files/2446837/docker-machine-driver-cloudca_v2.0.0_linux-amd64.zip",
		"https://objects-east.cloud.ca/v1/5ef827605f884961b94881e928e7a250/ui-driver-cloudca/v2.1.2/component.js", "2a55efd6d62d5f7fd27ce877d49596f4",
		[]string{"objects-east.cloud.ca"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver("cloudscale", "https://github.com/cloudscale-ch/docker-machine-driver-cloudscale/releases/download/v1.2.0/docker-machine-driver-cloudscale_v1.2.0_linux_amd64.tar.gz",
		"https://objects.rma.cloudscale.ch/cloudscale-rancher-v2-ui-driver/component.js", "e33fbd6c2f87b1c470bcb653cc8aa50baf914a9d641a2f18f86a07c398cfb544",
		[]string{"objects.rma.cloudscale.ch"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(DigitalOceandriver, "local://", "", "", []string{"api.digitalocean.com"}, true, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(ExoscaleDriver, "local://", "", "", []string{"api.exoscale.ch"}, false, true, management); err != nil {
		return err
	}
	linodeBuiltin := true
	if dl := os.Getenv("CATTLE_DEV_MODE"); dl != "" {
		linodeBuiltin = false
	}
	if err := addMachineDriver(Linodedriver, "https://github.com/linode/docker-machine-driver-linode/releases/download/v0.1.8/docker-machine-driver-linode_linux-amd64.zip",
		"/assets/rancher-ui-driver-linode/component.js", "b31b6a504c59ee758d2dda83029fe4a85b3f5601e22dfa58700a5e6c8f450dc7", []string{"api.linode.com"}, linodeBuiltin, linodeBuiltin, management); err != nil {
		return err
	}
	if err := addMachineDriver(OCIDriver, "https://github.com/rancher-plugins/rancher-machine-driver-oci/releases/download/v1.0.0/docker-machine-driver-oci-linux",
		"", "ae62d1f7f9bc894e57af4f264ab6776824212fb5e1b59f657e3ad953b621eb5f", []string{"*.oraclecloud.com"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(OpenstackDriver, "local://", "", "", nil, false, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(OTCDriver, "https://github.com/rancher-plugins/docker-machine-driver-otc/releases/download/v2019.5.7/docker-machine-driver-otc",
		"", "3f793ebb0ebd9477b9166ec542f77e25", nil, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(PacketDriver, "https://github.com/packethost/docker-machine-driver-packet/releases/download/v0.2.2/docker-machine-driver-packet_linux-amd64.zip",
		"https://packethost.github.io/ui-driver-packet/1.0.2/component.js", "e03c6bc9406c811e03e9bc2c39f43e6cc8c02d1615bd0e0b8ee1b38be6fe201c", []string{"api.packet.net", "packethost.github.io"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(RackspaceDriver, "local://", "", "", nil, false, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(SoftLayerDriver, "local://", "", "", nil, false, true, management); err != nil {
		return err
	}
	return addMachineDriver(Vmwaredriver, "local://", "", "", nil, true, true, management)
}

func addMachineDriver(name, url, uiURL, checksum string, whitelist []string, active, builtin bool, management *config.ManagementContext) error {
	lister := management.Management.NodeDrivers("").Controller().Lister()
	cli := management.Management.NodeDrivers("")
	m, _ := lister.Get("", name)
	// annotations can have keys cred and password, values []string to be considered as a part of cloud credential
	annotations := map[string]string{}
	if m != nil {
		for k, v := range m.Annotations {
			annotations[k] = v
		}
	}
	for key, fields := range driverData[name] {
		annotations[key] = strings.Join(fields, ",")
	}
	defaults := []string{}
	for key, val := range driverDefaults[name] {
		defaults = append(defaults, fmt.Sprintf("%s:%s", key, val))
	}
	if len(defaults) > 0 {
		annotations["defaults"] = strings.Join(defaults, ",")
	}
	if m != nil {
		old := machineDriverCompare{
			builtin:     m.Spec.Builtin,
			url:         m.Spec.URL,
			uiURL:       m.Spec.UIURL,
			checksum:    m.Spec.Checksum,
			name:        m.Spec.DisplayName,
			whitelist:   m.Spec.WhitelistDomains,
			annotations: m.Annotations,
		}
		new := machineDriverCompare{
			builtin:     builtin,
			url:         url,
			uiURL:       uiURL,
			checksum:    checksum,
			name:        name,
			whitelist:   whitelist,
			annotations: annotations,
		}
		if !reflect.DeepEqual(new, old) {
			logrus.Infof("Updating node driver %v", name)
			m.Spec.Builtin = builtin
			m.Spec.URL = url
			m.Spec.UIURL = uiURL
			m.Spec.Checksum = checksum
			m.Spec.DisplayName = name
			m.Spec.WhitelistDomains = whitelist
			m.Annotations = annotations
			_, err := cli.Update(m)
			return err
		}
		return nil
	}

	logrus.Infof("Creating node driver %v", name)
	_, err := cli.Create(&v3.NodeDriver{
		ObjectMeta: v1.ObjectMeta{
			Name:        name,
			Annotations: annotations,
		},
		Spec: v32.NodeDriverSpec{
			Active:           active,
			Builtin:          builtin,
			URL:              url,
			UIURL:            uiURL,
			DisplayName:      name,
			Checksum:         checksum,
			WhitelistDomains: whitelist,
		},
	})

	return err
}
<commit_msg>Update OCI node driver.<commit_after>package management

import (
	"fmt"
	"os"
	"reflect"
	"strings"

	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"

	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/types/config"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	Amazonec2driver    = "amazonec2"
	Azuredriver        = "azure"
	DigitalOceandriver = "digitalocean"
	ExoscaleDriver     = "exoscale"
	Linodedriver       = "linode"
	OCIDriver          = "oci"
	OTCDriver          = "otc"
	OpenstackDriver    = "openstack"
	PacketDriver       = "packet"
	RackspaceDriver    = "rackspace"
	SoftLayerDriver    = "softlayer"
	Vmwaredriver       = "vmwarevsphere"
)

var driverData = map[string]map[string][]string{
	Amazonec2driver:    {"publicCredentialFields": []string{"accessKey"}, "privateCredentialFields": []string{"secretKey"}},
	Azuredriver:        {"publicCredentialFields": []string{"clientId", "subscriptionId"}, "privateCredentialFields": []string{"clientSecret"}},
	DigitalOceandriver: {"privateCredentialFields": []string{"accessToken"}},
	ExoscaleDriver:     {"privateCredentialFields": []string{"apiSecretKey"}},
	Linodedriver:       {"privateCredentialFields": []string{"token"}, "passwordFields": []string{"rootPass"}},
	OCIDriver:          {"publicCredentialFields": []string{"tenancyId", "userId", "fingerprint"}, "privateCredentialFields": []string{"privateKeyContents"}, "passwordFields": []string{"privateKeyPassphrase"}},
	OTCDriver:          {"privateCredentialFields": []string{"accessKeySecret"}},
	OpenstackDriver:    {"privateCredentialFields": []string{"password"}},
	PacketDriver:       {"privateCredentialFields": []string{"apiKey"}},
	RackspaceDriver:    {"privateCredentialFields": []string{"apiKey"}},
	SoftLayerDriver:    {"privateCredentialFields": []string{"apiKey"}},
	Vmwaredriver:       {"publicCredentialFields": []string{"username", "vcenter", "vcenterPort"}, "privateCredentialFields": []string{"password"}},
}

var driverDefaults = map[string]map[string]string{
	Vmwaredriver: {"vcenterPort": "443"},
}

type machineDriverCompare struct {
	builtin     bool
	url         string
	uiURL       string
	checksum    string
	name        string
	whitelist   []string
	annotations map[string]string
}

func addMachineDrivers(management *config.ManagementContext) error {
	if err := addMachineDriver("pinganyunecs", "https://drivers.rancher.cn/node-driver-pinganyun/0.3.0/docker-machine-driver-pinganyunecs-linux.tgz",
		"https://drivers.rancher.cn/node-driver-pinganyun/0.3.0/component.js", "f84ccec11c2c1970d76d30150916933efe8ca49fe4c422c8954fc37f71273bb5",
		[]string{"drivers.rancher.cn"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver("aliyunecs", "https://drivers.rancher.cn/node-driver-aliyun/1.0.4/docker-machine-driver-aliyunecs.tgz",
		"", "5990d40d71c421a85563df9caf069466f300cd75723effe4581751b0de9a6a0e", []string{"ecs.aliyuncs.com"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(Amazonec2driver, "local://", "", "",
		[]string{"iam.amazonaws.com", "iam.%.amazonaws.com.cn", "ec2.%.amazonaws.com", "ec2.%.amazonaws.com.cn", "eks.%.amazonaws.com", "kms.%.amazonaws.com"},
		true, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(Azuredriver, "local://", "", "", nil, true, true, management); err != nil {
		return err
	}
	if err := addMachineDriver("cloudca", "https://github.com/cloud-ca/docker-machine-driver-cloudca/files/2446837/docker-machine-driver-cloudca_v2.0.0_linux-amd64.zip",
		"https://objects-east.cloud.ca/v1/5ef827605f884961b94881e928e7a250/ui-driver-cloudca/v2.1.2/component.js", "2a55efd6d62d5f7fd27ce877d49596f4",
		[]string{"objects-east.cloud.ca"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver("cloudscale", "https://github.com/cloudscale-ch/docker-machine-driver-cloudscale/releases/download/v1.2.0/docker-machine-driver-cloudscale_v1.2.0_linux_amd64.tar.gz",
		"https://objects.rma.cloudscale.ch/cloudscale-rancher-v2-ui-driver/component.js", "e33fbd6c2f87b1c470bcb653cc8aa50baf914a9d641a2f18f86a07c398cfb544",
		[]string{"objects.rma.cloudscale.ch"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(DigitalOceandriver, "local://", "", "", []string{"api.digitalocean.com"}, true, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(ExoscaleDriver, "local://", "", "", []string{"api.exoscale.ch"}, false, true, management); err != nil {
		return err
	}
	linodeBuiltin := true
	if dl := os.Getenv("CATTLE_DEV_MODE"); dl != "" {
		linodeBuiltin = false
	}
	if err := addMachineDriver(Linodedriver, "https://github.com/linode/docker-machine-driver-linode/releases/download/v0.1.8/docker-machine-driver-linode_linux-amd64.zip",
		"/assets/rancher-ui-driver-linode/component.js", "b31b6a504c59ee758d2dda83029fe4a85b3f5601e22dfa58700a5e6c8f450dc7", []string{"api.linode.com"}, linodeBuiltin, linodeBuiltin, management); err != nil {
		return err
	}
	if err := addMachineDriver(OCIDriver, "https://github.com/rancher-plugins/rancher-machine-driver-oci/releases/download/v1.0.1/docker-machine-driver-oci-linux",
		"", "6867f59e9f33bdbce34b5bf9476c48d2edc2ef4bca8a2ef82ccaa1de57af811c", []string{"*.oraclecloud.com"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(OpenstackDriver, "local://", "", "", nil, false, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(OTCDriver, "https://github.com/rancher-plugins/docker-machine-driver-otc/releases/download/v2019.5.7/docker-machine-driver-otc",
		"", "3f793ebb0ebd9477b9166ec542f77e25", nil, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(PacketDriver, "https://github.com/packethost/docker-machine-driver-packet/releases/download/v0.2.2/docker-machine-driver-packet_linux-amd64.zip",
		"https://packethost.github.io/ui-driver-packet/1.0.2/component.js", "e03c6bc9406c811e03e9bc2c39f43e6cc8c02d1615bd0e0b8ee1b38be6fe201c", []string{"api.packet.net", "packethost.github.io"}, false, false, management); err != nil {
		return err
	}
	if err := addMachineDriver(RackspaceDriver, "local://", "", "", nil, false, true, management); err != nil {
		return err
	}
	if err := addMachineDriver(SoftLayerDriver, "local://", "", "", nil, false, true, management); err != nil {
		return err
	}
	return addMachineDriver(Vmwaredriver, "local://", "", "", nil, true, true, management)
}

func addMachineDriver(name, url, uiURL, checksum string, whitelist []string, active, builtin bool, management *config.ManagementContext) error {
	lister := management.Management.NodeDrivers("").Controller().Lister()
	cli := management.Management.NodeDrivers("")
	m, _ := lister.Get("", name)
	// annotations can have keys cred and password, values []string to be considered as a part of cloud credential
	annotations := map[string]string{}
	if m != nil {
		for k, v := range m.Annotations {
			annotations[k] = v
		}
	}
	for key, fields := range driverData[name] {
		annotations[key] = strings.Join(fields, ",")
	}
	defaults := []string{}
	for key, val := range driverDefaults[name] {
		defaults = append(defaults, fmt.Sprintf("%s:%s", key, val))
	}
	if len(defaults) > 0 {
		annotations["defaults"] = strings.Join(defaults, ",")
	}
	if m != nil {
		old := machineDriverCompare{
			builtin:     m.Spec.Builtin,
			url:         m.Spec.URL,
			uiURL:       m.Spec.UIURL,
			checksum:    m.Spec.Checksum,
			name:        m.Spec.DisplayName,
			whitelist:   m.Spec.WhitelistDomains,
			annotations: m.Annotations,
		}
		new := machineDriverCompare{
			builtin:     builtin,
			url:         url,
			uiURL:       uiURL,
			checksum:    checksum,
			name:        name,
			whitelist:   whitelist,
			annotations: annotations,
		}
		if !reflect.DeepEqual(new, old) {
			logrus.Infof("Updating node driver %v", name)
			m.Spec.Builtin = builtin
			m.Spec.URL = url
			m.Spec.UIURL = uiURL
			m.Spec.Checksum = checksum
			m.Spec.DisplayName = name
			m.Spec.WhitelistDomains = whitelist
			m.Annotations = annotations
			_, err := cli.Update(m)
			return err
		}
		return nil
	}

	logrus.Infof("Creating node driver %v", name)
	_, err := cli.Create(&v3.NodeDriver{
		ObjectMeta: v1.ObjectMeta{
			Name:        name,
			Annotations: annotations,
		},
		Spec: v32.NodeDriverSpec{
			Active:           active,
			Builtin:          builtin,
			URL:              url,
			UIURL:            uiURL,
			DisplayName:      name,
			Checksum:         checksum,
			WhitelistDomains: whitelist,
		},
	})

	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 kuberuntime

import (
	"sort"
	"time"

	"github.com/golang/glog"
	internalApi "k8s.io/kubernetes/pkg/kubelet/api"
	runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	"k8s.io/kubernetes/pkg/types"
)

// containerGC is the manager of garbage collection.
type containerGC struct {
	client    internalApi.RuntimeService
	manager   *kubeGenericRuntimeManager
	podGetter podGetter
}

// NewContainerGC creates a new containerGC.
func NewContainerGC(client internalApi.RuntimeService, podGetter podGetter, manager *kubeGenericRuntimeManager) *containerGC {
	return &containerGC{
		client:    client,
		manager:   manager,
		podGetter: podGetter,
	}
}

// containerGCInfo is the internal information kept for containers being considered for GC.
type containerGCInfo struct {
	// The ID of the container.
	id string
	// The name of the container.
	name string
	// The sandbox ID which this container belongs to
	sandboxID string
	// Creation time for the container.
	createTime time.Time
}

// evictUnit is considered for eviction as units of (UID, container name) pair.
type evictUnit struct {
	// UID of the pod.
	uid types.UID
	// Name of the container in the pod.
	name string
}

type containersByEvictUnit map[evictUnit][]containerGCInfo

// NumContainers returns the number of containers in this map.
func (cu containersByEvictUnit) NumContainers() int {
	num := 0
	for key := range cu {
		num += len(cu[key])
	}
	return num
}

// NumEvictUnits returns the number of pod in this map.
func (cu containersByEvictUnit) NumEvictUnits() int {
	return len(cu)
}

// Newest first.
type byCreated []containerGCInfo

func (a byCreated) Len() int           { return len(a) }
func (a byCreated) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byCreated) Less(i, j int) bool { return a[i].createTime.After(a[j].createTime) }

// enforceMaxContainersPerEvictUnit enforces MaxPerPodContainer for each evictUnit.
func (cgc *containerGC) enforceMaxContainersPerEvictUnit(evictUnits containersByEvictUnit, MaxContainers int) {
	for key := range evictUnits {
		toRemove := len(evictUnits[key]) - MaxContainers

		if toRemove > 0 {
			evictUnits[key] = cgc.removeOldestN(evictUnits[key], toRemove)
		}
	}
}

// removeOldestN removes the oldest toRemove containers and returns the resulting slice.
func (cgc *containerGC) removeOldestN(containers []containerGCInfo, toRemove int) []containerGCInfo {
	// Remove from oldest to newest (last to first).
	numToKeep := len(containers) - toRemove
	for i := numToKeep; i < len(containers); i++ {
		cgc.removeContainer(containers[i].id, containers[i].name)
	}

	// Assume we removed the containers so that we're not too aggressive.
	return containers[:numToKeep]
}

// removeContainer removes the container by containerID.
func (cgc *containerGC) removeContainer(containerID, containerName string) {
	glog.V(4).Infof("Removing container %q name %q", containerID, containerName)
	if err := cgc.client.RemoveContainer(containerID); err != nil {
		glog.Warningf("Failed to remove container %q: %v", containerID, err)
	}
}

// removeSandbox removes the sandbox by sandboxID.
func (cgc *containerGC) removeSandbox(sandboxID string) {
	glog.V(4).Infof("Removing sandbox %q", sandboxID)
	if err := cgc.client.RemovePodSandbox(sandboxID); err != nil {
		glog.Warningf("Failed to remove sandbox %q: %v", sandboxID, err)
	}
}

// evictableContainers gets all containers that are evictable. Evictable containers are: not running
// and created more than MinAge ago.
func (cgc *containerGC) evictableContainers(minAge time.Duration) (containersByEvictUnit, error) {
	containers, err := cgc.manager.getKubeletContainers(true)
	if err != nil {
		return containersByEvictUnit{}, err
	}

	evictUnits := make(containersByEvictUnit)
	newestGCTime := time.Now().Add(-minAge)
	for _, container := range containers {
		// Prune out running containers.
		if container.GetState() == runtimeApi.ContainerState_RUNNING {
			continue
		}

		createdAt := time.Unix(0, container.GetCreatedAt())
		if newestGCTime.Before(createdAt) {
			continue
		}

		labeledInfo := getContainerInfoFromLabels(container.Labels)
		containerInfo := containerGCInfo{
			id:         container.GetId(),
			name:       container.Metadata.GetName(),
			createTime: createdAt,
			sandboxID:  container.GetPodSandboxId(),
		}
		key := evictUnit{
			uid:  labeledInfo.PodUID,
			name: containerInfo.name,
		}
		evictUnits[key] = append(evictUnits[key], containerInfo)
	}

	// Sort the containers by age.
	for uid := range evictUnits {
		sort.Sort(byCreated(evictUnits[uid]))
	}

	return evictUnits, nil
}

// evictableSandboxes gets all sandboxes that are evictable. Evictable sandboxes are: not running
// and contains no containers at all.
func (cgc *containerGC) evictableSandboxes() ([]string, error) {
	containers, err := cgc.manager.getKubeletContainers(true)
	if err != nil {
		return nil, err
	}

	sandboxes, err := cgc.manager.getKubeletSandboxes(true)
	if err != nil {
		return nil, err
	}

	evictSandboxes := make([]string, 0)
	for _, sandbox := range sandboxes {
		// Prune out ready sandboxes.
		if sandbox.GetState() == runtimeApi.PodSandBoxState_READY {
			continue
		}

		// Prune out sandboxes that still have containers.
		found := false
		sandboxID := sandbox.GetId()
		for _, container := range containers {
			if container.GetPodSandboxId() == sandboxID {
				found = true
				break
			}
		}
		if found {
			continue
		}

		evictSandboxes = append(evictSandboxes, sandboxID)
	}

	return evictSandboxes, nil
}

// isPodDeleted returns true if the pod is already deleted.
func (cgc *containerGC) isPodDeleted(podUID types.UID) bool {
	_, found := cgc.podGetter.GetPodByUID(podUID)
	return !found
}

// GarbageCollect removes dead containers using the specified container gc policy.
// Note that gc policy is not applied to sandboxes. Sandboxes are only removed when they are
// not ready and containing no containers.
//
// GarbageCollect consists of the following steps:
// * gets evictable containers which are not active and created more than gcPolicy.MinAge ago.
// * removes oldest dead containers for each pod by enforcing gcPolicy.MaxPerPodContainer.
// * removes oldest dead containers by enforcing gcPolicy.MaxContainers.
// * gets evictable sandboxes which are not ready and contains no containers.
// * removes evictable sandboxes.
func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy, allSourcesReady bool) error {
	// Separate containers by evict units.
	evictUnits, err := cgc.evictableContainers(gcPolicy.MinAge)
	if err != nil {
		return err
	}

	// Remove deleted pod containers if all sources are ready.
	if allSourcesReady {
		for key, unit := range evictUnits {
			if cgc.isPodDeleted(key.uid) {
				cgc.removeOldestN(unit, len(unit)) // Remove all.
				delete(evictUnits, key)
			}
		}
	}

	// Enforce max containers per evict unit.
	if gcPolicy.MaxPerPodContainer >= 0 {
		cgc.enforceMaxContainersPerEvictUnit(evictUnits, gcPolicy.MaxPerPodContainer)
	}

	// Enforce max total number of containers.
	if gcPolicy.MaxContainers >= 0 && evictUnits.NumContainers() > gcPolicy.MaxContainers {
		// Leave an equal number of containers per evict unit (min: 1).
		numContainersPerEvictUnit := gcPolicy.MaxContainers / evictUnits.NumEvictUnits()
		if numContainersPerEvictUnit < 1 {
			numContainersPerEvictUnit = 1
		}
		cgc.enforceMaxContainersPerEvictUnit(evictUnits, numContainersPerEvictUnit)

		// If we still need to evict, evict oldest first.
		numContainers := evictUnits.NumContainers()
		if numContainers > gcPolicy.MaxContainers {
			flattened := make([]containerGCInfo, 0, numContainers)
			for key := range evictUnits {
				flattened = append(flattened, evictUnits[key]...)
			}
			sort.Sort(byCreated(flattened))

			cgc.removeOldestN(flattened, numContainers-gcPolicy.MaxContainers)
		}
	}

	// Remove sandboxes with zero containers
	evictSandboxes, err := cgc.evictableSandboxes()
	if err != nil {
		return err
	}
	for _, sandbox := range evictSandboxes {
		cgc.removeSandbox(sandbox)
	}

	return nil
}
<commit_msg>Add MinAge for sandbox GC.<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 kuberuntime

import (
	"sort"
	"time"

	"github.com/golang/glog"
	internalApi "k8s.io/kubernetes/pkg/kubelet/api"
	runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	"k8s.io/kubernetes/pkg/types"
)

// sandboxMinGCAge is the minimum age for an empty sandbox before it is garbage collected.
// This is introduced to avoid a sandbox being garbage collected before its containers are
// created.
// Notice that if the first container of a sandbox is created too late (exceeds sandboxMinGCAge),
// the sandbox could still be garbaged collected. In that case, SyncPod will recreate the
// sandbox and make sure old containers are all stopped.
// In the following figure, 'o' is a stopped sandbox, 'x' is a removed sandbox. It shows
// that, approximately if a sandbox keeps crashing and MinAge = 1/n GC Period, there will
// be 1/n more sandboxes not garbage collected.
//      oooooo|xxxxxx|xxxxxx|  <--- MinAge = 0
//     gc     gc     gc    gc
//      oooooo|oooxxx|xxxxxx|  <--- MinAge = 1/2 GC Perod
const sandboxMinGCAge time.Duration = 30 * time.Second

// containerGC is the manager of garbage collection.
type containerGC struct {
	client    internalApi.RuntimeService
	manager   *kubeGenericRuntimeManager
	podGetter podGetter
}

// NewContainerGC creates a new containerGC.
func NewContainerGC(client internalApi.RuntimeService, podGetter podGetter, manager *kubeGenericRuntimeManager) *containerGC {
	return &containerGC{
		client:    client,
		manager:   manager,
		podGetter: podGetter,
	}
}

// containerGCInfo is the internal information kept for containers being considered for GC.
type containerGCInfo struct {
	// The ID of the container.
	id string
	// The name of the container.
	name string
	// The sandbox ID which this container belongs to
	sandboxID string
	// Creation time for the container.
	createTime time.Time
}

// evictUnit is considered for eviction as units of (UID, container name) pair.
type evictUnit struct {
	// UID of the pod.
	uid types.UID
	// Name of the container in the pod.
	name string
}

type containersByEvictUnit map[evictUnit][]containerGCInfo

// NumContainers returns the number of containers in this map.
func (cu containersByEvictUnit) NumContainers() int {
	num := 0
	for key := range cu {
		num += len(cu[key])
	}
	return num
}

// NumEvictUnits returns the number of pod in this map.
func (cu containersByEvictUnit) NumEvictUnits() int {
	return len(cu)
}

// Newest first.
type byCreated []containerGCInfo

func (a byCreated) Len() int           { return len(a) }
func (a byCreated) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byCreated) Less(i, j int) bool { return a[i].createTime.After(a[j].createTime) }

// enforceMaxContainersPerEvictUnit enforces MaxPerPodContainer for each evictUnit.
func (cgc *containerGC) enforceMaxContainersPerEvictUnit(evictUnits containersByEvictUnit, MaxContainers int) {
	for key := range evictUnits {
		toRemove := len(evictUnits[key]) - MaxContainers

		if toRemove > 0 {
			evictUnits[key] = cgc.removeOldestN(evictUnits[key], toRemove)
		}
	}
}

// removeOldestN removes the oldest toRemove containers and returns the resulting slice.
func (cgc *containerGC) removeOldestN(containers []containerGCInfo, toRemove int) []containerGCInfo {
	// Remove from oldest to newest (last to first).
	numToKeep := len(containers) - toRemove
	for i := numToKeep; i < len(containers); i++ {
		cgc.removeContainer(containers[i].id, containers[i].name)
	}

	// Assume we removed the containers so that we're not too aggressive.
	return containers[:numToKeep]
}

// removeContainer removes the container by containerID.
func (cgc *containerGC) removeContainer(containerID, containerName string) {
	glog.V(4).Infof("Removing container %q name %q", containerID, containerName)
	if err := cgc.client.RemoveContainer(containerID); err != nil {
		glog.Warningf("Failed to remove container %q: %v", containerID, err)
	}
}

// removeSandbox removes the sandbox by sandboxID.
func (cgc *containerGC) removeSandbox(sandboxID string) {
	glog.V(4).Infof("Removing sandbox %q", sandboxID)
	if err := cgc.client.RemovePodSandbox(sandboxID); err != nil {
		glog.Warningf("Failed to remove sandbox %q: %v", sandboxID, err)
	}
}

// evictableContainers gets all containers that are evictable. Evictable containers are: not running
// and created more than MinAge ago.
func (cgc *containerGC) evictableContainers(minAge time.Duration) (containersByEvictUnit, error) {
	containers, err := cgc.manager.getKubeletContainers(true)
	if err != nil {
		return containersByEvictUnit{}, err
	}

	evictUnits := make(containersByEvictUnit)
	newestGCTime := time.Now().Add(-minAge)
	for _, container := range containers {
		// Prune out running containers.
		if container.GetState() == runtimeApi.ContainerState_RUNNING {
			continue
		}

		createdAt := time.Unix(0, container.GetCreatedAt())
		if newestGCTime.Before(createdAt) {
			continue
		}

		labeledInfo := getContainerInfoFromLabels(container.Labels)
		containerInfo := containerGCInfo{
			id:         container.GetId(),
			name:       container.Metadata.GetName(),
			createTime: createdAt,
			sandboxID:  container.GetPodSandboxId(),
		}
		key := evictUnit{
			uid:  labeledInfo.PodUID,
			name: containerInfo.name,
		}
		evictUnits[key] = append(evictUnits[key], containerInfo)
	}

	// Sort the containers by age.
	for uid := range evictUnits {
		sort.Sort(byCreated(evictUnits[uid]))
	}

	return evictUnits, nil
}

// evictableSandboxes gets all sandboxes that are evictable. Evictable sandboxes are: not running
// and contains no containers at all.
func (cgc *containerGC) evictableSandboxes() ([]string, error) {
	containers, err := cgc.manager.getKubeletContainers(true)
	if err != nil {
		return nil, err
	}

	sandboxes, err := cgc.manager.getKubeletSandboxes(true)
	if err != nil {
		return nil, err
	}

	evictSandboxes := make([]string, 0)
	newestGCTime := time.Now().Add(-sandboxMinGCAge)
	for _, sandbox := range sandboxes {
		// Prune out ready sandboxes.
		if sandbox.GetState() == runtimeApi.PodSandBoxState_READY {
			continue
		}

		// Prune out sandboxes that still have containers.
		found := false
		sandboxID := sandbox.GetId()
		for _, container := range containers {
			if container.GetPodSandboxId() == sandboxID {
				found = true
				break
			}
		}
		if found {
			continue
		}

		// Only garbage collect sandboxes older than sandboxMinGCAge.
		createdAt := time.Unix(0, sandbox.GetCreatedAt())
		if createdAt.After(newestGCTime) {
			continue
		}

		evictSandboxes = append(evictSandboxes, sandboxID)
	}

	return evictSandboxes, nil
}

// isPodDeleted returns true if the pod is already deleted.
func (cgc *containerGC) isPodDeleted(podUID types.UID) bool {
	_, found := cgc.podGetter.GetPodByUID(podUID)
	return !found
}

// GarbageCollect removes dead containers using the specified container gc policy.
// Note that gc policy is not applied to sandboxes. Sandboxes are only removed when they are
// not ready and containing no containers.
//
// GarbageCollect consists of the following steps:
// * gets evictable containers which are not active and created more than gcPolicy.MinAge ago.
// * removes oldest dead containers for each pod by enforcing gcPolicy.MaxPerPodContainer.
// * removes oldest dead containers by enforcing gcPolicy.MaxContainers.
// * gets evictable sandboxes which are not ready and contains no containers.
// * removes evictable sandboxes.
func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy, allSourcesReady bool) error {
	// Separate containers by evict units.
	evictUnits, err := cgc.evictableContainers(gcPolicy.MinAge)
	if err != nil {
		return err
	}

	// Remove deleted pod containers if all sources are ready.
	if allSourcesReady {
		for key, unit := range evictUnits {
			if cgc.isPodDeleted(key.uid) {
				cgc.removeOldestN(unit, len(unit)) // Remove all.
				delete(evictUnits, key)
			}
		}
	}

	// Enforce max containers per evict unit.
	if gcPolicy.MaxPerPodContainer >= 0 {
		cgc.enforceMaxContainersPerEvictUnit(evictUnits, gcPolicy.MaxPerPodContainer)
	}

	// Enforce max total number of containers.
	if gcPolicy.MaxContainers >= 0 && evictUnits.NumContainers() > gcPolicy.MaxContainers {
		// Leave an equal number of containers per evict unit (min: 1).
		numContainersPerEvictUnit := gcPolicy.MaxContainers / evictUnits.NumEvictUnits()
		if numContainersPerEvictUnit < 1 {
			numContainersPerEvictUnit = 1
		}
		cgc.enforceMaxContainersPerEvictUnit(evictUnits, numContainersPerEvictUnit)

		// If we still need to evict, evict oldest first.
		numContainers := evictUnits.NumContainers()
		if numContainers > gcPolicy.MaxContainers {
			flattened := make([]containerGCInfo, 0, numContainers)
			for key := range evictUnits {
				flattened = append(flattened, evictUnits[key]...)
			}
			sort.Sort(byCreated(flattened))

			cgc.removeOldestN(flattened, numContainers-gcPolicy.MaxContainers)
		}
	}

	// Remove sandboxes with zero containers
	evictSandboxes, err := cgc.evictableSandboxes()
	if err != nil {
		return err
	}
	for _, sandbox := range evictSandboxes {
		cgc.removeSandbox(sandbox)
	}

	return nil
}
<|endoftext|>