<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"sync"
)

func init() {
	RowRegex = regexp.MustCompile("[\\s]+")
}

var RowRegex *regexp.Regexp

type ProcessIO struct {
	disk_read_rate  float64
	disk_write_rate float64
	swapin_percent  float64
	io_percent      float64
	Name            string
}

// expected format:
//13:05:19 24086 be/4 cfapache    0.00 K/s    0.00 K/s  0.00 %  0.00 % httpd -k start
func NewProcessIOFromString(row_data string) (*ProcessIO, error) {
	tokens := RowRegex.Split(row_data, 13)
	if len(tokens) != 13 {
		return nil, errors.New("Failed to parse row data for sample")
	}

	var err error
	process_io := &ProcessIO{}

	if process_io.disk_read_rate, err = strconv.ParseFloat(tokens[4], 64); err != nil {
		return nil, err
	}
	if process_io.disk_write_rate, err = strconv.ParseFloat(tokens[6], 64); err != nil {
		return nil, err
	}
	if process_io.swapin_percent, err = strconv.ParseFloat(tokens[8], 64); err != nil {
		return nil, err
	}
	if process_io.io_percent, err = strconv.ParseFloat(tokens[10], 64); err != nil {
		return nil, err
	}
	process_io.Name = tokens[12]

	return process_io, nil
}

func (p *ProcessIO) Aggregate(process *ProcessIO) {
	p.disk_read_rate += process.disk_read_rate
	p.disk_write_rate += process.disk_write_rate
	p.swapin_percent += process.swapin_percent
	p.io_percent += process.io_percent
}

// Total DISK READ: 0.20 K/s | Total DISK WRITE: 0.01 K/s
func IsSampleSummary(row_data string) bool {
	return strings.Contains(row_data, "Total DISK READ")
}

type Sample struct {
	processes_io map[string]*ProcessIO
}

func NewSample() *Sample {
	return &Sample{
		processes_io: make(map[string]*ProcessIO),
	}
}

func (s *Sample) Append(process *ProcessIO) {
	if val, has := s.processes_io[process.Name]; has {
		val.Aggregate(process)
	} else {
		s.processes_io[process.Name] = process
	}
}

func (s *Sample) Empty() bool {
	if len(s.processes_io) > 0 {
		return false
	}

	return true
}

type IOTopCollector struct {
	disk_read_rate    map[string]*StatSample
	disk_write_rate   map[string]*StatSample
	swapin_percent    map[string]*StatSample
	io_percent        map[string]*StatSample
	measurements_lock sync.RWMutex
}

func (i *IOTopCollector) Run() {
	i.measurements_lock.Lock()

	command_pipe := make(chan string, 1000)

	go i.executeIOTop(command_pipe)
	go i.processOutput(command_pipe)

	i.measurements_lock.Unlock()

}

func (i *IOTopCollector) GetAndPurgeIOPercent() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.io_percent
	i.io_percent = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetAndPurgeSwapinPercent() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.swapin_percent
	i.swapin_percent = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetAndPurgeDiskReadRate() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.disk_read_rate
	i.disk_read_rate = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetAndPurgeDiskWriteRate() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.disk_write_rate
	i.disk_write_rate = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetUniqKeys(data map[string]*StatSample) []string {
	var sample_list []string

	for key := range data {
		sample_list = append(sample_list, key)
	}

	return sample_list
}

func (i *IOTopCollector) processOutput(data <-chan string) {
	sample := NewSample()

	for row := range data {

		if IsSampleSummary(row) {
			if sample != nil && !sample.Empty() {
				i.FlushSample(sample)
			}

			sample = NewSample()
		} else {
			p, err := NewProcessIOFromString(row)
			if err != nil {
				continue
			}

			sample.Append(p)
		}
	}
}

func (i *IOTopCollector) FlushSample(sample *Sample) {
	i.measurements_lock.Lock()
	if i.disk_read_rate == nil {
		i.disk_read_rate = make(map[string]*StatSample, len(sample.processes_io))
	}

	if i.disk_write_rate == nil {
		i.disk_write_rate = make(map[string]*StatSample, len(sample.processes_io))
	}

	if i.io_percent == nil {
		i.io_percent = make(map[string]*StatSample, len(sample.processes_io))
	}

	if i.swapin_percent == nil {
		i.swapin_percent = make(map[string]*StatSample, len(sample.processes_io))
	}

	for key, val := range sample.processes_io {
		if entry, has := i.disk_read_rate[key]; has {
			entry.Append(val.disk_read_rate)
		} else {
			i.disk_read_rate[key] = NewStatSample(val.disk_read_rate)
		}

		if entry, has := i.disk_write_rate[key]; has {
			entry.Append(val.disk_write_rate)
		} else {
			i.disk_write_rate[key] = NewStatSample(val.disk_write_rate)
		}

		if entry, has := i.io_percent[key]; has {
			entry.Append(val.io_percent)
		} else {
			i.io_percent[key] = NewStatSample(val.io_percent)
		}

		if entry, has := i.swapin_percent[key]; has {
			entry.Append(val.swapin_percent)
		} else {
			i.swapin_percent[key] = NewStatSample(val.swapin_percent)
		}
	}
	i.measurements_lock.Unlock()
}

func (i *IOTopCollector) executeIOTop(ch chan<- string) {
	cmd := exec.Command("iotop", "-bPkqqt")
	stdout, err := cmd.StdoutPipe()

	if err != nil {
		log.Fatal(err)
	}

	if err = cmd.Start(); err != nil {
		log.Fatal(err)
	}

	in := bufio.NewScanner(stdout)

	for in.Scan() {
		ch <- in.Text()
	}

	if err := in.Err(); err != nil {
		log.Fatal(err)
	}

	close(ch)
}

type StatSample struct {
	total float64
	count float64
}

func NewStatSample(value float64) *StatSample {
	return &StatSample{
		total: value,
		count: 1,
	}
}

func (s *StatSample) Append(value float64) {
	s.count += 1
	s.total += value
}

func (s *StatSample) GetAverage() float64 {
	return s.total / s.count
}
<commit_msg>remove fmt packge<commit_after>package main

import (
	"bufio"
	"errors"
	"log"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"sync"
)

func init() {
	RowRegex = regexp.MustCompile("[\\s]+")
}

var RowRegex *regexp.Regexp

type ProcessIO struct {
	disk_read_rate  float64
	disk_write_rate float64
	swapin_percent  float64
	io_percent      float64
	Name            string
}

// expected format:
//13:05:19 24086 be/4 cfapache    0.00 K/s    0.00 K/s  0.00 %  0.00 % httpd -k start
func NewProcessIOFromString(row_data string) (*ProcessIO, error) {
	tokens := RowRegex.Split(row_data, 13)
	if len(tokens) != 13 {
		return nil, errors.New("Failed to parse row data for sample")
	}

	var err error
	process_io := &ProcessIO{}

	if process_io.disk_read_rate, err = strconv.ParseFloat(tokens[4], 64); err != nil {
		return nil, err
	}
	if process_io.disk_write_rate, err = strconv.ParseFloat(tokens[6], 64); err != nil {
		return nil, err
	}
	if process_io.swapin_percent, err = strconv.ParseFloat(tokens[8], 64); err != nil {
		return nil, err
	}
	if process_io.io_percent, err = strconv.ParseFloat(tokens[10], 64); err != nil {
		return nil, err
	}
	process_io.Name = tokens[12]

	return process_io, nil
}

func (p *ProcessIO) Aggregate(process *ProcessIO) {
	p.disk_read_rate += process.disk_read_rate
	p.disk_write_rate += process.disk_write_rate
	p.swapin_percent += process.swapin_percent
	p.io_percent += process.io_percent
}

// Total DISK READ: 0.20 K/s | Total DISK WRITE: 0.01 K/s
func IsSampleSummary(row_data string) bool {
	return strings.Contains(row_data, "Total DISK READ")
}

type Sample struct {
	processes_io map[string]*ProcessIO
}

func NewSample() *Sample {
	return &Sample{
		processes_io: make(map[string]*ProcessIO),
	}
}

func (s *Sample) Append(process *ProcessIO) {
	if val, has := s.processes_io[process.Name]; has {
		val.Aggregate(process)
	} else {
		s.processes_io[process.Name] = process
	}
}

func (s *Sample) Empty() bool {
	if len(s.processes_io) > 0 {
		return false
	}

	return true
}

type IOTopCollector struct {
	disk_read_rate    map[string]*StatSample
	disk_write_rate   map[string]*StatSample
	swapin_percent    map[string]*StatSample
	io_percent        map[string]*StatSample
	measurements_lock sync.RWMutex
}

func (i *IOTopCollector) Run() {
	i.measurements_lock.Lock()

	command_pipe := make(chan string, 1000)

	go i.executeIOTop(command_pipe)
	go i.processOutput(command_pipe)

	i.measurements_lock.Unlock()

}

func (i *IOTopCollector) GetAndPurgeIOPercent() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.io_percent
	i.io_percent = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetAndPurgeSwapinPercent() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.swapin_percent
	i.swapin_percent = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetAndPurgeDiskReadRate() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.disk_read_rate
	i.disk_read_rate = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetAndPurgeDiskWriteRate() map[string]*StatSample {
	i.measurements_lock.Lock()
	samples := i.disk_write_rate
	i.disk_write_rate = nil
	i.measurements_lock.Unlock()

	return samples
}

func (i *IOTopCollector) GetUniqKeys(data map[string]*StatSample) []string {
	var sample_list []string

	for key := range data {
		sample_list = append(sample_list, key)
	}

	return sample_list
}

func (i *IOTopCollector) processOutput(data <-chan string) {
	sample := NewSample()

	for row := range data {

		if IsSampleSummary(row) {
			if sample != nil && !sample.Empty() {
				i.FlushSample(sample)
			}

			sample = NewSample()
		} else {
			p, err := NewProcessIOFromString(row)
			if err != nil {
				continue
			}

			sample.Append(p)
		}
	}
}

func (i *IOTopCollector) FlushSample(sample *Sample) {
	i.measurements_lock.Lock()
	if i.disk_read_rate == nil {
		i.disk_read_rate = make(map[string]*StatSample, len(sample.processes_io))
	}

	if i.disk_write_rate == nil {
		i.disk_write_rate = make(map[string]*StatSample, len(sample.processes_io))
	}

	if i.io_percent == nil {
		i.io_percent = make(map[string]*StatSample, len(sample.processes_io))
	}

	if i.swapin_percent == nil {
		i.swapin_percent = make(map[string]*StatSample, len(sample.processes_io))
	}

	for key, val := range sample.processes_io {
		if entry, has := i.disk_read_rate[key]; has {
			entry.Append(val.disk_read_rate)
		} else {
			i.disk_read_rate[key] = NewStatSample(val.disk_read_rate)
		}

		if entry, has := i.disk_write_rate[key]; has {
			entry.Append(val.disk_write_rate)
		} else {
			i.disk_write_rate[key] = NewStatSample(val.disk_write_rate)
		}

		if entry, has := i.io_percent[key]; has {
			entry.Append(val.io_percent)
		} else {
			i.io_percent[key] = NewStatSample(val.io_percent)
		}

		if entry, has := i.swapin_percent[key]; has {
			entry.Append(val.swapin_percent)
		} else {
			i.swapin_percent[key] = NewStatSample(val.swapin_percent)
		}
	}
	i.measurements_lock.Unlock()
}

func (i *IOTopCollector) executeIOTop(ch chan<- string) {
	cmd := exec.Command("iotop", "-bPkqqt")
	stdout, err := cmd.StdoutPipe()

	if err != nil {
		log.Fatal(err)
	}

	if err = cmd.Start(); err != nil {
		log.Fatal(err)
	}

	in := bufio.NewScanner(stdout)

	for in.Scan() {
		ch <- in.Text()
	}

	if err := in.Err(); err != nil {
		log.Fatal(err)
	}

	close(ch)
}

