<commit_before>package main

import (
	mqttc "./utils/mqtt"
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	geoipc "github.com/rubiojr/freegeoip-client"
	"gopkg.in/alecthomas/kingpin.v1"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

type Host struct {
	IP          string  `json:"ip"`
	Name        string  `json:"hostname"`
	Hop         int     `json:"hop-number"`
	Sent        int     `json:"sent"`
	LostPercent float64 `json:"lost-percent"`
	Last        float64 `json:"mean"`
	Avg         float64 `json:"mean"`
	Best        float64 `json:"best"`
	Worst       float64 `json:"worst"`
	StDev       float64 `json:"standard-dev"`
}

type Report struct {
	Time        time.Time       `json:"time"`
	Hosts       []*Host         `json:"hosts"`
	Hops        int             `json:"hops"`
	ElapsedTime time.Duration   `json:"elapsed_time"`
	Location    geoipc.Location `json:"location"`
}

func NewReport(reportCycles int, host string, args ...string) *Report {
	report := &Report{}
	report.Time = time.Now()
	args = append([]string{"--report", "-n", "-c", strconv.Itoa(reportCycles), host}, args...)

	tstart := time.Now()
	mtr := findMtrBin()
	rawOutput, err := exec.Command(mtr, args...).Output()

	if err != nil {
		panic("Error running the mtr command")
	}

	buf := bytes.NewBuffer(rawOutput)
	scanner := bufio.NewScanner(buf)
	scanner.Split(bufio.ScanLines)

	skipHeader := 2
	for scanner.Scan() {
		if skipHeader != 0 {
			skipHeader -= 1
			continue
		}

		tokens := strings.Fields(scanner.Text())
		sent, err := strconv.Atoi(tokens[3])
		if err != nil {
			panic("Error parsing sent field")
		}

		host := Host{
			IP:   tokens[1],
			Sent: sent,
		}

		f2F(strings.Replace(tokens[2], "%", "", -1), &host.LostPercent)
		f2F(tokens[4], &host.Last)
		f2F(tokens[5], &host.Avg)
		f2F(tokens[6], &host.Best)
		f2F(tokens[7], &host.Worst)
		f2F(tokens[8], &host.StDev)

		report.Hosts = append(report.Hosts, &host)
	}

	report.Hops = len(report.Hosts)
	report.ElapsedTime = time.Since(tstart)
	loc, err := geoipc.GetLocation()
	if err != nil {
		report.Location = geoipc.Location{}
	} else {
		report.Location = loc
	}

	return report
}

func f2F(val string, field *float64) {
	f, err := strconv.ParseFloat(val, 64)
	*field = f
	if err != nil {
		panic("Error parsing field")
	}
}

func findMtrBin() string {
	paths := os.Getenv("PATH")
	if paths == "" {
		return ""
	}

	for _, path := range strings.Split(paths, ":") {
		if _, err := os.Stat(path + "/mtr"); err == nil {
			return path + "/mtr"
		}
	}

	return ""
}

func run(count int, host, brokerUrl, topic string, stdout bool) error {
	r := NewReport(count, host)

	if stdout {
		msg, _ := json.MarshalIndent(r, "", "  ")
		fmt.Println(string(msg))
		return nil
	} else {
		msg, _ := json.Marshal(r)
		err := mqttc.PushMsg("push-mtr", brokerUrl, topic, string(msg))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error sending report: %s\n", err)
		}
		return err
	}
}

func main() {
	count := kingpin.Flag("count", "Report cycles (mtr -c)").
		Default("10").Int()

	topic := kingpin.Flag("topic", "MTTQ topic").Default("/metrics/mtr").
		String()

	host := kingpin.Arg("host", "Target host").Required().String()

	repeat := kingpin.Flag("repeat", "Send the report every X seconds").
		Default("0").Int()

	brokerUrl := kingpin.Flag("broker-url", "MQTT broker URL").
		Default("").String()

	stdout := kingpin.Flag("stdout", "Print the report to stdout").
		Default("false").Bool()

	kingpin.Version("0.1")
	kingpin.Parse()

	if findMtrBin() == "" {
		fmt.Fprintf(os.Stderr, "mtr binary not found in path\n")
		os.Exit(1)
	}

	if *brokerUrl == "" {
		*brokerUrl = os.Getenv("MQTT_URL")
		if *brokerUrl == "" {
			fmt.Fprintf(os.Stderr, "Invalid MQTT broker URL\n")
			os.Exit(1)
		}
	}

	if *repeat != 0 {
		timer := time.NewTicker(1 * time.Second)
		for _ = range timer.C {
			run(*count, *host, *brokerUrl, *topic, *stdout)
		}
	} else {
		err := run(*count, *host, *brokerUrl, *topic, *stdout)
		if err != nil {
			os.Exit(1)
		}
	}
}
<commit_msg>repeat value was being ignored<commit_after>package main

import (
	mqttc "./utils/mqtt"
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	geoipc "github.com/rubiojr/freegeoip-client"
	"gopkg.in/alecthomas/kingpin.v1"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

type Host struct {
	IP          string  `json:"ip"`
	Name        string  `json:"hostname"`
	Hop         int     `json:"hop-number"`
	Sent        int     `json:"sent"`
	LostPercent float64 `json:"lost-percent"`
	Last        float64 `json:"mean"`
	Avg         float64 `json:"mean"`
	Best        float64 `json:"best"`
	Worst       float64 `json:"worst"`
	StDev       float64 `json:"standard-dev"`
}

type Report struct {
	Time        time.Time       `json:"time"`
	Hosts       []*Host         `json:"hosts"`
	Hops        int             `json:"hops"`
	ElapsedTime time.Duration   `json:"elapsed_time"`
	Location    geoipc.Location `json:"location"`
}

func NewReport(reportCycles int, host string, args ...string) *Report {
	report := &Report{}
	report.Time = time.Now()
	args = append([]string{"--report", "-n", "-c", strconv.Itoa(reportCycles), host}, args...)

	tstart := time.Now()
	mtr := findMtrBin()
	rawOutput, err := exec.Command(mtr, args...).Output()

	if err != nil {
		panic("Error running the mtr command")
	}

	buf := bytes.NewBuffer(rawOutput)
	scanner := bufio.NewScanner(buf)
	scanner.Split(bufio.ScanLines)

	skipHeader := 2
	for scanner.Scan() {
		if skipHeader != 0 {
			skipHeader -= 1
			continue
		}

		tokens := strings.Fields(scanner.Text())
		sent, err := strconv.Atoi(tokens[3])
		if err != nil {
			panic("Error parsing sent field")
		}

		host := Host{
			IP:   tokens[1],
			Sent: sent,
		}

		f2F(strings.Replace(tokens[2], "%", "", -1), &host.LostPercent)
		f2F(tokens[4], &host.Last)
		f2F(tokens[5], &host.Avg)
		f2F(tokens[6], &host.Best)
		f2F(tokens[7], &host.Worst)
		f2F(tokens[8], &host.StDev)

		report.Hosts = append(report.Hosts, &host)
	}

	report.Hops = len(report.Hosts)
	report.ElapsedTime = time.Since(tstart)
	loc, err := geoipc.GetLocation()
	if err != nil {
		report.Location = geoipc.Location{}
	} else {
		report.Location = loc
	}

	return report
}

func f2F(val string, field *float64) {
	f, err := strconv.ParseFloat(val, 64)
	*field = f
	if err != nil {
		panic("Error parsing field")
	}
}

func findMtrBin() string {
	paths := os.Getenv("PATH")
	if paths == "" {
		return ""
	}

	for _, path := range strings.Split(paths, ":") {
		if _, err := os.Stat(path + "/mtr"); err == nil {
			return path + "/mtr"
		}
	}

	return ""
}

func run(count int, host, brokerUrl, topic string, stdout bool) error {
	r := NewReport(count, host)

	if stdout {
		msg, _ := json.MarshalIndent(r, "", "  ")
		fmt.Println(string(msg))
		return nil
	} else {
		msg, _ := json.Marshal(r)
		err := mqttc.PushMsg("push-mtr", brokerUrl, topic, string(msg))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error sending report: %s\n", err)
		}
		return err
	}
}

