<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package healthz

import (
	"bytes"
	"fmt"
	"net/http"
)

// HealthzChecker is a named healthz check.
type HealthzChecker interface {
	Name() string
	Check(req *http.Request) error
}

// DefaultHealthz installs the default healthz check to the http.DefaultServeMux.
func DefaultHealthz(checks ...HealthzChecker) {
	InstallHandler(http.DefaultServeMux, checks...)
}

// PingHealthz returns true automatically when checked
var PingHealthz HealthzChecker = ping{}

// ping implements the simplest possible health checker.
type ping struct{}

func (ping) Name() string {
	return "ping"
}

// PingHealthz is a health check that returns true.
func (ping) Check(_ *http.Request) error {
	return nil
}

// NamedCheck returns a health checker for the given name and function.
func NamedCheck(name string, check func(r *http.Request) error) HealthzChecker {
	return &healthzCheck{name, check}
}

// InstallHandler registers a handler for health checking on the path "/healthz" to mux.
func InstallHandler(mux mux, checks ...HealthzChecker) {
	if len(checks) == 0 {
		checks = []HealthzChecker{PingHealthz}
	}
	mux.Handle("/healthz", handleRootHealthz(checks...))
	for _, check := range checks {
		mux.Handle(fmt.Sprintf("/healthz/%v", check.Name()), adaptCheckToHandler(check.Check))
	}
}

// mux is an interface describing the methods InstallHandler requires.
type mux interface {
	Handle(pattern string, handler http.Handler)
}

// healthzCheck implements HealthzChecker on an arbitrary name and check function.
type healthzCheck struct {
	name  string
	check func(r *http.Request) error
}

var _ HealthzChecker = &healthzCheck{}

func (c *healthzCheck) Name() string {
	return c.name
}

func (c *healthzCheck) Check(r *http.Request) error {
	return c.check(r)
}

// handleRootHealthz returns an http.HandlerFunc that serves the provided checks.
func handleRootHealthz(checks ...HealthzChecker) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		failed := false
		var verboseOut bytes.Buffer
		for _, check := range checks {
			err := check.Check(r)
			if err != nil {
				fmt.Fprintf(&verboseOut, "[-]%v failed: %v\n", check.Name(), err)
				failed = true
			} else {
				fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.Name())
			}
		}
		// always be verbose on failure
		if failed {
			http.Error(w, fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError)
			return
		}

		if _, found := r.URL.Query()["verbose"]; !found {
			fmt.Fprint(w, "ok")
			return
		}

		verboseOut.WriteTo(w)
		fmt.Fprint(w, "healthz check passed\n")
	})
}

// adaptCheckToHandler returns an http.HandlerFunc that serves the provided checks.
func adaptCheckToHandler(c func(r *http.Request) error) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := c(r)
		if err != nil {
			http.Error(w, fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError)
		} else {
			fmt.Fprint(w, "ok")
		}
	})
}
<commit_msg>DefaultMux should only register the first time<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package healthz

import (
	"bytes"
	"fmt"
	"net/http"
	"sync"
)

// HealthzChecker is a named healthz check.
type HealthzChecker interface {
	Name() string
	Check(req *http.Request) error
}

var defaultHealthz = sync.Once{}

// DefaultHealthz installs the default healthz check to the http.DefaultServeMux.
func DefaultHealthz(checks ...HealthzChecker) {
	defaultHealthz.Do(func() {
		InstallHandler(http.DefaultServeMux, checks...)
	})
}

// PingHealthz returns true automatically when checked
var PingHealthz HealthzChecker = ping{}

// ping implements the simplest possible health checker.
type ping struct{}

func (ping) Name() string {
	return "ping"
}

// PingHealthz is a health check that returns true.
func (ping) Check(_ *http.Request) error {
	return nil
}

// NamedCheck returns a health checker for the given name and function.
func NamedCheck(name string, check func(r *http.Request) error) HealthzChecker {
	return &healthzCheck{name, check}
}

// InstallHandler registers a handler for health checking on the path "/healthz" to mux.
func InstallHandler(mux mux, checks ...HealthzChecker) {
	if len(checks) == 0 {
		checks = []HealthzChecker{PingHealthz}
	}
	mux.Handle("/healthz", handleRootHealthz(checks...))
	for _, check := range checks {
		mux.Handle(fmt.Sprintf("/healthz/%v", check.Name()), adaptCheckToHandler(check.Check))
	}
}

// mux is an interface describing the methods InstallHandler requires.
type mux interface {
	Handle(pattern string, handler http.Handler)
}

// healthzCheck implements HealthzChecker on an arbitrary name and check function.
type healthzCheck struct {
	name  string
	check func(r *http.Request) error
}

var _ HealthzChecker = &healthzCheck{}

func (c *healthzCheck) Name() string {
	return c.name
}

func (c *healthzCheck) Check(r *http.Request) error {
	return c.check(r)
}

// handleRootHealthz returns an http.HandlerFunc that serves the provided checks.
func handleRootHealthz(checks ...HealthzChecker) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		failed := false
		var verboseOut bytes.Buffer
		for _, check := range checks {
			err := check.Check(r)
			if err != nil {
				fmt.Fprintf(&verboseOut, "[-]%v failed: %v\n", check.Name(), err)
				failed = true
			} else {
				fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.Name())
			}
		}
		// always be verbose on failure
		if failed {
			http.Error(w, fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError)
			return
		}

		if _, found := r.URL.Query()["verbose"]; !found {
			fmt.Fprint(w, "ok")
			return
		}

		verboseOut.WriteTo(w)
		fmt.Fprint(w, "healthz check passed\n")
	})
}

// adaptCheckToHandler returns an http.HandlerFunc that serves the provided checks.
func adaptCheckToHandler(c func(r *http.Request) error) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := c(r)
		if err != nil {
			http.Error(w, fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError)
		} else {
			fmt.Fprint(w, "ok")
		}
	})
}
<|endoftext|>


<commit_before>package network

import (
	"net"

	"collectd.org/api"
)

// DefaultService is the default port used by collectd's network plugin.
const DefaultService = "25826"

// Conn is a client connection to a collectd server.
type Conn struct {
	udp    net.Conn
	buffer *Buffer
}

// Dial connects to the collectd server at address. "address" must be a network
// address accepted by net.Dial().
func Dial(address string) (*Conn, error) {
	c, err := net.Dial("udp", address)
	if err != nil {
		return nil, err
	}

	return &Conn{
		udp:    c,
		buffer: NewBuffer(c),
	}, nil
}

// WriteValueList adds a ValueList to the internal buffer. Data is only written
// to the network when the buffer is full.
func (c *Conn) WriteValueList(vl api.ValueList) error {
	return c.buffer.WriteValueList(vl)
}

// Close closes a connection. You must not use "c" after this call.
func (c *Conn) Close() error {
	if err := c.buffer.Flush(); err != nil {
		return err
	}

	if err := c.udp.Close(); err != nil {
		return err
	}

	c.buffer = nil
	return nil
}
<commit_msg>network: Add Dial{Signed,Encrypted} and Conn.Flush().<commit_after>package network

import (
	"net"

	"collectd.org/api"
)

// DefaultService is the default port used by collectd's network plugin.
const DefaultService = "25826"

// Conn is a client connection to a collectd server.
type Conn struct {
	udp    net.Conn
	buffer *Buffer
}

// Dial connects to the collectd server at address. "address" must be a network
// address accepted by net.Dial().
func Dial(address string) (*Conn, error) {
	c, err := net.Dial("udp", address)
	if err != nil {
		return nil, err
	}

	return &Conn{
		udp:    c,
		buffer: NewBuffer(c),
	}, nil
}

// DialSigned connects to the collectd server at "address". Data is signed with
// the given username and password.
func DialSigned(address, username, password string) (*Conn, error) {
	c, err := net.Dial("udp", address)
	if err != nil {
		return nil, err
	}

	return &Conn{
		udp:    c,
		buffer: NewBufferSigned(c, username, password),
	}, nil
}

// DialEncrypted connects to the collectd server at "address". Data is
// encrypted with the given username and password.
func DialEncrypted(address, username, password string) (*Conn, error) {
	c, err := net.Dial("udp", address)
	if err != nil {
		return nil, err
	}

	return &Conn{
		udp:    c,
		buffer: NewBufferEncrypted(c, username, password),
	}, nil
}

// WriteValueList adds a ValueList to the internal buffer. Data is only written
// to the network when the buffer is full.
func (c *Conn) WriteValueList(vl api.ValueList) error {
	return c.buffer.WriteValueList(vl)
}

// Flush writes the contents of the underlying buffer to the network
// immediately.
func (c *Conn) Flush() error {
	return c.buffer.Flush()
}

// Close closes a connection. You must not use "c" after this call.
func (c *Conn) Close() error {
	if err := c.buffer.Flush(); err != nil {
		return err
	}

	if err := c.udp.Close(); err != nil {
		return err
	}

	c.buffer = nil
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 client

import (
	"context"
	"crypto/rand"
	"math/big"
	"net/http"
	"strconv"
	"time"

	"golang.org/x/crypto/acme"
)

type Interface interface {
	AuthorizeOrder(ctx context.Context, id []acme.AuthzID, opt ...acme.OrderOption) (*acme.Order, error)
	GetOrder(ctx context.Context, url string) (*acme.Order, error)
	FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error)
	WaitOrder(ctx context.Context, url string) (*acme.Order, error)
	CreateOrderCert(ctx context.Context, finalizeURL string, csr []byte, bundle bool) (der [][]byte, certURL string, err error)
	Accept(ctx context.Context, chal *acme.Challenge) (*acme.Challenge, error)
	GetChallenge(ctx context.Context, url string) (*acme.Challenge, error)
	GetAuthorization(ctx context.Context, url string) (*acme.Authorization, error)
	WaitAuthorization(ctx context.Context, url string) (*acme.Authorization, error)
	Register(ctx context.Context, a *acme.Account, prompt func(tosURL string) bool) (*acme.Account, error)
	GetReg(ctx context.Context, url string) (*acme.Account, error)
	HTTP01ChallengeResponse(token string) (string, error)
	DNS01ChallengeRecord(token string) (string, error)
	Discover(ctx context.Context) (acme.Directory, error)
	UpdateReg(ctx context.Context, a *acme.Account) (*acme.Account, error)
}

var _ Interface = &acme.Client{
	// inspired by acme/http.go
	RetryBackoff: func(n int, r *http.Request, res *http.Response) time.Duration {
		var jitter time.Duration
		if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
			// Set the minimum to 1ms to avoid a case where
			// an invalid Retry-After value is parsed into 0 below,
			// resulting in the 0 returned value which would unintentionally
			// stop the retries.
			jitter = (1 + time.Duration(x.Int64())) * time.Millisecond
		}
		if v, ok := res.Header["Retry-After"]; ok {
			if i, err := strconv.Atoi(v[0]); err == nil {
				return time.Duration(i) * time.Second
			}
			t, err := http.ParseTime(v[0])
			if err != nil {
				return 0
			}

			if t.Sub(time.Now()) > 5*time.Minute {
				// if Retry-After is bigger than 5 minutes we should
				// error and let the cert-manager logic retry instead
				return -1
			}

			return t.Sub(time.Now()) + jitter
		}

		// classic backoff here in case we got no reply
		// eg. flakes
		if n < 1 {
			n = 1
		}
		if n > 30 {
			n = 30
		}
		d := time.Duration(1<<uint(n-1))*time.Second + jitter
		if d > 10*time.Second {
			return 10 * time.Second
		}
		return d
	},
}
<commit_msg>Make it always error if retry-after is set<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 client

import (
	"context"
	"crypto/rand"
	"math/big"
	"net/http"
	"time"

	"golang.org/x/crypto/acme"
)

type Interface interface {
	AuthorizeOrder(ctx context.Context, id []acme.AuthzID, opt ...acme.OrderOption) (*acme.Order, error)
	GetOrder(ctx context.Context, url string) (*acme.Order, error)
	FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error)
	WaitOrder(ctx context.Context, url string) (*acme.Order, error)
	CreateOrderCert(ctx context.Context, finalizeURL string, csr []byte, bundle bool) (der [][]byte, certURL string, err error)
	Accept(ctx context.Context, chal *acme.Challenge) (*acme.Challenge, error)
	GetChallenge(ctx context.Context, url string) (*acme.Challenge, error)
	GetAuthorization(ctx context.Context, url string) (*acme.Authorization, error)
	WaitAuthorization(ctx context.Context, url string) (*acme.Authorization, error)
	Register(ctx context.Context, a *acme.Account, prompt func(tosURL string) bool) (*acme.Account, error)
	GetReg(ctx context.Context, url string) (*acme.Account, error)
	HTTP01ChallengeResponse(token string) (string, error)
	DNS01ChallengeRecord(token string) (string, error)
	Discover(ctx context.Context) (acme.Directory, error)
	UpdateReg(ctx context.Context, a *acme.Account) (*acme.Account, error)
}