type StatSample struct {
	total float64
	count float64
}

func NewStatSample(value float64) *StatSample {
	return &StatSample{
		total: value,
		count: 1,
	}
}

func (s *StatSample) Append(value float64) {
	s.count += 1
	s.total += value
}

func (s *StatSample) GetAverage() float64 {
	return s.total / s.count
}
<|endoftext|>


<commit_before>package configparser

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"
	"unicode"
)

const (
	defaultSectionName        = "DEFAULT"
	maxInterpolationDepth int = 10
)

var (
	sectionHeader    = regexp.MustCompile("\\[([^]]+)\\]")
	keyValue         = regexp.MustCompile("([^:=\\s][^:=]*)\\s*(?P<vi>[:=])\\s*(.*)$")
	continuationLine = regexp.MustCompile("\\w+(.*)$")
	interpolater     = regexp.MustCompile("%\\(([^)]*)\\)s")
)

var boolMapping = map[string]bool{
	"1":     true,
	"true":  true,
	"on":    true,
	"yes":   true,
	"0":     false,
	"false": false,
	"off":   false,
	"no":    false,
}

type Dict map[string]string
type Config map[string]Dict

type ConfigParser struct {
	config   Config
	defaults Dict
}

func getNoSectionError(section string) error {
	return fmt.Errorf("No section: '%s'", section)
}

func getNoOptionError(section, option string) error {
	return fmt.Errorf("No option '%s' in section: '%s'", option, section)
}

func New() *ConfigParser {
	return &ConfigParser{
		config:   make(Config),
		defaults: make(Dict),
	}
}

func NewWithDefaults(defaults Dict) *ConfigParser {
	p := ConfigParser{
		config:   make(Config),
		defaults: make(Dict),
	}
	for key, value := range defaults {
		p.defaults[key] = value
	}
	return &p
}

// Create a new ConfigParser struct populated from the supplied filename
func NewConfigParserFromFile(filename string) (*ConfigParser, error) {
	p, err := Parse(filename)
	if err != nil {
		return nil, err
	}
	return p, nil
}

func parseFile(file *os.File) (*ConfigParser, error) {
	p := New()
	defer file.Close()

	reader := bufio.NewReader(file)
	var lineNo int
	var err error
	var curSect Dict

	for err == nil {
		l, _, err := reader.ReadLine()
		if err != nil {
			break
		}
		lineNo++
		if len(l) == 0 {
			continue
		}
		line := strings.TrimFunc(string(l), unicode.IsSpace)

		// Skip comment lines and empty lines
		if strings.HasPrefix(line, "#") || line == "" {
			continue
		}

		if match := sectionHeader.FindStringSubmatch(line); len(match) > 0 {
			section := match[1]
			if section == defaultSectionName {
				curSect = p.defaults
			} else if _, present := p.config[section]; !present {
				curSect = make(Dict)
				p.config[section] = curSect
			}
		} else if match = keyValue.FindStringSubmatch(line); len(match) > 0 {
			if curSect == nil {
				return nil, fmt.Errorf("Missing Section Header: %d %s", lineNo, line)
			} else {
				option := match[1]
				// separator := match[2]
				value := p.transformOption(strings.TrimFunc(match[3], unicode.IsSpace))
				curSect[option] = value
			}
		}
	}
	return p, nil
}

func Parse(filename string) (*ConfigParser, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	p, err := parseFile(file)
	if err != nil {
		return nil, err
	}
	return p, nil
}

func writeSection(file *os.File, name, delimiter string, options Dict) error {
	_, err := file.WriteString(fmt.Sprintf("[%s]\n", name))
	if err != nil {
		return err
	}
	for k, v := range options {
		_, err = file.WriteString(fmt.Sprintf("%s %s %s\n", k, delimiter, v))
		if err != nil {
			return err
		}
	}
	_, err = file.WriteString("\n")
	return err
}

