<commit_before>package sortutil

import (
	"reflect"
	"sort"
	"testing"
	"time"
)

const (
	day = 24 * time.Hour
)

type Item struct {
	Id    int64
	Name  string
	Date  time.Time
	Valid bool
}

type SortableItems []Item

func (s SortableItems) Len() int {
	return len(s)
}

func (s SortableItems) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s SortableItems) Less(i, j int) bool {
	return s[i].Id > s[j].Id
}

func names() []string {
	return []string{"A", "C", "a", "b", "d", "g", "h", "y", "z"}
}

func namesInsensitive() []string {
	return []string{"A", "a", "b", "C", "d", "g", "h", "y", "z"}
}

var now = time.Now()

func dates() []time.Time {
	return []time.Time{
		now.Add(-3 * day),
		now.Add(-2 * day),
		now.Add(-1 * day),
		now,
		now.Add(1 * day),
		now.Add(2 * day),
		now.Add(4 * day),
		now.Add(5 * day),
		now.Add(7 * day),
	}
}

func items() []Item {
	n := names()
	d := dates()
	is := []Item{
		{6, n[4], d[0], true},
		{1, n[3], d[5], true},
		{9, n[1], d[6], true},
		{3, n[8], d[2], false},
		{7, n[7], d[8], true},
		{2, n[2], d[4], false},
		{8, n[0], d[1], false},
		{5, n[5], d[7], false},
		{4, n[6], d[3], true},
	}
	return is
}

func nestedIntSlice() [][]int {
	return [][]int{
		{4, 5, 1},
		{2, 1, 7},
		{9, 3, 3},
		{1, 6, 2},
	}
}

func TestSortReverseInterface(t *testing.T) {
	is := items()
	SortReverseInterface(SortableItems(is))
	for i, v := range is {
		if v.Id != int64(i+1) {
			t.Errorf("is[%d].Id is not %d, but %d", i, i+1, v.Id)
		}
	}
}

func TestSortByStringFieldAscending(t *testing.T) {
	is := items()
	AscByField(is, "Name")
	c := names()
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByStringFieldDescending(t *testing.T) {
	is := items()
	DescByField(is, "Name")
	c := names()
	ReverseInterface(sort.StringSlice(c))
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByStringFieldCaseInsensitiveAscending(t *testing.T) {
	is := items()
	CiAscByField(is, "Name")
	c := namesInsensitive()
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByStringFieldCaseInsensitiveDescending(t *testing.T) {
	is := items()
	CiDescByField(is, "Name")
	c := namesInsensitive()
	ReverseInterface(sort.StringSlice(c))
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByInt64FieldAscending(t *testing.T) {
	is := items()
	AscByField(is, "Id")
	for i, v := range is {
		if v.Id != int64(i+1) {
			t.Errorf("is[%d].Id is not %d, but %d", i, i+1, v.Id)
		}
	}
}

func TestSortByInt64FieldDescending(t *testing.T) {
	is := items()
	DescByField(is, "Id")
	l := len(is)
	for i, v := range is {
		if v.Id != int64(l-i) {
			t.Errorf("is[%d].Id is not %d, but %d", i, l-i, v.Id)
		}
	}
}

func TestSortByIntIndexAscending(t *testing.T) {
	is := nestedIntSlice()
	AscByIndex(is, 2)
	if !sort.IntsAreSorted([]int{is[0][2], is[1][2], is[2][2], is[3][2]}) {
		t.Errorf("Nested int slice is not sorted by index 2 in child slices: %v", is)
	}
}

func TestSortIntArray(t *testing.T) {
	return // TEMP: Disabled
	ints := [...]int{4, 3, 1, 5, 2}
	Sort(ints, nil, Ascending)
	if !sort.IntsAreSorted(ints[:]) {
		t.Errorf("Array ints weren't sorted: %v", ints)
	}
}

func TestSortByTimeFieldAscending(t *testing.T) {
	is := items()
	AscByField(is, "Date")
	c := dates()
	for i, v := range is {
		if !v.Date.Equal(c[i]) {
			t.Errorf("is[%d].Date is not %v, but %v", i, c[i], v.Date)
		}
	}
}

func TestSortByTimeFieldDescending(t *testing.T) {
	is := items()
	DescByField(is, "Date")
	c := dates()
	l := len(is)
	for i, v := range is {
		if !v.Date.Equal(c[l-i-1]) {
			t.Errorf("is[%d].Date is not %v, but %v", i, c[l-i], v.Date)
		}
	}
}

type TestStruct struct {
	TimePtr    *time.Time
	Invalid    InvalidType
	unexported int
}

type InvalidType struct {
	Foo string
	Bar int
}

func testStructs() []TestStruct {
	return []TestStruct{
		{
			TimePtr:    &now,
			Invalid:    InvalidType{"foo", 123},
			unexported: 5,
		},
	}
}

func TestSortInvalidType(t *testing.T) {
	// Sorting an invalid type should cause a panic
	defer func() {
		if x := recover(); x == nil {
			t.Fatal("Sorting an unrecognized type didn't cause a panic")
		}
	}()
	is := testStructs()
	AscByField(is, "Invalid")
}

func TestSortUnexportedType(t *testing.T) {
	// Sorting an unexported type should cause a panic
	// TODO: This should test on a field outside the package
	return // TEMP
	defer func() {
		if x := recover(); x == nil {
			t.Fatal("Sorting an unexported type didn't cause a panic")
		}
	}()
	is := testStructs()
	AscByField(is, "unexported")
}

func TestSortPointerType(t *testing.T) {
	// Sorting a pointer type shouldn't cause a panic
	is := testStructs()
	AscByField(is, "TimePtr")
}

func TestReverse(t *testing.T) {
	ints := []int{4, 2, 6, 4, 8}
	correct := []int{8, 4, 6, 2, 4}
	Reverse(ints)
	if !reflect.DeepEqual(ints, correct) {
		t.Errorf("Reversed slice was not %v: %v", correct, ints)
	}
}

func BenchmarkSortByInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		is := items()
		sort.Sort(SortableItems(is))
	}
}

func BenchmarkSortReverseByInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		is := items()
		SortReverseInterface(SortableItems(is))
	}
}

func benchmarkInts(n int) []int {
	ints := make([]int, n, n)
	v := 0
	for i := 0; i < n; i++ {
		ints[i] = v
		v++
		if v > 10 {
			v = 0
		}
	}
	return ints
}

func benchmarkInt64s(n int) []int64 {
	ints := make([]int64, n, n)
	v := int64(0)
	for i := 0; i < n; i++ {
		ints[i] = v
		v++
		if v > 10 {
			v = 0
		}
	}
	return ints
}

func BenchmarkSortInts(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInts(b.N)
	b.StartTimer()
	sort.Sort(sort.IntSlice(ints))
}

func BenchmarkAscInts(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInts(b.N)
	b.StartTimer()
	Asc(ints)
}

func BenchmarkDescInts(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInts(b.N)
	b.StartTimer()
	Desc(ints)
}

func BenchmarkAscInt64s(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInt64s(b.N)
	b.StartTimer()
	Asc(ints)
}

func BenchmarkDescInt64s(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInt64s(b.N)
	b.StartTimer()
	Desc(ints)
}

func benchmarkItems(l int) []Item {
	is := make([]Item, l, l)
	n := names()
	d := dates()
	v := 0
	for i := range is {
		is[i] = Item{int64(v), n[v], d[v], true}
		v++
		if v > 5 {
			v = 0
		}
	}
	return is
}

func BenchmarkAscByInt64(b *testing.B) {
	b.StopTimer()
	is := benchmarkItems(b.N)
	b.StartTimer()
	AscByField(is, "Id")
}
<commit_msg>Ditto<commit_after>package sortutil

import (
	"reflect"
	"sort"
	"testing"
	"time"
)

const (
	day = 24 * time.Hour
)

type Item struct {
	Id    int64
	Name  string
	Date  time.Time
	Valid bool
}

type SortableItems []Item

func (s SortableItems) Len() int {
	return len(s)
}

func (s SortableItems) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s SortableItems) Less(i, j int) bool {
	return s[i].Id > s[j].Id
}

func names() []string {
	return []string{"A", "C", "a", "b", "d", "g", "h", "y", "z"}
}

func namesInsensitive() []string {
	return []string{"A", "a", "b", "C", "d", "g", "h", "y", "z"}
}

var now = time.Now()

func dates() []time.Time {
	return []time.Time{
		now.Add(-3 * day),
		now.Add(-2 * day),
		now.Add(-1 * day),
		now,
		now.Add(1 * day),
		now.Add(2 * day),
		now.Add(4 * day),
		now.Add(5 * day),
		now.Add(7 * day),
	}
}

func items() []Item {
	n := names()
	d := dates()
	is := []Item{
		{6, n[4], d[0], true},
		{1, n[3], d[5], true},
		{9, n[1], d[6], true},
		{3, n[8], d[2], false},
		{7, n[7], d[8], true},
		{2, n[2], d[4], false},
		{8, n[0], d[1], false},
		{5, n[5], d[7], false},
		{4, n[6], d[3], true},
	}
	return is
}

func nestedIntSlice() [][]int {
	return [][]int{
		{4, 5, 1},
		{2, 1, 7},
		{9, 3, 3},
		{1, 6, 2},
	}
}

func TestSortReverseInterface(t *testing.T) {
	is := items()
	SortReverseInterface(SortableItems(is))
	for i, v := range is {
		if v.Id != int64(i+1) {
			t.Errorf("is[%d].Id is not %d, but %d", i, i+1, v.Id)
		}
	}
}