var _ Interface = &acme.Client{
	// inspired by acme/http.go
	RetryBackoff: func(n int, r *http.Request, res *http.Response) time.Duration {
		var jitter time.Duration
		if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
			// Set the minimum to 1ms to avoid a case where
			// an invalid Retry-After value is parsed into 0 below,
			// resulting in the 0 returned value which would unintentionally
			// stop the retries.
			jitter = (1 + time.Duration(x.Int64())) * time.Millisecond
		}
		if _, ok := res.Header["Retry-After"]; ok {
			// if Retry-After is set we should
			// error and let the cert-manager logic retry instead
			return -1
		}

		// classic backoff here in case we got no reply
		// eg. flakes
		if n < 1 {
			n = 1
		}
		if n > 30 {
			n = 30
		}
		d := time.Duration(1<<uint(n-1))*time.Second + jitter
		if d > 10*time.Second {
			return 10 * time.Second
		}
		return d
	},
}
<|endoftext|>


<commit_before>package avl

import "fmt"

// IntTreeSetNode is a node of IntTreeSet.
type IntTreeSetNode struct {
	value         int
	childL        *IntTreeSetNode
	childR        *IntTreeSetNode
	balanceFactor int
}

// TraversePreOrder traverses the subtree rooted at n in pre-order (NLR).
func (n *IntTreeSetNode) TraversePreOrder(consumer func(*IntTreeSetNode)) {
	if n == nil {
		return
	}
	consumer(n)
	n.childL.TraversePreOrder(consumer)
	n.childR.TraversePreOrder(consumer)
}

// TraversePreOrder traverses the subtree rooted at n in in-order (LNR).
func (n *IntTreeSetNode) TraverseInOrder(consumer func(*IntTreeSetNode)) {
	if n == nil {
		return
	}
	n.childL.TraversePreOrder(consumer)
	consumer(n)
	n.childR.TraversePreOrder(consumer)
}

// TraversePreOrder traverses the subtree rooted at n in post-order (LRN).
func (n *IntTreeSetNode) TraversePostOrder(consumer func(*IntTreeSetNode)) {
	if n == nil {
		return
	}
	n.childL.TraversePreOrder(consumer)
	n.childR.TraversePreOrder(consumer)
	consumer(n)
}

func (n *IntTreeSetNode) height() int {
	if n == nil {
		return -1
	}
	return max(n.childL.height(), n.childR.height()) + 1
}

func (n *IntTreeSetNode) String() string {
	if n == nil {
		return "/"
	}
	return fmt.Sprintf("(%d %s %s)", n.value, n.childL.String(), n.childR.String())
}

// Print prints the subtree rooted at n.
func (n *IntTreeSetNode) Print(indentString string, indentLevel int) {
	for i := 0; i < indentLevel; i++ {
		fmt.Print(indentString)
	}
	if n == nil {
		fmt.Println("nil")
	} else {
		fmt.Printf("%d (height: %d, balance factor: %d)\n", n.value, n.height(), n.balanceFactor)
		n.childL.Print(indentString, indentLevel+1)
		n.childR.Print(indentString, indentLevel+1)
	}
}

// Contains returns whether the subtree rooted at n contains v.
func (n *IntTreeSetNode) Contains(v int) bool {
	if n == nil {
		return false
	}
	if v < n.value {
		return n.childL.Contains(v)
	}
	if v > n.value {
		return n.childR.Contains(v)
	}
	return true
}

// Add adds v to the subtree rooted at n.
func (n *IntTreeSetNode) Add(v int, ptrN **IntTreeSetNode) bool {
	if n == nil {
		*ptrN = &IntTreeSetNode{value: v}
		return true
	}
	if v < n.value {
		if n.childL.Add(v, &n.childL) {
			if n.balanceFactor < 0 {
				// Rotate
				if v > n.childL.value {
					// LR Case
					n.rotateLeftRight(ptrN)
				} else {
					// LL Case
					n.rotateRight(ptrN)
				}
				return false
			}
			n.balanceFactor--
			return true
		}
	}
	if v > n.value {
		if n.childR.Add(v, &n.childR) {
			if n.balanceFactor > 0 {
				// Rotate
				if v < n.childR.value {
					// RL Case
					n.rotateRightLeft(ptrN)
				} else {
					// RR Case
					n.rotateLeft(ptrN)
				}
				return false
			}
			n.balanceFactor++
			return true
		}
	}
	// v already existed, nothing to be done
	return false
}

func (n *IntTreeSetNode) Remove(v int, ptrN **IntTreeSetNode) bool {
	// TODO: Write this!
	panic("Not implemented!")
}
<commit_msg>Dirty commit<commit_after>package avl

import "fmt"

// IntTreeSetNode is a node of IntTreeSet.
type IntTreeSetNode struct {
	value         int
	childL        *IntTreeSetNode
	childR        *IntTreeSetNode
	balanceFactor int
}

// TraversePreOrder traverses the subtree rooted at n in pre-order (NLR).
func (n *IntTreeSetNode) TraversePreOrder(consumer func(*IntTreeSetNode)) {
	if n == nil {
		return
	}
	consumer(n)
	n.childL.TraversePreOrder(consumer)
	n.childR.TraversePreOrder(consumer)
}

// TraversePreOrder traverses the subtree rooted at n in in-order (LNR).
func (n *IntTreeSetNode) TraverseInOrder(consumer func(*IntTreeSetNode)) {
	if n == nil {
		return
	}
	n.childL.TraversePreOrder(consumer)
	consumer(n)
	n.childR.TraversePreOrder(consumer)
}

// TraversePreOrder traverses the subtree rooted at n in post-order (LRN).
func (n *IntTreeSetNode) TraversePostOrder(consumer func(*IntTreeSetNode)) {
	if n == nil {
		return
	}
	n.childL.TraversePreOrder(consumer)
	n.childR.TraversePreOrder(consumer)
	consumer(n)
}

func (n *IntTreeSetNode) height() int {
	if n == nil {
		return -1
	}
	return max(n.childL.height(), n.childR.height()) + 1
}

func (n *IntTreeSetNode) String() string {
	if n == nil {
		return "/"
	}
	return fmt.Sprintf("(%d %s %s)", n.value, n.childL.String(), n.childR.String())
}

// Print prints the subtree rooted at n.
func (n *IntTreeSetNode) Print(indentString string, indentLevel int) {
	for i := 0; i < indentLevel; i++ {
		fmt.Print(indentString)
	}
	if n == nil {
		fmt.Println("nil")
	} else {
		fmt.Printf("%d (height: %d, balance factor: %d)\n", n.value, n.height(), n.balanceFactor)
		n.childL.Print(indentString, indentLevel+1)
		n.childR.Print(indentString, indentLevel+1)
	}
}

// Contains returns whether the subtree rooted at n contains v.
func (n *IntTreeSetNode) Contains(v int) bool {
	if n == nil {
		return false
	}
	if v < n.value {
		return n.childL.Contains(v)
	}
	if v > n.value {
		return n.childR.Contains(v)
	}
	return true
}

// Add adds v to the subtree rooted at n.
func (n *IntTreeSetNode) Add(v int, ptrN **IntTreeSetNode) bool {
	if n == nil {
		*ptrN = &IntTreeSetNode{value: v}
		return true
	}
	if v < n.value {
		if n.childL.Add(v, &n.childL) {
			if n.balanceFactor < 0 {
				// Rotate
				if v > n.childL.value {
					// LR Case
					p := n.childL
					q := p.childR
					p.childR = q.childL
					n.childL = q.childR
					q.childL = p
					q.childR = n
					*ptrN = q
					if q.balanceFactor < 0 {
						n.balanceFactor = 1
						p.balanceFactor = 0
					} else if q.balanceFactor > 0 {
						n.balanceFactor = 0
						p.balanceFactor = -1
					} else {
						n.balanceFactor = 0
						p.balanceFactor = 0
					}
					q.balanceFactor = 0
				} else {
					// LL Case
					p := n.childL
					n.childL = p.childR
					p.childR = n
					*ptrN = p
					n.balanceFactor = 0
					p.balanceFactor = 0
				}
				return false
			}
			n.balanceFactor--
			return true
		}
	}
	if v > n.value {
		if n.childR.Add(v, &n.childR) {
			if n.balanceFactor > 0 {
				// Rotate
				if v < n.childR.value {
					// RL Case
					p := n.childR
					q := p.childL
					p.childL = q.childR
					n.childR = q.childL
					q.childR = p
					q.childL = n
					*ptrN = q
					if q.balanceFactor < 0 {
						n.balanceFactor = 1
						p.balanceFactor = 0
					} else if q.balanceFactor > 0 {
						n.balanceFactor = 0
						p.balanceFactor = -1
					} else {
						n.balanceFactor = 0
						p.balanceFactor = 0
					}
					q.balanceFactor = 0
				} else {
					// RR Case
					p := n.childR
					n.childR = p.childL
					p.childL = n
					*ptrN = p
					n.balanceFactor = 0
					p.balanceFactor = 0
				}
				return false
			}
			n.balanceFactor++
			return true
		}
	}
	// v already existed, nothing to be done
	return false
}

func (n *IntTreeSetNode) Remove(v int, ptrN **IntTreeSetNode) bool {
	// TODO: Write this!
	panic("Not implemented!")
}
<|endoftext|>


<commit_before>// Copyright 2016  cbping. 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.

// client 包
// @author cbping
package client

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"time"
)

const (
	SlowReqRecord  = "SlowReqRecord"
	ReqRecord      = "ReqRecord"
	ErrorReqRecord = "ErrorReqRecord"
)

func init() {
	SetDefaultClient("", http.DefaultClient)
}

//----------------------------------------------------------------------------------------------------------------------

//
//  客户端
//  处理http请求
type Client struct {
	// 采用默认&http.Client{}
	*http.Client

	//
	UserAgent string

	// 超过SlowReqLong时间长度的请求，将记录为慢请求
	// 默认为2秒
	SlowReqLong time.Duration

	// 函数参数
	// 记录信息；如日志记录
	Record func(tag, msg string)

	// 和http.Client.Timeout相关
	Timeout time.Duration

	//版本号
	Version string
	//
	debug bool
}

func (c *Client) SetDebug(debug bool) {
	c.debug = debug
}

func (c *Client) SetRecord(record func(tag, msg string)) {
	c.Record = record
}

func (c *Client) SetTimeOut(timeout time.Duration) {
	c.Timeout = timeout
}

func (c *Client) SetSlowReqLong(long time.Duration) {
	c.SlowReqLong = long
}

// 设置代理
// example:
//
//	func(req *http.Request) (*url.URL, error) {
// 		u, _ := url.ParseRequestURI("http://127.0.0.1:8118")
// 		return u, nil
// 	}
func (c *Client) SetProxy(proxy func(*http.Request) (*url.URL, error)) {
	//TODO::默认http.Client或者默认http.Transport时，是否值得改变代理（影响其他请求）？
	if nil != c.Client && nil != c.Client.Transport {
		c.Client.Transport.(*http.Transport).Proxy = proxy
	}

	return
}

// 处理请求
func (c *Client) DoRequest(req Request) (resp *Response, err error) {
	if nil == c.Client {
		c.Client = http.DefaultClient
	}

	defer func() {
		if nil != err && nil != c.Record {
			c.Record(ErrorReqRecord, fmt.Sprintf("query:: %s errorr:: %v) ", req.String(), err))
			err = clientError(err)
		}
	}()

	if nil == req {
		return nil, errors.New("Request is nil")
	}

	httpReq, err := req.HttpRequest()
	if nil != err {
		return nil, err
	}

	//必要头部信息设置
	httpReq.Header.Set("User-Agent", `Bping-Curl-`+c.UserAgent+"/"+c.Version)

	// 超时时间设置
	// XXX:并发下同步未做处理。
	// 会混乱被覆盖，未能按照预期执行
	// 建议client使用统一超时时间即可，
	// 不必细化到每一个request中去
	timeout := req.GetTimeOut()
	if timeout < 0 {
		timeout = c.Timeout
	}
	c.Client.Timeout = timeout

	t0 := time.Now()
	httpResp, err := c.Client.Do(httpReq)
	t1 := time.Now()
	if nil != err {
		return nil, err
	}

	if nil != c.Record {
		reqInfo := fmt.Sprintf("http query:: %s status:%d \n ts:(%v) \n", req.String(), httpResp.StatusCode, t1.Sub(t0))
		if t1.Sub(t0) >= c.SlowReqLong {
			c.Record(SlowReqRecord, reqInfo)
		}
		c.Record(ReqRecord, reqInfo)
	}
	resp = &Response{Response: httpResp}
	return
}