// Save the current state of the ConfigParser to the named file with the specified delimiter
func (p *ConfigParser) SaveWithDelimiter(filename, delimiter string) error {
	f, err := os.Create(filename)
	defer f.Close()
	if err != nil {
		return err
	}

	d := p.Defaults()
	if len(d) > 0 {
		err = writeSection(f, "defaults", delimiter, d)
		if err != nil {
			return err
		}
	}

	for _, s := range p.Sections() {
		d, err = p.Items(s)
		if err != nil {
			return err
		}
		err = writeSection(f, s, delimiter, d)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Fix test failures due to random map iteration<commit_after>package configparser

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"unicode"
)

const (
	defaultSectionName        = "DEFAULT"
	maxInterpolationDepth int = 10
)

var (
	sectionHeader    = regexp.MustCompile("\\[([^]]+)\\]")
	keyValue         = regexp.MustCompile("([^:=\\s][^:=]*)\\s*(?P<vi>[:=])\\s*(.*)$")
	continuationLine = regexp.MustCompile("\\w+(.*)$")
	interpolater     = regexp.MustCompile("%\\(([^)]*)\\)s")
)

var boolMapping = map[string]bool{
	"1":     true,
	"true":  true,
	"on":    true,
	"yes":   true,
	"0":     false,
	"false": false,
	"off":   false,
	"no":    false,
}

type Dict map[string]string
type Config map[string]Dict

type ConfigParser struct {
	config   Config
	defaults Dict
}

// Keys returns a sorted slice of keys
func (d Dict) Keys() []string {
	var keys []string

	for key := range d {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	return keys
}

func getNoSectionError(section string) error {
	return fmt.Errorf("No section: '%s'", section)
}

func getNoOptionError(section, option string) error {
	return fmt.Errorf("No option '%s' in section: '%s'", option, section)
}

func New() *ConfigParser {
	return &ConfigParser{
		config:   make(Config),
		defaults: make(Dict),
	}
}

func NewWithDefaults(defaults Dict) *ConfigParser {
	p := ConfigParser{
		config:   make(Config),
		defaults: make(Dict),
	}
	for key, value := range defaults {
		p.defaults[key] = value
	}
	return &p
}

// Create a new ConfigParser struct populated from the supplied filename
func NewConfigParserFromFile(filename string) (*ConfigParser, error) {
	p, err := Parse(filename)
	if err != nil {
		return nil, err
	}
	return p, nil
}

func parseFile(file *os.File) (*ConfigParser, error) {
	p := New()
	defer file.Close()

	reader := bufio.NewReader(file)
	var lineNo int
	var err error
	var curSect Dict

	for err == nil {
		l, _, err := reader.ReadLine()
		if err != nil {
			break
		}
		lineNo++
		if len(l) == 0 {
			continue
		}
		line := strings.TrimFunc(string(l), unicode.IsSpace)

		// Skip comment lines and empty lines
		if strings.HasPrefix(line, "#") || line == "" {
			continue
		}

		if match := sectionHeader.FindStringSubmatch(line); len(match) > 0 {
			section := match[1]
			if section == defaultSectionName {
				curSect = p.defaults
			} else if _, present := p.config[section]; !present {
				curSect = make(Dict)
				p.config[section] = curSect
			}
		} else if match = keyValue.FindStringSubmatch(line); len(match) > 0 {
			if curSect == nil {
				return nil, fmt.Errorf("Missing Section Header: %d %s", lineNo, line)
			} else {
				option := match[1]
				// separator := match[2]
				value := p.transformOption(strings.TrimFunc(match[3], unicode.IsSpace))
				curSect[option] = value
			}
		}
	}
	return p, nil
}

func Parse(filename string) (*ConfigParser, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	p, err := parseFile(file)
	if err != nil {
		return nil, err
	}
	return p, nil
}

func writeSection(file *os.File, name, delimiter string, options Dict) error {
	_, err := file.WriteString(fmt.Sprintf("[%s]\n", name))
	if err != nil {
		return err
	}

	for _, key := range options.Keys() {
		_, err = file.WriteString(fmt.Sprintf("%s %s %s\n", key, delimiter, options[key]))
		if err != nil {
			return err
		}
	}
	_, err = file.WriteString("\n")
	return err
}

// Save the current state of the ConfigParser to the named file with the specified delimiter
func (p *ConfigParser) SaveWithDelimiter(filename, delimiter string) error {
	f, err := os.Create(filename)
	defer f.Close()
	if err != nil {
		return err
	}

	d := p.Defaults()
	if len(d) > 0 {
		err = writeSection(f, "defaults", delimiter, d)
		if err != nil {
			return err
		}
	}

	for _, s := range p.Sections() {
		d, err = p.Items(s)
		if err != nil {
			return err
		}
		err = writeSection(f, s, delimiter, d)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package connect

import (
	"bytes"
	"encoding/binary"
	"io"
	"net"

	"github.com/crunchydata/crunchy-proxy/config"
	"github.com/crunchydata/crunchy-proxy/protocol"
	"github.com/crunchydata/crunchy-proxy/util/log"
)

/*
 * Handle authentication requests that are sent by the backend to the client.
 *
 * connection - the connection to authenticate against.
 * message - the authentication message sent by the backend.
 */
func handleAuthenticationRequest(connection net.Conn, message []byte) bool {
	var msgLength int32
	var authType int32

	// Read message length.
	reader := bytes.NewReader(message[1:5])
	binary.Read(reader, binary.BigEndian, &msgLength)

	// Read authentication type.
	reader.Reset(message[5:9])
	binary.Read(reader, binary.BigEndian, &authType)

	switch authType {
	case protocol.AuthenticationKerberosV5:
		log.Error("KerberosV5 authentication is not currently supported.")
	case protocol.AuthenticationClearText:
		log.Info("Authenticating with clear text password.")
		return handleAuthClearText(connection)
	case protocol.AuthenticationMD5:
		log.Info("Authenticating with MD5 password.")
		return handleAuthMD5(connection, message)
	case protocol.AuthenticationSCM:
		log.Error("SCM authentication is not currently supported.")
	case protocol.AuthenticationGSS:
		log.Error("GSS authentication is not currently supported.")
	case protocol.AuthenticationGSSContinue:
		log.Error("GSS authentication is not currently supported.")
	case protocol.AuthenticationSSPI:
		log.Error("SSPI authentication is not currently supported.")
	case protocol.AuthenticationOk:
		/* Covers the case where the authentication type is 'cert' or 'trust' */
		return true
	default:
		log.Errorf("Unknown authentication method: %d", authType)
	}

	return false
}

func handleAuthMD5(connection net.Conn, message []byte) bool {
	return true
}

func handleAuthClearText(connection net.Conn) bool {
	password := config.GetString("credentials.password")
	passwordMessage := protocol.CreatePasswordMessage(password)

	_, err := connection.Write(passwordMessage.Bytes())

	if err != nil {
		log.Error("Error sending clear text password message to the backend.")
		log.Errorf("Error: %s", err.Error())
	}

	response := make([]byte, 4096)
	_, err = connection.Read(response)

	if err != nil {
		log.Error("Error receiving clear text authentication response.")
		log.Errorf("Error: %s", err.Error())
	}

	return protocol.IsAuthenticationOk(response)
}

// AuthenticateClient - Establish and authenticate client connection to the backend.
//
//  This function simply handles the passing of messages from the client to the
//  backend necessary for startup/authentication of a connection. All
//  communication is between the client and the master node. If the client
//  authenticates successfully with the master node, then 'true' is returned and
//  the authenticating connection is terminated.
func AuthenticateClient(client net.Conn, message []byte, length int) (bool, error) {
	var err error

	/*
	 * Validate that the client username and database are the same as that
	 * which is configured for the proxy connections.
	 *
	 * If the the client cannot be validated then send an appropriate PG error
	 * message back to the client.
	 */

	nodes := config.GetNodes()

	node := nodes["master"]

	/* Establish a connection with the master node. */
	master, err := net.Dial("tcp", node.HostPort)

	if err != nil {
		log.Error("An error occurred connecting to the master node")
		log.Errorf("Error %s", err.Error())
		return false, err
	}

	defer master.Close()

	/* Relay the startup message to master node. */
	_, err = master.Write(message[:length])

	/* Receive startup response. */
	message, length, err = Receive(master)

	if err != nil {
		log.Error("An error occurred receiving startup response.")
		log.Errorf("Error %s", err.Error())
		return false, err
	}

	/*
	 * While the response for the master node is not an AuthenticationOK or
	 * ErrorResponse keep relaying the mesages to/from the client/master.
	 */
	messageType := protocol.GetMessageType(message)

	for !protocol.IsAuthenticationOk(message) &&
		(messageType != protocol.ErrorMessageType) {
		Send(client, message[:length])
		message, length, err = Receive(client)

		/*
		 * Must check that the client has not closed the connection.  This in
		 * particular is specific to 'psql' when it prompts for a password.
		 * Apparently, when psql prompts the user for a password it closes the
		 * original connection, and then creates a new one. Eventually the
		 * following send/receives would timeout and no 'meaningful' messages
		 * are relayed. This would ultimately cause an infinite loop.  Thus it
		 * is better to short circuit here if the client connection has been
		 * closed.
		 */
		if (err != nil) && (err == io.EOF) {
			log.Info("The client closed the connection.")
			log.Debug("If the client is 'psql' and the authentication method " +
				"was 'password', then this behavior is expected.")
			return false, err
		}

		Send(master, message[:length])

		message, length, err = Receive(master)

		messageType = protocol.GetMessageType(message)
	}

	/*
	 * If the last response from the master node was AuthenticationOK, then
	 * terminate the connection and return 'true' for a successful
	 * authentication of the client.
	 */
	if protocol.IsAuthenticationOk(message) {
		termMsg := protocol.GetTerminateMessage()
		Send(master, termMsg)
		Send(client, message[:length])
		return true, nil
	}

	if protocol.GetMessageType(message) == protocol.ErrorMessageType {
		err = protocol.ParseError(message)
		log.Error("Error occurred on client startup.")
		log.Errorf("Error: %s", err.Error())
		log.Debugf("%s", message[:length])
	} else {
		log.Error("Unknown error occurred on client startup.")
	}

	Send(client, message[:length])

	return false, err
}

func ValidateClient(message []byte) bool {
	var clientUser string
	var clientDatabase string

	creds := config.GetCredentials()

	startup := protocol.NewMessageBuffer(message)

	startup.Seek(8) // Seek past the message length and protocol version.

	for param, err := startup.ReadString(); err != io.EOF; param, err = startup.ReadString() {
		switch param {
		case "user":
			clientUser, _ = startup.ReadString()
		case "database":
			clientDatabase, _ = startup.ReadString()
		}
	}

	return (clientUser == creds.Username && clientDatabase == creds.Database)
}
<commit_msg>update validate client parsing of startup message<commit_after>package connect

import (
	"bytes"
	"encoding/binary"
	"io"
	"net"

	"github.com/crunchydata/crunchy-proxy/config"
	"github.com/crunchydata/crunchy-proxy/protocol"
	"github.com/crunchydata/crunchy-proxy/util/log"
)

/*
 * Handle authentication requests that are sent by the backend to the client.
 *
 * connection - the connection to authenticate against.
 * message - the authentication message sent by the backend.
 */
func handleAuthenticationRequest(connection net.Conn, message []byte) bool {
	var msgLength int32
	var authType int32

	// Read message length.
	reader := bytes.NewReader(message[1:5])
	binary.Read(reader, binary.BigEndian, &msgLength)

	// Read authentication type.
	reader.Reset(message[5:9])
	binary.Read(reader, binary.BigEndian, &authType)

	switch authType {
	case protocol.AuthenticationKerberosV5:
		log.Error("KerberosV5 authentication is not currently supported.")
	case protocol.AuthenticationClearText:
		log.Info("Authenticating with clear text password.")
		return handleAuthClearText(connection)
	case protocol.AuthenticationMD5:
		log.Info("Authenticating with MD5 password.")
		return handleAuthMD5(connection, message)
	case protocol.AuthenticationSCM:
		log.Error("SCM authentication is not currently supported.")
	case protocol.AuthenticationGSS:
		log.Error("GSS authentication is not currently supported.")
	case protocol.AuthenticationGSSContinue:
		log.Error("GSS authentication is not currently supported.")
	case protocol.AuthenticationSSPI:
		log.Error("SSPI authentication is not currently supported.")
	case protocol.AuthenticationOk:
		/* Covers the case where the authentication type is 'cert' or 'trust' */
		return true
	default:
		log.Errorf("Unknown authentication method: %d", authType)
	}

	return false
}

func handleAuthMD5(connection net.Conn, message []byte) bool {
	return true
}

func handleAuthClearText(connection net.Conn) bool {
	password := config.GetString("credentials.password")
	passwordMessage := protocol.CreatePasswordMessage(password)

	_, err := connection.Write(passwordMessage.Bytes())

	if err != nil {
		log.Error("Error sending clear text password message to the backend.")
		log.Errorf("Error: %s", err.Error())
	}

	response := make([]byte, 4096)
	_, err = connection.Read(response)

	if err != nil {
		log.Error("Error receiving clear text authentication response.")
		log.Errorf("Error: %s", err.Error())
	}

	return protocol.IsAuthenticationOk(response)
}

// AuthenticateClient - Establish and authenticate client connection to the backend.
//
//  This function simply handles the passing of messages from the client to the
//  backend necessary for startup/authentication of a connection. All
//  communication is between the client and the master node. If the client
//  authenticates successfully with the master node, then 'true' is returned and
//  the authenticating connection is terminated.
func AuthenticateClient(client net.Conn, message []byte, length int) (bool, error) {
	var err error

	nodes := config.GetNodes()

	node := nodes["master"]

	/* Establish a connection with the master node. */
	master, err := net.Dial("tcp", node.HostPort)

	if err != nil {
		log.Error("An error occurred connecting to the master node")
		log.Errorf("Error %s", err.Error())
		return false, err
	}

	defer master.Close()

	/* Relay the startup message to master node. */
	_, err = master.Write(message[:length])

	/* Receive startup response. */
	message, length, err = Receive(master)

	if err != nil {
		log.Error("An error occurred receiving startup response.")
		log.Errorf("Error %s", err.Error())
		return false, err
	}

	/*
	 * While the response for the master node is not an AuthenticationOK or
	 * ErrorResponse keep relaying the mesages to/from the client/master.
	 */
	messageType := protocol.GetMessageType(message)

	for !protocol.IsAuthenticationOk(message) &&
		(messageType != protocol.ErrorMessageType) {
		Send(client, message[:length])
		message, length, err = Receive(client)

		/*
		 * Must check that the client has not closed the connection.  This in
		 * particular is specific to 'psql' when it prompts for a password.
		 * Apparently, when psql prompts the user for a password it closes the
		 * original connection, and then creates a new one. Eventually the
		 * following send/receives would timeout and no 'meaningful' messages
		 * are relayed. This would ultimately cause an infinite loop.  Thus it
		 * is better to short circuit here if the client connection has been
		 * closed.
		 */
		if (err != nil) && (err == io.EOF) {
			log.Info("The client closed the connection.")
			log.Debug("If the client is 'psql' and the authentication method " +
				"was 'password', then this behavior is expected.")
			return false, err
		}

		Send(master, message[:length])

		message, length, err = Receive(master)

		messageType = protocol.GetMessageType(message)
	}

	/*
	 * If the last response from the master node was AuthenticationOK, then
	 * terminate the connection and return 'true' for a successful
	 * authentication of the client.
	 */
	if protocol.IsAuthenticationOk(message) {
		termMsg := protocol.GetTerminateMessage()
		Send(master, termMsg)
		Send(client, message[:length])
		return true, nil
	}

	if protocol.GetMessageType(message) == protocol.ErrorMessageType {
		err = protocol.ParseError(message)
		log.Error("Error occurred on client startup.")
		log.Errorf("Error: %s", err.Error())
		log.Debugf("%s", message[:length])
	} else {
		log.Error("Unknown error occurred on client startup.")
	}

	Send(client, message[:length])

	return false, err
}

func ValidateClient(message []byte) bool {
	var clientUser string
	var clientDatabase string

	creds := config.GetCredentials()

	startup := protocol.NewMessageBuffer(message)

	startup.Seek(8) // Seek past the message length and protocol version.

	for {
		param, err := startup.ReadString()

		if err == io.EOF || param == "\x00" {
			break
		}

		switch param {
		case "user":
			clientUser, err = startup.ReadString()
		case "database":
			clientDatabase, err = startup.ReadString()
		}
	}

	return (clientUser == creds.Username && clientDatabase == creds.Database)
}
<|endoftext|>


<commit_before>package jsoniter

import (
	"fmt"
	"reflect"
	"strings"
	"unicode"
	"unsafe"
)

var typeDecoders = map[string]ValDecoder{}
var fieldDecoders = map[string]ValDecoder{}
var typeEncoders = map[string]ValEncoder{}
var fieldEncoders = map[string]ValEncoder{}
var extensions = []Extension{}

type StructDescriptor struct {
	onePtrEmbedded     bool
	onePtrOptimization bool
	Type               reflect.Type
	Fields             []*Binding
}

func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding {
	for _, binding := range structDescriptor.Fields {
		if binding.Field.Name == fieldName {
			return binding
		}
	}
	return nil
}

type Binding struct {
	Field     *reflect.StructField
	FromNames []string
	ToNames   []string
	Encoder   ValEncoder
	Decoder   ValDecoder
}

type Extension interface {
	UpdateStructDescriptor(structDescriptor *StructDescriptor)
	CreateDecoder(typ reflect.Type) ValDecoder
	CreateEncoder(typ reflect.Type) ValEncoder
	DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder
	DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder
}

type DummyExtension struct {
}

func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
}

func (extension *DummyExtension) CreateDecoder(typ reflect.Type) ValDecoder {
	return nil
}

func (extension *DummyExtension) CreateEncoder(typ reflect.Type) ValEncoder {
	return nil
}

func (extension *DummyExtension) DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder {
	return decoder
}

func (extension *DummyExtension) DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder {
	return encoder
}

type funcDecoder struct {
	fun DecoderFunc
}

func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
	decoder.fun(ptr, iter)
}

type funcEncoder struct {
	fun         EncoderFunc
	isEmptyFunc func(ptr unsafe.Pointer) bool
}

func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
	encoder.fun(ptr, stream)
}

func (encoder *funcEncoder) EncodeInterface(val interface{}, stream *Stream) {
	WriteToStream(val, stream, encoder)
}

func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	if encoder.isEmptyFunc == nil {
		return false
	}
	return encoder.isEmptyFunc(ptr)
}

func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) {
	typeDecoders[typ] = &funcDecoder{fun}
}

func RegisterTypeDecoder(typ string, decoder ValDecoder) {
	typeDecoders[typ] = decoder
}

func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) {
	RegisterFieldDecoder(typ, field, &funcDecoder{fun})
}

func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) {
	fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder
}

func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc}
}

func RegisterTypeEncoder(typ string, encoder ValEncoder) {
	typeEncoders[typ] = encoder
}

func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc})
}

func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) {
	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder
}

func RegisterExtension(extension Extension) {
	extensions = append(extensions, extension)
}

func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	decoder := _getTypeDecoderFromExtension(typ)
	if decoder != nil {
		for _, extension := range extensions {
			decoder = extension.DecorateDecoder(typ, decoder)
		}
	}
	return decoder
}
func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	for _, extension := range extensions {
		decoder := extension.CreateDecoder(typ)
		if decoder != nil {
			return decoder
		}
	}
	typeName := typ.String()
	decoder := typeDecoders[typeName]
	if decoder != nil {
		return decoder
	}
	if typ.Kind() == reflect.Ptr {
		decoder := typeDecoders[typ.Elem().String()]
		if decoder != nil {
			return &optionalDecoder{typ.Elem(), decoder}
		}
	}
	return nil
}