func main() {
	count := kingpin.Flag("count", "Report cycles (mtr -c)").
		Default("10").Int()

	topic := kingpin.Flag("topic", "MTTQ topic").Default("/metrics/mtr").
		String()

	host := kingpin.Arg("host", "Target host").Required().String()

	repeat := kingpin.Flag("repeat", "Send the report every X seconds").
		Default("0").Int()

	brokerUrl := kingpin.Flag("broker-url", "MQTT broker URL").
		Default("").String()

	stdout := kingpin.Flag("stdout", "Print the report to stdout").
		Default("false").Bool()

	kingpin.Version("0.1")
	kingpin.Parse()

	if findMtrBin() == "" {
		fmt.Fprintf(os.Stderr, "mtr binary not found in path\n")
		os.Exit(1)
	}

	if *brokerUrl == "" {
		*brokerUrl = os.Getenv("MQTT_URL")
		if *brokerUrl == "" {
			fmt.Fprintf(os.Stderr, "Invalid MQTT broker URL\n")
			os.Exit(1)
		}
	}

	if *repeat != 0 {
		timer := time.NewTicker(time.Duration(*repeat) * time.Second)
		for _ = range timer.C {
			run(*count, *host, *brokerUrl, *topic, *stdout)
		}
	} else {
		err := run(*count, *host, *brokerUrl, *topic, *stdout)
		if err != nil {
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/AlekSi/zabbix"
	"github.com/AlekSi/zabbix-sender"
	anomalydetector "github.com/chobie/go-anomalydetector"
	"net"
	"os"
	"strconv"
	"time"
)

type ChangeFinder struct {
	O         *anomalydetector.AnomalyDetector
	S         *anomalydetector.AnomalyDetector
	Smooth    int
	Last      float64
	LastScore float64
	Buffer    []float64
	Buffer2   []float64
}

func sum(array *[]float64) float64 {
	sum := 0.0
	for _, value := range *array {
		sum += value
	}
	return sum
}

func (finder *ChangeFinder) Update(v float64) float64 {
	var score float64 = 0.0

	if v == finder.Last && finder.LastScore < 3.0 {
		score = finder.LastScore
	} else {
		r := finder.O.Update(v)
		finder.Buffer = append(finder.Buffer, r)

		if len(finder.Buffer) > finder.Smooth {
			finder.Buffer = finder.Buffer[1:]
		}

		score = finder.S.Update(sum(&finder.Buffer) / float64(len(finder.Buffer)))
	}

	finder.Last = v
	finder.LastScore = score

	return finder.LastScore
}

func NewChangePoint(outlier_term int, outlier_discount float64, score_term int, score_discount float64, smooth_term int) *ChangeFinder {
	v := ChangeFinder{}
	v.O = anomalydetector.NewAnomalyDetector(outlier_term, outlier_discount)
	v.S = anomalydetector.NewAnomalyDetector(score_term, score_discount)
	v.Smooth = smooth_term

	return &v
}

func main() {
	var zabbix_host, zabbix_port, zabbix_api_url, zabbix_user, zabbix_password, itemid string
	var value_type, host_name, orig_item_key, orig_item_delay string
	var interval, from_time, num int64
	var send_data []zabbix_sender.DataItem
	var outlier_term, score_term, smooth_term int
	var outlier_discount, score_discount float64
	var item_prefix string
	// Set Option
	flag.StringVar(&zabbix_host, "host", "localhost", "Set zabbix host name")
	flag.StringVar(&zabbix_host, "h", "localhost", "Set zabbix host name")
	flag.StringVar(&zabbix_port, "port", "10051", "Set zabbix host port")
	flag.StringVar(&zabbix_port, "p", "10051", "Set zabbix host port")
	flag.StringVar(&zabbix_api_url, "url", "http://"+zabbix_host+"/zabbix/api_jsonrpc.php", "Set zabbix api url")
	flag.StringVar(&zabbix_api_url, "u", "http://"+zabbix_host+"/zabbix/api_jsonrpc.php", "Set zabbix api url")
	flag.StringVar(&zabbix_user, "user", "Admin", "Set zabbix login username")
	flag.StringVar(&zabbix_password, "pass", "zabbix", "Set zabbix login user password")
	flag.StringVar(&zabbix_password, "password", "zabbix", "Set zabbix login user password")
	flag.StringVar(&itemid, "itemid", "10000", "Set target zabbix item id")
	flag.StringVar(&itemid, "i", "10000", "Set target zabbix item id")
	flag.Int64Var(&interval, "interval", 300, "Set monitoring interval")
	flag.IntVar(&outlier_term, "outlier_term", 5, "Set outlier_term num")
	flag.IntVar(&score_term, "score_term", 5, "Set score_term num")
	flag.IntVar(&smooth_term, "smooth_term", 5, "Set smooth_term num")
	flag.Float64Var(&outlier_discount, "outlier_discount", 0.02, "Set outlier_discount value")
	flag.Float64Var(&score_discount, "scoure_discount", 0.02, "Set score_discount value")
	flag.Int64Var(&num, "num", 30, "Set evaluation datapoint num")
	flag.Int64Var(&num, "n", 30, "Set evaluation datapoint num")
	flag.StringVar(&item_prefix, "prefix", "anomaly", "Set registered trapper item key prefix")
	flag.Parse()

	api := zabbix.NewAPI(zabbix_api_url)
	_, err := api.Login(zabbix_user, zabbix_password)
	if err != nil {
		fmt.Printf("[ERROR]: zabbix api login error: %s", err)
		os.Exit(1)
	}
	now := time.Now().Unix()

	// Get orig item info
	item_response, err := api.Call("item.get", zabbix.Params{"itemids": itemid, "selectHosts": "extend", "output": "extend"})
	if err != nil {
		fmt.Printf("[ERROR]: zabbix api item.get error: %s", err)
		os.Exit(1)
	}
	for _, item := range item_response.Result.([]interface{}) {
		value_type = item.(map[string]interface{})["value_type"].(string)
		orig_item_key = item.(map[string]interface{})["key_"].(string)
		orig_item_delay = item.(map[string]interface{})["delay"].(string)
		int64_delay, _ := strconv.ParseInt(orig_item_delay, 10, 64)
		from_time = now - int64_delay*num

		for _, host := range item.(map[string]interface{})["hosts"].([]interface{}) {
			host_name = host.(map[string]interface{})["host"].(string)
		}
	}

	//fmt.Println(item_response)
	//fmt.Println(host_name)
	//fmt.Println(value_type)
	// Get Zabbix History
	response, _ := api.Call("history.get", zabbix.Params{"history": value_type, "itemids": itemid, "time_from": from_time, "time_till": now, "output": "extend"})
	//cp := NewChangePoint(12, 0.0275, 6, 0.1, 12)
	//cp := NewChangePoint(5, 0.02, 5, 0.02, 5)
	cp := NewChangePoint(outlier_term, outlier_discount, score_term, score_discount, smooth_term)
	//cp := NewChangePoint(7, 0.5, 28, 0.01, 7)
	for _, history := range response.Result.([]interface{}) {
		clock := history.(map[string]interface{})["clock"].(string)
		value := history.(map[string]interface{})["value"].(string)
		value_float64, err := strconv.ParseFloat(value, 64)
		if err != nil {
			panic(err)
		}
		score := cp.Update(value_float64)
		int64_clock, _ := strconv.ParseInt(clock, 10, 64)
		if int64_clock > time.Now().Unix()-interval {
			send_data = append(send_data, zabbix_sender.DataItem{Hostname: host_name, Key: item_prefix + "." + orig_item_key, Value: strconv.FormatFloat(score, 'f', 10, 64), Timestamp: int64_clock})
		}
		fmt.Printf("%s\t%s\t%f\n", clock, value, score)
	}
	addr, _ := net.ResolveTCPAddr("tcp", zabbix_host+":"+zabbix_port)
	res, err := zabbix_sender.Send(addr, send_data)
	if err != nil {
		fmt.Printf("[ERROR]: zabbix sender error!: %s", err)
		os.Exit(1)
	}
	fmt.Printf("[INFO]: Successful sending data to Zabbix: %s", res)
}
<commit_msg>fix typo<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/AlekSi/zabbix"
	"github.com/AlekSi/zabbix-sender"
	anomalydetector "github.com/chobie/go-anomalydetector"
	"net"
	"os"
	"strconv"
	"time"
)

type ChangeFinder struct {
	O         *anomalydetector.AnomalyDetector
	S         *anomalydetector.AnomalyDetector
	Smooth    int
	Last      float64
	LastScore float64
	Buffer    []float64
	Buffer2   []float64
}

func sum(array *[]float64) float64 {
	sum := 0.0
	for _, value := range *array {
		sum += value
	}
	return sum
}

func (finder *ChangeFinder) Update(v float64) float64 {
	var score float64 = 0.0

	if v == finder.Last && finder.LastScore < 3.0 {
		score = finder.LastScore
	} else {
		r := finder.O.Update(v)
		finder.Buffer = append(finder.Buffer, r)

		if len(finder.Buffer) > finder.Smooth {
			finder.Buffer = finder.Buffer[1:]
		}

		score = finder.S.Update(sum(&finder.Buffer) / float64(len(finder.Buffer)))
	}

	finder.Last = v
	finder.LastScore = score

	return finder.LastScore
}

func NewChangePoint(outlier_term int, outlier_discount float64, score_term int, score_discount float64, smooth_term int) *ChangeFinder {
	v := ChangeFinder{}
	v.O = anomalydetector.NewAnomalyDetector(outlier_term, outlier_discount)
	v.S = anomalydetector.NewAnomalyDetector(score_term, score_discount)
	v.Smooth = smooth_term

	return &v
}

func main() {
	var zabbix_host, zabbix_port, zabbix_api_url, zabbix_user, zabbix_password, itemid string
	var value_type, host_name, orig_item_key, orig_item_delay string
	var interval, from_time, num int64
	var send_data []zabbix_sender.DataItem
	var outlier_term, score_term, smooth_term int
	var outlier_discount, score_discount float64
	var item_prefix string
	// Set Option
	flag.StringVar(&zabbix_host, "host", "localhost", "Set zabbix host name")
	flag.StringVar(&zabbix_host, "h", "localhost", "Set zabbix host name")
	flag.StringVar(&zabbix_port, "port", "10051", "Set zabbix host port")
	flag.StringVar(&zabbix_port, "p", "10051", "Set zabbix host port")
	flag.StringVar(&zabbix_api_url, "url", "http://"+zabbix_host+"/zabbix/api_jsonrpc.php", "Set zabbix api url")
	flag.StringVar(&zabbix_api_url, "u", "http://"+zabbix_host+"/zabbix/api_jsonrpc.php", "Set zabbix api url")
	flag.StringVar(&zabbix_user, "user", "Admin", "Set zabbix login username")
	flag.StringVar(&zabbix_password, "pass", "zabbix", "Set zabbix login user password")
	flag.StringVar(&zabbix_password, "password", "zabbix", "Set zabbix login user password")
	flag.StringVar(&itemid, "itemid", "10000", "Set target zabbix item id")
	flag.StringVar(&itemid, "i", "10000", "Set target zabbix item id")
	flag.Int64Var(&interval, "interval", 300, "Set monitoring interval")
	flag.IntVar(&outlier_term, "outlier_term", 5, "Set outlier_term num")
	flag.IntVar(&score_term, "score_term", 5, "Set score_term num")
	flag.IntVar(&smooth_term, "smooth_term", 5, "Set smooth_term num")
	flag.Float64Var(&outlier_discount, "outlier_discount", 0.02, "Set outlier_discount value")
	flag.Float64Var(&score_discount, "score_discount", 0.02, "Set score_discount value")
	flag.Int64Var(&num, "num", 30, "Set evaluation datapoint num")
	flag.Int64Var(&num, "n", 30, "Set evaluation datapoint num")
	flag.StringVar(&item_prefix, "prefix", "anomaly", "Set registered trapper item key prefix")
	flag.Parse()

	api := zabbix.NewAPI(zabbix_api_url)
	_, err := api.Login(zabbix_user, zabbix_password)
	if err != nil {
		fmt.Printf("[ERROR]: zabbix api login error: %s", err)
		os.Exit(1)
	}
	now := time.Now().Unix()

	// Get orig item info
	item_response, err := api.Call("item.get", zabbix.Params{"itemids": itemid, "selectHosts": "extend", "output": "extend"})
	if err != nil {
		fmt.Printf("[ERROR]: zabbix api item.get error: %s", err)
		os.Exit(1)
	}
	for _, item := range item_response.Result.([]interface{}) {
		value_type = item.(map[string]interface{})["value_type"].(string)
		orig_item_key = item.(map[string]interface{})["key_"].(string)
		orig_item_delay = item.(map[string]interface{})["delay"].(string)
		int64_delay, _ := strconv.ParseInt(orig_item_delay, 10, 64)
		from_time = now - int64_delay*num

		for _, host := range item.(map[string]interface{})["hosts"].([]interface{}) {
			host_name = host.(map[string]interface{})["host"].(string)
		}
	}

	//fmt.Println(item_response)
	//fmt.Println(host_name)
	//fmt.Println(value_type)
	// Get Zabbix History
	response, _ := api.Call("history.get", zabbix.Params{"history": value_type, "itemids": itemid, "time_from": from_time, "time_till": now, "output": "extend"})
	//cp := NewChangePoint(12, 0.0275, 6, 0.1, 12)
	//cp := NewChangePoint(5, 0.02, 5, 0.02, 5)
	cp := NewChangePoint(outlier_term, outlier_discount, score_term, score_discount, smooth_term)
	//cp := NewChangePoint(7, 0.5, 28, 0.01, 7)
	for _, history := range response.Result.([]interface{}) {
		clock := history.(map[string]interface{})["clock"].(string)
		value := history.(map[string]interface{})["value"].(string)
		value_float64, err := strconv.ParseFloat(value, 64)
		if err != nil {
			panic(err)
		}
		score := cp.Update(value_float64)
		int64_clock, _ := strconv.ParseInt(clock, 10, 64)
		if int64_clock > time.Now().Unix()-interval {
			send_data = append(send_data, zabbix_sender.DataItem{Hostname: host_name, Key: item_prefix + "." + orig_item_key, Value: strconv.FormatFloat(score, 'f', 10, 64), Timestamp: int64_clock})
		}
		fmt.Printf("%s\t%s\t%f\n", clock, value, score)
	}
	addr, _ := net.ResolveTCPAddr("tcp", zabbix_host+":"+zabbix_port)
	res, err := zabbix_sender.Send(addr, send_data)
	if err != nil {
		fmt.Printf("[ERROR]: zabbix sender error!: %s", err)
		os.Exit(1)
	}
	fmt.Printf("[INFO]: Successful sending data to Zabbix: %s", res)
}
<|endoftext|>


<commit_before>/*
 * Minimalist Object Storage, (C) 2015 Minio, Inc.
 *
 * 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 quota

import (
	"encoding/binary"
	"net"
	"sync"
	"time"
)

// map[minute][address] = current quota
type quotaMap struct {
	sync.RWMutex
	data        map[int64]map[uint32]int64
	limit       int64
	duration    time.Duration
	segmentSize time.Duration
}

func (q *quotaMap) CanExpire() {
	currentMinute := time.Now().UnixNano() / q.segmentSize.Nanoseconds()
	// divide by segmentSize, otherwise expiredQuotas will always be negative
	expiredQuotas := currentMinute - (q.duration.Nanoseconds() / q.segmentSize.Nanoseconds())
	for time := range q.data {
		if time < expiredQuotas {
			delete(q.data, time)
		}
	}
}

func (q *quotaMap) Add(ip uint32, size int64) {
	q.Lock()
	defer q.Unlock()
	q.CanExpire()
	currentMinute := time.Now().UnixNano() / q.segmentSize.Nanoseconds()
	if _, ok := q.data[currentMinute]; !ok {
		q.data[currentMinute] = make(map[uint32]int64)
	}
	currentData, _ := q.data[currentMinute][ip]
	proposedDataSize := currentData + size
	q.data[currentMinute][ip] = proposedDataSize
}

func (q *quotaMap) IsQuotaMet(ip uint32) bool {
	q.CanExpire()
	if q.GetQuotaUsed(ip) >= q.limit {
		return true
	}
	return false
}

func (q *quotaMap) GetQuotaUsed(ip uint32) (total int64) {
	currentMinute := time.Now().UnixNano() / q.segmentSize.Nanoseconds()
	if _, ok := q.data[currentMinute]; !ok {
		q.data[currentMinute] = make(map[uint32]int64)
	}
	for _, segment := range q.data {
		if used, ok := segment[ip]; ok {
			total += used
		}
	}
	return
}

func (q *quotaMap) WillExceedQuota(ip uint32, size int64) (result bool) {
	return q.GetQuotaUsed(ip)+size > q.limit
}

type longIP struct {
	net.IP
}

// []byte to uint32 representation
func (p longIP) IptoUint32() (result uint32) {
	ip := p.To4()
	if ip == nil {
		return 0
	}
	return binary.BigEndian.Uint32(ip)
}
<commit_msg>Critical sections are now protected by lock<commit_after>/*
 * Minimalist Object Storage, (C) 2015 Minio, Inc.
 *
 * 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 quota

import (
	"encoding/binary"
	"net"
	"sync"
	"time"
)

// map[minute][address] = current quota
type quotaMap struct {
	sync.RWMutex
	data        map[int64]map[uint32]int64
	limit       int64
	duration    time.Duration
	segmentSize time.Duration
}

func (q *quotaMap) CanExpire() {
	q.Lock()
	defer q.Unlock()
	currentMinute := time.Now().UnixNano() / q.segmentSize.Nanoseconds()
	// divide by segmentSize, otherwise expiredQuotas will always be negative
	expiredQuotas := currentMinute - (q.duration.Nanoseconds() / q.segmentSize.Nanoseconds())
	for time := range q.data {
		if time < expiredQuotas {
			delete(q.data, time)
		}
	}
}

func (q *quotaMap) Add(ip uint32, size int64) {
	q.CanExpire()
	q.Lock()
	defer q.Unlock()
	currentMinute := time.Now().UnixNano() / q.segmentSize.Nanoseconds()
	if _, ok := q.data[currentMinute]; !ok {
		q.data[currentMinute] = make(map[uint32]int64)
	}
	currentData, _ := q.data[currentMinute][ip]
	proposedDataSize := currentData + size
	q.data[currentMinute][ip] = proposedDataSize
}

func (q *quotaMap) IsQuotaMet(ip uint32) bool {
	q.CanExpire()
	if q.GetQuotaUsed(ip) >= q.limit {
		return true
	}
	return false
}

func (q *quotaMap) GetQuotaUsed(ip uint32) (total int64) {
	q.CanExpire()
	q.RLock()
	defer q.RUnlock()
	for _, segment := range q.data {
		if used, ok := segment[ip]; ok {
			total += used
		}
	}
	return
}

func (q *quotaMap) WillExceedQuota(ip uint32, size int64) (result bool) {
	return q.GetQuotaUsed(ip)+size > q.limit
}

type longIP struct {
	net.IP
}

// []byte to uint32 representation
func (p longIP) IptoUint32() (result uint32) {
	ip := p.To4()
	if ip == nil {
		return 0
	}
	return binary.BigEndian.Uint32(ip)
}
<|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 v1

import (
	"time"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Returns string version of ResourceName.
func (self ResourceName) String() string {
	return string(self)
}

// Returns the CPU limit if specified.
func (self *ResourceList) Cpu() *resource.Quantity {
	if val, ok := (*self)[ResourceCPU]; ok {
		return &val
	}
	return &resource.Quantity{Format: resource.DecimalSI}
}

// Returns the Memory limit if specified.
func (self *ResourceList) Memory() *resource.Quantity {
	if val, ok := (*self)[ResourceMemory]; ok {
		return &val
	}
	return &resource.Quantity{Format: resource.BinarySI}
}

func (self *ResourceList) Pods() *resource.Quantity {
	if val, ok := (*self)[ResourcePods]; ok {
		return &val
	}
	return &resource.Quantity{}
}

func (self *ResourceList) NvidiaGPU() *resource.Quantity {
	if val, ok := (*self)[ResourceNvidiaGPU]; ok {
		return &val
	}
	return &resource.Quantity{}
}

func GetContainerStatus(statuses []ContainerStatus, name string) (ContainerStatus, bool) {
	for i := range statuses {
		if statuses[i].Name == name {
			return statuses[i], true
		}
	}
	return ContainerStatus{}, false
}

func GetExistingContainerStatus(statuses []ContainerStatus, name string) ContainerStatus {
	for i := range statuses {
		if statuses[i].Name == name {
			return statuses[i]
		}
	}
	return ContainerStatus{}
}

// IsPodAvailable returns true if a pod is available; false otherwise.
// Precondition for an available pod is that it must be ready. On top
// of that, there are two cases when a pod can be considered available:
// 1. minReadySeconds == 0, or
// 2. LastTransitionTime (is set) + minReadySeconds < current time
func IsPodAvailable(pod *Pod, minReadySeconds int32, now metav1.Time) bool {
	if !IsPodReady(pod) {
		return false
	}

	c := GetPodReadyCondition(pod.Status)
	minReadySecondsDuration := time.Duration(minReadySeconds) * time.Second
	if minReadySeconds == 0 || !c.LastTransitionTime.IsZero() && c.LastTransitionTime.Add(minReadySecondsDuration).Before(now.Time) {
		return true
	}
	return false
}

// IsPodReady returns true if a pod is ready; false otherwise.
func IsPodReady(pod *Pod) bool {
	return IsPodReadyConditionTrue(pod.Status)
}

// IsPodReady retruns true if a pod is ready; false otherwise.
func IsPodReadyConditionTrue(status PodStatus) bool {
	condition := GetPodReadyCondition(status)
	return condition != nil && condition.Status == ConditionTrue
}

// Extracts the pod ready condition from the given status and returns that.
// Returns nil if the condition is not present.
func GetPodReadyCondition(status PodStatus) *PodCondition {
	_, condition := GetPodCondition(&status, PodReady)
	return condition
}

// GetPodCondition extracts the provided condition from the given status and returns that.
// Returns nil and -1 if the condition is not present, and the index of the located condition.
func GetPodCondition(status *PodStatus, conditionType PodConditionType) (int, *PodCondition) {
	if status == nil {
		return -1, nil
	}
	for i := range status.Conditions {
		if status.Conditions[i].Type == conditionType {
			return i, &status.Conditions[i]
		}
	}
	return -1, nil
}

// GetNodeCondition extracts the provided condition from the given status and returns that.
// Returns nil and -1 if the condition is not present, and the index of the located condition.
func GetNodeCondition(status *NodeStatus, conditionType NodeConditionType) (int, *NodeCondition) {
	if status == nil {
		return -1, nil
	}
	for i := range status.Conditions {
		if status.Conditions[i].Type == conditionType {
			return i, &status.Conditions[i]
		}
	}
	return -1, nil
}

// Updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
// status has changed.
// Returns true if pod condition has changed or has been added.
func UpdatePodCondition(status *PodStatus, condition *PodCondition) bool {
	condition.LastTransitionTime = metav1.Now()
	// Try to find this pod condition.
	conditionIndex, oldCondition := GetPodCondition(status, condition.Type)

	if oldCondition == nil {
		// We are adding new pod condition.
		status.Conditions = append(status.Conditions, *condition)
		return true
	} else {
		// We are updating an existing condition, so we need to check if it has changed.
		if condition.Status == oldCondition.Status {
			condition.LastTransitionTime = oldCondition.LastTransitionTime
		}

		isEqual := condition.Status == oldCondition.Status &&
			condition.Reason == oldCondition.Reason &&
			condition.Message == oldCondition.Message &&
			condition.LastProbeTime.Equal(oldCondition.LastProbeTime) &&
			condition.LastTransitionTime.Equal(oldCondition.LastTransitionTime)

		status.Conditions[conditionIndex] = *condition
		// Return true if one of the fields have changed.
		return !isEqual
	}
}

// IsNodeReady returns true if a node is ready; false otherwise.
func IsNodeReady(node *Node) bool {
	for _, c := range node.Status.Conditions {
		if c.Type == NodeReady {
			return c.Status == ConditionTrue
		}
	}
	return false
}

// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
// containers of the pod.
func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, limits map[ResourceName]resource.Quantity, err error) {
	reqs, limits = map[ResourceName]resource.Quantity{}, map[ResourceName]resource.Quantity{}
	for _, container := range pod.Spec.Containers {
		for name, quantity := range container.Resources.Requests {
			if value, ok := reqs[name]; !ok {
				reqs[name] = *quantity.Copy()
			} else {
				value.Add(quantity)
				reqs[name] = value
			}
		}
		for name, quantity := range container.Resources.Limits {
			if value, ok := limits[name]; !ok {
				limits[name] = *quantity.Copy()
			} else {
				value.Add(quantity)
				limits[name] = value
			}
		}
	}
	// init containers define the minimum of any resource
	for _, container := range pod.Spec.InitContainers {
		for name, quantity := range container.Resources.Requests {
			value, ok := reqs[name]
			if !ok {
				reqs[name] = *quantity.Copy()
				continue
			}
			if quantity.Cmp(value) > 0 {
				reqs[name] = *quantity.Copy()
			}
		}
		for name, quantity := range container.Resources.Limits {
			value, ok := limits[name]
			if !ok {
				limits[name] = *quantity.Copy()
				continue
			}
			if quantity.Cmp(value) > 0 {
				limits[name] = *quantity.Copy()
			}
		}
	}
	return
}
<commit_msg>critical pods can preempt other pods to be admitted<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 v1

import (
	"time"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Returns string version of ResourceName.
func (self ResourceName) String() string {
	return string(self)
}

// Returns the CPU limit if specified.
func (self *ResourceList) Cpu() *resource.Quantity {
	if val, ok := (*self)[ResourceCPU]; ok {
		return &val
	}
	return &resource.Quantity{Format: resource.DecimalSI}
}

// Returns the Memory limit if specified.
func (self *ResourceList) Memory() *resource.Quantity {
	if val, ok := (*self)[ResourceMemory]; ok {
		return &val
	}
	return &resource.Quantity{Format: resource.BinarySI}
}

func (self *ResourceList) Pods() *resource.Quantity {
	if val, ok := (*self)[ResourcePods]; ok {
		return &val
	}
	return &resource.Quantity{}
}

func (self *ResourceList) NvidiaGPU() *resource.Quantity {
	if val, ok := (*self)[ResourceNvidiaGPU]; ok {
		return &val
	}
	return &resource.Quantity{}
}

func GetContainerStatus(statuses []ContainerStatus, name string) (ContainerStatus, bool) {
	for i := range statuses {
		if statuses[i].Name == name {
			return statuses[i], true
		}
	}
	return ContainerStatus{}, false
}

func GetExistingContainerStatus(statuses []ContainerStatus, name string) ContainerStatus {
	for i := range statuses {
		if statuses[i].Name == name {
			return statuses[i]
		}
	}
	return ContainerStatus{}
}

// IsPodAvailable returns true if a pod is available; false otherwise.
// Precondition for an available pod is that it must be ready. On top
// of that, there are two cases when a pod can be considered available:
// 1. minReadySeconds == 0, or
// 2. LastTransitionTime (is set) + minReadySeconds < current time
func IsPodAvailable(pod *Pod, minReadySeconds int32, now metav1.Time) bool {
	if !IsPodReady(pod) {
		return false
	}

	c := GetPodReadyCondition(pod.Status)
	minReadySecondsDuration := time.Duration(minReadySeconds) * time.Second
	if minReadySeconds == 0 || !c.LastTransitionTime.IsZero() && c.LastTransitionTime.Add(minReadySecondsDuration).Before(now.Time) {
		return true
	}
	return false
}

// IsPodReady returns true if a pod is ready; false otherwise.
func IsPodReady(pod *Pod) bool {
	return IsPodReadyConditionTrue(pod.Status)
}

// IsPodReady retruns true if a pod is ready; false otherwise.
func IsPodReadyConditionTrue(status PodStatus) bool {
	condition := GetPodReadyCondition(status)
	return condition != nil && condition.Status == ConditionTrue
}

// Extracts the pod ready condition from the given status and returns that.
// Returns nil if the condition is not present.
func GetPodReadyCondition(status PodStatus) *PodCondition {
	_, condition := GetPodCondition(&status, PodReady)
	return condition
}

// GetPodCondition extracts the provided condition from the given status and returns that.
// Returns nil and -1 if the condition is not present, and the index of the located condition.
func GetPodCondition(status *PodStatus, conditionType PodConditionType) (int, *PodCondition) {
	if status == nil {
		return -1, nil
	}
	for i := range status.Conditions {
		if status.Conditions[i].Type == conditionType {
			return i, &status.Conditions[i]
		}
	}
	return -1, nil
}

// GetNodeCondition extracts the provided condition from the given status and returns that.
// Returns nil and -1 if the condition is not present, and the index of the located condition.
func GetNodeCondition(status *NodeStatus, conditionType NodeConditionType) (int, *NodeCondition) {
	if status == nil {
		return -1, nil
	}
	for i := range status.Conditions {
		if status.Conditions[i].Type == conditionType {
			return i, &status.Conditions[i]
		}
	}
	return -1, nil
}

// Updates existing pod condition or creates a new one. Sets LastTransitionTime to now if the
// status has changed.
// Returns true if pod condition has changed or has been added.
func UpdatePodCondition(status *PodStatus, condition *PodCondition) bool {
	condition.LastTransitionTime = metav1.Now()
	// Try to find this pod condition.
	conditionIndex, oldCondition := GetPodCondition(status, condition.Type)

	if oldCondition == nil {
		// We are adding new pod condition.
		status.Conditions = append(status.Conditions, *condition)
		return true
	} else {
		// We are updating an existing condition, so we need to check if it has changed.
		if condition.Status == oldCondition.Status {
			condition.LastTransitionTime = oldCondition.LastTransitionTime
		}

		isEqual := condition.Status == oldCondition.Status &&
			condition.Reason == oldCondition.Reason &&
			condition.Message == oldCondition.Message &&
			condition.LastProbeTime.Equal(oldCondition.LastProbeTime) &&
			condition.LastTransitionTime.Equal(oldCondition.LastTransitionTime)

		status.Conditions[conditionIndex] = *condition
		// Return true if one of the fields have changed.
		return !isEqual
	}
}

// IsNodeReady returns true if a node is ready; false otherwise.
func IsNodeReady(node *Node) bool {
	for _, c := range node.Status.Conditions {
		if c.Type == NodeReady {
			return c.Status == ConditionTrue
		}
	}
	return false
}

// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
// containers of the pod.
func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, limits map[ResourceName]resource.Quantity, err error) {
	reqs, limits = map[ResourceName]resource.Quantity{}, map[ResourceName]resource.Quantity{}
	for _, container := range pod.Spec.Containers {
		for name, quantity := range container.Resources.Requests {
			if value, ok := reqs[name]; !ok {
				reqs[name] = *quantity.Copy()
			} else {
				value.Add(quantity)
				reqs[name] = value
			}
		}
		for name, quantity := range container.Resources.Limits {
			if value, ok := limits[name]; !ok {
				limits[name] = *quantity.Copy()
			} else {
				value.Add(quantity)
				limits[name] = value
			}
		}
	}
	// init containers define the minimum of any resource
	for _, container := range pod.Spec.InitContainers {
		for name, quantity := range container.Resources.Requests {
			value, ok := reqs[name]
			if !ok {
				reqs[name] = *quantity.Copy()
				continue
			}
			if quantity.Cmp(value) > 0 {
				reqs[name] = *quantity.Copy()
			}
		}
		for name, quantity := range container.Resources.Limits {
			value, ok := limits[name]
			if !ok {
				limits[name] = *quantity.Copy()
				continue
			}
			if quantity.Cmp(value) > 0 {
				limits[name] = *quantity.Copy()
			}
		}
	}
	return
}

// finds and returns the request for a specific resource.
func GetResourceRequest(pod *Pod, resource ResourceName) int64 {
	if resource == ResourcePods {
		return 1
	}
	totalResources := int64(0)
	for _, container := range pod.Spec.Containers {
		if rQuantity, ok := container.Resources.Requests[resource]; ok {
			if resource == ResourceCPU {
				totalResources += rQuantity.MilliValue()
			} else {
				totalResources += rQuantity.Value()
			}
		}
	}
	// take max_resource(sum_pod, any_init_container)
	for _, container := range pod.Spec.InitContainers {
		if rQuantity, ok := container.Resources.Requests[resource]; ok {
			if resource == ResourceCPU && rQuantity.MilliValue() > totalResources {
				totalResources = rQuantity.MilliValue()
			} else if rQuantity.Value() > totalResources {
				totalResources = rQuantity.Value()
			}
		}
	}
	return totalResources
}
<|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 certificates

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	api "k8s.io/kubernetes/pkg/apis/core"
)

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// Describes a certificate signing request
type CertificateSigningRequest struct {
	metav1.TypeMeta
	// +optional
	metav1.ObjectMeta

	// The certificate request itself and any additional information.
	// +optional
	Spec CertificateSigningRequestSpec

	// Derived information about the request.
	// +optional
	Status CertificateSigningRequestStatus
}

// This information is immutable after the request is created. Only the Request
// and Usages fields can be set on creation, other fields are derived by
// Kubernetes and cannot be modified by users.
type CertificateSigningRequestSpec struct {
	// Base64-encoded PKCS#10 CSR data
	Request []byte

	// Requested signer for the request. It is a qualified name in the form:
	// `scope-hostname.io/name`.
	// Distribution of trust for signers happens out of band.
	// You can select on this field using `spec.signerName`.
	// Kubernetes provides built-in signers that each have a well-known signerName:
	// 1. kubernetes.io/kube-apiserver-client
	// 2. kubernetes.io/kube-apiserver-client-kubelet
	// 3. kubernetes.io/kubelet-serving
	// 4. kubernetes.io/legacy-unknown
	// Custom signerNames can also be specified and that those are external signers and as such the control plane signer will not issue certificates.
	SignerName string

	// usages specifies a set of usage contexts the key will be
	// valid for.
	// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
	//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
	Usages []KeyUsage

	// Information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Username string
	// UID information about the requesting user.
	// See user.Info interface for details.
	// +optional
	UID string
	// Group information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Groups []string
	// Extra information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Extra map[string]ExtraValue
}

// Built in signerName values that are honoured by kube-controller-manager.
// None of these usages are related to ServiceAccount token secrets
// `.data[ca.crt]` in any way.
const (
	// Signs certificates that will be honored as client-certs by the
	// kube-apiserver. Never auto-approved by kube-controller-manager.
	KubeAPIServerClientSignerName = "kubernetes.io/kube-apiserver-client"

	// Signs client certificates that will be honored as client-certs by the
	// kube-apiserver for a kubelet.
	// May be auto-approved by kube-controller-manager.
	KubeAPIServerClientKubeletSignerName = "kubernetes.io/kube-apiserver-client-kubelet"

	// Signs serving certificates that are honored as a valid kubelet serving
	// certificate by the kube-apiserver, but has no other guarantees.
	KubeletServingSignerName = "kubernetes.io/kubelet-serving"

	// Has no guarantees for trust at all. Some distributions may honor these
	// as client certs, but that behavior is not standard kubernetes behavior.
	LegacyUnknownSignerName = "kubernetes.io/legacy-unknown"
)

// ExtraValue masks the value so protobuf can generate
type ExtraValue []string

type CertificateSigningRequestStatus struct {
	// Conditions applied to the request, such as approval or denial.
	// +optional
	Conditions []CertificateSigningRequestCondition

	// If request was approved, the controller will place the issued certificate here.
	// +optional
	Certificate []byte
}

type RequestConditionType string

// These are the possible conditions for a certificate request.
const (
	CertificateApproved RequestConditionType = "Approved"
	CertificateDenied   RequestConditionType = "Denied"
	CertificateFailed   RequestConditionType = "Failed"
)

type CertificateSigningRequestCondition struct {
	// type of the condition. Known conditions include "Approved", "Denied", and "Failed".
	Type RequestConditionType
	// Status of the condition, one of True, False, Unknown.
	// Approved, Denied, and Failed conditions may not be "False" or "Unknown".
	// If unset, should be treated as "True".
	// +optional
	Status api.ConditionStatus
	// brief reason for the request state
	// +optional
	Reason string
	// human readable message with details about the request state
	// +optional
	Message string
	// timestamp for the last update to this condition
	// +optional
	LastUpdateTime metav1.Time
	// lastTransitionTime is the time the condition last transitioned from one status to another.
	// +optional
	LastTransitionTime metav1.Time
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type CertificateSigningRequestList struct {
	metav1.TypeMeta
	// +optional
	metav1.ListMeta

	// +optional
	Items []CertificateSigningRequest
}

// KeyUsages specifies valid usage contexts for keys.
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
type KeyUsage string

const (
	UsageSigning           KeyUsage = "signing"
	UsageDigitalSignature  KeyUsage = "digital signature"
	UsageContentCommitment KeyUsage = "content commitment"
	UsageKeyEncipherment   KeyUsage = "key encipherment"
	UsageKeyAgreement      KeyUsage = "key agreement"
	UsageDataEncipherment  KeyUsage = "data encipherment"
	UsageCertSign          KeyUsage = "cert sign"
	UsageCRLSign           KeyUsage = "crl sign"
	UsageEncipherOnly      KeyUsage = "encipher only"
	UsageDecipherOnly      KeyUsage = "decipher only"
	UsageAny               KeyUsage = "any"
	UsageServerAuth        KeyUsage = "server auth"
	UsageClientAuth        KeyUsage = "client auth"
	UsageCodeSigning       KeyUsage = "code signing"
	UsageEmailProtection   KeyUsage = "email protection"
	UsageSMIME             KeyUsage = "s/mime"
	UsageIPsecEndSystem    KeyUsage = "ipsec end system"
	UsageIPsecTunnel       KeyUsage = "ipsec tunnel"
	UsageIPsecUser         KeyUsage = "ipsec user"
	UsageTimestamping      KeyUsage = "timestamping"
	UsageOCSPSigning       KeyUsage = "ocsp signing"
	UsageMicrosoftSGC      KeyUsage = "microsoft sgc"
	UsageNetscapeSGC       KeyUsage = "netscape sgc"
)
<commit_msg>update SingnerName field doc<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 certificates

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	api "k8s.io/kubernetes/pkg/apis/core"
)

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// Describes a certificate signing request
type CertificateSigningRequest struct {
	metav1.TypeMeta
	// +optional
	metav1.ObjectMeta

	// The certificate request itself and any additional information.
	// +optional
	Spec CertificateSigningRequestSpec

	// Derived information about the request.
	// +optional
	Status CertificateSigningRequestStatus
}

// This information is immutable after the request is created. Only the Request
// and Usages fields can be set on creation, other fields are derived by
// Kubernetes and cannot be modified by users.
type CertificateSigningRequestSpec struct {
	// Base64-encoded PKCS#10 CSR data
	Request []byte

	// signerName indicates the requested signer, and is a qualified name.
	//
	// List/watch requests for CertificateSigningRequests can filter on this field using a "spec.signerName=NAME" fieldSelector.
	//
	// Well-known Kubernetes signers are:
	//  1. "kubernetes.io/kube-apiserver-client": issues client certificates that can be used to authenticate to kube-apiserver.
	//   Requests for this signer are never auto-approved by kube-controller-manager, can be issued by the "csrsigning" controller in kube-controller-manager.
	//  2. "kubernetes.io/kube-apiserver-client-kubelet": issues client certificates that kubelets use to authenticate to kube-apiserver.
	//   Requests for this signer can be auto-approved by the "csrapproving" controller in kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager.
	//  3. "kubernetes.io/kubelet-serving" issues serving certificates that kubelets use to serve TLS endpoints, which kube-apiserver can connect to securely.
	//   Requests for this signer are never auto-approved by kube-controller-manager, and can be issued by the "csrsigning" controller in kube-controller-manager.
	//
	// More details are available at https://k8s.io/docs/reference/access-authn-authz/certificate-signing-requests/#kubernetes-signers
	//
	// Custom signerNames can also be specified. The signer defines:
	//  1. Trust distribution: how trust (CA bundles) are distributed.
	//  2. Permitted subjects: and behavior when a disallowed subject is requested.
	//  3. Required, permitted, or forbidden x509 extensions in the request (including whether subjectAltNames are allowed, which types, restrictions on allowed values) and behavior when a disallowed extension is requested.
	//  4. Required, permitted, or forbidden key usages / extended key usages.
	//  5. Expiration/certificate lifetime: whether it is fixed by the signer, configurable by the admin.
	//  6. Whether or not requests for CA certificates are allowed.
	SignerName string

	// usages specifies a set of usage contexts the key will be
	// valid for.
	// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
	//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
	Usages []KeyUsage

	// Information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Username string
	// UID information about the requesting user.
	// See user.Info interface for details.
	// +optional
	UID string
	// Group information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Groups []string
	// Extra information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Extra map[string]ExtraValue
}

// Built in signerName values that are honoured by kube-controller-manager.
// None of these usages are related to ServiceAccount token secrets
// `.data[ca.crt]` in any way.
const (
	// Signs certificates that will be honored as client-certs by the
	// kube-apiserver. Never auto-approved by kube-controller-manager.
	KubeAPIServerClientSignerName = "kubernetes.io/kube-apiserver-client"

	// Signs client certificates that will be honored as client-certs by the
	// kube-apiserver for a kubelet.
	// May be auto-approved by kube-controller-manager.
	KubeAPIServerClientKubeletSignerName = "kubernetes.io/kube-apiserver-client-kubelet"

	// Signs serving certificates that are honored as a valid kubelet serving
	// certificate by the kube-apiserver, but has no other guarantees.
	KubeletServingSignerName = "kubernetes.io/kubelet-serving"

	// Has no guarantees for trust at all. Some distributions may honor these
	// as client certs, but that behavior is not standard kubernetes behavior.
	LegacyUnknownSignerName = "kubernetes.io/legacy-unknown"
)

// ExtraValue masks the value so protobuf can generate
type ExtraValue []string

type CertificateSigningRequestStatus struct {
	// Conditions applied to the request, such as approval or denial.
	// +optional
	Conditions []CertificateSigningRequestCondition

	// If request was approved, the controller will place the issued certificate here.
	// +optional
	Certificate []byte
}

type RequestConditionType string

// These are the possible conditions for a certificate request.
const (
	CertificateApproved RequestConditionType = "Approved"
	CertificateDenied   RequestConditionType = "Denied"
	CertificateFailed   RequestConditionType = "Failed"
)

type CertificateSigningRequestCondition struct {
	// type of the condition. Known conditions include "Approved", "Denied", and "Failed".
	Type RequestConditionType
	// Status of the condition, one of True, False, Unknown.
	// Approved, Denied, and Failed conditions may not be "False" or "Unknown".
	// If unset, should be treated as "True".
	// +optional
	Status api.ConditionStatus
	// brief reason for the request state
	// +optional
	Reason string
	// human readable message with details about the request state
	// +optional
	Message string
	// timestamp for the last update to this condition
	// +optional
	LastUpdateTime metav1.Time
	// lastTransitionTime is the time the condition last transitioned from one status to another.
	// +optional
	LastTransitionTime metav1.Time
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type CertificateSigningRequestList struct {
	metav1.TypeMeta
	// +optional
	metav1.ListMeta

	// +optional
	Items []CertificateSigningRequest
}

// KeyUsages specifies valid usage contexts for keys.
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
type KeyUsage string

const (
	UsageSigning           KeyUsage = "signing"
	UsageDigitalSignature  KeyUsage = "digital signature"
	UsageContentCommitment KeyUsage = "content commitment"
	UsageKeyEncipherment   KeyUsage = "key encipherment"
	UsageKeyAgreement      KeyUsage = "key agreement"
	UsageDataEncipherment  KeyUsage = "data encipherment"
	UsageCertSign          KeyUsage = "cert sign"
	UsageCRLSign           KeyUsage = "crl sign"
	UsageEncipherOnly      KeyUsage = "encipher only"
	UsageDecipherOnly      KeyUsage = "decipher only"
	UsageAny               KeyUsage = "any"
	UsageServerAuth        KeyUsage = "server auth"
	UsageClientAuth        KeyUsage = "client auth"
	UsageCodeSigning       KeyUsage = "code signing"
	UsageEmailProtection   KeyUsage = "email protection"
	UsageSMIME             KeyUsage = "s/mime"
	UsageIPsecEndSystem    KeyUsage = "ipsec end system"
	UsageIPsecTunnel       KeyUsage = "ipsec tunnel"
	UsageIPsecUser         KeyUsage = "ipsec user"
	UsageTimestamping      KeyUsage = "timestamping"
	UsageOCSPSigning       KeyUsage = "ocsp signing"
	UsageMicrosoftSGC      KeyUsage = "microsoft sgc"
	UsageNetscapeSGC       KeyUsage = "netscape sgc"
)
<|endoftext|>


<commit_before>package api

import (
	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	kruntime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	kutil "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

// Authorization is calculated against
// 1. all deny RoleBinding PolicyRules in the master namespace - short circuit on match
// 2. all allow RoleBinding PolicyRules in the master namespace - short circuit on match
// 3. all deny RoleBinding PolicyRules in the namespace - short circuit on match
// 4. all allow RoleBinding PolicyRules in the namespace - short circuit on match
// 5. deny by default

const (
	// Policy is a singleton and this is its name
	PolicyName     = "default"
	ResourceAll    = "*"
	VerbAll        = "*"
	NonResourceAll = "*"
)

const (
	// ResourceGroupPrefix is the prefix for indicating that a resource entry is actually a group of resources.  The groups are defined in code and indicate resources that are commonly permissioned together
	ResourceGroupPrefix = "resourcegroup"
	BuildGroupName      = ResourceGroupPrefix + ":builds"
	DeploymentGroupName = ResourceGroupPrefix + ":deployments"
	ImageGroupName      = ResourceGroupPrefix + ":images"
	OAuthGroupName      = ResourceGroupPrefix + ":oauth"
	UserGroupName       = ResourceGroupPrefix + ":users"
	// PolicyOwnerGroupName includes the physical resources behind the PermissionGrantingGroupName.  Unless these physical objects are created first, users with privileges to PermissionGrantingGroupName will
	// only be able to bind to global roles
	PolicyOwnerGroupName = ResourceGroupPrefix + ":policy"
	// PermissionGrantingGroupName includes resources that are necessary to maintain authorization roles and bindings.  By itself, this group is insufficient to create anything except for bindings
	// to master roles.  If a local Policy already exists, then privileges to this group will allow for modification of local roles.
	PermissionGrantingGroupName = ResourceGroupPrefix + ":granter"
	// OpenshiftExposedGroupName includes resources that are commonly viewed and modified by end users of the system.  It does not include any sensitive resources that control authentication or authorization
	OpenshiftExposedGroupName = ResourceGroupPrefix + ":exposedopenshift"
	OpenshiftAllGroupName     = ResourceGroupPrefix + ":allopenshift"

	QuotaGroupName = ResourceGroupPrefix + ":quota"
	// KubeInternalsGroupName includes those resources that should reasonably be viewable to end users, but that most users should probably not modify.  Kubernetes herself will maintain these resources
	KubeInternalsGroupName = ResourceGroupPrefix + ":privatekube"
	// KubeExposedGroupName includes resources that are commonly viewed and modified by end users of the system.
	KubeExposedGroupName = ResourceGroupPrefix + ":exposedkube"
	KubeAllGroupName     = ResourceGroupPrefix + ":allkube"
)

var (
	GroupsToResources = map[string][]string{
		BuildGroupName:              {"builds", "buildconfigs", "buildlogs"},
		ImageGroupName:              {"images", "imagerepositories", "imagerepositorymappings", "imagerepositorytags"},
		DeploymentGroupName:         {"deployments", "deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigrollbacks"},
		UserGroupName:               {"users", "useridentitymappings"},
		OAuthGroupName:              {"oauthauthorizetokens", "oauthaccesstokens", "oauthclients", "oauthclientauthorizations"},
		PolicyOwnerGroupName:        {"policies", "policybindings"},
		PermissionGrantingGroupName: {"roles", "rolebindings"},
		OpenshiftExposedGroupName:   {BuildGroupName, ImageGroupName, DeploymentGroupName, "templateconfigs", "routes", "projects"},
		OpenshiftAllGroupName:       {OpenshiftExposedGroupName, UserGroupName, OAuthGroupName, PolicyOwnerGroupName, PermissionGrantingGroupName},

		QuotaGroupName:         {"limitranges", "resourcequotas", "resourcequotausages"},
		KubeInternalsGroupName: {"endpoints", "minions", "nodes", "bindings", "events"},
		KubeExposedGroupName:   {"pods", "replicationcontrollers", "services"},
		KubeAllGroupName:       {KubeInternalsGroupName, KubeExposedGroupName, QuotaGroupName},
	}
)

// PolicyRule holds information that describes a policy rule, but does not contain information
// about who the rule applies to or which namespace the rule applies to.
type PolicyRule struct {
	// Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule.  VerbAll represents all kinds.
	Verbs []string
	// AttributeRestrictions will vary depending on what the Authorizer/AuthorizationAttributeBuilder pair supports.
	// If the Authorizer does not recognize how to handle the AttributeRestrictions, the Authorizer should report an error.
	AttributeRestrictions kruntime.EmbeddedObject
	// Resources is a list of resources this rule applies to.  ResourceAll represents all resources.
	Resources []string
	// ResourceNames is an optional white list of names that the rule applies to.  An empty set means that everything is allowed.
	ResourceNames kutil.StringSet
	// NonResourceURLs is a set of partial urls that a user should have access to.  *s are allowed, but only as the full, final step in the path
	// If an action is not a resource API request, then the URL is split on '/' and is checked against the NonResourceURLs to look for a match.
	NonResourceURLs kutil.StringSet
}

// Role is a logical grouping of PolicyRules that can be referenced as a unit by RoleBindings.
type Role struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// Rules holds all the PolicyRules for this Role
	Rules []PolicyRule
}

// RoleBinding references a Role, but not contain it.  It can reference any Role in the same namespace or in the global namespace.
// It adds who information via Users and Groups and namespace information by which namespace it exists in.  RoleBindings in a given
// namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).
type RoleBinding struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// UserNames holds all the usernames directly bound to the role
	UserNames []string
	// GroupNames holds all the groups directly bound to the role
	GroupNames []string

	// Since Policy is a singleton, this is sufficient knowledge to locate a role
	// RoleRefs can only reference the current namespace and the global namespace
	// If the RoleRef cannot be resolved, the Authorizer must return an error.
	RoleRef kapi.ObjectReference
}

// Policy is a object that holds all the Roles for a particular namespace.  There is at most
// one Policy document per namespace.
type Policy struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// LastModified is the last time that any part of the Policy was created, updated, or deleted
	LastModified kutil.Time

	// Roles holds all the Roles held by this Policy, mapped by Role.Name
	Roles map[string]Role
}

// PolicyBinding is a object that holds all the RoleBindings for a particular namespace.  There is
// one PolicyBinding document per referenced Policy namespace
type PolicyBinding struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// LastModified is the last time that any part of the PolicyBinding was created, updated, or deleted
	LastModified kutil.Time

	// PolicyRef is a reference to the Policy that contains all the Roles that this PolicyBinding's RoleBindings may reference
	PolicyRef kapi.ObjectReference
	// RoleBindings holds all the RoleBindings held by this PolicyBinding, mapped by RoleBinding.Name
	RoleBindings map[string]RoleBinding
}

// ResourceAccessReviewResponse describes who can perform the action
type ResourceAccessReviewResponse struct {
	kapi.TypeMeta

	// Namespace is the namespace used for the access review
	Namespace string
	// Users is the list of users who can perform the action
	Users []string
	// Groups is the list of groups who can perform the action
	Groups []string
}

// ResourceAccessReview is a means to request a list of which users and groups are authorized to perform the
// action specified by spec
type ResourceAccessReview struct {
	kapi.TypeMeta

	// Verb is one of: get, list, watch, create, update, delete
	Verb string
	// Resource is one of the existing resource types
	Resource string
	// Content is the actual content of the request for create and update
	Content kruntime.EmbeddedObject
	// ResourceName is the name of the resource being requested for a "get" or deleted for a "delete"
	ResourceName string
}

// SubjectAccessReviewResponse describes whether or not a user or group can perform an action
type SubjectAccessReviewResponse struct {
	kapi.TypeMeta

	// Namespace is the namespace used for the access review
	Namespace string
	// Allowed is required.  True if the action would be allowed, false otherwise.
	Allowed bool
	// Reason is optional.  It indicates why a request was allowed or denied.
	Reason string
}

// SubjectAccessReview is an object for requesting information about whether a user or group can perform an action
type SubjectAccessReview struct {
	kapi.TypeMeta

	// Verb is one of: get, list, watch, create, update, delete
	Verb string
	// Resource is one of the existing resource types
	Resource string
	// User is optional.  If both User and Groups are empty, the current authenticated user is used.
	User string
	// Groups is optional.  Groups is the list of groups to which the User belongs.
	Groups []string
	// Content is the actual content of the request for create and update
	Content kruntime.EmbeddedObject
	// ResourceName is the name of the resource being requested for a "get" or deleted for a "delete"
	ResourceName string
}

// PolicyList is a collection of Policies
type PolicyList struct {
	kapi.TypeMeta
	kapi.ListMeta
	Items []Policy
}

// PolicyBindingList is a collection of PolicyBindings
type PolicyBindingList struct {
	kapi.TypeMeta
	kapi.ListMeta
	Items []PolicyBinding
}
<commit_msg>add namespaces to authorization rules<commit_after>package api

import (
	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	kruntime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	kutil "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

// Authorization is calculated against
// 1. all deny RoleBinding PolicyRules in the master namespace - short circuit on match
// 2. all allow RoleBinding PolicyRules in the master namespace - short circuit on match
// 3. all deny RoleBinding PolicyRules in the namespace - short circuit on match
// 4. all allow RoleBinding PolicyRules in the namespace - short circuit on match
// 5. deny by default

const (
	// Policy is a singleton and this is its name
	PolicyName     = "default"
	ResourceAll    = "*"
	VerbAll        = "*"
	NonResourceAll = "*"
)

const (
	// ResourceGroupPrefix is the prefix for indicating that a resource entry is actually a group of resources.  The groups are defined in code and indicate resources that are commonly permissioned together
	ResourceGroupPrefix = "resourcegroup"
	BuildGroupName      = ResourceGroupPrefix + ":builds"
	DeploymentGroupName = ResourceGroupPrefix + ":deployments"
	ImageGroupName      = ResourceGroupPrefix + ":images"
	OAuthGroupName      = ResourceGroupPrefix + ":oauth"
	UserGroupName       = ResourceGroupPrefix + ":users"
	// PolicyOwnerGroupName includes the physical resources behind the PermissionGrantingGroupName.  Unless these physical objects are created first, users with privileges to PermissionGrantingGroupName will
	// only be able to bind to global roles
	PolicyOwnerGroupName = ResourceGroupPrefix + ":policy"
	// PermissionGrantingGroupName includes resources that are necessary to maintain authorization roles and bindings.  By itself, this group is insufficient to create anything except for bindings
	// to master roles.  If a local Policy already exists, then privileges to this group will allow for modification of local roles.
	PermissionGrantingGroupName = ResourceGroupPrefix + ":granter"
	// OpenshiftExposedGroupName includes resources that are commonly viewed and modified by end users of the system.  It does not include any sensitive resources that control authentication or authorization
	OpenshiftExposedGroupName = ResourceGroupPrefix + ":exposedopenshift"
	OpenshiftAllGroupName     = ResourceGroupPrefix + ":allopenshift"

	QuotaGroupName = ResourceGroupPrefix + ":quota"
	// KubeInternalsGroupName includes those resources that should reasonably be viewable to end users, but that most users should probably not modify.  Kubernetes herself will maintain these resources
	KubeInternalsGroupName = ResourceGroupPrefix + ":privatekube"
	// KubeExposedGroupName includes resources that are commonly viewed and modified by end users of the system.
	KubeExposedGroupName = ResourceGroupPrefix + ":exposedkube"
	KubeAllGroupName     = ResourceGroupPrefix + ":allkube"
)

var (
	GroupsToResources = map[string][]string{
		BuildGroupName:              {"builds", "buildconfigs", "buildlogs"},
		ImageGroupName:              {"images", "imagerepositories", "imagerepositorymappings", "imagerepositorytags"},
		DeploymentGroupName:         {"deployments", "deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigrollbacks"},
		UserGroupName:               {"users", "useridentitymappings"},
		OAuthGroupName:              {"oauthauthorizetokens", "oauthaccesstokens", "oauthclients", "oauthclientauthorizations"},
		PolicyOwnerGroupName:        {"policies", "policybindings"},
		PermissionGrantingGroupName: {"roles", "rolebindings"},
		OpenshiftExposedGroupName:   {BuildGroupName, ImageGroupName, DeploymentGroupName, "templateconfigs", "routes", "projects"},
		OpenshiftAllGroupName:       {OpenshiftExposedGroupName, UserGroupName, OAuthGroupName, PolicyOwnerGroupName, PermissionGrantingGroupName},

		QuotaGroupName:         {"limitranges", "resourcequotas", "resourcequotausages"},
		KubeInternalsGroupName: {"endpoints", "minions", "nodes", "bindings", "events", "namespaces"},
		KubeExposedGroupName:   {"pods", "replicationcontrollers", "services"},
		KubeAllGroupName:       {KubeInternalsGroupName, KubeExposedGroupName, QuotaGroupName},
	}
)

// PolicyRule holds information that describes a policy rule, but does not contain information
// about who the rule applies to or which namespace the rule applies to.
type PolicyRule struct {
	// Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule.  VerbAll represents all kinds.
	Verbs []string
	// AttributeRestrictions will vary depending on what the Authorizer/AuthorizationAttributeBuilder pair supports.
	// If the Authorizer does not recognize how to handle the AttributeRestrictions, the Authorizer should report an error.
	AttributeRestrictions kruntime.EmbeddedObject
	// Resources is a list of resources this rule applies to.  ResourceAll represents all resources.
	Resources []string
	// ResourceNames is an optional white list of names that the rule applies to.  An empty set means that everything is allowed.
	ResourceNames kutil.StringSet
	// NonResourceURLs is a set of partial urls that a user should have access to.  *s are allowed, but only as the full, final step in the path
	// If an action is not a resource API request, then the URL is split on '/' and is checked against the NonResourceURLs to look for a match.
	NonResourceURLs kutil.StringSet
}

// Role is a logical grouping of PolicyRules that can be referenced as a unit by RoleBindings.
type Role struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// Rules holds all the PolicyRules for this Role
	Rules []PolicyRule
}

// RoleBinding references a Role, but not contain it.  It can reference any Role in the same namespace or in the global namespace.
// It adds who information via Users and Groups and namespace information by which namespace it exists in.  RoleBindings in a given
// namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).
type RoleBinding struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// UserNames holds all the usernames directly bound to the role
	UserNames []string
	// GroupNames holds all the groups directly bound to the role
	GroupNames []string

	// Since Policy is a singleton, this is sufficient knowledge to locate a role
	// RoleRefs can only reference the current namespace and the global namespace
	// If the RoleRef cannot be resolved, the Authorizer must return an error.
	RoleRef kapi.ObjectReference
}

// Policy is a object that holds all the Roles for a particular namespace.  There is at most
// one Policy document per namespace.
type Policy struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// LastModified is the last time that any part of the Policy was created, updated, or deleted
	LastModified kutil.Time

	// Roles holds all the Roles held by this Policy, mapped by Role.Name
	Roles map[string]Role
}

// PolicyBinding is a object that holds all the RoleBindings for a particular namespace.  There is
// one PolicyBinding document per referenced Policy namespace
type PolicyBinding struct {
	kapi.TypeMeta
	kapi.ObjectMeta

	// LastModified is the last time that any part of the PolicyBinding was created, updated, or deleted
	LastModified kutil.Time

	// PolicyRef is a reference to the Policy that contains all the Roles that this PolicyBinding's RoleBindings may reference
	PolicyRef kapi.ObjectReference
	// RoleBindings holds all the RoleBindings held by this PolicyBinding, mapped by RoleBinding.Name
	RoleBindings map[string]RoleBinding
}

// ResourceAccessReviewResponse describes who can perform the action
type ResourceAccessReviewResponse struct {
	kapi.TypeMeta

	// Namespace is the namespace used for the access review
	Namespace string
	// Users is the list of users who can perform the action
	Users []string
	// Groups is the list of groups who can perform the action
	Groups []string
}

// ResourceAccessReview is a means to request a list of which users and groups are authorized to perform the
// action specified by spec
type ResourceAccessReview struct {
	kapi.TypeMeta

	// Verb is one of: get, list, watch, create, update, delete
	Verb string
	// Resource is one of the existing resource types
	Resource string
	// Content is the actual content of the request for create and update
	Content kruntime.EmbeddedObject
	// ResourceName is the name of the resource being requested for a "get" or deleted for a "delete"
	ResourceName string
}

// SubjectAccessReviewResponse describes whether or not a user or group can perform an action
type SubjectAccessReviewResponse struct {
	kapi.TypeMeta

	// Namespace is the namespace used for the access review
	Namespace string
	// Allowed is required.  True if the action would be allowed, false otherwise.
	Allowed bool
	// Reason is optional.  It indicates why a request was allowed or denied.
	Reason string
}

// SubjectAccessReview is an object for requesting information about whether a user or group can perform an action
type SubjectAccessReview struct {
	kapi.TypeMeta

	// Verb is one of: get, list, watch, create, update, delete
	Verb string
	// Resource is one of the existing resource types
	Resource string
	// User is optional.  If both User and Groups are empty, the current authenticated user is used.
	User string
	// Groups is optional.  Groups is the list of groups to which the User belongs.
	Groups []string
	// Content is the actual content of the request for create and update
	Content kruntime.EmbeddedObject
	// ResourceName is the name of the resource being requested for a "get" or deleted for a "delete"
	ResourceName string
}

// PolicyList is a collection of Policies
type PolicyList struct {
	kapi.TypeMeta
	kapi.ListMeta
	Items []Policy
}

// PolicyBindingList is a collection of PolicyBindings
type PolicyBindingList struct {
	kapi.TypeMeta
	kapi.ListMeta
	Items []PolicyBinding
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 admin

import (
	"context"
	"net/http"

	"github.com/google/exposure-notifications-verification-server/pkg/controller"
	"github.com/gorilla/mux"
)

type cacheItem struct {
	Name        string
	Description string
}

var caches = map[string]*cacheItem{
	"apps:":               {"Mobile apps", "Registered mobile apps for the redirector service"},
	"authorized_apps:":    {"API keys", "Authentication for API keys"},
	"jwks:":               {"JWKs", "JSON web key sets"},
	"memberships:":        {"Memberships", "All membership information"},
	"public_keys:":        {"Public keys", "PEM data from upstream key provider"},
	"realms:":             {"Realms", "All realm data"},
	"stats:":              {"Statistics", "API key, user, and realm statistics"},
	"token_signing_keys:": {"Token signing keys", "All token signing keys, including currently active"},
	"users:":              {"Users", "All user data"},
}

// HandleCachesIndex shows the caches page.
func (c *Controller) HandleCachesIndex() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		c.renderCachesIndex(ctx, w)
	})
}

// HandleCachesClear clears the given caches.
func (c *Controller) HandleCachesClear() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		vars := mux.Vars(r)

		session := controller.SessionFromContext(ctx)
		if session == nil {
			controller.MissingSession(w, r, c.h)
			return
		}
		flash := controller.Flash(session)

		id := vars["id"]
		item, ok := caches[id]
		if !ok {
			flash.Error("Unknown cache type: %q", id)
			controller.Back(w, r, c.h)
			return
		}

		if err := c.cacher.DeletePrefix(ctx, id); err != nil {
			flash.Error("Failed to clear cache for %s: %v", item.Name, err)
			controller.Back(w, r, c.h)
			return
		}

		flash.Alert("Successfully cleared cache for %s!", item.Name)
		controller.Back(w, r, c.h)
		return
	})
}

func (c *Controller) renderCachesIndex(ctx context.Context, w http.ResponseWriter) {
	m := controller.TemplateMapFromContext(ctx)
	m.Title("Caches - System Admin")
	m["caches"] = caches
	c.h.RenderHTML(w, "admin/caches/index", m)
}
<commit_msg>add translations cache clear (#2110)<commit_after>// Copyright 2020 Google LLC
//
// 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 admin

import (
	"context"
	"net/http"

	"github.com/google/exposure-notifications-verification-server/pkg/controller"
	"github.com/gorilla/mux"
)

type cacheItem struct {
	Name        string
	Description string
}

var caches = map[string]*cacheItem{
	"apps:":               {"Mobile apps", "Registered mobile apps for the redirector service"},
	"authorized_apps:":    {"API keys", "Authentication for API keys"},
	"jwks:":               {"JWKs", "JSON web key sets"},
	"memberships:":        {"Memberships", "All membership information"},
	"public_keys:":        {"Public keys", "PEM data from upstream key provider"},
	"realms:":             {"Realms", "All realm data"},
	"stats:":              {"Statistics", "API key, user, and realm statistics"},
	"token_signing_keys:": {"Token signing keys", "All token signing keys, including currently active"},
	"translations:":       {"Translations", "Realm specific tranlations for the user report webview"},
	"users:":              {"Users", "All user data"},
}

// HandleCachesIndex shows the caches page.
func (c *Controller) HandleCachesIndex() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		c.renderCachesIndex(ctx, w)
	})
}

// HandleCachesClear clears the given caches.
func (c *Controller) HandleCachesClear() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		vars := mux.Vars(r)

		session := controller.SessionFromContext(ctx)
		if session == nil {
			controller.MissingSession(w, r, c.h)
			return
		}
		flash := controller.Flash(session)

		id := vars["id"]
		item, ok := caches[id]
		if !ok {
			flash.Error("Unknown cache type: %q", id)
			controller.Back(w, r, c.h)
			return
		}

		if err := c.cacher.DeletePrefix(ctx, id); err != nil {
			flash.Error("Failed to clear cache for %s: %v", item.Name, err)
			controller.Back(w, r, c.h)
			return
		}

		flash.Alert("Successfully cleared cache for %s!", item.Name)
		controller.Back(w, r, c.h)
		return
	})
}

func (c *Controller) renderCachesIndex(ctx context.Context, w http.ResponseWriter) {
	m := controller.TemplateMapFromContext(ctx)
	m.Title("Caches - System Admin")
	m["caches"] = caches
	c.h.RenderHTML(w, "admin/caches/index", m)
}
<|endoftext|>


<commit_before>/*
 Copyright 2010 Jeremy Wall (jeremy@marzhillstudios.com)
 Use of this source code is governed by the Artistic License 2.0.
 That License is included in the LICENSE file.
*/
package transform

import (
	. "html"
	v "container/vector"
	"log"
	s "strings"
)

type SelectorQuery struct {
	*v.Vector
}

type SelectorPart struct {
	Type    byte // a bitmask of the selector types
	Val     string // the value we are matching against
}

type Selector struct {
	TagName string // "*" for any tag otherwise the name of the tag
	Parts []SelectorPart
	Attr map[string]string
}

const (
	TAGNAME byte = iota // zero value so the default
	CLASS   byte = '.'
	ID      byte = '#'
	PSEUDO  byte = ':'
	ANY     byte = '*'
	ATTR    byte = '['
)

const (
	SELECTOR_CHARS string = ".:#["
)

func newAnyTagClassOrIdSelector(str string) *Selector {
	return &Selector{
	Parts:    []SelectorPart{
			SelectorPart{
			Type: str[0],
			Val:     str[1:],
		}},
	TagName: "*",
	}
}

func newAnyTagSelector(str string) *Selector {
	return &Selector{
		TagName: "*",
	}
}

func splitAttrs(str string) []string {
	attrs := s.FieldsFunc(str[1:len(str)-1], func(c int) bool {
		if c == '=' {
			return true
		}
		return false
	})
	return attrs
}

func newAnyTagAttrSelector(str string) *Selector {
	attrs := splitAttrs(str)
	return &Selector{
		TagName: "*",
		Attr:    map[string]string{attrs[0]: attrs[1]},
	}
}

func newTagNameSelector(str string) *Selector {
	return &Selector{
		TagName: str,
	}
}

func newTagNameWithConstraints(str string, i int) *Selector {
	// TODO(jwall): indexAny use [CLASS,...]
	var selector = new(Selector)
	switch str[i] {
	case CLASS, ID, PSEUDO: // with class or id
		selector = newAnyTagClassOrIdSelector(str[i:])
	case ATTR: // with attribute
		selector = newAnyTagAttrSelector(str[i:])
	default:
		panic("Invalid constraint type for the tagname selector")
	}
	selector.TagName = str[0:i]
	//selector.Type = TAGNAME
	return selector
}

func NewSelector(str string) *Selector {
	str = s.TrimSpace(str) // trim whitespace
	// TODO(jwall): split on one of ".:#["
	var selector *Selector
	switch str[0] {
	case CLASS, ID: // Any tagname with class or id
		selector = newAnyTagClassOrIdSelector(str)
	case ANY: // Any tagname
		selector = newAnyTagSelector(str)
	case ATTR: // any tagname with attribute
		// TODO(jwall): expanded attribute selectors
		selector = newAnyTagAttrSelector(str)
	default: // TAGNAME
		// TODO(jwall): indexAny use [CLASS,...]
		if i := s.IndexAny(str, SELECTOR_CHARS); i != -1 {
			selector = newTagNameWithConstraints(str, i)
		} else { // just a tagname
			selector = newTagNameSelector(str)
		}
	}
	return selector
}

func NewSelectorQuery(sel ...string) *SelectorQuery {
	q := SelectorQuery{Vector: new(v.Vector)}
	for _, str := range sel {
		selPart := NewSelector(str)
		if selPart == nil {
			log.Panic("Invalid Selector in query")
		}
		q.Push(selPart)
	}
	return &q
}

func testSelectorAttrs(attrs []Attribute, sel *Selector) bool {
	result := false
	for key, val := range sel.Attr {
		result = result || testAttr(attrs, key, val)
	}
	return result
}

func testAttr(attrs []Attribute, key string, val string) bool {
	for _, attr := range attrs {
		// TODO(jwall): we need to handle the multiple match types
		// [att] [att=val] [att~=val] [att|=val]?
		if attr.Key == key && attr.Val == val {
			return true
		}
	}
	return false
}

func testNode(node *Node, sel Selector) bool {
	/*
	if sel.TagName == "*" {
		attrs := node.Attr
		// TODO(jwall): abstract this out
		switch sel.Type {
		case ID:
			if testAttr(attrs, "id",  sel.Val) {
				return true
			}
		case CLASS:
			if testAttr(attrs, "class", sel.Val) {
				return true
			}
		case ATTR:
			if testSelectorAttrs(attrs, &sel) {
				return true
			}
			//case PSEUDO:
			//TODO(jwall): implement these
		}
	} else {
		if node.Data == sel.TagName {
			attrs := node.Attr
			switch sel.Type {
			case ID:
				if testAttr(attrs, "id", sel.Val) {
					return true
				}
			case CLASS:
				if testAttr(attrs, "class", sel.Val) {
					return true
				}
			case ATTR:
				if testSelectorAttrs(attrs, &sel) {
					return true
				}
			//case PSEUDO:
			//TODO(jwall): implement these
			default:
				return true
			}
		}
	}
	*/
	return false
}

/*
 Apply the css selector to a document.

 Returns a Vector of nodes that the selector matched.
*/
func (sel *SelectorQuery) Apply(doc *Document) *v.Vector {
	interesting := new(v.Vector)
	return interesting
}

/*
 Replace each node the selector matches with the passed in node.

 Applies the selector against the doc and replaces the returned
 Nodes with the passed in n HtmlNode.
*/
func (sel *SelectorQuery) Replace(doc *Document, n *Node) {
	nv := sel.Apply(doc)
	for i := 0; i <= nv.Len(); i++ {
		// Change to take into account new usage of *Node
		//nv.At(i).(*Node).Copy(n)
	}
	return
}
<commit_msg>TODO rearrangement.<commit_after>/*
 Copyright 2010 Jeremy Wall (jeremy@marzhillstudios.com)
 Use of this source code is governed by the Artistic License 2.0.
 That License is included in the LICENSE file.
*/
package transform

import (
	. "html"
	v "container/vector"
	"log"
	s "strings"
)

type SelectorQuery struct {
	*v.Vector
}

type SelectorPart struct {
	Type    byte // a bitmask of the selector types
	Val     string // the value we are matching against
}

type Selector struct {
	TagName string // "*" for any tag otherwise the name of the tag
	Parts []SelectorPart
	Attr map[string]string
}

const (
	TAGNAME byte = iota // zero value so the default
	CLASS   byte = '.'
	ID      byte = '#'
	PSEUDO  byte = ':'
	ANY     byte = '*'
	ATTR    byte = '['
)

const (
	SELECTOR_CHARS string = ".:#["
)

func newAnyTagClassOrIdSelector(str string) *Selector {
	return &Selector{
	Parts:    []SelectorPart{
			SelectorPart{
			Type: str[0],
			Val:     str[1:],
		}},
	TagName: "*",
	}
}

func newAnyTagSelector(str string) *Selector {
	return &Selector{
		TagName: "*",
	}
}

func splitAttrs(str string) []string {
	attrs := s.FieldsFunc(str[1:len(str)-1], func(c int) bool {
		if c == '=' {
			return true
		}
		return false
	})
	return attrs
}

func newAnyTagAttrSelector(str string) *Selector {
	attrs := splitAttrs(str)
	return &Selector{
		TagName: "*",
		Attr:    map[string]string{attrs[0]: attrs[1]},
	}
}

func newTagNameSelector(str string) *Selector {
	return &Selector{
		TagName: str,
	}
}

func newTagNameWithConstraints(str string, i int) *Selector {
	// TODO(jwall): indexAny use [CLASS,...]
	var selector = new(Selector)
	switch str[i] {
	case CLASS, ID, PSEUDO: // with class or id
		selector = newAnyTagClassOrIdSelector(str[i:])
	case ATTR: // with attribute
		selector = newAnyTagAttrSelector(str[i:])
	default:
		panic("Invalid constraint type for the tagname selector")
	}
	selector.TagName = str[0:i]
	//selector.Type = TAGNAME
	return selector
}

func NewSelector(str string) *Selector {
	str = s.TrimSpace(str) // trim whitespace
	// TODO(jwall): support combinators > + \S
	// TODO(jwall): split on one of ".:#["
	var selector *Selector
	switch str[0] {
	case CLASS, ID: // Any tagname with class or id
		selector = newAnyTagClassOrIdSelector(str)
	case ANY: // Any tagname
		selector = newAnyTagSelector(str)
	case ATTR: // any tagname with attribute
		// TODO(jwall): expanded attribute selectors
		selector = newAnyTagAttrSelector(str)
	default: // TAGNAME
		// TODO(jwall): indexAny use [CLASS,...]
		if i := s.IndexAny(str, SELECTOR_CHARS); i != -1 {
			selector = newTagNameWithConstraints(str, i)
		} else { // just a tagname
			selector = newTagNameSelector(str)
		}
	}
	return selector
}

func NewSelectorQuery(sel ...string) *SelectorQuery {
	q := SelectorQuery{Vector: new(v.Vector)}
	for _, str := range sel {
		selPart := NewSelector(str)
		if selPart == nil {
			log.Panic("Invalid Selector in query")
		}
		q.Push(selPart)
	}
	return &q
}

func testSelectorAttrs(attrs []Attribute, sel *Selector) bool {
	result := false
	for key, val := range sel.Attr {
		result = result || testAttr(attrs, key, val)
	}
	return result
}

func testAttr(attrs []Attribute, key string, val string) bool {
	for _, attr := range attrs {
		// TODO(jwall): we need to handle the multiple match types
		// [att] [att=val] [att~=val] [att|=val]?
		if attr.Key == key && attr.Val == val {
			return true
		}
	}
	return false
}

func testNode(node *Node, sel Selector) bool {
	/*
	if sel.TagName == "*" {
		attrs := node.Attr
		switch sel.Type {
		case ID:
			if testAttr(attrs, "id",  sel.Val) {
				return true
			}
		case CLASS:
			if testAttr(attrs, "class", sel.Val) {
				return true
			}
		case ATTR:
			if testSelectorAttrs(attrs, &sel) {
				return true
			}
			//case PSEUDO:
			//TODO(jwall): implement these
		}
	} else {
		if node.Data == sel.TagName {
			attrs := node.Attr
			switch sel.Type {
			case ID:
				if testAttr(attrs, "id", sel.Val) {
					return true
				}
			case CLASS:
				if testAttr(attrs, "class", sel.Val) {
					return true
				}
			case ATTR:
				if testSelectorAttrs(attrs, &sel) {
					return true
				}
			//case PSEUDO:
			//TODO(jwall): implement these
			default:
				return true
			}
		}
	}
	*/
	return false
}

/*
 Apply the css selector to a document.

 Returns a Vector of nodes that the selector matched.
*/
func (sel *SelectorQuery) Apply(doc *Document) *v.Vector {
	interesting := new(v.Vector)
	return interesting
}

/*
 Replace each node the selector matches with the passed in node.

 Applies the selector against the doc and replaces the returned
 Nodes with the passed in n HtmlNode.
*/
func (sel *SelectorQuery) Replace(doc *Document, n *Node) {
	nv := sel.Apply(doc)
	for i := 0; i <= nv.Len(); i++ {
		// Change to take into account new usage of *Node
		//nv.At(i).(*Node).Copy(n)
	}
	return
}
<|endoftext|>