func NewClient(title string, client *http.Client) *Client {
	return &Client{
		Client:      client,
		Version:     Version,
		UserAgent:   title,
		debug:       false,
		SlowReqLong: 2 * time.Second,
	}
}

func clientError(err error) error {
	if nil == err {
		return nil
	}
	return errors.New("Bping-Curl-Client-Failure:" + err.Error())
}

//----------------------------------------------------------------------------------------------------------------------

var DefaultClient *Client

// 设置DefaultClient
func SetDefaultClient(title string, client *http.Client) {
	DefaultClient = NewClient(title, client)
}

// 设置代理
// example:
//
//	func(req *http.Request) (*url.URL, error) {
// 		u, _ := url.ParseRequestURI("http://127.0.0.1:8118")
// 		return u, nil
// 	}
// 内部调用DefaultClient
func SetProxy(proxy func(*http.Request) (*url.URL, error)) {
	DefaultClient.SetProxy(proxy)
}

// 设置记录
// 内部调用DefaultClient
func SetRecord(record func(tag, msg string)) {
	DefaultClient.SetRecord(record)
}

// 设置慢请求时间限制
// 内部调用DefaultClient
func SetSlowReqLong(long time.Duration) {
	DefaultClient.SetSlowReqLong(long)
}

// 设置超时时间
// 内部调用DefaultClient
func SetTimeOut(timeout time.Duration) {
	DefaultClient.SetTimeOut(timeout)
}

// 处理请求，内部调用DefaultClient
func DoRequest(req Request) (*Response, error) {
	return DefaultClient.DoRequest(req)
}
<commit_msg>record the response msg<commit_after>// Copyright 2016  cbping. 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.

// client 包
// @author cbping
package client

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"time"
)

const (
	SlowReqRecord  = "SlowReqRecord"
	ReqRecord      = "ReqRecord"
	ErrorReqRecord = "ErrorReqRecord"
)

func init() {
	SetDefaultClient("", http.DefaultClient)
}

//----------------------------------------------------------------------------------------------------------------------

//
//  客户端
//  处理http请求
type Client struct {
	// 采用默认&http.Client{}
	*http.Client

	//
	UserAgent string

	// 超过SlowReqLong时间长度的请求，将记录为慢请求
	// 默认为2秒
	SlowReqLong time.Duration

	// 函数参数
	// 记录信息；如日志记录
	Record func(tag, msg string)

	// 和http.Client.Timeout相关
	Timeout time.Duration

	//版本号
	Version string
	//
	debug bool
}

func (c *Client) SetDebug(debug bool) {
	c.debug = debug
}

func (c *Client) SetRecord(record func(tag, msg string)) {
	c.Record = record
}

func (c *Client) SetTimeOut(timeout time.Duration) {
	c.Timeout = timeout
}

func (c *Client) SetSlowReqLong(long time.Duration) {
	c.SlowReqLong = long
}

// 设置代理
// example:
//
//	func(req *http.Request) (*url.URL, error) {
// 		u, _ := url.ParseRequestURI("http://127.0.0.1:8118")
// 		return u, nil
// 	}
func (c *Client) SetProxy(proxy func(*http.Request) (*url.URL, error)) {
	//TODO::默认http.Client或者默认http.Transport时，是否值得改变代理（影响其他请求）？
	if nil != c.Client && nil != c.Client.Transport {
		c.Client.Transport.(*http.Transport).Proxy = proxy
	}

	return
}

// 处理请求
func (c *Client) DoRequest(req Request) (resp *Response, err error) {
	if nil == c.Client {
		c.Client = http.DefaultClient
	}

	defer func() {
		if nil != err && nil != c.Record {
			c.Record(ErrorReqRecord, fmt.Sprintf("query:: %s errorr:: %v) ", req.String(), err))
			err = clientError(err)
		}
	}()

	if nil == req {
		return nil, errors.New("Request is nil")
	}

	httpReq, err := req.HttpRequest()
	if nil != err {
		return nil, err
	}

	//必要头部信息设置
	httpReq.Header.Set("User-Agent", `Bping-Curl-`+c.UserAgent+"/"+c.Version)

	// 超时时间设置
	// XXX:并发下同步未做处理。
	// 会混乱被覆盖，未能按照预期执行
	// 建议client使用统一超时时间即可，
	// 不必细化到每一个request中去
	timeout := req.GetTimeOut()
	if timeout < 0 {
		timeout = c.Timeout
	}
	c.Client.Timeout = timeout

	t0 := time.Now()
	httpResp, err := c.Client.Do(httpReq)
	t1 := time.Now()
	if nil != err {
		return nil, err
	}
	resp = &Response{Response: httpResp}
	if nil != c.Record {
		resStr,_:=resp.Bytes()
		reqInfo := fmt.Sprintf("http query:: %s status:%d \n response:%s \n ts:(%v) \n", req.String(), httpResp.StatusCode,string(resStr),t1.Sub(t0))
		if t1.Sub(t0) >= c.SlowReqLong {
			c.Record(SlowReqRecord, reqInfo)
		}
		c.Record(ReqRecord, reqInfo)
	}
	return
}

func NewClient(title string, client *http.Client) *Client {
	return &Client{
		Client:      client,
		Version:     Version,
		UserAgent:   title,
		debug:       false,
		SlowReqLong: 2 * time.Second,
	}
}

func clientError(err error) error {
	if nil == err {
		return nil
	}
	return errors.New("Bping-Curl-Client-Failure:" + err.Error())
}

//----------------------------------------------------------------------------------------------------------------------

var DefaultClient *Client

// 设置DefaultClient
func SetDefaultClient(title string, client *http.Client) {
	DefaultClient = NewClient(title, client)
}

// 设置代理
// example:
//
//	func(req *http.Request) (*url.URL, error) {
// 		u, _ := url.ParseRequestURI("http://127.0.0.1:8118")
// 		return u, nil
// 	}
// 内部调用DefaultClient
func SetProxy(proxy func(*http.Request) (*url.URL, error)) {
	DefaultClient.SetProxy(proxy)
}

// 设置记录
// 内部调用DefaultClient
func SetRecord(record func(tag, msg string)) {
	DefaultClient.SetRecord(record)
}

// 设置慢请求时间限制
// 内部调用DefaultClient
func SetSlowReqLong(long time.Duration) {
	DefaultClient.SetSlowReqLong(long)
}

// 设置超时时间
// 内部调用DefaultClient
func SetTimeOut(timeout time.Duration) {
	DefaultClient.SetTimeOut(timeout)
}

// 处理请求，内部调用DefaultClient
func DoRequest(req Request) (*Response, error) {
	return DefaultClient.DoRequest(req)
}
<|endoftext|>


<commit_before>package tracker

import (
	"context"
	"net/url"

	trHttp "github.com/anacrolix/torrent/tracker/http"
	"github.com/anacrolix/torrent/tracker/udp"
)

type Client interface {
	Announce(context.Context, AnnounceRequest, trHttp.AnnounceOpt) (AnnounceResponse, error)
	Close() error
}

type NewClientOpts struct {
	Http trHttp.NewClientOpts
	// Overrides the network in the scheme. Probably a legacy thing.
	UdpNetwork string
}

func NewClient(urlStr string, opts NewClientOpts) (Client, error) {
	_url, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}
	switch _url.Scheme {
	case "http", "https":
		return trHttp.NewClient(_url, opts.Http), nil
	case "udp", "udp4", "udp6":
		network := _url.Scheme
		if opts.UdpNetwork != "" {
			network = opts.UdpNetwork
		}
		cc, err := udp.NewConnClient(udp.NewConnClientOpts{
			Network: network,
			Host:    _url.Host,
		})
		if err != nil {
			return nil, err
		}
		return &udpClient{
			cl:         cc,
			requestUri: _url.RequestURI(),
		}, nil
	default:
		return nil, ErrBadScheme
	}
}
<commit_msg>Pull AnnounceOpt into tracker package<commit_after>package tracker

import (
	"context"
	"net/url"

	trHttp "github.com/anacrolix/torrent/tracker/http"
	"github.com/anacrolix/torrent/tracker/udp"
)

type Client interface {
	Announce(context.Context, AnnounceRequest, AnnounceOpt) (AnnounceResponse, error)
	Close() error
}

type AnnounceOpt = trHttp.AnnounceOpt

type NewClientOpts struct {
	Http trHttp.NewClientOpts
	// Overrides the network in the scheme. Probably a legacy thing.
	UdpNetwork string
}

func NewClient(urlStr string, opts NewClientOpts) (Client, error) {
	_url, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}
	switch _url.Scheme {
	case "http", "https":
		return trHttp.NewClient(_url, opts.Http), nil
	case "udp", "udp4", "udp6":
		network := _url.Scheme
		if opts.UdpNetwork != "" {
			network = opts.UdpNetwork
		}
		cc, err := udp.NewConnClient(udp.NewConnClientOpts{
			Network: network,
			Host:    _url.Host,
		})
		if err != nil {
			return nil, err
		}
		return &udpClient{
			cl:         cc,
			requestUri: _url.RequestURI(),
		}, nil
	default:
		return nil, ErrBadScheme
	}
}
<|endoftext|>


<commit_before>package helm

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"os"
	"sort"

	batchclient "github.com/rancher/k3s/types/apis/batch/v1"
	coreclient "github.com/rancher/k3s/types/apis/core/v1"
	k3s "github.com/rancher/k3s/types/apis/k3s.cattle.io/v1"
	rbacclients "github.com/rancher/k3s/types/apis/rbac.authorization.k8s.io/v1"
	"github.com/rancher/norman/pkg/changeset"
	"github.com/rancher/norman/pkg/objectset"
	batch "k8s.io/api/batch/v1"
	core "k8s.io/api/core/v1"
	rbac "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/intstr"
)

const (
	namespace = "kube-system"
	image     = "rancher/klipper-helm:v0.1.5"
	label     = "helm.k3s.cattle.io/chart"
)

var (
	trueVal = true
)

func Register(ctx context.Context) error {
	k3sClients := k3s.ClientsFrom(ctx)
	coreClients := coreclient.ClientsFrom(ctx)
	jobClients := batchclient.ClientsFrom(ctx)
	rbacClients := rbacclients.ClientsFrom(ctx)

	h := &handler{
		jobs:     jobClients.Job,
		jobCache: jobClients.Job.Cache(),
		processor: objectset.NewProcessor("k3s.helm").
			Client(coreClients.ConfigMap).
			Client(coreClients.ServiceAccount).
			Client(jobClients.Job).
			Client(rbacClients.ClusterRoleBinding).
			Patcher(batch.SchemeGroupVersion.WithKind("Job"), objectset.ReplaceOnChange),
	}

	k3sClients.HelmChart.OnChange(ctx, "helm", h.onChange)
	k3sClients.HelmChart.OnRemove(ctx, "helm", h.onRemove)

	changeset.Watch(ctx, "helm-pod-watch",
		func(namespace, name string, obj runtime.Object) ([]changeset.Key, error) {
			if job, ok := obj.(*batch.Job); ok {
				name := job.Labels[label]
				if name != "" {
					return []changeset.Key{
						{
							Name:      name,
							Namespace: namespace,
						},
					}, nil
				}
			}
			return nil, nil
		},
		k3sClients.HelmChart,
		jobClients.Job)
	return nil
}

type handler struct {
	jobCache  batchclient.JobClientCache
	jobs      batchclient.JobClient
	processor *objectset.Processor
}

func (h *handler) onChange(chart *k3s.HelmChart) (runtime.Object, error) {
	if chart.Namespace != namespace || chart.Spec.Chart == "" {
		return chart, nil
	}

	objs := objectset.NewObjectSet()
	job, configMap := job(chart)
	objs.Add(serviceAccount(chart))
	objs.Add(roleBinding(chart))
	objs.Add(job)
	if configMap != nil {
		objs.Add(configMap)
	}

	if err := h.processor.NewDesiredSet(chart, objs).Apply(); err != nil {
		return chart, err
	}

	chart.Status.JobName = job.Name
	return chart, nil
}