func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	encoder := _getTypeEncoderFromExtension(typ)
	if encoder != nil {
		for _, extension := range extensions {
			encoder = extension.DecorateEncoder(typ, encoder)
		}
	}
	return encoder
}

func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	for _, extension := range extensions {
		encoder := extension.CreateEncoder(typ)
		if encoder != nil {
			return encoder
		}
	}
	typeName := typ.String()
	encoder := typeEncoders[typeName]
	if encoder != nil {
		return encoder
	}
	if typ.Kind() == reflect.Ptr {
		encoder := typeEncoders[typ.Elem().String()]
		if encoder != nil {
			return &optionalEncoder{encoder}
		}
	}
	return nil
}

func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) {
	headAnonymousBindings := []*Binding{}
	tailAnonymousBindings := []*Binding{}
	bindings := []*Binding{}
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		if field.Anonymous {
			if field.Type.Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type)
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
				continue
			} else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type.Elem())
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					cloneField := field
					cloneField.Name = binding.Field.Name
					binding.Encoder = &optionalEncoder{binding.Encoder}
					binding.Encoder = &structFieldEncoder{&cloneField, binding.Encoder, false}
					binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
					binding.Decoder = &structFieldDecoder{&cloneField, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
				continue
			}
		}
		tagParts := strings.Split(field.Tag.Get("json"), ",")
		fieldNames := calcFieldNames(field.Name, tagParts[0], string(field.Tag))
		fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
		decoder := fieldDecoders[fieldCacheKey]
		if decoder == nil {
			var err error
			decoder, err = decoderOfType(cfg, field.Type)
			if err != nil {
				return nil, err
			}
		}
		encoder := fieldEncoders[fieldCacheKey]
		if encoder == nil {
			var err error
			encoder, err = encoderOfType(cfg, field.Type)
			if err != nil {
				return nil, err
			}
			// map is stored as pointer in the struct
			if field.Type.Kind() == reflect.Map {
				encoder = &optionalEncoder{encoder}
			}
		}
		binding := &Binding{
			Field:     &field,
			FromNames: fieldNames,
			ToNames:   fieldNames,
			Decoder:   decoder,
			Encoder:   encoder,
		}
		bindings = append(bindings, binding)
	}
	return createStructDescriptor(cfg, typ, bindings, headAnonymousBindings, tailAnonymousBindings), nil
}
func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, headAnonymousBindings []*Binding, tailAnonymousBindings []*Binding) *StructDescriptor {
	onePtrEmbedded := false
	onePtrOptimization := false
	if typ.NumField() == 1 {
		firstField := typ.Field(0)
		switch firstField.Type.Kind() {
		case reflect.Ptr:
			if firstField.Anonymous && firstField.Type.Elem().Kind() == reflect.Struct {
				onePtrEmbedded = true
			}
			fallthrough
		case reflect.Map:
			fallthrough
		case reflect.Slice:
			onePtrOptimization = true
		}
	}
	structDescriptor := &StructDescriptor{
		onePtrEmbedded:     onePtrEmbedded,
		onePtrOptimization: onePtrOptimization,
		Type:               typ,
		Fields:             bindings,
	}
	for _, extension := range extensions {
		extension.UpdateStructDescriptor(structDescriptor)
	}
	processTags(structDescriptor, cfg)
	// insert anonymous bindings to the head
	structDescriptor.Fields = append(headAnonymousBindings, structDescriptor.Fields...)
	structDescriptor.Fields = append(structDescriptor.Fields, tailAnonymousBindings...)
	return structDescriptor
}

func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) {
	for _, binding := range structDescriptor.Fields {
		shouldOmitEmpty := false
		tagParts := strings.Split(binding.Field.Tag.Get("json"), ",")
		for _, tagPart := range tagParts[1:] {
			if tagPart == "omitempty" {
				shouldOmitEmpty = true
			} else if tagPart == "string" {
				if binding.Field.Type.Kind() == reflect.String {
					binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg}
					binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg}
				} else {
					binding.Decoder = &stringModeNumberDecoder{binding.Decoder}
					binding.Encoder = &stringModeNumberEncoder{binding.Encoder}
				}
			}
		}
		binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder}
		binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty}
	}
}

func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string {
	// ignore?
	if wholeTag == "-" {
		return []string{}
	}
	// rename?
	var fieldNames []string
	if tagProvidedFieldName == "" {
		fieldNames = []string{originalFieldName}
	} else {
		fieldNames = []string{tagProvidedFieldName}
	}
	// private?
	isNotExported := unicode.IsLower(rune(originalFieldName[0]))
	if isNotExported {
		fieldNames = []string{}
	}
	return fieldNames
}
<commit_msg>slice embedded in struct will not be optimized by interface{}<commit_after>package jsoniter

import (
	"fmt"
	"reflect"
	"strings"
	"unicode"
	"unsafe"
)

var typeDecoders = map[string]ValDecoder{}
var fieldDecoders = map[string]ValDecoder{}
var typeEncoders = map[string]ValEncoder{}
var fieldEncoders = map[string]ValEncoder{}
var extensions = []Extension{}

type StructDescriptor struct {
	onePtrEmbedded     bool
	onePtrOptimization bool
	Type               reflect.Type
	Fields             []*Binding
}

func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding {
	for _, binding := range structDescriptor.Fields {
		if binding.Field.Name == fieldName {
			return binding
		}
	}
	return nil
}

type Binding struct {
	Field     *reflect.StructField
	FromNames []string
	ToNames   []string
	Encoder   ValEncoder
	Decoder   ValDecoder
}

type Extension interface {
	UpdateStructDescriptor(structDescriptor *StructDescriptor)
	CreateDecoder(typ reflect.Type) ValDecoder
	CreateEncoder(typ reflect.Type) ValEncoder
	DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder
	DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder
}

type DummyExtension struct {
}

func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
}

func (extension *DummyExtension) CreateDecoder(typ reflect.Type) ValDecoder {
	return nil
}

func (extension *DummyExtension) CreateEncoder(typ reflect.Type) ValEncoder {
	return nil
}

func (extension *DummyExtension) DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder {
	return decoder
}

func (extension *DummyExtension) DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder {
	return encoder
}

type funcDecoder struct {
	fun DecoderFunc
}

func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
	decoder.fun(ptr, iter)
}

type funcEncoder struct {
	fun         EncoderFunc
	isEmptyFunc func(ptr unsafe.Pointer) bool
}

func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
	encoder.fun(ptr, stream)
}

func (encoder *funcEncoder) EncodeInterface(val interface{}, stream *Stream) {
	WriteToStream(val, stream, encoder)
}

func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	if encoder.isEmptyFunc == nil {
		return false
	}
	return encoder.isEmptyFunc(ptr)
}

func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) {
	typeDecoders[typ] = &funcDecoder{fun}
}

func RegisterTypeDecoder(typ string, decoder ValDecoder) {
	typeDecoders[typ] = decoder
}

func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) {
	RegisterFieldDecoder(typ, field, &funcDecoder{fun})
}

func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) {
	fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder
}

func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc}
}

func RegisterTypeEncoder(typ string, encoder ValEncoder) {
	typeEncoders[typ] = encoder
}

func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
	RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc})
}

func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) {
	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder
}

func RegisterExtension(extension Extension) {
	extensions = append(extensions, extension)
}

func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	decoder := _getTypeDecoderFromExtension(typ)
	if decoder != nil {
		for _, extension := range extensions {
			decoder = extension.DecorateDecoder(typ, decoder)
		}
	}
	return decoder
}
func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
	for _, extension := range extensions {
		decoder := extension.CreateDecoder(typ)
		if decoder != nil {
			return decoder
		}
	}
	typeName := typ.String()
	decoder := typeDecoders[typeName]
	if decoder != nil {
		return decoder
	}
	if typ.Kind() == reflect.Ptr {
		decoder := typeDecoders[typ.Elem().String()]
		if decoder != nil {
			return &optionalDecoder{typ.Elem(), decoder}
		}
	}
	return nil
}

func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	encoder := _getTypeEncoderFromExtension(typ)
	if encoder != nil {
		for _, extension := range extensions {
			encoder = extension.DecorateEncoder(typ, encoder)
		}
	}
	return encoder
}

func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
	for _, extension := range extensions {
		encoder := extension.CreateEncoder(typ)
		if encoder != nil {
			return encoder
		}
	}
	typeName := typ.String()
	encoder := typeEncoders[typeName]
	if encoder != nil {
		return encoder
	}
	if typ.Kind() == reflect.Ptr {
		encoder := typeEncoders[typ.Elem().String()]
		if encoder != nil {
			return &optionalEncoder{encoder}
		}
	}
	return nil
}

func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) {
	headAnonymousBindings := []*Binding{}
	tailAnonymousBindings := []*Binding{}
	bindings := []*Binding{}
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		if field.Anonymous {
			if field.Type.Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type)
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
					binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
				continue
			} else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
				structDescriptor, err := describeStruct(cfg, field.Type.Elem())
				if err != nil {
					return nil, err
				}
				for _, binding := range structDescriptor.Fields {
					cloneField := field
					cloneField.Name = binding.Field.Name
					binding.Encoder = &optionalEncoder{binding.Encoder}
					binding.Encoder = &structFieldEncoder{&cloneField, binding.Encoder, false}
					binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
					binding.Decoder = &structFieldDecoder{&cloneField, binding.Decoder}
					if field.Offset == 0 {
						headAnonymousBindings = append(headAnonymousBindings, binding)
					} else {
						tailAnonymousBindings = append(tailAnonymousBindings, binding)
					}
				}
				continue
			}
		}
		tagParts := strings.Split(field.Tag.Get("json"), ",")
		fieldNames := calcFieldNames(field.Name, tagParts[0], string(field.Tag))
		fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
		decoder := fieldDecoders[fieldCacheKey]
		if decoder == nil {
			var err error
			decoder, err = decoderOfType(cfg, field.Type)
			if err != nil {
				return nil, err
			}
		}
		encoder := fieldEncoders[fieldCacheKey]
		if encoder == nil {
			var err error
			encoder, err = encoderOfType(cfg, field.Type)
			if err != nil {
				return nil, err
			}
			// map is stored as pointer in the struct
			if field.Type.Kind() == reflect.Map {
				encoder = &optionalEncoder{encoder}
			}
		}
		binding := &Binding{
			Field:     &field,
			FromNames: fieldNames,
			ToNames:   fieldNames,
			Decoder:   decoder,
			Encoder:   encoder,
		}
		bindings = append(bindings, binding)
	}
	return createStructDescriptor(cfg, typ, bindings, headAnonymousBindings, tailAnonymousBindings), nil
}
func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, headAnonymousBindings []*Binding, tailAnonymousBindings []*Binding) *StructDescriptor {
	onePtrEmbedded := false
	onePtrOptimization := false
	if typ.NumField() == 1 {
		firstField := typ.Field(0)
		switch firstField.Type.Kind() {
		case reflect.Ptr:
			if firstField.Anonymous && firstField.Type.Elem().Kind() == reflect.Struct {
				onePtrEmbedded = true
			}
			fallthrough
		case reflect.Map:
			onePtrOptimization = true
		}
	}
	structDescriptor := &StructDescriptor{
		onePtrEmbedded:     onePtrEmbedded,
		onePtrOptimization: onePtrOptimization,
		Type:               typ,
		Fields:             bindings,
	}
	for _, extension := range extensions {
		extension.UpdateStructDescriptor(structDescriptor)
	}
	processTags(structDescriptor, cfg)
	// insert anonymous bindings to the head
	structDescriptor.Fields = append(headAnonymousBindings, structDescriptor.Fields...)
	structDescriptor.Fields = append(structDescriptor.Fields, tailAnonymousBindings...)
	return structDescriptor
}