func TestSortByStringFieldAscending(t *testing.T) {
	is := items()
	AscByField(is, "Name")
	c := names()
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByStringFieldDescending(t *testing.T) {
	is := items()
	DescByField(is, "Name")
	c := names()
	ReverseInterface(sort.StringSlice(c))
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByStringFieldCaseInsensitiveAscending(t *testing.T) {
	is := items()
	CiAscByField(is, "Name")
	c := namesInsensitive()
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByStringFieldCaseInsensitiveDescending(t *testing.T) {
	is := items()
	CiDescByField(is, "Name")
	c := namesInsensitive()
	ReverseInterface(sort.StringSlice(c))
	for i, v := range is {
		if v.Name != c[i] {
			t.Errorf("is[%d].Name is not %s, but %s", i, c[i], v.Name)
		}
	}
}

func TestSortByInt64FieldAscending(t *testing.T) {
	is := items()
	AscByField(is, "Id")
	for i, v := range is {
		if v.Id != int64(i+1) {
			t.Errorf("is[%d].Id is not %d, but %d", i, i+1, v.Id)
		}
	}
}

func TestSortByInt64FieldDescending(t *testing.T) {
	is := items()
	DescByField(is, "Id")
	l := len(is)
	for i, v := range is {
		if v.Id != int64(l-i) {
			t.Errorf("is[%d].Id is not %d, but %d", i, l-i, v.Id)
		}
	}
}

func TestSortByIntIndexAscending(t *testing.T) {
	is := nestedIntSlice()
	AscByIndex(is, 2)
	if !sort.IntsAreSorted([]int{is[0][2], is[1][2], is[2][2], is[3][2]}) {
		t.Errorf("Nested int slice is not sorted by index 2 in child slices: %v", is)
	}
}

func TestSortIntArray(t *testing.T) {
	return // TEMP: Disabled
	ints := [...]int{4, 3, 1, 5, 2}
	Asc(ints)
	if !sort.IntsAreSorted(ints[:]) {
		t.Errorf("Array ints weren't sorted: %v", ints)
	}
}

func TestSortByTimeFieldAscending(t *testing.T) {
	is := items()
	AscByField(is, "Date")
	c := dates()
	for i, v := range is {
		if !v.Date.Equal(c[i]) {
			t.Errorf("is[%d].Date is not %v, but %v", i, c[i], v.Date)
		}
	}
}

func TestSortByTimeFieldDescending(t *testing.T) {
	is := items()
	DescByField(is, "Date")
	c := dates()
	l := len(is)
	for i, v := range is {
		if !v.Date.Equal(c[l-i-1]) {
			t.Errorf("is[%d].Date is not %v, but %v", i, c[l-i], v.Date)
		}
	}
}

type TestStruct struct {
	TimePtr    *time.Time
	Invalid    InvalidType
	unexported int
}

type InvalidType struct {
	Foo string
	Bar int
}

func testStructs() []TestStruct {
	return []TestStruct{
		{
			TimePtr:    &now,
			Invalid:    InvalidType{"foo", 123},
			unexported: 5,
		},
	}
}

func TestSortInvalidType(t *testing.T) {
	// Sorting an invalid type should cause a panic
	defer func() {
		if x := recover(); x == nil {
			t.Fatal("Sorting an unrecognized type didn't cause a panic")
		}
	}()
	is := testStructs()
	AscByField(is, "Invalid")
}

func TestSortUnexportedType(t *testing.T) {
	// Sorting an unexported type should cause a panic
	// TODO: This should test on a field outside the package
	return // TEMP
	defer func() {
		if x := recover(); x == nil {
			t.Fatal("Sorting an unexported type didn't cause a panic")
		}
	}()
	is := testStructs()
	AscByField(is, "unexported")
}

func TestSortPointerType(t *testing.T) {
	// Sorting a pointer type shouldn't cause a panic
	is := testStructs()
	AscByField(is, "TimePtr")
}

func TestReverse(t *testing.T) {
	ints := []int{4, 2, 6, 4, 8}
	correct := []int{8, 4, 6, 2, 4}
	Reverse(ints)
	if !reflect.DeepEqual(ints, correct) {
		t.Errorf("Reversed slice was not %v: %v", correct, ints)
	}
}

func BenchmarkSortByInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		is := items()
		sort.Sort(SortableItems(is))
	}
}

func BenchmarkSortReverseByInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		is := items()
		SortReverseInterface(SortableItems(is))
	}
}

func benchmarkInts(n int) []int {
	ints := make([]int, n, n)
	v := 0
	for i := 0; i < n; i++ {
		ints[i] = v
		v++
		if v > 10 {
			v = 0
		}
	}
	return ints
}

func benchmarkInt64s(n int) []int64 {
	ints := make([]int64, n, n)
	v := int64(0)
	for i := 0; i < n; i++ {
		ints[i] = v
		v++
		if v > 10 {
			v = 0
		}
	}
	return ints
}

func BenchmarkSortInts(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInts(b.N)
	b.StartTimer()
	sort.Sort(sort.IntSlice(ints))
}

func BenchmarkAscInts(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInts(b.N)
	b.StartTimer()
	Asc(ints)
}

func BenchmarkDescInts(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInts(b.N)
	b.StartTimer()
	Desc(ints)
}

func BenchmarkAscInt64s(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInt64s(b.N)
	b.StartTimer()
	Asc(ints)
}

func BenchmarkDescInt64s(b *testing.B) {
	b.StopTimer()
	ints := benchmarkInt64s(b.N)
	b.StartTimer()
	Desc(ints)
}

func benchmarkItems(l int) []Item {
	is := make([]Item, l, l)
	n := names()
	d := dates()
	v := 0
	for i := range is {
		is[i] = Item{int64(v), n[v], d[v], true}
		v++
		if v > 5 {
			v = 0
		}
	}
	return is
}

func BenchmarkAscByInt64(b *testing.B) {
	b.StopTimer()
	is := benchmarkItems(b.N)
	b.StartTimer()
	AscByField(is, "Id")
}
<|endoftext|>


<commit_before>package path

import (
	"github.com/catorpilor/leetcode/utils"
)

func PathSum(root *utils.TreeNode, sum int) [][]int {
	var ret [][]int
	if root == nil {
		return ret
	}
	var temp []int
	helper(root, sum, &temp, &ret)
	return ret
}

func helper(node *utils.TreeNode, k int, nodes *[]int, res *[][]int) {
	n := len(*nodes)
	*nodes = append(*nodes, node.Val)
	if node.Left == nil && node.Right == nil && k == node.Val {
		// find one
		bak := make([]int, len(*nodes))
		copy(bak, *nodes)
		*res = append(*res, bak)
	} else {
		if node.Left != nil {
			helper(node.Left, k-node.Val, nodes, res)
		}
		if node.Right != nil {
			helper(node.Right, k-node.Val, nodes, res)
		}
	}
	*nodes = (*nodes)[:n]
}
<commit_msg>add comments<commit_after>package path

import (
	"github.com/catorpilor/leetcode/utils"
)

func PathSum(root *utils.TreeNode, sum int) [][]int {
	// backtracking and dfs
	var ret [][]int
	if root == nil {
		return ret
	}
	var temp []int
	helper(root, sum, &temp, &ret)
	return ret
}

func helper(node *utils.TreeNode, k int, nodes *[]int, res *[][]int) {
	n := len(*nodes)
	*nodes = append(*nodes, node.Val)
	if node.Left == nil && node.Right == nil && k == node.Val {
		// find one
		bak := make([]int, len(*nodes))
		copy(bak, *nodes)
		*res = append(*res, bak)
	} else {
		if node.Left != nil {
			helper(node.Left, k-node.Val, nodes, res)
		}
		if node.Right != nil {
			helper(node.Right, k-node.Val, nodes, res)
		}
	}
	*nodes = (*nodes)[:n]
}
<|endoftext|>