func (h *handler) onRemove(chart *k3s.HelmChart) (runtime.Object, error) {
	if chart.Namespace != namespace || chart.Spec.Chart == "" {
		return chart, nil
	}

	job, _ := job(chart)

	job, err := h.jobCache.Get(chart.Namespace, job.Name)
	if errors.IsNotFound(err) {
		_, err := h.onChange(chart)
		if err != nil {
			return chart, err
		}
	} else if err != nil {
		return nil, err
	}

	if job.Status.Succeeded <= 0 {
		return nil, fmt.Errorf("waiting for delete of helm chart %s", chart.Name)
	}

	return chart, h.processor.NewDesiredSet(chart, objectset.NewObjectSet()).Apply()
}

func job(chart *k3s.HelmChart) (*batch.Job, *core.ConfigMap) {
	oneThousand := int32(1000)
	valuesHash := sha256.Sum256([]byte(chart.Spec.ValuesContent))

	action := "install"
	if chart.DeletionTimestamp != nil {
		action = "delete"
	}
	job := &batch.Job{
		TypeMeta: meta.TypeMeta{
			APIVersion: "batch/v1",
			Kind:       "Job",
		},
		ObjectMeta: meta.ObjectMeta{
			Name:      fmt.Sprintf("helm-%s-%s", action, chart.Name),
			Namespace: chart.Namespace,
			Labels: map[string]string{
				label: chart.Name,
			},
		},
		Spec: batch.JobSpec{
			BackoffLimit: &oneThousand,
			Template: core.PodTemplateSpec{
				ObjectMeta: meta.ObjectMeta{
					Labels: map[string]string{
						label: chart.Name,
					},
				},
				Spec: core.PodSpec{
					RestartPolicy: core.RestartPolicyOnFailure,
					Containers: []core.Container{
						{
							Name:            "helm",
							Image:           image,
							ImagePullPolicy: core.PullIfNotPresent,
							Args:            args(chart),
							Env: []core.EnvVar{
								{
									Name:  "NAME",
									Value: chart.Name,
								},
								{
									Name:  "VERSION",
									Value: chart.Spec.Version,
								},
								{
									Name:  "REPO",
									Value: chart.Spec.Repo,
								},
								{
									Name:  "VALUES_HASH",
									Value: hex.EncodeToString(valuesHash[:]),
								},
							},
						},
					},
					ServiceAccountName: fmt.Sprintf("helm-%s", chart.Name),
				},
			},
		},
	}
	setProxyEnv(job)
	configMap := configMap(chart)
	if configMap == nil {
		return job, nil
	}

	job.Spec.Template.Spec.Volumes = []core.Volume{
		{
			Name: "values",
			VolumeSource: core.VolumeSource{
				ConfigMap: &core.ConfigMapVolumeSource{
					LocalObjectReference: core.LocalObjectReference{
						Name: configMap.Name,
					},
				},
			},
		},
	}

	job.Spec.Template.Spec.Containers[0].VolumeMounts = []core.VolumeMount{
		{
			MountPath: "/config",
			Name:      "values",
		},
	}

	return job, configMap
}

func configMap(chart *k3s.HelmChart) *core.ConfigMap {
	if chart.Spec.ValuesContent == "" {
		return nil
	}

	return &core.ConfigMap{
		TypeMeta: meta.TypeMeta{
			APIVersion: "v1",
			Kind:       "ConfigMap",
		},
		ObjectMeta: meta.ObjectMeta{
			Name:      fmt.Sprintf("chart-values-%s", chart.Name),
			Namespace: chart.Namespace,
		},
		Data: map[string]string{
			"values.yaml": chart.Spec.ValuesContent,
		},
	}
}

func roleBinding(chart *k3s.HelmChart) *rbac.ClusterRoleBinding {
	return &rbac.ClusterRoleBinding{
		TypeMeta: meta.TypeMeta{
			APIVersion: "rbac.authorization.k8s.io/v1",
			Kind:       "ClusterRoleBinding",
		},
		ObjectMeta: meta.ObjectMeta{
			Name: fmt.Sprintf("helm-%s-%s", chart.Namespace, chart.Name),
		},
		RoleRef: rbac.RoleRef{
			Kind:     "ClusterRole",
			APIGroup: "rbac.authorization.k8s.io",
			Name:     "cluster-admin",
		},
		Subjects: []rbac.Subject{
			{
				Name:      fmt.Sprintf("helm-%s", chart.Name),
				Kind:      "ServiceAccount",
				Namespace: chart.Namespace,
			},
		},
	}

}

func serviceAccount(chart *k3s.HelmChart) *core.ServiceAccount {
	return &core.ServiceAccount{
		TypeMeta: meta.TypeMeta{
			APIVersion: "v1",
			Kind:       "ServiceAccount",
		},
		ObjectMeta: meta.ObjectMeta{
			Name:      fmt.Sprintf("helm-%s", chart.Name),
			Namespace: chart.Namespace,
		},
		AutomountServiceAccountToken: &trueVal,
	}
}

func args(chart *k3s.HelmChart) []string {
	if chart.DeletionTimestamp != nil {
		return []string{
			"delete",
			"--purge", chart.Name,
		}
	}

	spec := chart.Spec
	args := []string{
		"install",
		"--name", chart.Name,
		spec.Chart,
	}
	if spec.TargetNamespace != "" {
		args = append(args, "--namespace", spec.TargetNamespace)
	}
	if spec.Repo != "" {
		args = append(args, "--repo", spec.Repo)
	}
	if spec.Version != "" {
		args = append(args, "--version", spec.Version)
	}

	for _, k := range keys(spec.Set) {
		val := spec.Set[k]
		if val.StrVal != "" {
			args = append(args, "--set-string", fmt.Sprintf("%s=%s", k, val.StrVal))
		} else {
			args = append(args, "--set", fmt.Sprintf("%s=%d", k, val.IntVal))
		}
	}

	return args
}

func keys(val map[string]intstr.IntOrString) []string {
	var keys []string
	for k := range val {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	return keys
}

func setProxyEnv(job *batch.Job) {
	proxySysEnv := []string{
		"http_proxy",
		"https_proxy",
		"HTTP_PROXY",
		"HTTPS_PROXY",
		"NO_PROXY",
	}
	for _, proxyEnv := range proxySysEnv {
		proxyEnvValue := os.Getenv(proxyEnv)
		if len(proxyEnvValue) == 0 {
			continue
		}
		envar := core.EnvVar{
			Name:  proxyEnv,
			Value: proxyEnvValue,
		}
		job.Spec.Template.Spec.Containers[0].Env = append(
			job.Spec.Template.Spec.Containers[0].Env,
			envar)
	}
}
<commit_msg>Update proxy environment for helm controller<commit_after>package helm

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"os"
	"sort"

	batchclient "github.com/rancher/k3s/types/apis/batch/v1"
	coreclient "github.com/rancher/k3s/types/apis/core/v1"
	k3s "github.com/rancher/k3s/types/apis/k3s.cattle.io/v1"
	rbacclients "github.com/rancher/k3s/types/apis/rbac.authorization.k8s.io/v1"
	"github.com/rancher/norman/pkg/changeset"
	"github.com/rancher/norman/pkg/objectset"
	batch "k8s.io/api/batch/v1"
	core "k8s.io/api/core/v1"
	rbac "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/intstr"
)

const (
	namespace = "kube-system"
	image     = "rancher/klipper-helm:v0.1.5"
	label     = "helm.k3s.cattle.io/chart"
)

var (
	trueVal = true
)

func Register(ctx context.Context) error {
	k3sClients := k3s.ClientsFrom(ctx)
	coreClients := coreclient.ClientsFrom(ctx)
	jobClients := batchclient.ClientsFrom(ctx)
	rbacClients := rbacclients.ClientsFrom(ctx)

	h := &handler{
		jobs:     jobClients.Job,
		jobCache: jobClients.Job.Cache(),
		processor: objectset.NewProcessor("k3s.helm").
			Client(coreClients.ConfigMap).
			Client(coreClients.ServiceAccount).
			Client(jobClients.Job).
			Client(rbacClients.ClusterRoleBinding).
			Patcher(batch.SchemeGroupVersion.WithKind("Job"), objectset.ReplaceOnChange),
	}

	k3sClients.HelmChart.OnChange(ctx, "helm", h.onChange)
	k3sClients.HelmChart.OnRemove(ctx, "helm", h.onRemove)

	changeset.Watch(ctx, "helm-pod-watch",
		func(namespace, name string, obj runtime.Object) ([]changeset.Key, error) {
			if job, ok := obj.(*batch.Job); ok {
				name := job.Labels[label]
				if name != "" {
					return []changeset.Key{
						{
							Name:      name,
							Namespace: namespace,
						},
					}, nil
				}
			}
			return nil, nil
		},
		k3sClients.HelmChart,
		jobClients.Job)
	return nil
}

type handler struct {
	jobCache  batchclient.JobClientCache
	jobs      batchclient.JobClient
	processor *objectset.Processor
}

func (h *handler) onChange(chart *k3s.HelmChart) (runtime.Object, error) {
	if chart.Namespace != namespace || chart.Spec.Chart == "" {
		return chart, nil
	}

	objs := objectset.NewObjectSet()
	job, configMap := job(chart)
	objs.Add(serviceAccount(chart))
	objs.Add(roleBinding(chart))
	objs.Add(job)
	if configMap != nil {
		objs.Add(configMap)
	}

	if err := h.processor.NewDesiredSet(chart, objs).Apply(); err != nil {
		return chart, err
	}

	chart.Status.JobName = job.Name
	return chart, nil
}

func (h *handler) onRemove(chart *k3s.HelmChart) (runtime.Object, error) {
	if chart.Namespace != namespace || chart.Spec.Chart == "" {
		return chart, nil
	}

	job, _ := job(chart)

	job, err := h.jobCache.Get(chart.Namespace, job.Name)
	if errors.IsNotFound(err) {
		_, err := h.onChange(chart)
		if err != nil {
			return chart, err
		}
	} else if err != nil {
		return nil, err
	}

	if job.Status.Succeeded <= 0 {
		return nil, fmt.Errorf("waiting for delete of helm chart %s", chart.Name)
	}

	return chart, h.processor.NewDesiredSet(chart, objectset.NewObjectSet()).Apply()
}

func job(chart *k3s.HelmChart) (*batch.Job, *core.ConfigMap) {
	oneThousand := int32(1000)
	valuesHash := sha256.Sum256([]byte(chart.Spec.ValuesContent))

	action := "install"
	if chart.DeletionTimestamp != nil {
		action = "delete"
	}
	job := &batch.Job{
		TypeMeta: meta.TypeMeta{
			APIVersion: "batch/v1",
			Kind:       "Job",
		},
		ObjectMeta: meta.ObjectMeta{
			Name:      fmt.Sprintf("helm-%s-%s", action, chart.Name),
			Namespace: chart.Namespace,
			Labels: map[string]string{
				label: chart.Name,
			},
		},
		Spec: batch.JobSpec{
			BackoffLimit: &oneThousand,
			Template: core.PodTemplateSpec{
				ObjectMeta: meta.ObjectMeta{
					Labels: map[string]string{
						label: chart.Name,
					},
				},
				Spec: core.PodSpec{
					RestartPolicy: core.RestartPolicyOnFailure,
					Containers: []core.Container{
						{
							Name:            "helm",
							Image:           image,
							ImagePullPolicy: core.PullIfNotPresent,
							Args:            args(chart),
							Env: []core.EnvVar{
								{
									Name:  "NAME",
									Value: chart.Name,
								},
								{
									Name:  "VERSION",
									Value: chart.Spec.Version,
								},
								{
									Name:  "REPO",
									Value: chart.Spec.Repo,
								},
								{
									Name:  "VALUES_HASH",
									Value: hex.EncodeToString(valuesHash[:]),
								},
							},
						},
					},
					ServiceAccountName: fmt.Sprintf("helm-%s", chart.Name),
				},
			},
		},
	}
	setProxyEnv(job)
	configMap := configMap(chart)
	if configMap == nil {
		return job, nil
	}

	job.Spec.Template.Spec.Volumes = []core.Volume{
		{
			Name: "values",
			VolumeSource: core.VolumeSource{
				ConfigMap: &core.ConfigMapVolumeSource{
					LocalObjectReference: core.LocalObjectReference{
						Name: configMap.Name,
					},
				},
			},
		},
	}

	job.Spec.Template.Spec.Containers[0].VolumeMounts = []core.VolumeMount{
		{
			MountPath: "/config",
			Name:      "values",
		},
	}

	return job, configMap
}