func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) {
	for _, binding := range structDescriptor.Fields {
		shouldOmitEmpty := false
		tagParts := strings.Split(binding.Field.Tag.Get("json"), ",")
		for _, tagPart := range tagParts[1:] {
			if tagPart == "omitempty" {
				shouldOmitEmpty = true
			} else if tagPart == "string" {
				if binding.Field.Type.Kind() == reflect.String {
					binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg}
					binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg}
				} else {
					binding.Decoder = &stringModeNumberDecoder{binding.Decoder}
					binding.Encoder = &stringModeNumberEncoder{binding.Encoder}
				}
			}
		}
		binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder}
		binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty}
	}
}

func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string {
	// ignore?
	if wholeTag == "-" {
		return []string{}
	}
	// rename?
	var fieldNames []string
	if tagProvidedFieldName == "" {
		fieldNames = []string{originalFieldName}
	} else {
		fieldNames = []string{tagProvidedFieldName}
	}
	// private?
	isNotExported := unicode.IsLower(rune(originalFieldName[0]))
	if isNotExported {
		fieldNames = []string{}
	}
	return fieldNames
}
<|endoftext|>


<commit_before>package main

import "os"
import "github.com/docker/engine-api/client"
import "math/rand"
import "os/exec"
import "strconv"
import "github.com/seehuhn/mt19937"
import "time"
import "os/user"
import "fmt"
import "math"

var cli *client.Client

type ExecRequest struct {
	Image string
	Cmd []string
	SourceFileName string
}

type Judge struct {
	Code string
	Compile *ExecRequest
	Exec ExecRequest
	Time int64
	Mem  int64
	TCCount int // The number of test cases
}

type JudgeResult int

const (
	Accepted            JudgeResult = 0
	WrongAnswer         JudgeResult = 1
	MemoryLimitExceeded        JudgeResult = 2
	TimeLimitExceeded   JudgeResult = 3
	RuntimeError JudgeResult = 4
	InternalError        JudgeResult = 5
	Judging       JudgeResult = 6
	CompileError             JudgeResult = 7
	CompileTimeLimitExceeded JudgeResult = 8
	CompileMemoryLimitExceeded JudgeResult = 9
)

const JudgeResultToStr []string = []string{"Accepted", "WrongAnswer", "MemoryLimitExceeded", "TimeLimitExceeded", "RuntimeError", "InternalError", "Judging", "CompileError", "CompileTimeLimitExceeded", "CompileMemoryLimitExceeded"}

type JudgeStatus struct {
	Case     *string
	JR       JudgeResult
	Mem      int64
	Time     int64
	Msg      *string
}

func CreateInternalError(msg string) JudgeStatus {
	return JudgeStatus{nil, InternalError, 0, 0, &msg}
}

const BASE_RAND_STRING = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func RandomName() string {
	rng := rand.New(mt19937.New())
	rng.Seed(time.Now().UnixNano())

	res := make([]byte, 0, 32)
	for i := 0; i < 32; i++ {
		res = append(res, BASE_RAND_STRING[rng.Intn(len(BASE_RAND_STRING))])
	}

	return string(res)
}

func (j *Judge) Run(ch chan<- JudgeStatus, tests <-chan struct {
	Name string
	In  string
	Out string
}) {
	// Close a channel to send results of judging
	defer close(ch)

	// Identity
	id := RandomName()

	// User
	_, err := exec.Command("useradd", "--no-create-home", id).Output()

	if err != nil {
		ch <- CreateInternalError("Failed to create a directory to build your code. " + err.Error())

		return
	}

	uid, err := user.Lookup(id)

	if err != nil {
		ch <- CreateInternalError("Failed to look up a user. " + err.Error())

		return
	}

	uidInt, err := strconv.ParseInt(uid.Uid, 10, 64)
	if err != nil {
		ch <- CreateInternalError("Failed to parseInt uid. " + err.Error())

		return
	}

	gidInt, err := strconv.ParseInt(uid.Gid, 10, 64)
	if err != nil {
		ch <- CreateInternalError("Failed to parseInt gid. " + err.Error())

		return
	}

	defer exec.Command("userdel", id).Output()

	// Working Directory
	path := workingDirectory + "/" + id

	err = os.Mkdir(path, 0777)

	if err != nil {
		ch <- CreateInternalError("Failed to create a directory. " + err.Error())

		return
	}

	defer os.RemoveAll(path)

	uidInt = uidInt * gidInt / gidInt
	err = os.Chown(path, int(uidInt), int(gidInt))

	if err != nil {
		ch <- CreateInternalError("Failed to chown the directory. " + err.Error())

		return
	}

	err = os.Chmod(path, 0777)

	if err != nil {
		ch <- CreateInternalError("Failed to chmod the directory. " + err.Error())

		return
	}

	// Source File
	fp, err := os.Create(path + "/" + j.Compile.SourceFileName)

	if err != nil {
		ch <- CreateInternalError("Failed to create source file." + err.Error())

		return
	}

	l, err := fp.Write([]byte(j.Code))

	if err != nil {
		ch <- CreateInternalError("Failed to write your code on your file. " + err.Error())

		return
	}

	if l != len(j.Code) {
		ch <- CreateInternalError("Failed to write your code on your file.")

		return
	}

	fp.Close()

	err = os.Chmod(path + "/" + j.Compile.SourceFileName, 0644)

	if err != nil {
		ch <- CreateInternalError("Failed to chmod the source file. " + err.Error())

		return
	}

	// Compile
	if j.Compile != nil {
		exe, err := NewExecutor(id, 512 * 1024 * 1024, j.Compile.Cmd, j.Compile.Image, []string{path + ":" + "/work"}, uid.Uid)

		if err != nil {
			ch <- CreateInternalError("Failed to create a Docker container to compile your code." + err.Error())

			return
		}

		res := exe.Run(10000, "")

		exe.Delete()
		if res.Status != ExecFinished {
			switch res.Status {
			case ExecError:
				ch <- CreateInternalError("Failed to execute a compiler." + res.Stderr)

				return
			case ExecMemoryLimitExceeded:
				ch <- JudgeStatus{JR: CompileMemoryLimitExceeded}

				return
			case ExecTimeLimitExceeded:
				ch <- JudgeStatus{JR: CompileTimeLimitExceeded}

				return
			}
		}

		if res.ExitCode != 0 { // Debug
			msg := res.Stdout + res.Stderr
			ch <- JudgeStatus{JR: CompileError, Msg: &msg}

			return
		}
	}

	exe, err := NewExecutor(id, j.Mem, j.Exec.Cmd, j.Exec.Image, []string{path + ":" + "/work:ro"}, uid.Uid)

	if err != nil {
		ch <- CreateInternalError("Failed to create a Docker container to judge." + err.Error())

		return
	}

	defer exe.Delete()

	tcCounter := 0

	totalResult := 0
	maxInt := func(a int, b int) int {
		if a > b {
			return a
		}else {
			return b
		}
	}
	maxInt64 := func(a int64, b int64) int64 {
		if a > b {
			return a
		}else {
			return b
		}
	}

	var maxTime, maxMem int64
	for tc, res := <-tests; res; tc, res = <-tests {
		tcCounter++

		msg := strconv.FormatInt(int64(tcCounter), 10) + "/" + strconv.FormatInt(int64(j.TCCount), 10)
		ch <- JudgeStatus{JR: Judging, Msg: &msg}

		r := Accepted
		res := exe.Run(j.Time, tc.In)

		if res.Status != ExecFinished {
			switch res.Status {
			case ExecError:
				msg := "Failed to execute your code." + res.Stderr
				ch <- JudgeStatus{Case: &tc.Name, JR: InternalError, Msg: &msg}
				r = InternalError
				maxMem = -1
				maxTime = -1
			case ExecMemoryLimitExceeded:
				ch <- JudgeStatus{Case: &tc.Name, JR: MemoryLimitExceeded}
				r = MemoryLimitExceeded
				maxMem = -1
				maxTime = -1
			case ExecTimeLimitExceeded:
				ch <- JudgeStatus{Case: &tc.Name, JR: TimeLimitExceeded}
				r = InternalError
				maxMem = -1
				maxTime = -1
			}
		}else {
			if res.ExitCode != 0 {
				ch <- JudgeStatus{Case: &tc.Name, JR: RuntimeError}
				r = RuntimeError
				maxMem = -1
				maxTime = -1
			}else {
				if res.Stdout == tc.Out {
					ch <- JudgeStatus{Case: &tc.Name, JR: Accepted, Mem: res.Mem, Time: res.Time}
					r = Accepted
				}else {
					ch <- JudgeStatus{Case: &tc.Name, JR: WrongAnswer, Mem: res.Mem, Time: res.Time}
					r = WrongAnswer
				}
				if maxMem != -1 {
					maxMem = maxInt64(maxMem, res.Mem)
				}
				if maxTime != -1 {
					maxTime = maxInt64(maxTime, res.Time)
				}
			}
		}

		totalResult = maxInt(totalResult, int(r))
	}

	ch <- JudgeStatus{JR: JudgeResult(totalResult), Time: maxTime, Mem: maxMem}
}
<commit_msg>Sun May 22 21:09:35 JST 2016<commit_after>package main

import "os"
import "github.com/docker/engine-api/client"
import "math/rand"
import "os/exec"
import "strconv"
import "github.com/seehuhn/mt19937"
import "time"
import "os/user"
import "fmt"
import "math"

var cli *client.Client

type ExecRequest struct {
	Image string
	Cmd []string
	SourceFileName string
}

type Judge struct {
	Code string
	Compile *ExecRequest
	Exec ExecRequest
	Time int64
	Mem  int64
	TCCount int // The number of test cases
}

type JudgeResult int

const (
	Accepted            JudgeResult = 0
	WrongAnswer         JudgeResult = 1
	MemoryLimitExceeded        JudgeResult = 2
	TimeLimitExceeded   JudgeResult = 3
	RuntimeError JudgeResult = 4
	InternalError        JudgeResult = 5
	Judging       JudgeResult = 6
	CompileError             JudgeResult = 7
	CompileTimeLimitExceeded JudgeResult = 8
	CompileMemoryLimitExceeded JudgeResult = 9
)

var JudgeResultToStr = [...]string{"Accepted", "WrongAnswer", "MemoryLimitExceeded", "TimeLimitExceeded", "RuntimeError", "InternalError", "Judging", "CompileError", "CompileTimeLimitExceeded", "CompileMemoryLimitExceeded"}

type JudgeStatus struct {
	Case     *string
	JR       JudgeResult
	Mem      int64
	Time     int64
	Msg      *string
}

func CreateInternalError(msg string) JudgeStatus {
	return JudgeStatus{nil, InternalError, 0, 0, &msg}
}

const BASE_RAND_STRING = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func RandomName() string {
	rng := rand.New(mt19937.New())
	rng.Seed(time.Now().UnixNano())

	res := make([]byte, 0, 32)
	for i := 0; i < 32; i++ {
		res = append(res, BASE_RAND_STRING[rng.Intn(len(BASE_RAND_STRING))])
	}

	return string(res)
}