<commit_before>/*
Copyright 2019 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 v1

const (
	// TaintNodeNotReady will be added when node is not ready
	// and removed when node becomes ready.
	TaintNodeNotReady = "node.kubernetes.io/not-ready"

	// TaintNodeUnreachable will be added when node becomes unreachable
	// (corresponding to NodeReady status ConditionUnknown)
	// and removed when node becomes reachable (NodeReady status ConditionTrue).
	TaintNodeUnreachable = "node.kubernetes.io/unreachable"

	// TaintNodeUnschedulable will be added when node becomes unschedulable
	// and removed when node becomes scheduable.
	TaintNodeUnschedulable = "node.kubernetes.io/unschedulable"

	// TaintNodeMemoryPressure will be added when node has memory pressure
	// and removed when node has enough memory.
	TaintNodeMemoryPressure = "node.kubernetes.io/memory-pressure"

	// TaintNodeDiskPressure will be added when node has disk pressure
	// and removed when node has enough disk.
	TaintNodeDiskPressure = "node.kubernetes.io/disk-pressure"

	// TaintNodeNetworkUnavailable will be added when node's network is unavailable
	// and removed when network becomes ready.
	TaintNodeNetworkUnavailable = "node.kubernetes.io/network-unavailable"

	// TaintNodePIDPressure will be added when node has pid pressure
	// and removed when node has enough pid.
	TaintNodePIDPressure = "node.kubernetes.io/pid-pressure"
)
<commit_msg>Fix spelling typos: scheduable -> schedulable<commit_after>/*
Copyright 2019 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 v1

const (
	// TaintNodeNotReady will be added when node is not ready
	// and removed when node becomes ready.
	TaintNodeNotReady = "node.kubernetes.io/not-ready"

	// TaintNodeUnreachable will be added when node becomes unreachable
	// (corresponding to NodeReady status ConditionUnknown)
	// and removed when node becomes reachable (NodeReady status ConditionTrue).
	TaintNodeUnreachable = "node.kubernetes.io/unreachable"

	// TaintNodeUnschedulable will be added when node becomes unschedulable
	// and removed when node becomes schedulable.
	TaintNodeUnschedulable = "node.kubernetes.io/unschedulable"

	// TaintNodeMemoryPressure will be added when node has memory pressure
	// and removed when node has enough memory.
	TaintNodeMemoryPressure = "node.kubernetes.io/memory-pressure"

	// TaintNodeDiskPressure will be added when node has disk pressure
	// and removed when node has enough disk.
	TaintNodeDiskPressure = "node.kubernetes.io/disk-pressure"

	// TaintNodeNetworkUnavailable will be added when node's network is unavailable
	// and removed when network becomes ready.
	TaintNodeNetworkUnavailable = "node.kubernetes.io/network-unavailable"

	// TaintNodePIDPressure will be added when node has pid pressure
	// and removed when node has enough pid.
	TaintNodePIDPressure = "node.kubernetes.io/pid-pressure"
)
<|endoftext|>


<commit_before>package xlogtools

import (
	"errors"
	"regexp"
	"strconv"
	"strings"

	"github.com/greensnark/go-sequell/crawl/data"
	"github.com/greensnark/go-sequell/crawl/god"
	"github.com/greensnark/go-sequell/crawl/killer"
	"github.com/greensnark/go-sequell/crawl/place"
	"github.com/greensnark/go-sequell/crawl/player"
	"github.com/greensnark/go-sequell/crawl/version"
	"github.com/greensnark/go-sequell/text"
	"github.com/greensnark/go-sequell/xlog"
)

type XlogType int

const (
	Unknown XlogType = iota
	Log
	Milestone
)

var ErrNoSrc = errors.New("`src` field is not set")

func (x XlogType) String() string {
	switch x {
	case Log:
		return "logfile"
	case Milestone:
		return "milestones"
	}
	return "unk"
}

func (x XlogType) BaseTable() string {
	switch x {
	case Log:
		return "logrecord"
	case Milestone:
		return "milestone"
	}
	return ""
}

func Type(line xlog.Xlog) XlogType {
	if _, ok := line["type"]; ok {
		return Milestone
	}
	return Log
}

func NormalizeBool(b string) string {
	if b != "" && b != "0" {
		return "t"
	}
	return "f"
}

func ValidXlog(log xlog.Xlog) bool {
	return log["start"] != "" && log["name"] != "" &&
		(log["end"] != "" || log["time"] != "")
}

func NormalizeLog(log xlog.Xlog) (xlog.Xlog, error) {
	if _, exists := log["src"]; !exists {
		return log, ErrNoSrc
	}

	log["v"] = version.FullVersion(log["v"])
	log["cv"] = version.MajorVersion(log["v"])
	if version.IsAlpha(log["v"]) {
		log["alpha"] = "y"
	}
	if log["alpha"] != "" {
		log["cv"] += "-a"
	}
	log["vnum"] = strconv.FormatUint(version.VersionNumericId(log["v"]), 10)
	log["cvnum"] = strconv.FormatUint(version.VersionNumericId(log["cv"]), 10)
	if vlong, ok := log["vlong"]; ok {
		log["vlongnum"] =
			strconv.FormatUint(version.VersionNumericId(vlong), 10)
	}
	log["tiles"] = NormalizeBool(log["tiles"])
	if log["ntv"] == "" {
		log["ntv"] = "0"
	}
	log["place"] = place.CanonicalPlace(log["place"])
	log["oplace"] = place.CanonicalPlace(log["oplace"])
	log["br"] = place.CanonicalPlace(log["br"])
	log["god"] = god.CanonicalGod(log["god"])
	log["crace"] = player.NormalizeRace(log["race"])
	log["rstart"] = log["start"]
	log["game_key"] = log["name"] + ":" + log["src"] + ":" + log["rstart"]

	milestone := Type(log) == Milestone
	if milestone {
		log["verb"] = log["type"]
		log["noun"] = text.FirstNotEmpty(log["milestone"], "?")
		log["rtime"] = log["time"]
		log["oplace"] = text.FirstNotEmpty(log["oplace"], log["place"])
		NormalizeMilestoneFields(log)
	} else {
		log["vmsg"] = text.FirstNotEmpty(log["vsmg"], log["tmsg"])
		log["map"] = NormalizeMapName(log["map"])
		log["killermap"] = NormalizeMapName(log["killermap"])
		log["ikiller"] = text.FirstNotEmpty(log["ikiller"], log["killer"])
		log["ckiller"] =
			killer.NormalizeKiller(
				text.FirstNotEmpty(log["killer"], log["ktyp"]),
				log["killer"], log["killer_flags"])
		log["cikiller"] =
			killer.NormalizeKiller(log["ikiller"], log["ikiller"], "")
		log["kmod"] = killer.NormalizeKmod(log["killer"])
		log["ckaux"] = killer.NormalizeKaux(log["kaux"])
		log["rend"] = log["end"]
	}

	CanonicalizeFields(log)
	sanitizeGold(log)

	return log, nil
}

func NormalizeMapName(mapname string) string {
	return strings.Replace(mapname, ",", ";", -1)
}

var milestoneVerbMap = data.Crawl.StringMap("milestone-verb-mappings")
var rActionWord = regexp.MustCompile(`(\w+) (.*?)\.?$`)
var rGhostWord = regexp.MustCompile(`(\w+) the ghost of (\S+)`)
var rAbyssCause = regexp.MustCompile(`\((.*?)\)$`)

func NormalizeMilestoneFields(log xlog.Xlog) {
	verb := log["verb"]
	if mappedVerb, ok := milestoneVerbMap[verb]; ok {
		log["verb"] = mappedVerb
		verb = mappedVerb
	}

	noun := log["noun"]
	switch verb {
	case "uniq":
		actionMatch := rActionWord.FindStringSubmatch(noun)
		if actionMatch != nil {
			actionWord, actedUpon := actionMatch[1], actionMatch[2]
			noun = actedUpon
			verb = qualifyVerbAction(verb, actionWord)
		}
	case "ghost":
		ghostMatch := rGhostWord.FindStringSubmatch(noun)
		if ghostMatch != nil {
			verb = qualifyVerbAction(verb, ghostMatch[1])
			noun = ghostMatch[2]
		}
	case "abyss.enter":
		abyssCauseMatch := rAbyssCause.FindStringSubmatch(noun)
		if abyssCauseMatch != nil {
			noun = text.FirstNotEmpty(abyssCauseMatch[1], "?")
		}
	case "br.enter", "br.end", "br.mid":
		noun = place.StripPlaceDepth(log["place"])
	case "br.exit":
		noun = place.StripPlaceDepth(log["oplace"])
	case "rune":
		noun = FoundRuneName(noun)
	case "orb":
		noun = "orb"
	case "god.mollify":
		noun = MollifiedGodName(noun)
	case "god.renounce":
		noun = RenouncedGodName(noun)
	case "god.worship":
		noun = WorshippedGodName(noun)
	case "god.maxpiety":
		noun = MaxedPietyGodName(noun)
	case "monstrous":
		noun = "demonspawn"
	case "shaft":
		noun = ShaftedPlace(noun)
	}
	log["verb"] = verb
	if noun != "" {
		log["noun"] = noun
	}
}

func qualifyVerbAction(verb string, actionWord string) string {
	if actionWord == "banished" {
		return verb + ".ban"
	}
	if actionWord == "pacified" {
		return verb + ".pac"
	}
	if actionWord == "enslaved" {
		return verb + ".ens"
	}
	return verb
}

var rFoundRune = regexp.MustCompile(`found an? (\S+) rune`)

func textReSubmatch(text string, reg *regexp.Regexp, submatch int) string {
	m := reg.FindStringSubmatch(text)
	if m != nil {
		return m[submatch]
	}
	return text
}

func FoundRuneName(found string) string {
	return textReSubmatch(found, rFoundRune, 1)
}

var rMollifiedGod = regexp.MustCompile(`^(?:partially )?mollified (.*)[.]$`)

func MollifiedGodName(mollifiedMsg string) string {
	return textReSubmatch(mollifiedMsg, rMollifiedGod, 1)
}

var rRenouncedGod = regexp.MustCompile(`^abandoned (.*)[.]$`)

func RenouncedGodName(renounceMsg string) string {
	return textReSubmatch(renounceMsg, rRenouncedGod, 1)
}

var rMaxedPietyGod = regexp.MustCompile(`^became the Champion of (.*)[.]$`)

func MaxedPietyGodName(maxpietyMsg string) string {
	return textReSubmatch(maxpietyMsg, rMaxedPietyGod, 1)
}

var rWorshippedGod = regexp.MustCompile(`^became a worshipper of (.*)[.]$`)

func WorshippedGodName(worshipMsg string) string {
	return textReSubmatch(worshipMsg, rWorshippedGod, 1)
}

var rShaftedPlace = regexp.MustCompile(`fell down a shaft to (.*)[.]$`)

func ShaftedPlace(shaftMsg string) string {
	return textReSubmatch(shaftMsg, rShaftedPlace, 1)
}

var fieldInputTransforms = data.Crawl.Map("field-input-transforms")

func CanonicalizeFields(log xlog.Xlog) {
	for field, transforms := range fieldInputTransforms {
		fieldname := field.(string)
		if value, ok := log[fieldname]; ok {
			transformMap := transforms.(map[interface{}]interface{})
			for isearch, ireplace := range transformMap {
				search := isearch.(string)
				replace := ireplace.(string)
				if value == search {
					value = replace
				}
			}
			log[fieldname] = value
		}
	}
}

func sanitizeGold(log xlog.Xlog) {
	if text.ParseInt(log["gold"], 0) < 0 ||
		text.ParseInt(log["goldfound"], 0) < 0 ||
		text.ParseInt(log["goldspent"], 0) < 0 {
		log["gold"] = "0"
		log["goldfound"] = "0"
		log["goldspent"] = "0"
	}
}
<commit_msg>Use NormalizeBool for wiz.<commit_after>package xlogtools

import (
	"errors"
	"regexp"
	"strconv"
	"strings"

	"github.com/greensnark/go-sequell/crawl/data"
	"github.com/greensnark/go-sequell/crawl/god"
	"github.com/greensnark/go-sequell/crawl/killer"
	"github.com/greensnark/go-sequell/crawl/place"
	"github.com/greensnark/go-sequell/crawl/player"
	"github.com/greensnark/go-sequell/crawl/version"
	"github.com/greensnark/go-sequell/text"
	"github.com/greensnark/go-sequell/xlog"
)

type XlogType int

const (
	Unknown XlogType = iota
	Log
	Milestone
)

var ErrNoSrc = errors.New("`src` field is not set")

func (x XlogType) String() string {
	switch x {
	case Log:
		return "logfile"
	case Milestone:
		return "milestones"
	}
	return "unk"
}

func (x XlogType) BaseTable() string {
	switch x {
	case Log:
		return "logrecord"
	case Milestone:
		return "milestone"
	}
	return ""
}

func Type(line xlog.Xlog) XlogType {
	if _, ok := line["type"]; ok {
		return Milestone
	}
	return Log
}

func NormalizeBool(b string) string {
	if b != "" && b != "0" {
		return "t"
	}
	return "f"
}

func ValidXlog(log xlog.Xlog) bool {
	return log["start"] != "" && log["name"] != "" &&
		(log["end"] != "" || log["time"] != "")
}

func NormalizeLog(log xlog.Xlog) (xlog.Xlog, error) {
	if _, exists := log["src"]; !exists {
		return log, ErrNoSrc
	}

	log["v"] = version.FullVersion(log["v"])
	log["cv"] = version.MajorVersion(log["v"])
	if version.IsAlpha(log["v"]) {
		log["alpha"] = "t"
	}
	if log["alpha"] != "" {
		log["cv"] += "-a"
	}
	log["vnum"] = strconv.FormatUint(version.VersionNumericId(log["v"]), 10)
	log["cvnum"] = strconv.FormatUint(version.VersionNumericId(log["cv"]), 10)
	if vlong, ok := log["vlong"]; ok {
		log["vlongnum"] =
			strconv.FormatUint(version.VersionNumericId(vlong), 10)
	}
	log["tiles"] = NormalizeBool(log["tiles"])
	log["wiz"] = NormalizeBool(log["wiz"])
	if log["ntv"] == "" {
		log["ntv"] = "0"
	}
	log["place"] = place.CanonicalPlace(log["place"])
	log["oplace"] = place.CanonicalPlace(log["oplace"])
	log["br"] = place.CanonicalPlace(log["br"])
	log["god"] = god.CanonicalGod(log["god"])
	log["crace"] = player.NormalizeRace(log["race"])
	log["rstart"] = log["start"]
	log["game_key"] = log["name"] + ":" + log["src"] + ":" + log["rstart"]

	milestone := Type(log) == Milestone
	if milestone {
		log["verb"] = log["type"]
		log["noun"] = text.FirstNotEmpty(log["milestone"], "?")
		log["rtime"] = log["time"]
		log["oplace"] = text.FirstNotEmpty(log["oplace"], log["place"])
		NormalizeMilestoneFields(log)
	} else {
		log["vmsg"] = text.FirstNotEmpty(log["vsmg"], log["tmsg"])
		log["map"] = NormalizeMapName(log["map"])
		log["killermap"] = NormalizeMapName(log["killermap"])
		log["ikiller"] = text.FirstNotEmpty(log["ikiller"], log["killer"])
		log["ckiller"] =
			killer.NormalizeKiller(
				text.FirstNotEmpty(log["killer"], log["ktyp"]),
				log["killer"], log["killer_flags"])
		log["cikiller"] =
			killer.NormalizeKiller(log["ikiller"], log["ikiller"], "")
		log["kmod"] = killer.NormalizeKmod(log["killer"])
		log["ckaux"] = killer.NormalizeKaux(log["kaux"])
		log["rend"] = log["end"]
	}

	CanonicalizeFields(log)
	sanitizeGold(log)

	return log, nil
}

func NormalizeMapName(mapname string) string {
	return strings.Replace(mapname, ",", ";", -1)
}

var milestoneVerbMap = data.Crawl.StringMap("milestone-verb-mappings")
var rActionWord = regexp.MustCompile(`(\w+) (.*?)\.?$`)
var rGhostWord = regexp.MustCompile(`(\w+) the ghost of (\S+)`)
var rAbyssCause = regexp.MustCompile(`\((.*?)\)$`)

func NormalizeMilestoneFields(log xlog.Xlog) {
	verb := log["verb"]
	if mappedVerb, ok := milestoneVerbMap[verb]; ok {
		log["verb"] = mappedVerb
		verb = mappedVerb
	}

	noun := log["noun"]
	switch verb {
	case "uniq":
		actionMatch := rActionWord.FindStringSubmatch(noun)
		if actionMatch != nil {
			actionWord, actedUpon := actionMatch[1], actionMatch[2]
			noun = actedUpon
			verb = qualifyVerbAction(verb, actionWord)
		}
	case "ghost":
		ghostMatch := rGhostWord.FindStringSubmatch(noun)
		if ghostMatch != nil {
			verb = qualifyVerbAction(verb, ghostMatch[1])
			noun = ghostMatch[2]
		}
	case "abyss.enter":
		abyssCauseMatch := rAbyssCause.FindStringSubmatch(noun)
		if abyssCauseMatch != nil {
			noun = text.FirstNotEmpty(abyssCauseMatch[1], "?")
		}
	case "br.enter", "br.end", "br.mid":
		noun = place.StripPlaceDepth(log["place"])
	case "br.exit":
		noun = place.StripPlaceDepth(log["oplace"])
	case "rune":
		noun = FoundRuneName(noun)
	case "orb":
		noun = "orb"
	case "god.mollify":
		noun = MollifiedGodName(noun)
	case "god.renounce":
		noun = RenouncedGodName(noun)
	case "god.worship":
		noun = WorshippedGodName(noun)
	case "god.maxpiety":
		noun = MaxedPietyGodName(noun)
	case "monstrous":
		noun = "demonspawn"
	case "shaft":
		noun = ShaftedPlace(noun)
	}
	log["verb"] = verb
	if noun != "" {
		log["noun"] = noun
	}
}

func qualifyVerbAction(verb string, actionWord string) string {
	if actionWord == "banished" {
		return verb + ".ban"
	}
	if actionWord == "pacified" {
		return verb + ".pac"
	}
	if actionWord == "enslaved" {
		return verb + ".ens"
	}
	return verb
}

var rFoundRune = regexp.MustCompile(`found an? (\S+) rune`)

func textReSubmatch(text string, reg *regexp.Regexp, submatch int) string {
	m := reg.FindStringSubmatch(text)
	if m != nil {
		return m[submatch]
	}
	return text
}

func FoundRuneName(found string) string {
	return textReSubmatch(found, rFoundRune, 1)
}

var rMollifiedGod = regexp.MustCompile(`^(?:partially )?mollified (.*)[.]$`)

func MollifiedGodName(mollifiedMsg string) string {
	return textReSubmatch(mollifiedMsg, rMollifiedGod, 1)
}

var rRenouncedGod = regexp.MustCompile(`^abandoned (.*)[.]$`)

func RenouncedGodName(renounceMsg string) string {
	return textReSubmatch(renounceMsg, rRenouncedGod, 1)
}

var rMaxedPietyGod = regexp.MustCompile(`^became the Champion of (.*)[.]$`)

func MaxedPietyGodName(maxpietyMsg string) string {
	return textReSubmatch(maxpietyMsg, rMaxedPietyGod, 1)
}

var rWorshippedGod = regexp.MustCompile(`^became a worshipper of (.*)[.]$`)

func WorshippedGodName(worshipMsg string) string {
	return textReSubmatch(worshipMsg, rWorshippedGod, 1)
}

var rShaftedPlace = regexp.MustCompile(`fell down a shaft to (.*)[.]$`)

func ShaftedPlace(shaftMsg string) string {
	return textReSubmatch(shaftMsg, rShaftedPlace, 1)
}

var fieldInputTransforms = data.Crawl.Map("field-input-transforms")

func CanonicalizeFields(log xlog.Xlog) {
	for field, transforms := range fieldInputTransforms {
		fieldname := field.(string)
		if value, ok := log[fieldname]; ok {
			transformMap := transforms.(map[interface{}]interface{})
			for isearch, ireplace := range transformMap {
				search := isearch.(string)
				replace := ireplace.(string)
				if value == search {
					value = replace
				}
			}
			log[fieldname] = value
		}
	}
}

func sanitizeGold(log xlog.Xlog) {
	if text.ParseInt(log["gold"], 0) < 0 ||
		text.ParseInt(log["goldfound"], 0) < 0 ||
		text.ParseInt(log["goldspent"], 0) < 0 {
		log["gold"] = "0"
		log["goldfound"] = "0"
		log["goldspent"] = "0"
	}
}
<|endoftext|>


<commit_before>// +build !nopkcs11

package pkcs11key

import (
	"bytes"
	"crypto"
	"crypto/rand"
	"testing"

	"github.com/miekg/pkcs11"
)

type mockCtx struct{}

const privateKeyHandle = pkcs11.ObjectHandle(23)
const sessionHandle = pkcs11.SessionHandle(17)

var slots = []uint{7, 8, 9}
var tokenInfo = pkcs11.TokenInfo{
	Label: "token label",
}

func (c mockCtx) CloseSession(sh pkcs11.SessionHandle) error {
	return nil
}

func (c mockCtx) FindObjectsFinal(sh pkcs11.SessionHandle) error {
	return nil
}

func (c mockCtx) FindObjectsInit(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error {
	return nil
}

func (c mockCtx) FindObjects(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error) {
	return []pkcs11.ObjectHandle{privateKeyHandle}, true, nil
}

func (c mockCtx) GetAttributeValue(sh pkcs11.SessionHandle, o pkcs11.ObjectHandle, template []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
	var output []*pkcs11.Attribute
	for _, a := range template {
		// Return simple values for these attributes. Note that a value of `1` for
		// both modulus an public exponent would be a very bad public key, but it's
		// sufficient to satisfy the current code.
		if a.Type == pkcs11.CKA_MODULUS ||
			a.Type == pkcs11.CKA_PUBLIC_EXPONENT ||
			a.Type == pkcs11.CKA_ALWAYS_AUTHENTICATE {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: []byte{byte(1)},
			})
		}
	}
	return output, nil
}

func (c mockCtx) GetSlotList(tokenPresent bool) ([]uint, error) {
	return slots, nil
}

func (c mockCtx) GetTokenInfo(slotID uint) (pkcs11.TokenInfo, error) {
	return tokenInfo, nil
}

func (c mockCtx) Initialize() error {
	return nil
}

func (c mockCtx) Login(sh pkcs11.SessionHandle, userType uint, pin string) error {
	return nil
}

func (c mockCtx) Logout(sh pkcs11.SessionHandle) error {
	return nil
}

func (c mockCtx) OpenSession(slotID uint, flags uint) (pkcs11.SessionHandle, error) {
	return sessionHandle, nil
}

func (c mockCtx) SignInit(sh pkcs11.SessionHandle, m []*pkcs11.Mechanism, o pkcs11.ObjectHandle) error {
	return nil
}

func (c mockCtx) Sign(sh pkcs11.SessionHandle, message []byte) ([]byte, error) {
	return []byte("some signed data"), nil
}

func TestSetup(t *testing.T) {
	ps := &Key{
		module:     mockCtx{},
		tokenLabel: "token label",
		pin:        "unused",
	}
	err := ps.setup("private key label")
	if err != nil {
		t.Errorf("Failed to set up Key: %s", err)
	}
}

func setup(t *testing.T) *Key {
	ps := Key{
		module:     mockCtx{},
		tokenLabel: "token label",
		pin:        "unused",
	}
	err := ps.setup("private key label")
	if err != nil {
		t.Fatalf("Failed to set up Key: %s", err)
	}
	return &ps
}

func TestSign(t *testing.T) {
	ps := setup(t)
	// Sign input must be exactly 32 bytes to match SHA256 size. In normally
	// usage, Sign would be called by e.g. x509.CreateCertificate, which would
	// handle padding to the necessary size.
	signInput := []byte("1234567890 1234567890 1234567890")
	output, err := ps.Sign(rand.Reader, signInput, crypto.SHA256)
	if err != nil {
		t.Fatalf("Failed to sign: %s", err)
	}
	if !bytes.Equal(output, []byte("some signed data")) {
		t.Fatal("Incorrect sign output")
	}
}

// This is a version of the mock that gives CKR_ATTRIBUTE_TYPE_INVALID when
// asked about the CKA_ALWAYS_AUTHENTICATE attribute.
type mockCtxFailsAlwaysAuthenticate struct {
	mockCtx
}

func (c mockCtxFailsAlwaysAuthenticate) GetAttributeValue(sh pkcs11.SessionHandle, o pkcs11.ObjectHandle, template []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
	for _, a := range template {
		if a.Type == pkcs11.CKA_ALWAYS_AUTHENTICATE {
			return nil, pkcs11.Error(pkcs11.CKR_ATTRIBUTE_TYPE_INVALID)
		}
	}
	return c.mockCtx.GetAttributeValue(sh, o, template)
}

func TestAttributeTypeInvalid(t *testing.T) {
	ps := &Key{
		module:     mockCtxFailsAlwaysAuthenticate{},
		tokenLabel: "token label",
		pin:        "unused",
	}
	err := ps.setup("private key label")
	if err != nil {
		t.Errorf("Failed to set up with a token that returns CKR_ATTRIBUTE_TYPE_INVALID: %s", err)
	}
}
<commit_msg>Adding unit test for ECDSA PKCS#11 key<commit_after>// +build !nopkcs11

package pkcs11key

import (
	"bytes"
	"crypto"
	"crypto/rand"
	"github.com/miekg/pkcs11"
	"testing"
)

type mockCtx struct{}

const rsaPrivateKeyHandle = pkcs11.ObjectHandle(23)
const ecPrivateKeyHandle = pkcs11.ObjectHandle(32)
const ecPublicKeyHandle = pkcs11.ObjectHandle(33)
const sessionHandle = pkcs11.SessionHandle(17)

var slots = []uint{7, 8, 9}
var tokenInfo = pkcs11.TokenInfo{
	Label: "token label",
}
var currentSearch []*pkcs11.Attribute

func (c mockCtx) CloseSession(sh pkcs11.SessionHandle) error {
	return nil
}

func (c mockCtx) FindObjectsFinal(sh pkcs11.SessionHandle) error {
	return nil
}

func (c mockCtx) FindObjectsInit(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error {
	currentSearch = temp
	return nil
}

func (c mockCtx) FindObjects(sh pkcs11.SessionHandle, max int) ([]pkcs11.ObjectHandle, bool, error) {
	for _, a := range currentSearch {
		// We search private keys using CKA_LABEL
		if a.Type == pkcs11.CKA_LABEL {
			if a.Value[0] == 0x72 { // Label start with 'r'
				return []pkcs11.ObjectHandle{rsaPrivateKeyHandle}, true, nil
			} else if a.Value[0] == 0x65 { // Label start with 'e'
				return []pkcs11.ObjectHandle{ecPrivateKeyHandle}, true, nil
			}
		}
		// We search th EC public key using CKA_ID
		if a.Type == pkcs11.CKA_ID {
			return []pkcs11.ObjectHandle{ecPublicKeyHandle}, true, nil
		}
	}
	return nil, false, nil
}

func rsaPrivateAttributes(template []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
	var output []*pkcs11.Attribute
	for _, a := range template {
		// Return simple values for these attributes. Note that a value of `1` for
		// both modulus an public exponent would be a very bad public key, but it's
		// sufficient to satisfy the current code.
		if a.Type == pkcs11.CKA_MODULUS ||
			a.Type == pkcs11.CKA_PUBLIC_EXPONENT ||
			a.Type == pkcs11.CKA_ALWAYS_AUTHENTICATE {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: []byte{byte(1)},
			})
		}
		if a.Type == pkcs11.CKA_KEY_TYPE {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: []byte{byte(0)},
			})
		}
	}
	return output, nil
}

var ecOid = []byte{0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}

func ecPrivateAttributes(template []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
	var output []*pkcs11.Attribute
	for _, a := range template {
		if a.Type == pkcs11.CKA_EC_PARAMS {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: ecOid,
			})
		}
		if a.Type == pkcs11.CKA_KEY_TYPE ||
			a.Type == pkcs11.CKA_ID {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: []byte{byte(3)},
			})
		}
	}
	return output, nil
}

var ecPoint = []byte{0x04, 0x41, 0x04, 0x4C, 0xD7, 0x7B, 0x7B, 0x2E,
	0x3D, 0x57, 0x98, 0xB8, 0x2F, 0x99, 0xB4, 0x83,
	0x99, 0xE6, 0xD4, 0x4C, 0x4F, 0xBC, 0x2D, 0x60,
	0xCD, 0x08, 0x8E, 0x93, 0x65, 0x6F, 0x20, 0x51,
	0x1C, 0xE7, 0xFD, 0x59, 0x34, 0xAA, 0xA9, 0x36,
	0x26, 0xCE, 0x4A, 0xC5, 0xA2, 0x4A, 0x85, 0x6C,
	0xB3, 0x95, 0xFF, 0x92, 0x0F, 0x56, 0x76, 0x34,
	0x1F, 0x69, 0x52, 0x5F, 0x20, 0x83, 0x13, 0x50,
	0xA3, 0xDE, 0xBE}

func ecPublicAttributes(template []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
	var output []*pkcs11.Attribute
	for _, a := range template {
		if a.Type == pkcs11.CKA_EC_PARAMS {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: ecOid,
			})
		}
		if a.Type == pkcs11.CKA_EC_POINT {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: ecPoint,
			})
		}
		if a.Type == pkcs11.CKA_KEY_TYPE ||
			a.Type == pkcs11.CKA_ID {
			output = append(output, &pkcs11.Attribute{
				Type:  a.Type,
				Value: []byte{byte(3)},
			})
		}
	}
	return output, nil
}

func (c mockCtx) GetAttributeValue(sh pkcs11.SessionHandle, o pkcs11.ObjectHandle, template []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
	if o == rsaPrivateKeyHandle {
		return rsaPrivateAttributes(template)
	} else if o == ecPrivateKeyHandle {
		return ecPrivateAttributes(template)
	} else if o == ecPublicKeyHandle {
		return ecPublicAttributes(template)
	}
	return nil, nil
}

func (c mockCtx) GetSlotList(tokenPresent bool) ([]uint, error) {
	return slots, nil
}

func (c mockCtx) GetTokenInfo(slotID uint) (pkcs11.TokenInfo, error) {
	return tokenInfo, nil
}

func (c mockCtx) Initialize() error {
	return nil
}

func (c mockCtx) Login(sh pkcs11.SessionHandle, userType uint, pin string) error {
	return nil
}

func (c mockCtx) Logout(sh pkcs11.SessionHandle) error {
	return nil
}

func (c mockCtx) OpenSession(slotID uint, flags uint) (pkcs11.SessionHandle, error) {
	return sessionHandle, nil
}

func (c mockCtx) SignInit(sh pkcs11.SessionHandle, m []*pkcs11.Mechanism, o pkcs11.ObjectHandle) error {
	return nil
}

func (c mockCtx) Sign(sh pkcs11.SessionHandle, message []byte) ([]byte, error) {
	return []byte("some signed data"), nil
}

func TestSetup(t *testing.T) {
	ps := &Key{
		module:     mockCtx{},
		tokenLabel: "token label",
		pin:        "unused",
	}
	err := ps.setup("rsa")
	if err != nil {
		t.Errorf("Failed to set up Key: %s", err)
	}
}

func setup(t *testing.T, label string) *Key {
	ps := Key{
		module:     mockCtx{},
		tokenLabel: "token label",
		pin:        "unused",
	}
	err := ps.setup(label)
	if err != nil {
		t.Fatalf("Failed to set up Key: %s", err)
	}
	return &ps
}

func sign(t *testing.T, ps *Key) {
	// Sign input must be exactly 32 bytes to match SHA256 size. In normally
	// usage, Sign would be called by e.g. x509.CreateCertificate, which would
	// handle padding to the necessary size.
	signInput := []byte("1234567890 1234567890 1234567890")
	output, err := ps.Sign(rand.Reader, signInput, crypto.SHA256)
	if err != nil {
		t.Fatalf("Failed to sign: %s", err)
	}
	if !bytes.Equal(output, []byte("some signed data")) {
		t.Fatal("Incorrect sign output")
	}
}

func TestSign(t *testing.T) {
	ps := setup(t, "rsa")
	sign(t, ps)

	ps = setup(t, "ec")
	sign(t, ps)
}

// This is a version of the mock that gives CKR_ATTRIBUTE_TYPE_INVALID when
// asked about the CKA_ALWAYS_AUTHENTICATE attribute.
type mockCtxFailsAlwaysAuthenticate struct {
	mockCtx
}

func (c mockCtxFailsAlwaysAuthenticate) GetAttributeValue(sh pkcs11.SessionHandle, o pkcs11.ObjectHandle, template []*pkcs11.Attribute) ([]*pkcs11.Attribute, error) {
	for _, a := range template {
		if a.Type == pkcs11.CKA_ALWAYS_AUTHENTICATE {
			return nil, pkcs11.Error(pkcs11.CKR_ATTRIBUTE_TYPE_INVALID)
		}
	}
	return c.mockCtx.GetAttributeValue(sh, o, template)
}

func TestAttributeTypeInvalid(t *testing.T) {
	ps := &Key{
		module:     mockCtxFailsAlwaysAuthenticate{},
		tokenLabel: "token label",
		pin:        "unused",
	}
	err := ps.setup("rsa")
	if err != nil {
		t.Errorf("Failed to set up with a token that returns CKR_ATTRIBUTE_TYPE_INVALID: %s", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 aggregator

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/go-openapi/spec"

	"k8s.io/kube-openapi/pkg/util"
)

// usedDefinitionForSpec returns a map with all used definitions in the provided spec as keys and true as values.
func usedDefinitionForSpec(root *spec.Swagger) map[string]bool {
	usedDefinitions := map[string]bool{}
	walkOnAllReferences(func(ref *spec.Ref) {
		if refStr := ref.String(); refStr != "" && strings.HasPrefix(refStr, definitionPrefix) {
			usedDefinitions[refStr[len(definitionPrefix):]] = true
		}
	}, root)
	return usedDefinitions
}

// FilterSpecByPaths removes unnecessary paths and definitions used by those paths.
// i.e. if a Path removed by this function, all definitions used by it and not used
// anywhere else will also be removed.
func FilterSpecByPaths(sp *spec.Swagger, keepPathPrefixes []string) {
	*sp = *FilterSpecByPathsWithoutSideEffects(sp, keepPathPrefixes)
}

// FilterSpecByPathsWithoutSideEffects removes unnecessary paths and definitions used by those paths.
// i.e. if a Path removed by this function, all definitions used by it and not used
// anywhere else will also be removed.
// It does not modify the input, but the output shares data structures with the input.
func FilterSpecByPathsWithoutSideEffects(sp *spec.Swagger, keepPathPrefixes []string) *spec.Swagger {
	if sp.Paths == nil {
		return sp
	}

	// Walk all references to find all used definitions. This function
	// want to only deal with unused definitions resulted from filtering paths.
	// Thus a definition will be removed only if it has been used before but
	// it is unused because of a path prune.
	initialUsedDefinitions := usedDefinitionForSpec(sp)

	// First remove unwanted paths
	prefixes := util.NewTrie(keepPathPrefixes)
	ret := *sp
	ret.Paths = &spec.Paths{
		VendorExtensible: sp.Paths.VendorExtensible,
		Paths:            map[string]spec.PathItem{},
	}
	for path, pathItem := range sp.Paths.Paths {
		if !prefixes.HasPrefix(path) {
			continue
		}
		ret.Paths.Paths[path] = pathItem
	}

	// Walk all references to find all definition references.
	usedDefinitions := usedDefinitionForSpec(&ret)

	// Remove unused definitions
	ret.Definitions = spec.Definitions{}
	for k, v := range sp.Definitions {
		if usedDefinitions[k] || !initialUsedDefinitions[k] {
			ret.Definitions[k] = v
		}
	}

	return &ret
}

// renameDefinition renames references, without mutating the input.
// The output might share data structures with the input.
func renameDefinition(s *spec.Swagger, old, new string) *spec.Swagger {
	oldRef := definitionPrefix + old
	newRef := definitionPrefix + new

	if _, ok := s.Definitions[old]; !ok {
		return s
	}

	ret := &spec.Swagger{}
	*ret = *s

	ret = replaceReferences(func(ref *spec.Ref) *spec.Ref {
		if ref.String() == oldRef {
			ret := spec.MustCreateRef(newRef)
			return &ret
		}
		return ref
	}, ret)

	renamedDefinitions := make(spec.Definitions, len(ret.Definitions))
	for k, v := range ret.Definitions {
		if k == old {
			k = new
		}
		renamedDefinitions[k] = v
	}
	ret.Definitions = renamedDefinitions

	return ret
}

// MergeSpecsIgnorePathConflict is the same as MergeSpecs except it will ignore any path
// conflicts by keeping the paths of destination. It will rename definition conflicts.
// The source is not mutated.
func MergeSpecsIgnorePathConflict(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, true, true)
}

// MergeSpecsFailOnDefinitionConflict is differ from MergeSpecs as it fails if there is
// a definition conflict.
// The source is not mutated.
func MergeSpecsFailOnDefinitionConflict(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, false, false)
}

// MergeSpecs copies paths and definitions from source to dest, rename definitions if needed.
// dest will be mutated, and source will not be changed. It will fail on path conflicts.
// The source is not mutated.
func MergeSpecs(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, true, false)
}

// mergeSpecs merged source into dest while resolving conflicts.
// The source is not mutated.
func mergeSpecs(dest, source *spec.Swagger, renameModelConflicts, ignorePathConflicts bool) (err error) {
	// Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
	if source.Paths == nil {
		// When a source spec does not have any path, that means none of the definitions
		// are used thus we should not do anything
		return nil
	}
	if dest.Paths == nil {
		dest.Paths = &spec.Paths{}
	}
	if ignorePathConflicts {
		keepPaths := []string{}
		hasConflictingPath := false
		for k := range source.Paths.Paths {
			if _, found := dest.Paths.Paths[k]; !found {
				keepPaths = append(keepPaths, k)
			} else {
				hasConflictingPath = true
			}
		}
		if len(keepPaths) == 0 {
			// There is nothing to merge. All paths are conflicting.
			return nil
		}
		if hasConflictingPath {
			source = FilterSpecByPathsWithoutSideEffects(source, keepPaths)
		}
	}
	// Check for model conflicts
	conflicts := false
	for k, v := range source.Definitions {
		v2, found := dest.Definitions[k]
		if found && !reflect.DeepEqual(v, v2) {
			if !renameModelConflicts {
				return fmt.Errorf("model name conflict in merging OpenAPI spec: %s", k)
			}
			conflicts = true
			break
		}
	}

	if conflicts {
		usedNames := map[string]bool{}
		for k := range dest.Definitions {
			usedNames[k] = true
		}
		type Rename struct {
			from, to string
		}
		renames := []Rename{}

	OUTERLOOP:
		for k, v := range source.Definitions {
			if usedNames[k] {
				v2, found := dest.Definitions[k]
				// Reuse model if they are exactly the same.
				if found && reflect.DeepEqual(v, v2) {
					continue
				}

				// Reuse previously renamed model if one exists
				var newName string
				i := 1
				for found {
					i++
					newName = fmt.Sprintf("%s_v%d", k, i)
					v2, found = dest.Definitions[newName]
					if found && reflect.DeepEqual(v, v2) {
						renames = append(renames, Rename{from: k, to: newName})
						continue OUTERLOOP
					}
				}

				_, foundInSource := source.Definitions[newName]
				for usedNames[newName] || foundInSource {
					i++
					newName = fmt.Sprintf("%s_v%d", k, i)
					_, foundInSource = source.Definitions[newName]
				}
				renames = append(renames, Rename{from: k, to: newName})
				usedNames[newName] = true
			}
		}
		for _, r := range renames {
			source = renameDefinition(source, r.from, r.to)
		}
	}
	for k, v := range source.Definitions {
		if _, found := dest.Definitions[k]; !found {
			if dest.Definitions == nil {
				dest.Definitions = spec.Definitions{}
			}
			dest.Definitions[k] = v
		}
	}
	// Check for path conflicts
	for k, v := range source.Paths.Paths {
		if _, found := dest.Paths.Paths[k]; found {
			return fmt.Errorf("unable to merge: duplicated path %s", k)
		}
		// PathItem may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
		if dest.Paths.Paths == nil {
			dest.Paths.Paths = map[string]spec.PathItem{}
		}
		dest.Paths.Paths[k] = v
	}
	return nil
}
<commit_msg>aggregator: do conrurrent renames<commit_after>/*
Copyright 2017 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 aggregator

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/go-openapi/spec"

	"k8s.io/kube-openapi/pkg/util"
)

// usedDefinitionForSpec returns a map with all used definitions in the provided spec as keys and true as values.
func usedDefinitionForSpec(root *spec.Swagger) map[string]bool {
	usedDefinitions := map[string]bool{}
	walkOnAllReferences(func(ref *spec.Ref) {
		if refStr := ref.String(); refStr != "" && strings.HasPrefix(refStr, definitionPrefix) {
			usedDefinitions[refStr[len(definitionPrefix):]] = true
		}
	}, root)
	return usedDefinitions
}

// FilterSpecByPaths removes unnecessary paths and definitions used by those paths.
// i.e. if a Path removed by this function, all definitions used by it and not used
// anywhere else will also be removed.
func FilterSpecByPaths(sp *spec.Swagger, keepPathPrefixes []string) {
	*sp = *FilterSpecByPathsWithoutSideEffects(sp, keepPathPrefixes)
}

// FilterSpecByPathsWithoutSideEffects removes unnecessary paths and definitions used by those paths.
// i.e. if a Path removed by this function, all definitions used by it and not used
// anywhere else will also be removed.
// It does not modify the input, but the output shares data structures with the input.
func FilterSpecByPathsWithoutSideEffects(sp *spec.Swagger, keepPathPrefixes []string) *spec.Swagger {
	if sp.Paths == nil {
		return sp
	}

	// Walk all references to find all used definitions. This function
	// want to only deal with unused definitions resulted from filtering paths.
	// Thus a definition will be removed only if it has been used before but
	// it is unused because of a path prune.
	initialUsedDefinitions := usedDefinitionForSpec(sp)

	// First remove unwanted paths
	prefixes := util.NewTrie(keepPathPrefixes)
	ret := *sp
	ret.Paths = &spec.Paths{
		VendorExtensible: sp.Paths.VendorExtensible,
		Paths:            map[string]spec.PathItem{},
	}
	for path, pathItem := range sp.Paths.Paths {
		if !prefixes.HasPrefix(path) {
			continue
		}
		ret.Paths.Paths[path] = pathItem
	}

	// Walk all references to find all definition references.
	usedDefinitions := usedDefinitionForSpec(&ret)

	// Remove unused definitions
	ret.Definitions = spec.Definitions{}
	for k, v := range sp.Definitions {
		if usedDefinitions[k] || !initialUsedDefinitions[k] {
			ret.Definitions[k] = v
		}
	}

	return &ret
}

type rename struct {
	from, to string
}

// renameDefinition renames references, without mutating the input.
// The output might share data structures with the input.
func renameDefinition(s *spec.Swagger, renames map[string]string) *spec.Swagger {
	refRenames := make(map[string]string, len(renames))
	foundOne := false
	for k, v := range renames {
		refRenames[definitionPrefix+k] = definitionPrefix + v
		if _, ok := s.Definitions[k]; ok {
			foundOne = true
		}
	}

	if !foundOne {
		return s
	}

	ret := &spec.Swagger{}
	*ret = *s

	ret = replaceReferences(func(ref *spec.Ref) *spec.Ref {
		refName := ref.String()
		if newRef, found := refRenames[refName]; found {
			ret := spec.MustCreateRef(newRef)
			return &ret
		}
		return ref
	}, ret)

	renamedDefinitions := make(spec.Definitions, len(ret.Definitions))
	for k, v := range ret.Definitions {
		if newRef, found := renames[k]; found {
			k = newRef
		}
		renamedDefinitions[k] = v
	}
	ret.Definitions = renamedDefinitions

	return ret
}

// MergeSpecsIgnorePathConflict is the same as MergeSpecs except it will ignore any path
// conflicts by keeping the paths of destination. It will rename definition conflicts.
// The source is not mutated.
func MergeSpecsIgnorePathConflict(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, true, true)
}

// MergeSpecsFailOnDefinitionConflict is differ from MergeSpecs as it fails if there is
// a definition conflict.
// The source is not mutated.
func MergeSpecsFailOnDefinitionConflict(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, false, false)
}

// MergeSpecs copies paths and definitions from source to dest, rename definitions if needed.
// dest will be mutated, and source will not be changed. It will fail on path conflicts.
// The source is not mutated.
func MergeSpecs(dest, source *spec.Swagger) error {
	return mergeSpecs(dest, source, true, false)
}

// mergeSpecs merged source into dest while resolving conflicts.
// The source is not mutated.
func mergeSpecs(dest, source *spec.Swagger, renameModelConflicts, ignorePathConflicts bool) (err error) {
	// Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
	if source.Paths == nil {
		// When a source spec does not have any path, that means none of the definitions
		// are used thus we should not do anything
		return nil
	}
	if dest.Paths == nil {
		dest.Paths = &spec.Paths{}
	}
	if ignorePathConflicts {
		keepPaths := []string{}
		hasConflictingPath := false
		for k := range source.Paths.Paths {
			if _, found := dest.Paths.Paths[k]; !found {
				keepPaths = append(keepPaths, k)
			} else {
				hasConflictingPath = true
			}
		}
		if len(keepPaths) == 0 {
			// There is nothing to merge. All paths are conflicting.
			return nil
		}
		if hasConflictingPath {
			source = FilterSpecByPathsWithoutSideEffects(source, keepPaths)
		}
	}
	// Check for model conflicts
	conflicts := false
	for k, v := range source.Definitions {
		v2, found := dest.Definitions[k]
		if found && !reflect.DeepEqual(v, v2) {
			if !renameModelConflicts {
				return fmt.Errorf("model name conflict in merging OpenAPI spec: %s", k)
			}
			conflicts = true
			break
		}
	}

	if conflicts {
		usedNames := map[string]bool{}
		for k := range dest.Definitions {
			usedNames[k] = true
		}
		renames := map[string]string{}

	OUTERLOOP:
		for k, v := range source.Definitions {
			if usedNames[k] {
				v2, found := dest.Definitions[k]
				// Reuse model if they are exactly the same.
				if found && reflect.DeepEqual(v, v2) {
					continue
				}

				// Reuse previously renamed model if one exists
				var newName string
				i := 1
				for found {
					i++
					newName = fmt.Sprintf("%s_v%d", k, i)
					v2, found = dest.Definitions[newName]
					if found && reflect.DeepEqual(v, v2) {
						renames[k] = newName
						continue OUTERLOOP
					}
				}

				_, foundInSource := source.Definitions[newName]
				for usedNames[newName] || foundInSource {
					i++
					newName = fmt.Sprintf("%s_v%d", k, i)
					_, foundInSource = source.Definitions[newName]
				}
				renames[k] = newName
				usedNames[newName] = true
			}
		}
		source = renameDefinition(source, renames)
	}
	for k, v := range source.Definitions {
		if _, found := dest.Definitions[k]; !found {
			if dest.Definitions == nil {
				dest.Definitions = spec.Definitions{}
			}
			dest.Definitions[k] = v
		}
	}
	// Check for path conflicts
	for k, v := range source.Paths.Paths {
		if _, found := dest.Paths.Paths[k]; found {
			return fmt.Errorf("unable to merge: duplicated path %s", k)
		}
		// PathItem may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
		if dest.Paths.Paths == nil {
			dest.Paths.Paths = map[string]spec.PathItem{}
		}
		dest.Paths.Paths[k] = v
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 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 describe

import (
	"fmt"
	"strings"

	"github.com/spf13/cobra"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/resource"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/describe"
	"k8s.io/kubectl/pkg/util/completion"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

var (
	describeLong = templates.LongDesc(i18n.T(`
		Show details of a specific resource or group of resources.

		Print a detailed description of the selected resources, including related resources such
		as events or controllers. You may select a single object by name, all objects of that
		type, provide a name prefix, or label selector. For example:

		    $ kubectl describe TYPE NAME_PREFIX

		will first check for an exact match on TYPE and NAME_PREFIX. If no such resource
		exists, it will output details for every resource that has a name prefixed with NAME_PREFIX.`))

	describeExample = templates.Examples(i18n.T(`
		# Describe a node
		kubectl describe nodes kubernetes-node-emt8.c.myproject.internal

		# Describe a pod
		kubectl describe pods/nginx

		# Describe a pod identified by type and name in "pod.json"
		kubectl describe -f pod.json

		# Describe all pods
		kubectl describe pods

		# Describe pods by label name=myLabel
		kubectl describe po -l name=myLabel

		# Describe all pods managed by the 'frontend' replication controller
		# (rc-created pods get the name of the rc as a prefix in the pod name)
		kubectl describe pods frontend`))
)

type DescribeOptions struct {
	CmdParent string
	Selector  string
	Namespace string

	Describer  func(*meta.RESTMapping) (describe.ResourceDescriber, error)
	NewBuilder func() *resource.Builder

	BuilderArgs []string

	EnforceNamespace bool
	AllNamespaces    bool

	DescriberSettings *describe.DescriberSettings
	FilenameOptions   *resource.FilenameOptions

	genericclioptions.IOStreams
}

func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := &DescribeOptions{
		FilenameOptions: &resource.FilenameOptions{},
		DescriberSettings: &describe.DescriberSettings{
			ShowEvents: true,
			ChunkSize:  cmdutil.DefaultChunkSize,
		},

		CmdParent: parent,

		IOStreams: streams,
	}

	cmd := &cobra.Command{
		Use:                   "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Show details of a specific resource or group of resources"),
		Long:                  describeLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
		Example:               describeExample,
		ValidArgsFunction:     completion.ResourceTypeAndNameCompletionFunc(f),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}
	usage := "containing the resource to describe"
	cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
	cmdutil.AddLabelSelectorFlagVar(cmd, &o.Selector)
	cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
	cmd.Flags().BoolVar(&o.DescriberSettings.ShowEvents, "show-events", o.DescriberSettings.ShowEvents, "If true, display events related to the described object.")
	cmdutil.AddChunkSizeFlag(cmd, &o.DescriberSettings.ChunkSize)
	return cmd
}

func (o *DescribeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
	var err error
	o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	if o.AllNamespaces {
		o.EnforceNamespace = false
	}

	if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
		return fmt.Errorf("You must specify the type of resource to describe. %s\n", cmdutil.SuggestAPIResources(o.CmdParent))
	}

	o.BuilderArgs = args

	o.Describer = func(mapping *meta.RESTMapping) (describe.ResourceDescriber, error) {
		return describe.DescriberFn(f, mapping)
	}

	o.NewBuilder = f.NewBuilder

	return nil
}

func (o *DescribeOptions) Validate() error {
	return nil
}

func (o *DescribeOptions) Run() error {
	r := o.NewBuilder().
		Unstructured().
		ContinueOnError().
		NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
		FilenameParam(o.EnforceNamespace, o.FilenameOptions).
		LabelSelectorParam(o.Selector).
		ResourceTypeOrNameArgs(true, o.BuilderArgs...).
		RequestChunksOf(o.DescriberSettings.ChunkSize).
		Flatten().
		Do()
	err := r.Err()
	if err != nil {
		return err
	}

	allErrs := []error{}
	infos, err := r.Infos()
	if err != nil {
		if apierrors.IsNotFound(err) && len(o.BuilderArgs) == 2 {
			return o.DescribeMatchingResources(err, o.BuilderArgs[0], o.BuilderArgs[1])
		}
		allErrs = append(allErrs, err)
	}

	errs := sets.NewString()
	first := true
	for _, info := range infos {
		mapping := info.ResourceMapping()
		describer, err := o.Describer(mapping)
		if err != nil {
			if errs.Has(err.Error()) {
				continue
			}
			allErrs = append(allErrs, err)
			errs.Insert(err.Error())
			continue
		}
		s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
		if err != nil {
			if errs.Has(err.Error()) {
				continue
			}
			allErrs = append(allErrs, err)
			errs.Insert(err.Error())
			continue
		}
		if first {
			first = false
			fmt.Fprint(o.Out, s)
		} else {
			fmt.Fprintf(o.Out, "\n\n%s", s)
		}
	}

	if len(infos) == 0 && len(allErrs) == 0 {
		// if we wrote no output, and had no errors, be sure we output something.
		if o.AllNamespaces {
			fmt.Fprintln(o.ErrOut, "No resources found")
		} else {
			fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
		}
	}

	return utilerrors.NewAggregate(allErrs)
}

func (o *DescribeOptions) DescribeMatchingResources(originalError error, resource, prefix string) error {
	r := o.NewBuilder().
		Unstructured().
		NamespaceParam(o.Namespace).DefaultNamespace().
		ResourceTypeOrNameArgs(true, resource).
		SingleResourceType().
		RequestChunksOf(o.DescriberSettings.ChunkSize).
		Flatten().
		Do()
	mapping, err := r.ResourceMapping()
	if err != nil {
		return err
	}
	describer, err := o.Describer(mapping)
	if err != nil {
		return err
	}
	infos, err := r.Infos()
	if err != nil {
		return err
	}
	isFound := false
	for ix := range infos {
		info := infos[ix]
		if strings.HasPrefix(info.Name, prefix) {
			isFound = true
			s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
			if err != nil {
				return err
			}
			fmt.Fprintf(o.Out, "%s\n", s)
		}
	}
	if !isFound {
		return originalError
	}
	return nil
}
<commit_msg>Refactors describe command to split flags from options<commit_after>/*
Copyright 2014 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 describe

import (
	"fmt"
	"strings"

	"github.com/spf13/cobra"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/resource"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/describe"
	"k8s.io/kubectl/pkg/util/completion"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

var (
	describeLong = templates.LongDesc(i18n.T(`
		Show details of a specific resource or group of resources.

		Print a detailed description of the selected resources, including related resources such
		as events or controllers. You may select a single object by name, all objects of that
		type, provide a name prefix, or label selector. For example:

		    $ kubectl describe TYPE NAME_PREFIX

		will first check for an exact match on TYPE and NAME_PREFIX. If no such resource
		exists, it will output details for every resource that has a name prefixed with NAME_PREFIX.`))

	describeExample = templates.Examples(i18n.T(`
		# Describe a node
		kubectl describe nodes kubernetes-node-emt8.c.myproject.internal

		# Describe a pod
		kubectl describe pods/nginx

		# Describe a pod identified by type and name in "pod.json"
		kubectl describe -f pod.json

		# Describe all pods
		kubectl describe pods

		# Describe pods by label name=myLabel
		kubectl describe po -l name=myLabel

		# Describe all pods managed by the 'frontend' replication controller
		# (rc-created pods get the name of the rc as a prefix in the pod name)
		kubectl describe pods frontend`))
)

// DescribeFlags directly reflect the information that CLI is gathering via flags. They will be converted to Options,
// which reflect the runtime requirements for the command.
type DescribeFlags struct {
	Factory           cmdutil.Factory
	Selector          string
	AllNamespaces     bool
	FilenameOptions   *resource.FilenameOptions
	DescriberSettings *describe.DescriberSettings
	genericclioptions.IOStreams
}

// NewDescribeFlags returns a default DescribeFlags
func NewDescribeFlags(f cmdutil.Factory, streams genericclioptions.IOStreams) *DescribeFlags {
	return &DescribeFlags{
		Factory:         f,
		FilenameOptions: &resource.FilenameOptions{},
		DescriberSettings: &describe.DescriberSettings{
			ShowEvents: true,
			ChunkSize:  cmdutil.DefaultChunkSize,
		},
		IOStreams: streams,
	}
}

// AddFlags registers flags for a cli
func (flags *DescribeFlags) AddFlags(cmd *cobra.Command) {
	cmdutil.AddFilenameOptionFlags(cmd, flags.FilenameOptions, "containing the resource to describe")
	cmdutil.AddLabelSelectorFlagVar(cmd, &flags.Selector)
	cmd.Flags().BoolVarP(&flags.AllNamespaces, "all-namespaces", "A", flags.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
	cmd.Flags().BoolVar(&flags.DescriberSettings.ShowEvents, "show-events", flags.DescriberSettings.ShowEvents, "If true, display events related to the described object.")
	cmdutil.AddChunkSizeFlag(cmd, &flags.DescriberSettings.ChunkSize)
}

// ToOptions converts from CLI inputs to runtime input
func (flags *DescribeFlags) ToOptions(parent string, args []string) (*DescribeOptions, error) {

	var err error
	namespace, enforceNamespace, err := flags.Factory.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return nil, err
	}

	if flags.AllNamespaces {
		enforceNamespace = false
	}

	if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(flags.FilenameOptions.Filenames, flags.FilenameOptions.Kustomize) {
		return nil, fmt.Errorf("You must specify the type of resource to describe. %s\n", cmdutil.SuggestAPIResources(parent))
	}

	builderArgs := args

	describer := func(mapping *meta.RESTMapping) (describe.ResourceDescriber, error) {
		return describe.DescriberFn(flags.Factory, mapping)
	}

	o := &DescribeOptions{
		Selector:          flags.Selector,
		Namespace:         namespace,
		Describer:         describer,
		NewBuilder:        flags.Factory.NewBuilder,
		BuilderArgs:       builderArgs,
		EnforceNamespace:  enforceNamespace,
		AllNamespaces:     flags.AllNamespaces,
		FilenameOptions:   flags.FilenameOptions,
		DescriberSettings: flags.DescriberSettings,
		IOStreams:         flags.IOStreams,
	}

	return o, nil
}

func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	flags := NewDescribeFlags(f, streams)

	cmd := &cobra.Command{
		Use:                   "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Show details of a specific resource or group of resources"),
		Long:                  describeLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
		Example:               describeExample,
		ValidArgsFunction:     completion.ResourceTypeAndNameCompletionFunc(f),
		Run: func(cmd *cobra.Command, args []string) {
			o, err := flags.ToOptions(parent, args)
			cmdutil.CheckErr(err)
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}

	flags.AddFlags(cmd)

	return cmd
}

func (o *DescribeOptions) Validate() error {
	return nil
}

func (o *DescribeOptions) Run() error {
	r := o.NewBuilder().
		Unstructured().
		ContinueOnError().
		NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
		FilenameParam(o.EnforceNamespace, o.FilenameOptions).
		LabelSelectorParam(o.Selector).
		ResourceTypeOrNameArgs(true, o.BuilderArgs...).
		RequestChunksOf(o.DescriberSettings.ChunkSize).
		Flatten().
		Do()
	err := r.Err()
	if err != nil {
		return err
	}

	allErrs := []error{}
	infos, err := r.Infos()
	if err != nil {
		if apierrors.IsNotFound(err) && len(o.BuilderArgs) == 2 {
			return o.DescribeMatchingResources(err, o.BuilderArgs[0], o.BuilderArgs[1])
		}
		allErrs = append(allErrs, err)
	}

	errs := sets.NewString()
	first := true
	for _, info := range infos {
		mapping := info.ResourceMapping()
		describer, err := o.Describer(mapping)
		if err != nil {
			if errs.Has(err.Error()) {
				continue
			}
			allErrs = append(allErrs, err)
			errs.Insert(err.Error())
			continue
		}
		s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
		if err != nil {
			if errs.Has(err.Error()) {
				continue
			}
			allErrs = append(allErrs, err)
			errs.Insert(err.Error())
			continue
		}
		if first {
			first = false
			fmt.Fprint(o.Out, s)
		} else {
			fmt.Fprintf(o.Out, "\n\n%s", s)
		}
	}

	if len(infos) == 0 && len(allErrs) == 0 {
		// if we wrote no output, and had no errors, be sure we output something.
		if o.AllNamespaces {
			fmt.Fprintln(o.ErrOut, "No resources found")
		} else {
			fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
		}
	}

	return utilerrors.NewAggregate(allErrs)
}

func (o *DescribeOptions) DescribeMatchingResources(originalError error, resource, prefix string) error {
	r := o.NewBuilder().
		Unstructured().
		NamespaceParam(o.Namespace).DefaultNamespace().
		ResourceTypeOrNameArgs(true, resource).
		SingleResourceType().
		RequestChunksOf(o.DescriberSettings.ChunkSize).
		Flatten().
		Do()
	mapping, err := r.ResourceMapping()
	if err != nil {
		return err
	}
	describer, err := o.Describer(mapping)
	if err != nil {
		return err
	}
	infos, err := r.Infos()
	if err != nil {
		return err
	}
	isFound := false
	for ix := range infos {
		info := infos[ix]
		if strings.HasPrefix(info.Name, prefix) {
			isFound = true
			s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
			if err != nil {
				return err
			}
			fmt.Fprintf(o.Out, "%s\n", s)
		}
	}
	if !isFound {
		return originalError
	}
	return nil
}

type DescribeOptions struct {
	CmdParent string
	Selector  string
	Namespace string

	Describer  func(*meta.RESTMapping) (describe.ResourceDescriber, error)
	NewBuilder func() *resource.Builder

	BuilderArgs []string

	EnforceNamespace bool
	AllNamespaces    bool

	DescriberSettings *describe.DescriberSettings
	FilenameOptions   *resource.FilenameOptions

	genericclioptions.IOStreams
}
<|endoftext|>


<commit_before>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package upspin contains global interface and other definitions for the
components of the system.

Upspin provides a global hierarchical name space for accessing arbitrary
user-defined data. The interfaces for accessing and protecting data are
general: Any service that implements the interfaces defined here, whether
provided by the Upspin project itself or by an external agent that implements
these interfaces as an alternate access method, contributes to the global name
space.

The name space itself is a single rooted tree. The root of the tree contains a
subdirectory for each user, called the user root, that contains all directories
and storage for that user. The user root is identified by the user's name,
which has an email-like format. Thus the fully qualified name (called a path
name) of an item looks analogous to
	user@name.com/file/name
There is no leading slash in a path name.

There are three fundamental services defined in Upspin.

* The StoreServer is the ultimate location for user-provided data. Every piece
of user data stored in the system is identified by a Location, which identifies
where it is stored and how to address it.

* The DirServer implements the name space, binding hierarchical, Unix-like
names to Locations of data stored in StoreServers. Directories also attach
metadata to file names, which may include encryption/decryption keys or other
access-control information.

* The KeyServer stores, for each registered user, the Location of the user root
and any public encryption keys exported by that user.

Each of these three services is itself distributed, so for instance a user root
may be hosted on or split across multiple DirServer instances, which coordinate
to provide a consistent view of the user's data.

Finally, the Client interface provides a coherent high-level file-like API
that, internally, calls upon the other services to access and manage the data.
Most applications using Upspin will talk to the Client interface alone.

Many of the methods of the types in this package accept or return slices or
pointers to data structures. It is a requirement that all implementations of
these methods do not share data with the caller, that is, that data that can be
modified safely by the method or the caller without affecting the memory of the
caller or the method, respectively.
*/
package upspin
<commit_msg>upspin: fix typo in comment in previous CL<commit_after>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package upspin contains global interface and other definitions for the
components of the system.