func configMap(chart *k3s.HelmChart) *core.ConfigMap {
	if chart.Spec.ValuesContent == "" {
		return nil
	}

	return &core.ConfigMap{
		TypeMeta: meta.TypeMeta{
			APIVersion: "v1",
			Kind:       "ConfigMap",
		},
		ObjectMeta: meta.ObjectMeta{
			Name:      fmt.Sprintf("chart-values-%s", chart.Name),
			Namespace: chart.Namespace,
		},
		Data: map[string]string{
			"values.yaml": chart.Spec.ValuesContent,
		},
	}
}

func roleBinding(chart *k3s.HelmChart) *rbac.ClusterRoleBinding {
	return &rbac.ClusterRoleBinding{
		TypeMeta: meta.TypeMeta{
			APIVersion: "rbac.authorization.k8s.io/v1",
			Kind:       "ClusterRoleBinding",
		},
		ObjectMeta: meta.ObjectMeta{
			Name: fmt.Sprintf("helm-%s-%s", chart.Namespace, chart.Name),
		},
		RoleRef: rbac.RoleRef{
			Kind:     "ClusterRole",
			APIGroup: "rbac.authorization.k8s.io",
			Name:     "cluster-admin",
		},
		Subjects: []rbac.Subject{
			{
				Name:      fmt.Sprintf("helm-%s", chart.Name),
				Kind:      "ServiceAccount",
				Namespace: chart.Namespace,
			},
		},
	}

}

func serviceAccount(chart *k3s.HelmChart) *core.ServiceAccount {
	return &core.ServiceAccount{
		TypeMeta: meta.TypeMeta{
			APIVersion: "v1",
			Kind:       "ServiceAccount",
		},
		ObjectMeta: meta.ObjectMeta{
			Name:      fmt.Sprintf("helm-%s", chart.Name),
			Namespace: chart.Namespace,
		},
		AutomountServiceAccountToken: &trueVal,
	}
}

func args(chart *k3s.HelmChart) []string {
	if chart.DeletionTimestamp != nil {
		return []string{
			"delete",
			"--purge", chart.Name,
		}
	}

	spec := chart.Spec
	args := []string{
		"install",
		"--name", chart.Name,
		spec.Chart,
	}
	if spec.TargetNamespace != "" {
		args = append(args, "--namespace", spec.TargetNamespace)
	}
	if spec.Repo != "" {
		args = append(args, "--repo", spec.Repo)
	}
	if spec.Version != "" {
		args = append(args, "--version", spec.Version)
	}

	for _, k := range keys(spec.Set) {
		val := spec.Set[k]
		if val.StrVal != "" {
			args = append(args, "--set-string", fmt.Sprintf("%s=%s", k, val.StrVal))
		} else {
			args = append(args, "--set", fmt.Sprintf("%s=%d", k, val.IntVal))
		}
	}

	return args
}