func (j *Judge) Run(ch chan<- JudgeStatus, tests <-chan struct {
	Name string
	In  string
	Out string
}) {
	// Close a channel to send results of judging
	defer close(ch)

	// Identity
	id := RandomName()

	// User
	_, err := exec.Command("useradd", "--no-create-home", id).Output()

	if err != nil {
		ch <- CreateInternalError("Failed to create a directory to build your code. " + err.Error())

		return
	}

	uid, err := user.Lookup(id)

	if err != nil {
		ch <- CreateInternalError("Failed to look up a user. " + err.Error())

		return
	}

	uidInt, err := strconv.ParseInt(uid.Uid, 10, 64)
	if err != nil {
		ch <- CreateInternalError("Failed to parseInt uid. " + err.Error())

		return
	}

	gidInt, err := strconv.ParseInt(uid.Gid, 10, 64)
	if err != nil {
		ch <- CreateInternalError("Failed to parseInt gid. " + err.Error())

		return
	}

	defer exec.Command("userdel", id).Output()

	// Working Directory
	path := workingDirectory + "/" + id

	err = os.Mkdir(path, 0777)

	if err != nil {
		ch <- CreateInternalError("Failed to create a directory. " + err.Error())

		return
	}

	defer os.RemoveAll(path)

	uidInt = uidInt * gidInt / gidInt
	err = os.Chown(path, int(uidInt), int(gidInt))

	if err != nil {
		ch <- CreateInternalError("Failed to chown the directory. " + err.Error())

		return
	}

	err = os.Chmod(path, 0777)

	if err != nil {
		ch <- CreateInternalError("Failed to chmod the directory. " + err.Error())

		return
	}

	// Source File
	fp, err := os.Create(path + "/" + j.Compile.SourceFileName)

	if err != nil {
		ch <- CreateInternalError("Failed to create source file." + err.Error())

		return
	}

	l, err := fp.Write([]byte(j.Code))

	if err != nil {
		ch <- CreateInternalError("Failed to write your code on your file. " + err.Error())

		return
	}

	if l != len(j.Code) {
		ch <- CreateInternalError("Failed to write your code on your file.")

		return
	}

	fp.Close()

	err = os.Chmod(path + "/" + j.Compile.SourceFileName, 0644)

	if err != nil {
		ch <- CreateInternalError("Failed to chmod the source file. " + err.Error())

		return
	}

	// Compile
	if j.Compile != nil {
		exe, err := NewExecutor(id, 512 * 1024 * 1024, j.Compile.Cmd, j.Compile.Image, []string{path + ":" + "/work"}, uid.Uid)

		if err != nil {
			ch <- CreateInternalError("Failed to create a Docker container to compile your code." + err.Error())

			return
		}

		res := exe.Run(10000, "")

		exe.Delete()
		if res.Status != ExecFinished {
			switch res.Status {
			case ExecError:
				ch <- CreateInternalError("Failed to execute a compiler." + res.Stderr)

				return
			case ExecMemoryLimitExceeded:
				ch <- JudgeStatus{JR: CompileMemoryLimitExceeded}

				return
			case ExecTimeLimitExceeded:
				ch <- JudgeStatus{JR: CompileTimeLimitExceeded}

				return
			}
		}

		if res.ExitCode != 0 { // Debug
			msg := res.Stdout + res.Stderr
			ch <- JudgeStatus{JR: CompileError, Msg: &msg}

			return
		}
	}

	exe, err := NewExecutor(id, j.Mem, j.Exec.Cmd, j.Exec.Image, []string{path + ":" + "/work:ro"}, uid.Uid)

	if err != nil {
		ch <- CreateInternalError("Failed to create a Docker container to judge." + err.Error())

		return
	}

	defer exe.Delete()

	tcCounter := 0

	totalResult := 0
	maxInt := func(a int, b int) int {
		if a > b {
			return a
		}else {
			return b
		}
	}
	maxInt64 := func(a int64, b int64) int64 {
		if a > b {
			return a
		}else {
			return b
		}
	}

	var maxTime, maxMem int64
	for tc, res := <-tests; res; tc, res = <-tests {
		tcCounter++

		msg := strconv.FormatInt(int64(tcCounter), 10) + "/" + strconv.FormatInt(int64(j.TCCount), 10)
		ch <- JudgeStatus{JR: Judging, Msg: &msg}

		r := Accepted
		res := exe.Run(j.Time, tc.In)

		if res.Status != ExecFinished {
			switch res.Status {
			case ExecError:
				msg := "Failed to execute your code." + res.Stderr
				ch <- JudgeStatus{Case: &tc.Name, JR: InternalError, Msg: &msg}
				r = InternalError
				maxMem = -1
				maxTime = -1
			case ExecMemoryLimitExceeded:
				ch <- JudgeStatus{Case: &tc.Name, JR: MemoryLimitExceeded}
				r = MemoryLimitExceeded
				maxMem = -1
				maxTime = -1
			case ExecTimeLimitExceeded:
				ch <- JudgeStatus{Case: &tc.Name, JR: TimeLimitExceeded}
				r = InternalError
				maxMem = -1
				maxTime = -1
			}
		}else {
			if res.ExitCode != 0 {
				ch <- JudgeStatus{Case: &tc.Name, JR: RuntimeError}
				r = RuntimeError
				maxMem = -1
				maxTime = -1
			}else {
				if res.Stdout == tc.Out {
					ch <- JudgeStatus{Case: &tc.Name, JR: Accepted, Mem: res.Mem, Time: res.Time}
					r = Accepted
				}else {
					ch <- JudgeStatus{Case: &tc.Name, JR: WrongAnswer, Mem: res.Mem, Time: res.Time}
					r = WrongAnswer
				}
				if maxMem != -1 {
					maxMem = maxInt64(maxMem, res.Mem)
				}
				if maxTime != -1 {
					maxTime = maxInt64(maxTime, res.Time)
				}
			}
		}

		totalResult = maxInt(totalResult, int(r))
	}

	ch <- JudgeStatus{JR: JudgeResult(totalResult), Time: maxTime, Mem: maxMem}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
	"errors"
	"net"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"
)

var (
	ErrRegistration   = errors.New("unable to register all nodes.")
	ErrQueryIPAddress = errors.New("unable to query IP address.")
	ErrCloudInstance  = errors.New("cloud provider doesn't support instances.")
)

type NodeController struct {
	cloud           cloudprovider.Interface
	matchRE         string
	staticResources *api.NodeResources
	nodes           []string
	kubeClient      client.Interface
	kubeletClient   client.KubeletHealthChecker
}

// NewNodeController returns a new node controller to sync instances from cloudprovider.
// TODO: NodeController health checker should be a separate package other than
// kubeletclient, node health check != kubelet health check.
func NewNodeController(
	cloud cloudprovider.Interface,
	matchRE string,
	nodes []string,
	staticResources *api.NodeResources,
	kubeClient client.Interface,
	kubeletClient client.KubeletHealthChecker) *NodeController {
	return &NodeController{
		cloud:           cloud,
		matchRE:         matchRE,
		nodes:           nodes,
		staticResources: staticResources,
		kubeClient:      kubeClient,
		kubeletClient:   kubeletClient,
	}
}

// Run creates initial node list and start syncing instances from cloudprovider if any.
// It also starts syncing cluster node status.
func (s *NodeController) Run(period time.Duration, retryCount int) {
	// Register intial set of nodes with their status set.
	var nodes *api.NodeList
	var err error
	if s.isRunningCloudProvider() {
		nodes, err = s.CloudNodes()
		if err != nil {
			glog.Errorf("Error loading initial node from cloudprovider: %v", err)
		}
	} else {
		nodes, err = s.StaticNodes()
		if err != nil {
			glog.Errorf("Error loading initial static nodes: %v", err)
		}
	}
	nodes = s.DoChecks(nodes)
	nodes, err = s.PopulateIPs(nodes)
	if err != nil {
		glog.Errorf("Error getting nodes ips: %v", err)
	}
	if err = s.RegisterNodes(nodes, retryCount, period); err != nil {
		glog.Errorf("Error registrying node list %+v: %v", nodes, err)
	}

	// Start syncing node list from cloudprovider.
	if s.isRunningCloudProvider() {
		go util.Forever(func() {
			if err = s.SyncCloud(); err != nil {
				glog.Errorf("Error syncing cloud: %v", err)
			}
		}, period)
	}

	// Start syncing node status.
	go util.Forever(func() {
		if err = s.SyncNodeStatus(); err != nil {
			glog.Errorf("Error syncing status: %v", err)
		}
	}, period)
}

// RegisterNodes registers the given list of nodes, it keeps retrying for `retryCount` times.
func (s *NodeController) RegisterNodes(nodes *api.NodeList, retryCount int, retryInterval time.Duration) error {
	registered := util.NewStringSet()
	nodes = s.canonicalizeName(nodes)
	for i := 0; i < retryCount; i++ {
		for _, node := range nodes.Items {
			if registered.Has(node.Name) {
				continue
			}
			_, err := s.kubeClient.Nodes().Create(&node)
			if err == nil {
				registered.Insert(node.Name)
				glog.Infof("Registered node in registry: %s", node.Name)
			} else {
				glog.Errorf("Error registrying node %s, retrying: %s", node.Name, err)
			}
			if registered.Len() == len(nodes.Items) {
				glog.Infof("Successfully Registered all nodes")
				return nil
			}
		}
		time.Sleep(retryInterval)
	}
	if registered.Len() != len(nodes.Items) {
		return ErrRegistration
	} else {
		return nil
	}
}

// SyncCloud synchronizes the list of instances from cloudprovider to master server.
func (s *NodeController) SyncCloud() error {
	matches, err := s.CloudNodes()
	if err != nil {
		return err
	}
	nodes, err := s.kubeClient.Nodes().List()
	if err != nil {
		return err
	}
	nodeMap := make(map[string]*api.Node)
	for _, node := range nodes.Items {
		nodeMap[node.Name] = &node
	}

	// Create nodes which have been created in cloud, but not in kubernetes cluster.
	for _, node := range matches.Items {
		if _, ok := nodeMap[node.Name]; !ok {
			glog.Infof("Create node in registry: %s", node.Name)
			_, err = s.kubeClient.Nodes().Create(&node)
			if err != nil {
				glog.Errorf("Create node error: %s", node.Name)
			}
		}
		delete(nodeMap, node.Name)
	}

	// Delete nodes which have been deleted from cloud, but not from kubernetes cluster.
	for nodeID := range nodeMap {
		glog.Infof("Delete node from registry: %s", nodeID)
		err = s.kubeClient.Nodes().Delete(nodeID)
		if err != nil {
			glog.Errorf("Delete node error: %s", nodeID)
		}
	}

	return nil
}

// SyncNodeStatus synchronizes cluster nodes status to master server.
func (s *NodeController) SyncNodeStatus() error {
	nodes, err := s.kubeClient.Nodes().List()
	if err != nil {
		return err
	}
	oldNodes := make(map[string]api.Node)
	for _, node := range nodes.Items {
		oldNodes[node.Name] = node
	}
	nodes = s.DoChecks(nodes)
	nodes, err = s.PopulateIPs(nodes)
	if err != nil {
		return err
	}
	for _, node := range nodes.Items {
		if reflect.DeepEqual(node, oldNodes[node.Name]) {
			glog.V(2).Infof("skip updating node %v", node.Name)
			continue
		}
		glog.V(2).Infof("updating node %v", node.Name)
		_, err = s.kubeClient.Nodes().Update(&node)
		if err != nil {
			glog.Errorf("error updating node %s: %v", node.Name, err)
		}
	}
	return nil
}

// PopulateIPs queries IPs for given list of nodes.
func (s *NodeController) PopulateIPs(nodes *api.NodeList) (*api.NodeList, error) {
	if s.isRunningCloudProvider() {
		instances, ok := s.cloud.Instances()
		if !ok {
			return nodes, ErrCloudInstance
		}
		for i := range nodes.Items {
			node := &nodes.Items[i]
			hostIP, err := instances.IPAddress(node.Name)
			if err != nil {
				glog.Errorf("error getting instance ip address for %s: %v", node.Name, err)
			} else {
				node.Status.HostIP = hostIP.String()
			}
		}
	} else {
		for i := range nodes.Items {
			node := &nodes.Items[i]
			addr := net.ParseIP(node.Name)
			if addr != nil {
				node.Status.HostIP = node.Name
			} else {
				addrs, err := net.LookupIP(node.Name)
				if err != nil {
					glog.Errorf("Can't get ip address of node %s: %v", node.Name, err)
				} else if len(addrs) == 0 {
					glog.Errorf("No ip address for node %v", node.Name)
				} else {
					node.Status.HostIP = addrs[0].String()
				}
			}
		}
	}
	return nodes, nil
}