Upspin provides a global hierarchical name space for accessing arbitrary
user-defined data. The interfaces for accessing and protecting data are
general: Any service that implements the interfaces defined here, whether
provided by the Upspin project itself or by an external agent that implements
these interfaces as an alternate access method, contributes to the global name
space.

The name space itself is a single rooted tree. The root of the tree contains a
subdirectory for each user, called the user root, that contains all directories
and storage for that user. The user root is identified by the user's name,
which has an email-like format. Thus the fully qualified name (called a path
name) of an item looks analogous to
	user@name.com/file/name
There is no leading slash in a path name.

There are three fundamental services defined in Upspin.

* The StoreServer is the ultimate location for user-provided data. Every piece
of user data stored in the system is identified by a Location, which identifies
where it is stored and how to address it.

* The DirServer implements the name space, binding hierarchical, Unix-like
names to Locations of data stored in StoreServers. Directories also attach
metadata to file names, which may include encryption/decryption keys or other
access-control information.

* The KeyServer stores, for each registered user, the Location of the user root
and any public encryption keys exported by that user.

Each of these three services is itself distributed, so for instance a user root
may be hosted on or split across multiple DirServer instances, which coordinate
to provide a consistent view of the user's data.

Finally, the Client interface provides a coherent high-level file-like API
that, internally, calls upon the other services to access and manage the data.
Most applications using Upspin will talk to the Client interface alone.