func keys(val map[string]intstr.IntOrString) []string {
	var keys []string
	for k := range val {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	return keys
}

func setProxyEnv(job *batch.Job) {
	proxySysEnv := []string{
		"all_proxy",
		"ALL_PROXY",
		"http_proxy",
		"HTTP_PROXY",
		"https_proxy",
		"HTTPS_PROXY",
		"no_proxy",
		"NO_PROXY",
	}
	for _, proxyEnv := range proxySysEnv {
		proxyEnvValue := os.Getenv(proxyEnv)
		if len(proxyEnvValue) == 0 {
			continue
		}
		envar := core.EnvVar{
			Name:  proxyEnv,
			Value: proxyEnvValue,
		}
		job.Spec.Template.Spec.Containers[0].Env = append(
			job.Spec.Template.Spec.Containers[0].Env,
			envar)
	}
}
<|endoftext|>


<commit_before>// network子包提供网络相关的一些小函数
package network

import (
	"errors"
	"net"
	"strings"
)

// 获取本地IP地址，除loopback地址(127.0.0.1)
func GetLocalIPAddrs() (ipaddrs []string, err error) {
	var (
		addrs []net.Addr
		addr  []net.Addr
	)

	// 获取所有网络接口
	i, err := net.Interfaces()
	if err != nil {
		return
	}

	// 循环每个网络接口,如果一个接口获取addrs失败，不返回，而是继续
	// 这样可以保证获取可用addrs
	for _, iface := range i {
		if strings.Contains(strings.ToLower(iface.Flags.String()), "loopback") {
			continue
		}
		addr, err = iface.Addrs()
		if err != nil {
			continue
		}
		addrs = append(addrs, addr...)
	}

	if len(addrs) == 0 {
		err = errors.New("can not get any addrs")
	}

	ipaddrs = make([]string, len(addrs))
	for _, addr := range addrs {
		inet, ok := addr.(*net.IPNet)
		if ok {
			ip := inet.IP.To4()
			if ip != nil {
				ipaddrs = append(ipaddrs, ip.String())
			}
		}
	}
	return
}
<commit_msg>fix slice len<commit_after>// network子包提供网络相关的一些小函数
package network

import (
	"errors"
	"net"
	"strings"
)

// 获取本地IP地址，除loopback地址(127.0.0.1)
func GetLocalIPAddrs() (ipaddrs []string, err error) {
	var (
		addrs []net.Addr
		addr  []net.Addr
	)

	// 获取所有网络接口
	i, err := net.Interfaces()
	if err != nil {
		return
	}

	// 循环每个网络接口,如果一个接口获取addrs失败，不返回，而是继续
	// 这样可以保证获取可用addrs
	for _, iface := range i {
		if strings.Contains(strings.ToLower(iface.Flags.String()), "loopback") {
			continue
		}
		addr, err = iface.Addrs()
		if err != nil {
			continue
		}
		addrs = append(addrs, addr...)
	}

	if len(addrs) == 0 {
		err = errors.New("can not get any addrs")
	}

	ipaddrs = make([]string, 0)
	for _, addr := range addrs {
		inet, ok := addr.(*net.IPNet)
		if ok {
			ip := inet.IP.To4()
			if ip != nil {
				ipaddrs = append(ipaddrs, ip.String())
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package latest

import (
	"encoding/json"
	"testing"

	internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)

func TestResourceVersioner(t *testing.T) {
	pod := internal.Pod{ObjectMeta: internal.ObjectMeta{ResourceVersion: "10"}}
	version, err := accessor.ResourceVersion(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}

	podList := internal.PodList{ListMeta: internal.ListMeta{ResourceVersion: "10"}}
	version, err = accessor.ResourceVersion(&podList)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}
}

func TestCodec(t *testing.T) {
	pod := internal.Pod{}
	data, err := Codec.Encode(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	other := internal.Pod{}
	if err := json.Unmarshal(data, &other); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if other.APIVersion != Version || other.Kind != "Pod" {
		t.Errorf("unexpected unmarshalled object %#v", other)
	}
}

func TestInterfacesFor(t *testing.T) {
	if _, err := InterfacesFor(""); err == nil {
		t.Fatalf("unexpected non-error: %v", err)
	}
	for i, version := range append([]string{Version, OldestVersion}, Versions...) {
		if vi, err := InterfacesFor(version); err != nil || vi == nil {
			t.Fatalf("%d: unexpected result: %v", i, err)
		}
	}
}

func TestRESTMapper(t *testing.T) {
	if v, k, err := RESTMapper.VersionAndKindForResource("replicationControllers"); err != nil || v != "v1beta3" || k != "ReplicationController" {
		t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
	}
	if v, k, err := RESTMapper.VersionAndKindForResource("replicationcontrollers"); err != nil || v != "v1beta3" || k != "ReplicationController" {
		t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
	}

	if m, err := RESTMapper.RESTMapping("PodTemplate", ""); err != nil || m.APIVersion != "v1beta3" || m.Resource != "podtemplates" {
		t.Errorf("unexpected version mapping: %#v %v", m, err)
	}

	for _, version := range Versions {
		mapping, err := RESTMapper.RESTMapping("ReplicationController", version)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}

		if mapping.Resource != "replicationControllers" && mapping.Resource != "replicationcontrollers" {
			t.Errorf("incorrect resource name: %#v", mapping)
		}
		if mapping.APIVersion != version {
			t.Errorf("incorrect version: %v", mapping)
		}

		interfaces, _ := InterfacesFor(version)
		if mapping.Codec != interfaces.Codec {
			t.Errorf("unexpected codec: %#v, expected: %#v", mapping, interfaces)
		}

		rc := &internal.ReplicationController{ObjectMeta: internal.ObjectMeta{Name: "foo"}}
		name, err := mapping.MetadataAccessor.Name(rc)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if name != "foo" {
			t.Errorf("unable to retrieve object meta with: %v", mapping.MetadataAccessor)
		}
	}
}
<commit_msg>remove outdated test from latest_test.go<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package latest

import (
	"encoding/json"
	"testing"

	internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)

func TestResourceVersioner(t *testing.T) {
	pod := internal.Pod{ObjectMeta: internal.ObjectMeta{ResourceVersion: "10"}}
	version, err := accessor.ResourceVersion(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}

	podList := internal.PodList{ListMeta: internal.ListMeta{ResourceVersion: "10"}}
	version, err = accessor.ResourceVersion(&podList)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}
}

func TestCodec(t *testing.T) {
	pod := internal.Pod{}
	data, err := Codec.Encode(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	other := internal.Pod{}
	if err := json.Unmarshal(data, &other); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if other.APIVersion != Version || other.Kind != "Pod" {
		t.Errorf("unexpected unmarshalled object %#v", other)
	}
}

func TestInterfacesFor(t *testing.T) {
	if _, err := InterfacesFor(""); err == nil {
		t.Fatalf("unexpected non-error: %v", err)
	}
	for i, version := range append([]string{Version, OldestVersion}, Versions...) {
		if vi, err := InterfacesFor(version); err != nil || vi == nil {
			t.Fatalf("%d: unexpected result: %v", i, err)
		}
	}
}

func TestRESTMapper(t *testing.T) {
	if v, k, err := RESTMapper.VersionAndKindForResource("replicationcontrollers"); err != nil || v != "v1beta3" || k != "ReplicationController" {
		t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
	}

	if m, err := RESTMapper.RESTMapping("PodTemplate", ""); err != nil || m.APIVersion != "v1beta3" || m.Resource != "podtemplates" {
		t.Errorf("unexpected version mapping: %#v %v", m, err)
	}

	for _, version := range Versions {
		mapping, err := RESTMapper.RESTMapping("ReplicationController", version)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}

		if mapping.Resource != "replicationControllers" && mapping.Resource != "replicationcontrollers" {
			t.Errorf("incorrect resource name: %#v", mapping)
		}
		if mapping.APIVersion != version {
			t.Errorf("incorrect version: %v", mapping)
		}

		interfaces, _ := InterfacesFor(version)
		if mapping.Codec != interfaces.Codec {
			t.Errorf("unexpected codec: %#v, expected: %#v", mapping, interfaces)
		}

		rc := &internal.ReplicationController{ObjectMeta: internal.ObjectMeta{Name: "foo"}}
		name, err := mapping.MetadataAccessor.Name(rc)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if name != "foo" {
			t.Errorf("unable to retrieve object meta with: %v", mapping.MetadataAccessor)
		}
	}
}
<|endoftext|>


<commit_before>package script

import (
	"errors"
	"fmt"
	"github.com/aarzilli/golua/lua"
	anko_core "github.com/mattn/anko/builtins"
	anko_encoding "github.com/mattn/anko/builtins/encoding"
	anko_flag "github.com/mattn/anko/builtins/flag"
	anko_io "github.com/mattn/anko/builtins/io"
	anko_math "github.com/mattn/anko/builtins/math"
	anko_net "github.com/mattn/anko/builtins/net"
	anko_os "github.com/mattn/anko/builtins/os"
	anko_path "github.com/mattn/anko/builtins/path"
	anko_regexp "github.com/mattn/anko/builtins/regexp"
	anko_sort "github.com/mattn/anko/builtins/sort"
	anko_strings "github.com/mattn/anko/builtins/strings"
	anko_term "github.com/mattn/anko/builtins/term"
	anko "github.com/mattn/anko/vm"
	"github.com/robertkrimen/otto"
	"github.com/tyler-sommer/squircy2/squircy/event"
	glispext "github.com/zhemao/glisp/extensions"
	glisp "github.com/zhemao/glisp/interpreter"
	"reflect"
	"strconv"
)

func newJavascriptVm(m *ScriptManager) *otto.Otto {
	jsVm := otto.New()
	jsVm.Set("Http", &m.httpHelper)
	jsVm.Set("Config", &m.configHelper)
	jsVm.Set("Data", &m.dataHelper)
	jsVm.Set("Irc", &m.ircHelper)
	jsVm.Set("bind", func(call otto.FunctionCall) otto.Value {
		eventType := call.Argument(0).String()
		fnName := call.Argument(1).String()
		m.scriptHelper.Bind(Javascript, event.EventType(eventType), fnName)
		return otto.UndefinedValue()
	})
	jsVm.Set("unbind", func(call otto.FunctionCall) otto.Value {
		eventType := call.Argument(0).String()
		fnName := call.Argument(1).String()
		m.scriptHelper.Unbind(Javascript, event.EventType(eventType), fnName)
		return otto.UndefinedValue()
	})
	jsVm.Set("trigger", func(call otto.FunctionCall) otto.Value {
		eventType := call.Argument(0).String()
		data, _ := call.Argument(1).Export()
		if data == nil {
			data = make(map[string]interface{}, 0)
		}
		m.scriptHelper.Trigger(event.EventType(eventType), data.(map[string]interface{}))
		return otto.UndefinedValue()
	})

	return jsVm
}

func newLuaVm(m *ScriptManager) *lua.State {
	luaVm := lua.NewState()
	luaVm.OpenLibs()
	luaVm.Register("typename", func(vm *lua.State) int {
		o := vm.Typename(int(vm.Type(1)))
		vm.PushString(o)
		return 1
	})
	luaVm.Register("setex", func(vm *lua.State) int {
		key := vm.ToString(1)
		value := vm.ToString(2)
		m.dataHelper.Set(key, value)
		return 0
	})
	luaVm.Register("getex", func(vm *lua.State) int {
		key := vm.ToString(1)
		value := m.dataHelper.Get(key)
		if value != nil {
			vm.PushString(value.(string))
			return 1
		}
		vm.PushNil()
		return 1
	})
	luaVm.Register("joinchan", func(vm *lua.State) int {
		channel := vm.ToString(1)
		m.ircHelper.Join(channel)
		return 0
	})
	luaVm.Register("partchan", func(vm *lua.State) int {
		channel := vm.ToString(1)
		m.ircHelper.Part(channel)
		return 0
	})
	luaVm.Register("privmsg", func(vm *lua.State) int {
		target := vm.ToString(1)
		message := vm.ToString(2)
		m.ircHelper.Privmsg(target, message)
		return 0
	})
	luaVm.Register("currentnick", func(vm *lua.State) int {
		vm.PushString(m.ircHelper.CurrentNick())
		return 1
	})
	luaVm.Register("nick", func(vm *lua.State) int {
		newNick := vm.ToString(1)
		m.ircHelper.Nick(newNick)
		return 0
	})
	luaVm.Register("httpget", func(vm *lua.State) int {
		url := vm.ToString(1)
		res := m.httpHelper.Get(url)
		vm.PushString(res)
		return 1
	})
	luaVm.Register("bind", func(vm *lua.State) int {
		eventType := vm.ToString(1)
		fnName := vm.ToString(2)
		m.scriptHelper.Bind(Lua, event.EventType(eventType), fnName)
		return 0
	})
	luaVm.Register("unbind", func(vm *lua.State) int {
		eventType := vm.ToString(1)
		fnName := vm.ToString(2)
		m.scriptHelper.Unbind(Lua, event.EventType(eventType), fnName)
		return 0
	})

	return luaVm
}

func newLispVm(m *ScriptManager) *glisp.Glisp {
	lispVm := glisp.NewGlisp()
	lispVm.ImportEval()
	glispext.ImportRandom(lispVm)
	glispext.ImportTime(lispVm)
	glispext.ImportChannels(lispVm)
	glispext.ImportCoroutines(lispVm)

	lispVm.AddFunction("setex", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		key := sexpToString(args[0])
		val := exportSexp(args[1])
		m.dataHelper.Set(key, val)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("getex", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		key := sexpToString(args[0])
		val := m.dataHelper.Get(key).(string)

		return glisp.SexpStr(val), nil
	})
	lispVm.AddFunction("joinchan", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		channel := sexpToString(args[0])
		m.ircHelper.Join(channel)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("partchan", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		channel := sexpToString(args[0])
		m.ircHelper.Part(channel)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("privmsg", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		target := sexpToString(args[0])
		message := sexpToString(args[1])
		m.ircHelper.Privmsg(target, message)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("currentnick", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		res := m.ircHelper.CurrentNick()

		return glisp.SexpStr(res), nil
	})
	lispVm.AddFunction("nick", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		newNick := sexpToString(args[0])
		m.ircHelper.Nick(newNick)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("httpget", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		url := sexpToString(args[0])
		resp := m.httpHelper.Get(url)

		return glisp.SexpStr(resp), nil
	})
	lispVm.AddFunction("bind", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		eventType := sexpToString(args[0])
		fnName := sexpToString(args[1])
		m.scriptHelper.Bind(Lisp, event.EventType(eventType), fnName)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("unbind", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		eventType := sexpToString(args[0])
		fnName := sexpToString(args[1])
		m.scriptHelper.Unbind(Lisp, event.EventType(eventType), fnName)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("parse-integer", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		switch t := args[0].(type) {
		case glisp.SexpStr:
			val, err := strconv.ParseInt(string(t), 0, 64)
			if err != nil {
				return glisp.SexpNull, err
			}
			return glisp.SexpInt(int(val)), nil

		default:
			return glisp.SexpNull, errors.New(fmt.Sprintf("cannot convert %v to int", t))
		}
	})
	lispVm.AddFunction("write-to-string", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		switch t := args[0].(type) {
		case glisp.SexpStr:
			return t, nil

		case glisp.SexpInt:
			return glisp.SexpStr(strconv.Itoa(int(t))), nil

		default:
			return glisp.SexpStr(fmt.Sprintf("%v", t)), nil
		}
	})

	return lispVm
}

func newAnkoVm(m *ScriptManager) *anko.Env {
	ankoVm := anko.NewEnv()
	anko_core.Import(ankoVm)
	anko_flag.Import(ankoVm)
	anko_net.Import(ankoVm)
	anko_encoding.Import(ankoVm)
	anko_os.Import(ankoVm)
	anko_io.Import(ankoVm)
	anko_math.Import(ankoVm)
	anko_path.Import(ankoVm)
	anko_regexp.Import(ankoVm)
	anko_sort.Import(ankoVm)
	anko_strings.Import(ankoVm)
	anko_term.Import(ankoVm)

	mod := ankoVm.NewModule("data")
	mod.Define("Get", reflect.ValueOf(m.dataHelper.Get))
	mod.Define("Set", reflect.ValueOf(m.dataHelper.Set))

	mod = ankoVm.NewModule("irc")
	mod.Define("Join", reflect.ValueOf(func(channel string) {
		m.ircHelper.Join(channel)
	}))
	mod.Define("Part", reflect.ValueOf(func(channel string) {
		m.ircHelper.Part(channel)
	}))
	mod.Define("Privmsg", reflect.ValueOf(func(target, message string) {
		m.ircHelper.Privmsg(target, message)
	}))
	mod.Define("CurrentNick", reflect.ValueOf(func() string {
		return m.ircHelper.CurrentNick()
	}))
	mod.Define("Nick", reflect.ValueOf(func(newNick string) {
		m.ircHelper.Nick(newNick)
	}))

	mod = ankoVm.NewModule("strconv")
	mod.Define("ParseInt", reflect.ValueOf(func(s string) int {
		i, _ := strconv.ParseInt(s, 0, 64)
		return int(i)
	}))

	ankoVm.Define("bind", reflect.ValueOf(func(eventType, fnName string) {
		m.scriptHelper.Bind(Anko, event.EventType(eventType), fnName)
	}))

	ankoVm.Define("unbind", reflect.ValueOf(func(eventType, fnName string) {
		m.scriptHelper.Unbind(Anko, event.EventType(eventType), fnName)
	}))

	return ankoVm
}
<commit_msg>Javascript handlers now accept functions in addition to string function names<commit_after>package script

import (
	"errors"
	"fmt"
	"github.com/aarzilli/golua/lua"
	anko_core "github.com/mattn/anko/builtins"
	anko_encoding "github.com/mattn/anko/builtins/encoding"
	anko_flag "github.com/mattn/anko/builtins/flag"
	anko_io "github.com/mattn/anko/builtins/io"
	anko_math "github.com/mattn/anko/builtins/math"
	anko_net "github.com/mattn/anko/builtins/net"
	anko_os "github.com/mattn/anko/builtins/os"
	anko_path "github.com/mattn/anko/builtins/path"
	anko_regexp "github.com/mattn/anko/builtins/regexp"
	anko_sort "github.com/mattn/anko/builtins/sort"
	anko_strings "github.com/mattn/anko/builtins/strings"
	anko_term "github.com/mattn/anko/builtins/term"
	anko "github.com/mattn/anko/vm"
	"github.com/robertkrimen/otto"
	"github.com/tyler-sommer/squircy2/squircy/event"
	glispext "github.com/zhemao/glisp/extensions"
	glisp "github.com/zhemao/glisp/interpreter"
	"reflect"
	"strconv"
	"crypto/sha1"
)

func newJavascriptVm(m *ScriptManager) *otto.Otto {
	getFnName := func(fn otto.Value) (name string) {
		if fn.IsFunction() {
			name = fmt.Sprintf("__Handler%x", sha1.Sum([]byte(fn.String())))
		} else {
			name = fn.String()
		}

		return
	}

	jsVm := otto.New()
	jsVm.Set("Http", &m.httpHelper)
	jsVm.Set("Config", &m.configHelper)
	jsVm.Set("Data", &m.dataHelper)
	jsVm.Set("Irc", &m.ircHelper)
	jsVm.Set("bind", func(call otto.FunctionCall) otto.Value {
		eventType := call.Argument(0).String()
		fn := call.Argument(1)
		fnName := getFnName(fn)
		if fn.IsFunction() {
			m.jsDriver.vm.Set(fnName, func(call otto.FunctionCall) otto.Value {
				fn.Call(call.This, call.ArgumentList)
				return otto.UndefinedValue()
			})
		}
		m.scriptHelper.Bind(Javascript, event.EventType(eventType), fnName)
		val, _ := otto.ToValue(fnName)
		return val
	})
	jsVm.Set("unbind", func(call otto.FunctionCall) otto.Value {
		eventType := call.Argument(0).String()
		fnName := getFnName(call.Argument(1))
		m.scriptHelper.Unbind(Javascript, event.EventType(eventType), fnName)
		return otto.UndefinedValue()
	})
	jsVm.Set("trigger", func(call otto.FunctionCall) otto.Value {
		eventType := call.Argument(0).String()
		data, _ := call.Argument(1).Export()
		if data == nil {
			data = make(map[string]interface{}, 0)
		}
		m.scriptHelper.Trigger(event.EventType(eventType), data.(map[string]interface{}))
		return otto.UndefinedValue()
	})

	return jsVm
}

func newLuaVm(m *ScriptManager) *lua.State {
	luaVm := lua.NewState()
	luaVm.OpenLibs()
	luaVm.Register("typename", func(vm *lua.State) int {
		o := vm.Typename(int(vm.Type(1)))
		vm.PushString(o)
		return 1
	})
	luaVm.Register("setex", func(vm *lua.State) int {
		key := vm.ToString(1)
		value := vm.ToString(2)
		m.dataHelper.Set(key, value)
		return 0
	})
	luaVm.Register("getex", func(vm *lua.State) int {
		key := vm.ToString(1)
		value := m.dataHelper.Get(key)
		if value != nil {
			vm.PushString(value.(string))
			return 1
		}
		vm.PushNil()
		return 1
	})
	luaVm.Register("joinchan", func(vm *lua.State) int {
		channel := vm.ToString(1)
		m.ircHelper.Join(channel)
		return 0
	})
	luaVm.Register("partchan", func(vm *lua.State) int {
		channel := vm.ToString(1)
		m.ircHelper.Part(channel)
		return 0
	})
	luaVm.Register("privmsg", func(vm *lua.State) int {
		target := vm.ToString(1)
		message := vm.ToString(2)
		m.ircHelper.Privmsg(target, message)
		return 0
	})
	luaVm.Register("currentnick", func(vm *lua.State) int {
		vm.PushString(m.ircHelper.CurrentNick())
		return 1
	})
	luaVm.Register("nick", func(vm *lua.State) int {
		newNick := vm.ToString(1)
		m.ircHelper.Nick(newNick)
		return 0
	})
	luaVm.Register("httpget", func(vm *lua.State) int {
		url := vm.ToString(1)
		res := m.httpHelper.Get(url)
		vm.PushString(res)
		return 1
	})
	luaVm.Register("bind", func(vm *lua.State) int {
		eventType := vm.ToString(1)
		fnName := vm.ToString(2)
		m.scriptHelper.Bind(Lua, event.EventType(eventType), fnName)
		return 0
	})
	luaVm.Register("unbind", func(vm *lua.State) int {
		eventType := vm.ToString(1)
		fnName := vm.ToString(2)
		m.scriptHelper.Unbind(Lua, event.EventType(eventType), fnName)
		return 0
	})

	return luaVm
}

func newLispVm(m *ScriptManager) *glisp.Glisp {
	lispVm := glisp.NewGlisp()
	lispVm.ImportEval()
	glispext.ImportRandom(lispVm)
	glispext.ImportTime(lispVm)
	glispext.ImportChannels(lispVm)
	glispext.ImportCoroutines(lispVm)

	lispVm.AddFunction("setex", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		key := sexpToString(args[0])
		val := exportSexp(args[1])
		m.dataHelper.Set(key, val)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("getex", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		key := sexpToString(args[0])
		val := m.dataHelper.Get(key).(string)

		return glisp.SexpStr(val), nil
	})
	lispVm.AddFunction("joinchan", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		channel := sexpToString(args[0])
		m.ircHelper.Join(channel)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("partchan", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		channel := sexpToString(args[0])
		m.ircHelper.Part(channel)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("privmsg", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		target := sexpToString(args[0])
		message := sexpToString(args[1])
		m.ircHelper.Privmsg(target, message)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("currentnick", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		res := m.ircHelper.CurrentNick()

		return glisp.SexpStr(res), nil
	})
	lispVm.AddFunction("nick", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		newNick := sexpToString(args[0])
		m.ircHelper.Nick(newNick)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("httpget", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		url := sexpToString(args[0])
		resp := m.httpHelper.Get(url)

		return glisp.SexpStr(resp), nil
	})
	lispVm.AddFunction("bind", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		eventType := sexpToString(args[0])
		fnName := sexpToString(args[1])
		m.scriptHelper.Bind(Lisp, event.EventType(eventType), fnName)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("unbind", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 2 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		eventType := sexpToString(args[0])
		fnName := sexpToString(args[1])
		m.scriptHelper.Unbind(Lisp, event.EventType(eventType), fnName)

		return glisp.SexpNull, nil
	})
	lispVm.AddFunction("parse-integer", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		switch t := args[0].(type) {
		case glisp.SexpStr:
			val, err := strconv.ParseInt(string(t), 0, 64)
			if err != nil {
				return glisp.SexpNull, err
			}
			return glisp.SexpInt(int(val)), nil

		default:
			return glisp.SexpNull, errors.New(fmt.Sprintf("cannot convert %v to int", t))
		}
	})
	lispVm.AddFunction("write-to-string", func(vm *glisp.Glisp, name string, args []glisp.Sexp) (glisp.Sexp, error) {
		if len(args) != 1 {
			return glisp.SexpNull, errors.New("incorrect number of arguments")
		}

		switch t := args[0].(type) {
		case glisp.SexpStr:
			return t, nil

		case glisp.SexpInt:
			return glisp.SexpStr(strconv.Itoa(int(t))), nil

		default:
			return glisp.SexpStr(fmt.Sprintf("%v", t)), nil
		}
	})

	return lispVm
}

func newAnkoVm(m *ScriptManager) *anko.Env {
	ankoVm := anko.NewEnv()
	anko_core.Import(ankoVm)
	anko_flag.Import(ankoVm)
	anko_net.Import(ankoVm)
	anko_encoding.Import(ankoVm)
	anko_os.Import(ankoVm)
	anko_io.Import(ankoVm)
	anko_math.Import(ankoVm)
	anko_path.Import(ankoVm)
	anko_regexp.Import(ankoVm)
	anko_sort.Import(ankoVm)
	anko_strings.Import(ankoVm)
	anko_term.Import(ankoVm)

	mod := ankoVm.NewModule("data")
	mod.Define("Get", reflect.ValueOf(m.dataHelper.Get))
	mod.Define("Set", reflect.ValueOf(m.dataHelper.Set))

	mod = ankoVm.NewModule("irc")
	mod.Define("Join", reflect.ValueOf(func(channel string) {
		m.ircHelper.Join(channel)
	}))
	mod.Define("Part", reflect.ValueOf(func(channel string) {
		m.ircHelper.Part(channel)
	}))
	mod.Define("Privmsg", reflect.ValueOf(func(target, message string) {
		m.ircHelper.Privmsg(target, message)
	}))
	mod.Define("CurrentNick", reflect.ValueOf(func() string {
		return m.ircHelper.CurrentNick()
	}))
	mod.Define("Nick", reflect.ValueOf(func(newNick string) {
		m.ircHelper.Nick(newNick)
	}))

	mod = ankoVm.NewModule("strconv")
	mod.Define("ParseInt", reflect.ValueOf(func(s string) int {
		i, _ := strconv.ParseInt(s, 0, 64)
		return int(i)
	}))

	ankoVm.Define("bind", reflect.ValueOf(func(eventType, fnName string) {
		m.scriptHelper.Bind(Anko, event.EventType(eventType), fnName)
	}))

	ankoVm.Define("unbind", reflect.ValueOf(func(eventType, fnName string) {
		m.scriptHelper.Unbind(Anko, event.EventType(eventType), fnName)
	}))

	return ankoVm
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package apiserver

import (
	"errors"
	"net/http"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	"k8s.io/apiserver/pkg/endpoints/request"

	apiregistrationapi "k8s.io/kube-aggregator/pkg/apis/apiregistration"
	apiregistrationv1beta1api "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
	listers "k8s.io/kube-aggregator/pkg/client/listers/apiregistration/internalversion"
)

// apisHandler serves the `/apis` endpoint.
// This is registered as a filter so that it never collides with any explictly registered endpoints
type apisHandler struct {
	codecs serializer.CodecFactory
	lister listers.APIServiceLister
	mapper request.RequestContextMapper
}

var discoveryGroup = metav1.APIGroup{
	Name: apiregistrationapi.GroupName,
	Versions: []metav1.GroupVersionForDiscovery{
		{
			GroupVersion: apiregistrationv1beta1api.SchemeGroupVersion.String(),
			Version:      apiregistrationv1beta1api.SchemeGroupVersion.Version,
		},
	},
	PreferredVersion: metav1.GroupVersionForDiscovery{
		GroupVersion: apiregistrationv1beta1api.SchemeGroupVersion.String(),
		Version:      apiregistrationv1beta1api.SchemeGroupVersion.Version,
	},
}

func (r *apisHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ctx, ok := r.mapper.Get(req)
	if !ok {
		responsewriters.InternalError(w, req, errors.New("no context found for request"))
		return
	}

	discoveryGroupList := &metav1.APIGroupList{
		// always add OUR api group to the list first.  Since we'll never have a registered APIService for it
		// and since this is the crux of the API, having this first will give our names priority.  It's good to be king.
		Groups: []metav1.APIGroup{discoveryGroup},
	}

	apiServices, err := r.lister.List(labels.Everything())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	apiServicesByGroup := apiregistrationapi.SortedByGroupAndVersion(apiServices)
	for _, apiGroupServers := range apiServicesByGroup {
		// skip the legacy group
		if len(apiGroupServers[0].Spec.Group) == 0 {
			continue
		}
		discoveryGroup := convertToDiscoveryAPIGroup(apiGroupServers)
		if discoveryGroup != nil {
			discoveryGroupList.Groups = append(discoveryGroupList.Groups, *discoveryGroup)
		}
	}

	responsewriters.WriteObjectNegotiated(ctx, r.codecs, schema.GroupVersion{}, w, req, http.StatusOK, discoveryGroupList)
}

// convertToDiscoveryAPIGroup takes apiservices in a single group and returns a discovery compatible object.
// if none of the services are available, it will return nil.
func convertToDiscoveryAPIGroup(apiServices []*apiregistrationapi.APIService) *metav1.APIGroup {
	apiServicesByGroup := apiregistrationapi.SortedByGroupAndVersion(apiServices)[0]

	var discoveryGroup *metav1.APIGroup

	for _, apiService := range apiServicesByGroup {
		if !apiregistrationapi.IsAPIServiceConditionTrue(apiService, apiregistrationapi.Available) {
			continue
		}

		// the first APIService which is valid becomes the default
		if discoveryGroup == nil {
			discoveryGroup = &metav1.APIGroup{
				Name: apiService.Spec.Group,
				PreferredVersion: metav1.GroupVersionForDiscovery{
					GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
					Version:      apiService.Spec.Version,
				},
			}
		}

		discoveryGroup.Versions = append(discoveryGroup.Versions,
			metav1.GroupVersionForDiscovery{
				GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
				Version:      apiService.Spec.Version,
			},
		)
	}

	return discoveryGroup
}

// apiGroupHandler serves the `/apis/<group>` endpoint.
type apiGroupHandler struct {
	codecs        serializer.CodecFactory
	groupName     string
	contextMapper request.RequestContextMapper

	lister listers.APIServiceLister

	delegate http.Handler
}

func (r *apiGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ctx, ok := r.contextMapper.Get(req)
	if !ok {
		responsewriters.InternalError(w, req, errors.New("no context found for request"))
		return
	}

	apiServices, err := r.lister.List(labels.Everything())
	if statusErr, ok := err.(*apierrors.StatusError); ok && err != nil {
		responsewriters.WriteRawJSON(int(statusErr.Status().Code), statusErr.Status(), w)
		return
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	apiServicesForGroup := []*apiregistrationapi.APIService{}
	for _, apiService := range apiServices {
		if apiService.Spec.Group == r.groupName {
			apiServicesForGroup = append(apiServicesForGroup, apiService)
		}
	}

	if len(apiServicesForGroup) == 0 {
		r.delegate.ServeHTTP(w, req)
		return
	}

	discoveryGroup := convertToDiscoveryAPIGroup(apiServicesForGroup)
	if discoveryGroup == nil {
		http.Error(w, "", http.StatusNotFound)
		return
	}
	responsewriters.WriteObjectNegotiated(ctx, r.codecs, schema.GroupVersion{}, w, req, http.StatusOK, discoveryGroup)
}
<commit_msg>continue fix the typo<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package apiserver

import (
	"errors"
	"net/http"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	"k8s.io/apiserver/pkg/endpoints/request"

	apiregistrationapi "k8s.io/kube-aggregator/pkg/apis/apiregistration"
	apiregistrationv1beta1api "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
	listers "k8s.io/kube-aggregator/pkg/client/listers/apiregistration/internalversion"
)

// apisHandler serves the `/apis` endpoint.
// This is registered as a filter so that it never collides with any explicitly registered endpoints
type apisHandler struct {
	codecs serializer.CodecFactory
	lister listers.APIServiceLister
	mapper request.RequestContextMapper
}

var discoveryGroup = metav1.APIGroup{
	Name: apiregistrationapi.GroupName,
	Versions: []metav1.GroupVersionForDiscovery{
		{
			GroupVersion: apiregistrationv1beta1api.SchemeGroupVersion.String(),
			Version:      apiregistrationv1beta1api.SchemeGroupVersion.Version,
		},
	},
	PreferredVersion: metav1.GroupVersionForDiscovery{
		GroupVersion: apiregistrationv1beta1api.SchemeGroupVersion.String(),
		Version:      apiregistrationv1beta1api.SchemeGroupVersion.Version,
	},
}

func (r *apisHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ctx, ok := r.mapper.Get(req)
	if !ok {
		responsewriters.InternalError(w, req, errors.New("no context found for request"))
		return
	}

	discoveryGroupList := &metav1.APIGroupList{
		// always add OUR api group to the list first.  Since we'll never have a registered APIService for it
		// and since this is the crux of the API, having this first will give our names priority.  It's good to be king.
		Groups: []metav1.APIGroup{discoveryGroup},
	}

	apiServices, err := r.lister.List(labels.Everything())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	apiServicesByGroup := apiregistrationapi.SortedByGroupAndVersion(apiServices)
	for _, apiGroupServers := range apiServicesByGroup {
		// skip the legacy group
		if len(apiGroupServers[0].Spec.Group) == 0 {
			continue
		}
		discoveryGroup := convertToDiscoveryAPIGroup(apiGroupServers)
		if discoveryGroup != nil {
			discoveryGroupList.Groups = append(discoveryGroupList.Groups, *discoveryGroup)
		}
	}

	responsewriters.WriteObjectNegotiated(ctx, r.codecs, schema.GroupVersion{}, w, req, http.StatusOK, discoveryGroupList)
}

// convertToDiscoveryAPIGroup takes apiservices in a single group and returns a discovery compatible object.
// if none of the services are available, it will return nil.
func convertToDiscoveryAPIGroup(apiServices []*apiregistrationapi.APIService) *metav1.APIGroup {
	apiServicesByGroup := apiregistrationapi.SortedByGroupAndVersion(apiServices)[0]

	var discoveryGroup *metav1.APIGroup

	for _, apiService := range apiServicesByGroup {
		if !apiregistrationapi.IsAPIServiceConditionTrue(apiService, apiregistrationapi.Available) {
			continue
		}

		// the first APIService which is valid becomes the default
		if discoveryGroup == nil {
			discoveryGroup = &metav1.APIGroup{
				Name: apiService.Spec.Group,
				PreferredVersion: metav1.GroupVersionForDiscovery{
					GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
					Version:      apiService.Spec.Version,
				},
			}
		}

		discoveryGroup.Versions = append(discoveryGroup.Versions,
			metav1.GroupVersionForDiscovery{
				GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
				Version:      apiService.Spec.Version,
			},
		)
	}

	return discoveryGroup
}

// apiGroupHandler serves the `/apis/<group>` endpoint.
type apiGroupHandler struct {
	codecs        serializer.CodecFactory
	groupName     string
	contextMapper request.RequestContextMapper

	lister listers.APIServiceLister

	delegate http.Handler
}

func (r *apiGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ctx, ok := r.contextMapper.Get(req)
	if !ok {
		responsewriters.InternalError(w, req, errors.New("no context found for request"))
		return
	}

	apiServices, err := r.lister.List(labels.Everything())
	if statusErr, ok := err.(*apierrors.StatusError); ok && err != nil {
		responsewriters.WriteRawJSON(int(statusErr.Status().Code), statusErr.Status(), w)
		return
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	apiServicesForGroup := []*apiregistrationapi.APIService{}
	for _, apiService := range apiServices {
		if apiService.Spec.Group == r.groupName {
			apiServicesForGroup = append(apiServicesForGroup, apiService)
		}
	}

	if len(apiServicesForGroup) == 0 {
		r.delegate.ServeHTTP(w, req)
		return
	}

	discoveryGroup := convertToDiscoveryAPIGroup(apiServicesForGroup)
	if discoveryGroup == nil {
		http.Error(w, "", http.StatusNotFound)
		return
	}
	responsewriters.WriteObjectNegotiated(ctx, r.codecs, schema.GroupVersion{}, w, req, http.StatusOK, discoveryGroup)
}
<|endoftext|>


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

// Package dict implements the Dictionary Server Protocol
// as defined in RFC 2229.
package dict

import (
	"container/vector"
	"net/textproto"
	"os"
	"strconv"
	"strings"
)

// A Client represents a client connection to a dictionary server.
type Client struct {
	text *textproto.Conn
}

// Dial returns a new client connected to a dictionary server at
// addr on the given network.
func Dial(network, addr string) (*Client, os.Error) {
	text, err := textproto.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	_, _, err = text.ReadCodeLine(220)
	if err != nil {
		text.Close()
		return nil, err
	}
	return &Client{text: text}, nil
}

// Close closes the connection to the dictionary server.
func (c *Client) Close() os.Error {
	return c.text.Close()
}

// A Dict represents a dictionary available on the server.
type Dict struct {
	Name string // short name of dictionary
	Desc string // long description
}

// Dicts returns a list of the dictionaries available on the server.
func (c *Client) Dicts() ([]Dict, os.Error) {
	id, err := c.text.Cmd("SHOW DB")
	if err != nil {
		return nil, err
	}

	c.text.StartResponse(id)
	defer c.text.EndResponse(id)

	lines, err := c.text.ReadDotLines()
	if err != nil {
		return nil, err
	}
	_, _, err = c.text.ReadCodeLine(250)

	dicts := make([]Dict, len(lines))
	for i := range dicts {
		d := &dicts[i]
		a, _ := fields(lines[i])
		if len(a) < 2 {
			return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
		}
		d.Name = a[0]
		d.Desc = a[1]
	}
	return dicts, err
}

// A Defn represents a definition.
type Defn struct {
	Dict Dict   // Dict where definition was found
	Word string // Word being defined
	Text []byte // Definition text, typically multiple lines
}

// Define requests the definition of the given word.
// The argument dict names the dictionary to use,
// the Name field of a Dict returned by Dicts.
//
// The special dictionary name "!" means to look in all the
// server's dictionaries.
// The special dictionary name "*" means to look in all the
// server's dictionaries in turn, stopping after finding the word
// in one of them.
func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
	id, err := c.text.Cmd("DEFINE %s %q", dict, word)
	if err != nil {
		return nil, err
	}

	c.text.StartResponse(id)
	defer c.text.EndResponse(id)

	_, line, err := c.text.ReadCodeLine(150)
	a, _ := fields(line)
	if len(a) < 1 {
		return nil, textproto.ProtocolError("malformed response: " + line)
	}
	n, err := strconv.Atoi(a[0])
	if err != nil {
		return nil, textproto.ProtocolError("invalid definition count: " + a[0])
	}
	def := make([]*Defn, n)
	for i := 0; i < n; i++ {
		_, line, err = c.text.ReadCodeLine(151)
		if err != nil {
			return nil, err
		}
		a, _ := fields(line)
		if len(a) < 3 {
			// skip it, to keep protocol in sync
			i--
			n--
			def = def[0:n]
			continue
		}
		d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
		d.Text, err = c.text.ReadDotBytes()
		if err != nil {
			return nil, err
		}
		def[i] = d
	}
	_, _, err = c.text.ReadCodeLine(250)
	return def, err
}

// Fields returns the fields in s.
// Fields are space separated unquoted words
// or quoted with single or double quote.
func fields(s string) ([]string, os.Error) {
	var v vector.StringVector
	i := 0
	for {
		for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
			i++
		}
		if i >= len(s) {
			break
		}
		if s[i] == '"' || s[i] == '\'' {
			q := s[i]
			// quoted string
			var j int
			for j = i + 1; ; j++ {
				if j >= len(s) {
					return nil, textproto.ProtocolError("malformed quoted string")
				}
				if s[j] == '\\' {
					j++
					continue
				}
				if s[j] == q {
					j++
					break
				}
			}
			v.Push(unquote(s[i+1 : j-1]))
			i = j
		} else {
			// atom
			var j int
			for j = i; j < len(s); j++ {
				if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
					break
				}
			}
			v.Push(s[i:j])
			i = j
		}
		if i < len(s) {
			c := s[i]
			if c != ' ' && c != '\t' {
				return nil, textproto.ProtocolError("quotes not on word boundaries")
			}
		}
	}
	return v, nil
}

func unquote(s string) string {
	if strings.Index(s, "\\") < 0 {
		return s
	}
	b := []byte(s)
	w := 0
	for r := 0; r < len(b); r++ {
		c := b[r]
		if c == '\\' {
			r++
			c = b[r]
		}
		b[w] = c
		w++
	}
	return string(b[0:w])
}
<commit_msg>net/dict: parse response correctly + typo<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package dict implements the Dictionary Server Protocol
// as defined in RFC 2229.
package dict

import (
	"container/vector"
	"net/textproto"
	"os"
	"strconv"
	"strings"
)

// A Client represents a client connection to a dictionary server.
type Client struct {
	text *textproto.Conn
}

// Dial returns a new client connected to a dictionary server at
// addr on the given network.
func Dial(network, addr string) (*Client, os.Error) {
	text, err := textproto.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	_, _, err = text.ReadCodeLine(220)
	if err != nil {
		text.Close()
		return nil, err
	}
	return &Client{text: text}, nil
}

// Close closes the connection to the dictionary server.
func (c *Client) Close() os.Error {
	return c.text.Close()
}

// A Dict represents a dictionary available on the server.
type Dict struct {
	Name string // short name of dictionary
	Desc string // long description
}

// Dicts returns a list of the dictionaries available on the server.
func (c *Client) Dicts() ([]Dict, os.Error) {
	id, err := c.text.Cmd("SHOW DB")
	if err != nil {
		return nil, err
	}

	c.text.StartResponse(id)
	defer c.text.EndResponse(id)

	_, _, err = c.text.ReadCodeLine(110)
	if err != nil {
		return nil, err
	}
	lines, err := c.text.ReadDotLines()
	if err != nil {
		return nil, err
	}
	_, _, err = c.text.ReadCodeLine(250)

	dicts := make([]Dict, len(lines))
	for i := range dicts {
		d := &dicts[i]
		a, _ := fields(lines[i])
		if len(a) < 2 {
			return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
		}
		d.Name = a[0]
		d.Desc = a[1]
	}
	return dicts, err
}

// A Defn represents a definition.
type Defn struct {
	Dict Dict   // Dict where definition was found
	Word string // Word being defined
	Text []byte // Definition text, typically multiple lines
}

// Define requests the definition of the given word.
// The argument dict names the dictionary to use,
// the Name field of a Dict returned by Dicts.
//
// The special dictionary name "*" means to look in all the
// server's dictionaries.
// The special dictionary name "!" means to look in all the
// server's dictionaries in turn, stopping after finding the word
// in one of them.
func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
	id, err := c.text.Cmd("DEFINE %s %q", dict, word)
	if err != nil {
		return nil, err
	}

	c.text.StartResponse(id)
	defer c.text.EndResponse(id)

	_, line, err := c.text.ReadCodeLine(150)
	if err != nil {
		return nil, err
	}
	a, _ := fields(line)
	if len(a) < 1 {
		return nil, textproto.ProtocolError("malformed response: " + line)
	}
	n, err := strconv.Atoi(a[0])
	if err != nil {
		return nil, textproto.ProtocolError("invalid definition count: " + a[0])
	}
	def := make([]*Defn, n)
	for i := 0; i < n; i++ {
		_, line, err = c.text.ReadCodeLine(151)
		if err != nil {
			return nil, err
		}
		a, _ := fields(line)
		if len(a) < 3 {
			// skip it, to keep protocol in sync
			i--
			n--
			def = def[0:n]
			continue
		}
		d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
		d.Text, err = c.text.ReadDotBytes()
		if err != nil {
			return nil, err
		}
		def[i] = d
	}
	_, _, err = c.text.ReadCodeLine(250)
	return def, err
}

// Fields returns the fields in s.
// Fields are space separated unquoted words
// or quoted with single or double quote.
func fields(s string) ([]string, os.Error) {
	var v vector.StringVector
	i := 0
	for {
		for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
			i++
		}
		if i >= len(s) {
			break
		}
		if s[i] == '"' || s[i] == '\'' {
			q := s[i]
			// quoted string
			var j int
			for j = i + 1; ; j++ {
				if j >= len(s) {
					return nil, textproto.ProtocolError("malformed quoted string")
				}
				if s[j] == '\\' {
					j++
					continue
				}
				if s[j] == q {
					j++
					break
				}
			}
			v.Push(unquote(s[i+1 : j-1]))
			i = j
		} else {
			// atom
			var j int
			for j = i; j < len(s); j++ {
				if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
					break
				}
			}
			v.Push(s[i:j])
			i = j
		}
		if i < len(s) {
			c := s[i]
			if c != ' ' && c != '\t' {
				return nil, textproto.ProtocolError("quotes not on word boundaries")
			}
		}
	}
	return v, nil
}

func unquote(s string) string {
	if strings.Index(s, "\\") < 0 {
		return s
	}
	b := []byte(s)
	w := 0
	for r := 0; r < len(b); r++ {
		c := b[r]
		if c == '\\' {
			r++
			c = b[r]
		}
		b[w] = c
		w++
	}
	return string(b[0:w])
}
<|endoftext|>