// DoChecks performs health checking for given list of nodes.
func (s *NodeController) DoChecks(nodes *api.NodeList) *api.NodeList {
	var wg sync.WaitGroup
	wg.Add(len(nodes.Items))
	for i := range nodes.Items {
		go func(node *api.Node) {
			node.Status.Conditions = s.DoCheck(node)
			wg.Done()
		}(&nodes.Items[i])
	}
	wg.Wait()
	return nodes
}

// DoCheck performs health checking for given node.
func (s *NodeController) DoCheck(node *api.Node) []api.NodeCondition {
	var conditions []api.NodeCondition
	switch status, err := s.kubeletClient.HealthCheck(node.Name); {
	case err != nil:
		glog.V(2).Infof("NodeController: node %s health check error: %v", node.Name, err)
		conditions = append(conditions, api.NodeCondition{
			Kind:   api.NodeReady,
			Status: api.ConditionUnknown,
		})
	case status == probe.Failure:
		conditions = append(conditions, api.NodeCondition{
			Kind:   api.NodeReady,
			Status: api.ConditionNone,
		})
	default:
		conditions = append(conditions, api.NodeCondition{
			Kind:   api.NodeReady,
			Status: api.ConditionFull,
		})
	}
	glog.V(5).Infof("NodeController: node %q status was %+v", node.Name, conditions)
	return conditions
}

// StaticNodes constructs and returns api.NodeList for static nodes. If error
// occurs, an empty NodeList will be returned with a non-nil error info.
func (s *NodeController) StaticNodes() (*api.NodeList, error) {
	result := &api.NodeList{}
	for _, nodeID := range s.nodes {
		node := api.Node{
			ObjectMeta: api.ObjectMeta{Name: nodeID},
			Spec:       api.NodeSpec{Capacity: s.staticResources.Capacity},
		}
		result.Items = append(result.Items, node)
	}
	return result, nil
}

// CloudNodes constructs and returns api.NodeList from cloudprovider. If error
// occurs, an empty NodeList will be returned with a non-nil error info.
func (s *NodeController) CloudNodes() (*api.NodeList, error) {
	result := &api.NodeList{}
	instances, ok := s.cloud.Instances()
	if !ok {
		return result, ErrCloudInstance
	}
	matches, err := instances.List(s.matchRE)
	if err != nil {
		return result, err
	}
	for i := range matches {
		node := api.Node{}
		node.Name = matches[i]
		resources, err := instances.GetNodeResources(matches[i])
		if err != nil {
			return nil, err
		}
		if resources == nil {
			resources = s.staticResources
		}
		if resources != nil {
			node.Spec.Capacity = resources.Capacity
		}
		result.Items = append(result.Items, node)
	}
	return result, nil
}

// isRunningCloudProvider checks if cluster is running with cloud provider.
func (s *NodeController) isRunningCloudProvider() bool {
	return s.cloud != nil && len(s.matchRE) > 0
}

// canonicalizeName takes a node list and lowercases all nodes' name.
func (s *NodeController) canonicalizeName(nodes *api.NodeList) *api.NodeList {
	for i := range nodes.Items {
		nodes.Items[i].Name = strings.ToLower(nodes.Items[i].Name)
	}
	return nodes
}
<commit_msg>UPSTREAM: Register nodes that already exist statically<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
	"errors"
	"net"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"
)

var (
	ErrRegistration   = errors.New("unable to register all nodes.")
	ErrQueryIPAddress = errors.New("unable to query IP address.")
	ErrCloudInstance  = errors.New("cloud provider doesn't support instances.")
)

type NodeController struct {
	cloud           cloudprovider.Interface
	matchRE         string
	staticResources *api.NodeResources
	nodes           []string
	kubeClient      client.Interface
	kubeletClient   client.KubeletHealthChecker
}

// NewNodeController returns a new node controller to sync instances from cloudprovider.
// TODO: NodeController health checker should be a separate package other than
// kubeletclient, node health check != kubelet health check.
func NewNodeController(
	cloud cloudprovider.Interface,
	matchRE string,
	nodes []string,
	staticResources *api.NodeResources,
	kubeClient client.Interface,
	kubeletClient client.KubeletHealthChecker) *NodeController {
	return &NodeController{
		cloud:           cloud,
		matchRE:         matchRE,
		nodes:           nodes,
		staticResources: staticResources,
		kubeClient:      kubeClient,
		kubeletClient:   kubeletClient,
	}
}

// Run creates initial node list and start syncing instances from cloudprovider if any.
// It also starts syncing cluster node status.
func (s *NodeController) Run(period time.Duration, retryCount int) {
	// Register intial set of nodes with their status set.
	var nodes *api.NodeList
	var err error
	if s.isRunningCloudProvider() {
		nodes, err = s.CloudNodes()
		if err != nil {
			glog.Errorf("Error loading initial node from cloudprovider: %v", err)
		}
	} else {
		nodes, err = s.StaticNodes()
		if err != nil {
			glog.Errorf("Error loading initial static nodes: %v", err)
		}
	}
	nodes = s.DoChecks(nodes)
	nodes, err = s.PopulateIPs(nodes)
	if err != nil {
		glog.Errorf("Error getting nodes ips: %v", err)
	}
	if err = s.RegisterNodes(nodes, retryCount, period); err != nil {
		glog.Errorf("Error registrying node list %+v: %v", nodes, err)
	}

	// Start syncing node list from cloudprovider.
	if s.isRunningCloudProvider() {
		go util.Forever(func() {
			if err = s.SyncCloud(); err != nil {
				glog.Errorf("Error syncing cloud: %v", err)
			}
		}, period)
	}

	// Start syncing node status.
	go util.Forever(func() {
		if err = s.SyncNodeStatus(); err != nil {
			glog.Errorf("Error syncing status: %v", err)
		}
	}, period)
}

// RegisterNodes registers the given list of nodes, it keeps retrying for `retryCount` times.
func (s *NodeController) RegisterNodes(nodes *api.NodeList, retryCount int, retryInterval time.Duration) error {
	registered := util.NewStringSet()
	nodes = s.canonicalizeName(nodes)
	for i := 0; i < retryCount; i++ {
		for _, node := range nodes.Items {
			if registered.Has(node.Name) {
				continue
			}
			_, err := s.kubeClient.Nodes().Create(&node)
			if err == nil || apierrors.IsAlreadyExists(err) {
				registered.Insert(node.Name)
				glog.Infof("Registered node in registry: %s", node.Name)
			} else {
				glog.Errorf("Error registrying node %s, retrying: %s", node.Name, err)
			}
			if registered.Len() == len(nodes.Items) {
				glog.Infof("Successfully Registered all nodes")
				return nil
			}
		}
		time.Sleep(retryInterval)
	}
	if registered.Len() != len(nodes.Items) {
		return ErrRegistration
	} else {
		return nil
	}
}

// SyncCloud synchronizes the list of instances from cloudprovider to master server.
func (s *NodeController) SyncCloud() error {
	matches, err := s.CloudNodes()
	if err != nil {
		return err
	}
	nodes, err := s.kubeClient.Nodes().List()
	if err != nil {
		return err
	}
	nodeMap := make(map[string]*api.Node)
	for _, node := range nodes.Items {
		nodeMap[node.Name] = &node
	}

	// Create nodes which have been created in cloud, but not in kubernetes cluster.
	for _, node := range matches.Items {
		if _, ok := nodeMap[node.Name]; !ok {
			glog.Infof("Create node in registry: %s", node.Name)
			_, err = s.kubeClient.Nodes().Create(&node)
			if err != nil {
				glog.Errorf("Create node error: %s", node.Name)
			}
		}
		delete(nodeMap, node.Name)
	}

	// Delete nodes which have been deleted from cloud, but not from kubernetes cluster.
	for nodeID := range nodeMap {
		glog.Infof("Delete node from registry: %s", nodeID)
		err = s.kubeClient.Nodes().Delete(nodeID)
		if err != nil {
			glog.Errorf("Delete node error: %s", nodeID)
		}
	}

	return nil
}

// SyncNodeStatus synchronizes cluster nodes status to master server.
func (s *NodeController) SyncNodeStatus() error {
	nodes, err := s.kubeClient.Nodes().List()
	if err != nil {
		return err
	}
	oldNodes := make(map[string]api.Node)
	for _, node := range nodes.Items {
		oldNodes[node.Name] = node
	}
	nodes = s.DoChecks(nodes)
	nodes, err = s.PopulateIPs(nodes)
	if err != nil {
		return err
	}
	for _, node := range nodes.Items {
		if reflect.DeepEqual(node, oldNodes[node.Name]) {
			glog.V(2).Infof("skip updating node %v", node.Name)
			continue
		}
		glog.V(2).Infof("updating node %v", node.Name)
		_, err = s.kubeClient.Nodes().Update(&node)
		if err != nil {
			glog.Errorf("error updating node %s: %v", node.Name, err)
		}
	}
	return nil
}

// PopulateIPs queries IPs for given list of nodes.
func (s *NodeController) PopulateIPs(nodes *api.NodeList) (*api.NodeList, error) {
	if s.isRunningCloudProvider() {
		instances, ok := s.cloud.Instances()
		if !ok {
			return nodes, ErrCloudInstance
		}
		for i := range nodes.Items {
			node := &nodes.Items[i]
			hostIP, err := instances.IPAddress(node.Name)
			if err != nil {
				glog.Errorf("error getting instance ip address for %s: %v", node.Name, err)
			} else {
				node.Status.HostIP = hostIP.String()
			}
		}
	} else {
		for i := range nodes.Items {
			node := &nodes.Items[i]
			addr := net.ParseIP(node.Name)
			if addr != nil {
				node.Status.HostIP = node.Name
			} else {
				addrs, err := net.LookupIP(node.Name)
				if err != nil {
					glog.Errorf("Can't get ip address of node %s: %v", node.Name, err)
				} else if len(addrs) == 0 {
					glog.Errorf("No ip address for node %v", node.Name)
				} else {
					node.Status.HostIP = addrs[0].String()
				}
			}
		}
	}
	return nodes, nil
}

// DoChecks performs health checking for given list of nodes.
func (s *NodeController) DoChecks(nodes *api.NodeList) *api.NodeList {
	var wg sync.WaitGroup
	wg.Add(len(nodes.Items))
	for i := range nodes.Items {
		go func(node *api.Node) {
			node.Status.Conditions = s.DoCheck(node)
			wg.Done()
		}(&nodes.Items[i])
	}
	wg.Wait()
	return nodes
}

// DoCheck performs health checking for given node.
func (s *NodeController) DoCheck(node *api.Node) []api.NodeCondition {
	var conditions []api.NodeCondition
	switch status, err := s.kubeletClient.HealthCheck(node.Name); {
	case err != nil:
		glog.V(2).Infof("NodeController: node %s health check error: %v", node.Name, err)
		conditions = append(conditions, api.NodeCondition{
			Kind:   api.NodeReady,
			Status: api.ConditionUnknown,
		})
	case status == probe.Failure:
		conditions = append(conditions, api.NodeCondition{
			Kind:   api.NodeReady,
			Status: api.ConditionNone,
		})
	default:
		conditions = append(conditions, api.NodeCondition{
			Kind:   api.NodeReady,
			Status: api.ConditionFull,
		})
	}
	glog.V(5).Infof("NodeController: node %q status was %+v", node.Name, conditions)
	return conditions
}