Many of the methods of the types in this package accept or return slices or
pointers to data structures. It is a requirement that all implementations of
these methods do not share data with the caller, that is, that data passed can
be modified safely by the method or the caller without affecting the memory of
the caller or the method, respectively.
*/
package upspin
<|endoftext|>


<commit_before>/*
Copyright The KubeDB 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 controller

import (
	"time"

	api "kubedb.dev/apimachinery/apis/kubedb/v1alpha1"
	cs "kubedb.dev/apimachinery/client/clientset/versioned"
	kubedbinformers "kubedb.dev/apimachinery/client/informers/externalversions"

	"github.com/appscode/go/log/golog"
	batch "k8s.io/api/batch/v1"
	crd_cs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"kmodules.xyz/client-go/tools/queue"
	appcat_cs "kmodules.xyz/custom-resources/client/clientset/versioned"
	appcat_in "kmodules.xyz/custom-resources/client/informers/externalversions"
	scs "stash.appscode.dev/stash/client/clientset/versioned"
	stashInformers "stash.appscode.dev/stash/client/informers/externalversions"
)

type Controller struct {
	ClientConfig *rest.Config
	// Kubernetes client
	Client kubernetes.Interface
	// Api Extension Client
	ApiExtKubeClient crd_cs.ApiextensionsV1beta1Interface
	// ThirdPartyExtension client
	ExtClient cs.Interface //#TODO: rename to DBClient
	// Dynamic client
	DynamicClient dynamic.Interface
	// AppCatalog client
	AppCatalogClient appcat_cs.Interface
	// StashClient for stash
	StashClient scs.Interface
}

type Config struct {
	// Informer factory
	KubeInformerFactory   informers.SharedInformerFactory
	KubedbInformerFactory kubedbinformers.SharedInformerFactory
	StashInformerFactory  stashInformers.SharedInformerFactory
	AppCatInformerFactory appcat_in.SharedInformerFactory

	// DormantDb queue
	DrmnQueue    *queue.Worker
	DrmnInformer cache.SharedIndexInformer
	// job queue
	JobQueue    *queue.Worker
	JobInformer cache.SharedIndexInformer
	// snapshot queue
	SnapQueue    *queue.Worker
	SnapInformer cache.SharedIndexInformer
	// restoreSession queue
	RSQueue    *queue.Worker
	RSInformer cache.SharedIndexInformer

	EnableRBAC              bool
	OperatorNamespace       string
	GoverningService        string
	ResyncPeriod            time.Duration
	MaxNumRequeues          int
	NumThreads              int
	LoggerOptions           golog.Options
	EnableAnalytics         bool
	AnalyticsClientID       string
	WatchNamespace          string
	EnableValidatingWebhook bool
	EnableMutatingWebhook   bool
}

type Snapshotter interface {
	ValidateSnapshot(*api.Snapshot) error
	GetDatabase(metav1.ObjectMeta) (runtime.Object, error)
	GetSnapshotter(*api.Snapshot) (*batch.Job, error)
	WipeOutSnapshot(*api.Snapshot) error
	SetDatabaseStatus(metav1.ObjectMeta, api.DatabasePhase, string) error
	UpsertDatabaseAnnotation(metav1.ObjectMeta, map[string]string) error
}

type Deleter interface {
	// WaitUntilPaused will block until db pods and service are deleted. PV/PVC will remain intact.
	WaitUntilPaused(*api.DormantDatabase) error
	// WipeOutDatabase won't need to handle snapshots and PVCs.
	// All other elements of database will be Wipedout on WipeOutDatabase function.
	// Ex: secrets, wal-g data and other staff that is required.
	WipeOutDatabase(*api.DormantDatabase) error
}
<commit_msg>Always create RBAC roles (#474)<commit_after>/*
Copyright The KubeDB 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 controller

import (
	"time"

	api "kubedb.dev/apimachinery/apis/kubedb/v1alpha1"
	cs "kubedb.dev/apimachinery/client/clientset/versioned"
	kubedbinformers "kubedb.dev/apimachinery/client/informers/externalversions"

	"github.com/appscode/go/log/golog"
	batch "k8s.io/api/batch/v1"
	crd_cs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"kmodules.xyz/client-go/tools/queue"
	appcat_cs "kmodules.xyz/custom-resources/client/clientset/versioned"
	appcat_in "kmodules.xyz/custom-resources/client/informers/externalversions"
	scs "stash.appscode.dev/stash/client/clientset/versioned"
	stashInformers "stash.appscode.dev/stash/client/informers/externalversions"
)

type Controller struct {
	ClientConfig *rest.Config
	// Kubernetes client
	Client kubernetes.Interface
	// Api Extension Client
	ApiExtKubeClient crd_cs.ApiextensionsV1beta1Interface
	// ThirdPartyExtension client
	ExtClient cs.Interface //#TODO: rename to DBClient
	// Dynamic client
	DynamicClient dynamic.Interface
	// AppCatalog client
	AppCatalogClient appcat_cs.Interface
	// StashClient for stash
	StashClient scs.Interface
}

type Config struct {
	// Informer factory
	KubeInformerFactory   informers.SharedInformerFactory
	KubedbInformerFactory kubedbinformers.SharedInformerFactory
	StashInformerFactory  stashInformers.SharedInformerFactory
	AppCatInformerFactory appcat_in.SharedInformerFactory

	// DormantDb queue
	DrmnQueue    *queue.Worker
	DrmnInformer cache.SharedIndexInformer
	// job queue
	JobQueue    *queue.Worker
	JobInformer cache.SharedIndexInformer
	// snapshot queue
	SnapQueue    *queue.Worker
	SnapInformer cache.SharedIndexInformer
	// restoreSession queue
	RSQueue    *queue.Worker
	RSInformer cache.SharedIndexInformer

	OperatorNamespace       string
	GoverningService        string
	ResyncPeriod            time.Duration
	MaxNumRequeues          int
	NumThreads              int
	LoggerOptions           golog.Options
	EnableAnalytics         bool
	AnalyticsClientID       string
	WatchNamespace          string
	EnableValidatingWebhook bool
	EnableMutatingWebhook   bool
}

type Snapshotter interface {
	ValidateSnapshot(*api.Snapshot) error
	GetDatabase(metav1.ObjectMeta) (runtime.Object, error)
	GetSnapshotter(*api.Snapshot) (*batch.Job, error)
	WipeOutSnapshot(*api.Snapshot) error
	SetDatabaseStatus(metav1.ObjectMeta, api.DatabasePhase, string) error
	UpsertDatabaseAnnotation(metav1.ObjectMeta, map[string]string) error
}

type Deleter interface {
	// WaitUntilPaused will block until db pods and service are deleted. PV/PVC will remain intact.
	WaitUntilPaused(*api.DormantDatabase) error
	// WipeOutDatabase won't need to handle snapshots and PVCs.
	// All other elements of database will be Wipedout on WipeOutDatabase function.
	// Ex: secrets, wal-g data and other staff that is required.
	WipeOutDatabase(*api.DormantDatabase) error
}
<|endoftext|>