// StaticNodes constructs and returns api.NodeList for static nodes. If error
// occurs, an empty NodeList will be returned with a non-nil error info.
func (s *NodeController) StaticNodes() (*api.NodeList, error) {
	result := &api.NodeList{}
	for _, nodeID := range s.nodes {
		node := api.Node{
			ObjectMeta: api.ObjectMeta{Name: nodeID},
			Spec:       api.NodeSpec{Capacity: s.staticResources.Capacity},
		}
		result.Items = append(result.Items, node)
	}
	return result, nil
}

// CloudNodes constructs and returns api.NodeList from cloudprovider. If error
// occurs, an empty NodeList will be returned with a non-nil error info.
func (s *NodeController) CloudNodes() (*api.NodeList, error) {
	result := &api.NodeList{}
	instances, ok := s.cloud.Instances()
	if !ok {
		return result, ErrCloudInstance
	}
	matches, err := instances.List(s.matchRE)
	if err != nil {
		return result, err
	}
	for i := range matches {
		node := api.Node{}
		node.Name = matches[i]
		resources, err := instances.GetNodeResources(matches[i])
		if err != nil {
			return nil, err
		}
		if resources == nil {
			resources = s.staticResources
		}
		if resources != nil {
			node.Spec.Capacity = resources.Capacity
		}
		result.Items = append(result.Items, node)
	}
	return result, nil
}

// isRunningCloudProvider checks if cluster is running with cloud provider.
func (s *NodeController) isRunningCloudProvider() bool {
	return s.cloud != nil && len(s.matchRE) > 0
}

// canonicalizeName takes a node list and lowercases all nodes' name.
func (s *NodeController) canonicalizeName(nodes *api.NodeList) *api.NodeList {
	for i := range nodes.Items {
		nodes.Items[i].Name = strings.ToLower(nodes.Items[i].Name)
	}
	return nodes
}
<|endoftext|>


<commit_before>/*
Copyright 2021 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 fieldmanager

import (
	"context"
	"fmt"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apiserver/pkg/admission"
	"k8s.io/apiserver/pkg/warning"
)

// InvalidManagedFieldsAfterMutatingAdmissionWarningFormat is the warning that a client receives
// when a create/update/patch request results in invalid managedFields after going through the admission chain.
const InvalidManagedFieldsAfterMutatingAdmissionWarningFormat = ".metadata.managedFields was in an invalid state after admission; this could be caused by an outdated mutating admission controller; please fix your requests: %v"

// NewManagedFieldsValidatingAdmissionController validates the managedFields after calling
// the provided admission and resets them to their original state if they got changed to an invalid value
func NewManagedFieldsValidatingAdmissionController(wrap admission.Interface) admission.Interface {
	return &managedFieldsValidatingAdmissionController{wrap: wrap}
}

type managedFieldsValidatingAdmissionController struct {
	wrap admission.Interface
}

var _ admission.Interface = &managedFieldsValidatingAdmissionController{}
var _ admission.MutationInterface = &managedFieldsValidatingAdmissionController{}
var _ admission.ValidationInterface = &managedFieldsValidatingAdmissionController{}

// Handles calls the wrapped admission.Interface if aplicable
func (admit *managedFieldsValidatingAdmissionController) Handles(operation admission.Operation) bool {
	return admit.wrap.Handles(operation)
}

// Admit calls the wrapped admission.Interface if aplicable and resets the managedFields to their state before admission if they
// got modified in an invalid way
func (admit *managedFieldsValidatingAdmissionController) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
	mutationInterface, isMutationInterface := admit.wrap.(admission.MutationInterface)
	if !isMutationInterface {
		return nil
	}
	objectMeta, err := meta.Accessor(a.GetObject())
	if err != nil {
		return err
	}
	managedFieldsBeforeAdmission := objectMeta.GetManagedFields()
	if err := mutationInterface.Admit(ctx, a, o); err != nil {
		return err
	}
	managedFieldsAfterAdmission := objectMeta.GetManagedFields()
	if err := ValidateManagedFields(managedFieldsAfterAdmission); err != nil {
		objectMeta.SetManagedFields(managedFieldsBeforeAdmission)
		warning.AddWarning(ctx, "",
			fmt.Sprintf(InvalidManagedFieldsAfterMutatingAdmissionWarningFormat,
				err.Error()),
		)
	}
	return nil
}

// Validate calls the wrapped admission.Interface if aplicable
func (admit *managedFieldsValidatingAdmissionController) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
	if validationInterface, isValidationInterface := admit.wrap.(admission.ValidationInterface); isValidationInterface {
		return validationInterface.Validate(ctx, a, o)
	}
	return nil
}
<commit_msg>prevent fieldManager admission from wrapping nil<commit_after>/*
Copyright 2021 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 fieldmanager

import (
	"context"
	"fmt"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apiserver/pkg/admission"
	"k8s.io/apiserver/pkg/warning"
)

// InvalidManagedFieldsAfterMutatingAdmissionWarningFormat is the warning that a client receives
// when a create/update/patch request results in invalid managedFields after going through the admission chain.
const InvalidManagedFieldsAfterMutatingAdmissionWarningFormat = ".metadata.managedFields was in an invalid state after admission; this could be caused by an outdated mutating admission controller; please fix your requests: %v"

// NewManagedFieldsValidatingAdmissionController validates the managedFields after calling
// the provided admission and resets them to their original state if they got changed to an invalid value
func NewManagedFieldsValidatingAdmissionController(wrap admission.Interface) admission.Interface {
	if wrap == nil {
		return nil
	}
	return &managedFieldsValidatingAdmissionController{wrap: wrap}
}

type managedFieldsValidatingAdmissionController struct {
	wrap admission.Interface
}

var _ admission.Interface = &managedFieldsValidatingAdmissionController{}
var _ admission.MutationInterface = &managedFieldsValidatingAdmissionController{}
var _ admission.ValidationInterface = &managedFieldsValidatingAdmissionController{}

// Handles calls the wrapped admission.Interface if aplicable
func (admit *managedFieldsValidatingAdmissionController) Handles(operation admission.Operation) bool {
	return admit.wrap.Handles(operation)
}

// Admit calls the wrapped admission.Interface if aplicable and resets the managedFields to their state before admission if they
// got modified in an invalid way
func (admit *managedFieldsValidatingAdmissionController) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
	mutationInterface, isMutationInterface := admit.wrap.(admission.MutationInterface)
	if !isMutationInterface {
		return nil
	}
	objectMeta, err := meta.Accessor(a.GetObject())
	if err != nil {
		return err
	}
	managedFieldsBeforeAdmission := objectMeta.GetManagedFields()
	if err := mutationInterface.Admit(ctx, a, o); err != nil {
		return err
	}
	managedFieldsAfterAdmission := objectMeta.GetManagedFields()
	if err := ValidateManagedFields(managedFieldsAfterAdmission); err != nil {
		objectMeta.SetManagedFields(managedFieldsBeforeAdmission)
		warning.AddWarning(ctx, "",
			fmt.Sprintf(InvalidManagedFieldsAfterMutatingAdmissionWarningFormat,
				err.Error()),
		)
	}
	return nil
}

// Validate calls the wrapped admission.Interface if aplicable
func (admit *managedFieldsValidatingAdmissionController) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
	if validationInterface, isValidationInterface := admit.wrap.(admission.ValidationInterface); isValidationInterface {
		return validationInterface.Validate(ctx, a, o)
	}
	return nil
}
<|endoftext|>


<commit_before>package steve

import (
	"context"
	"io"
	"net/http"
	"sync"
	"time"

	"github.com/rancher/rancher/pkg/features"
	"github.com/rancher/rancher/pkg/rancher"
	"github.com/sirupsen/logrus"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

var (
	running bool
	runLock sync.Mutex
)

func Run(ctx context.Context) error {
	if !features.Steve.Enabled() {
		return nil
	}

	runLock.Lock()
	defer runLock.Unlock()

	if running {
		return nil
	}

	logrus.Info("Starting steve")
	c, err := rest.InClusterConfig()
	if err != nil {
		return err
	}

	go func() {
		err = http.ListenAndServe(":8080", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
			resp, err := http.Get("http://localhost:6080/healthz")
			if err != nil {
				http.Error(rw, err.Error(), http.StatusInternalServerError)
				return
			}
			defer resp.Body.Close()
			rw.WriteHeader(resp.StatusCode)
			_, _ = io.Copy(rw, resp.Body)
		}))
		panic("health check server failed: " + err.Error())
	}()

	go func() {
		for {
			ctx, cancel := context.WithCancel(ctx)
			r, err := rancher.New(ctx, reverseClientConfig{cfg: c}, &rancher.Options{
				BindHost:        "127.0.0.1",
				HTTPListenPort:  6080,
				HTTPSListenPort: 0,
				AddLocal:        "true",
				Agent:           true,
			})
			if err != nil {
				cancel()
				logrus.Errorf("failed to initialize Rancher: %v", err)
				time.Sleep(10 * time.Second)
				continue
			}

			if err := r.ListenAndServe(ctx); err != nil {
				cancel()
				logrus.Errorf("failed to start Rancher: %v", err)
				time.Sleep(10 * time.Second)
				continue
			}

			cancel()
		}
	}()

	running = true
	return nil
}

type reverseClientConfig struct {
	cfg *rest.Config
}

func (r reverseClientConfig) RawConfig() (clientcmdapi.Config, error) {
	panic("not implemented")
}

func (r reverseClientConfig) ClientConfig() (*rest.Config, error) {
	panic("not implemented ")
}

func (r reverseClientConfig) Namespace() (string, bool, error) {
	return "", false, nil
}

func (r reverseClientConfig) ConfigAccess() clientcmd.ConfigAccess {
	panic("not implemented ")
}
<commit_msg>Return wrapped rest.Config<commit_after>package steve

import (
	"context"
	"io"
	"net/http"
	"sync"
	"time"

	"github.com/rancher/rancher/pkg/features"
	"github.com/rancher/rancher/pkg/rancher"
	"github.com/sirupsen/logrus"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

var (
	running bool
	runLock sync.Mutex
)

func Run(ctx context.Context) error {
	if !features.Steve.Enabled() {
		return nil
	}

	runLock.Lock()
	defer runLock.Unlock()

	if running {
		return nil
	}

	logrus.Info("Starting steve")
	c, err := rest.InClusterConfig()
	if err != nil {
		return err
	}

	go func() {
		err = http.ListenAndServe(":8080", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
			resp, err := http.Get("http://localhost:6080/healthz")
			if err != nil {
				http.Error(rw, err.Error(), http.StatusInternalServerError)
				return
			}
			defer resp.Body.Close()
			rw.WriteHeader(resp.StatusCode)
			_, _ = io.Copy(rw, resp.Body)
		}))
		panic("health check server failed: " + err.Error())
	}()

	go func() {
		for {
			ctx, cancel := context.WithCancel(ctx)
			r, err := rancher.New(ctx, reverseClientConfig{cfg: c}, &rancher.Options{
				BindHost:        "127.0.0.1",
				HTTPListenPort:  6080,
				HTTPSListenPort: 0,
				AddLocal:        "true",
				Agent:           true,
			})
			if err != nil {
				cancel()
				logrus.Errorf("failed to initialize Rancher: %v", err)
				time.Sleep(10 * time.Second)
				continue
			}

			if err := r.ListenAndServe(ctx); err != nil {
				cancel()
				logrus.Errorf("failed to start Rancher: %v", err)
				time.Sleep(10 * time.Second)
				continue
			}

			cancel()
		}
	}()

	running = true
	return nil
}

type reverseClientConfig struct {
	cfg *rest.Config
}

func (r reverseClientConfig) RawConfig() (clientcmdapi.Config, error) {
	panic("not implemented")
}

func (r reverseClientConfig) ClientConfig() (*rest.Config, error) {
	return r.cfg, nil
}

func (r reverseClientConfig) Namespace() (string, bool, error) {
	return "", false, nil
}

func (r reverseClientConfig) ConfigAccess() clientcmd.ConfigAccess {
	panic("not implemented ")
}
<|endoftext|>