<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"koding/kite-handler/command"
	"koding/kite-handler/docker"
	"koding/kite-handler/fs"
	"koding/kite-handler/terminal"
	"koding/kites/klient/collaboration"
	"koding/kites/klient/protocol"
	"koding/kites/klient/usage"

	"github.com/koding/kite"
	"github.com/koding/kite/config"
)

var (
	flagIP          = flag.String("ip", "", "Change public ip")
	flagPort        = flag.Int("port", 56789, "Change running port")
	flagVersion     = flag.Bool("version", false, "Show version and exit")
	flagEnvironment = flag.String("env", protocol.Environment, "Change environment")
	flagRegion      = flag.String("region", protocol.Region, "Change region")
	flagRegisterURL = flag.String("register-url", "", "Change register URL to kontrol")
	flagDebug       = flag.Bool("debug", false, "Debug mode")

	// update paramters
	flagUpdateInterval = flag.Duration("update-interval", time.Minute*5,
		"Change interval for checking for new updates")
	flagUpdateURL = flag.String("update-url",
		"https://s3.amazonaws.com/koding-klient/"+protocol.Environment+"/latest-version.txt",
		"Change update endpoint for latest version")

	VERSION = protocol.Version
	NAME    = protocol.Name

	// this is our main reference to count and measure metrics for the klient
	// we count only those methods, please add/remove methods here that will
	// reset the timer of a klient.
	usg = usage.NewUsage(map[string]bool{
		"fs.readDirectory":    true,
		"fs.glob":             true,
		"fs.readFile":         true,
		"fs.writeFile":        true,
		"fs.uniquePath":       true,
		"fs.getInfo":          true,
		"fs.setPermissions":   true,
		"fs.remove":           true,
		"fs.rename":           true,
		"fs.createDirectory":  true,
		"fs.move":             true,
		"fs.copy":             true,
		"webterm.getSessions": true,
		"webterm.connect":     true,
		"webterm.killSession": true,
		"exec":                true,
		"klient.share":        true,
		"klient.unshare":      true,
		"klient.shared":       true,
	})

	// this is used to allow other users to call any klient method.
	collab = collaboration.New()

	// we also could use an atomic boolean this is simple for now.
	updating   = false
	updatingMu sync.Mutex // protects updating
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	k := newKite()

	// Close the klient.db in any case. Corrupt db would be catastrophic
	defer collab.Close()

	k.Log.Info("Running as version %s", VERSION)
	k.Run()
}

func newKite() *kite.Kite {
	k := kite.New(NAME, VERSION)

	if *flagDebug {
		k.SetLogLevel(kite.DEBUG)
	}

	conf := config.MustGet()
	k.Config = conf
	k.Config.Port = *flagPort
	k.Config.Environment = *flagEnvironment
	k.Config.Region = *flagRegion
	k.Id = conf.Id // always boot up with the same id in the kite.key

	// FIXME: It's ugly I know. It's a fix for Koding local development and is
	// needed
	if !strings.Contains(k.Config.KontrolURL, "ngrok") {
		// override current kontrolURL so it talks to port 3000, this is needed
		// because ELB can forward requests based on ports. The port 80 and 443 are
		// HTTP/HTTPS only so our kite can't connect it (we use websocket). However
		// We have a TCP proxy at 3000 which allows us to connect via WebSocket.
		u, _ := url.Parse(k.Config.KontrolURL)

		host := u.Host
		if HasPort(u.Host) {
			host, _, _ = net.SplitHostPort(u.Host)
		}

		u.Host = AddPort(host, "3000")
		u.Scheme = "http"
		k.Config.KontrolURL = u.String()
	}

	if *flagUpdateInterval < time.Minute {
		k.Log.Warning("Update interval can't be less than one minute. Setting to one minute.")
		*flagUpdateInterval = time.Minute
	}

	updater := &Updater{
		Endpoint: *flagUpdateURL,
		Interval: *flagUpdateInterval,
		Log:      k.Log,
	}

	// before we register check for latest update and re-update itself before
	// we continue
	k.Log.Info("Checking for new updates")
	if err := updater.checkAndUpdate(); err != nil {
		k.Log.Warning("Self-update: %s", err)
	}

	go updater.Run()

	userIn := func(user string, users ...string) bool {
		for _, u := range users {
			if u == user {
				return true
			}
		}
		return false
	}

	// don't pass any request if the caller is outside of our scope.
	// don't allow anyone to call a method if we are during an update.
	k.PreHandleFunc(func(r *kite.Request) (interface{}, error) {
		// only authenticated methods have correct username. For example
		// kite.ping has authentication disabled so username can be empty.
		if r.Auth != nil {
			k.Log.Info("Kite '%s/%s/%s' called method: '%s'",
				r.Username, r.Client.Environment, r.Client.Name, r.Method)

			// Allow these users by default
			allowedUsers := []string{k.Config.Username, "koding"}

			// Allow collaboration users as well
			sharedUsers, err := collab.GetAll()
			if err != nil {
				return nil, fmt.Errorf("Can't read shared users from the storage. Err: %v", err)
			}
			allowedUsers = append(allowedUsers, sharedUsers...)

			if !userIn(r.Username, allowedUsers...) {
				return nil, fmt.Errorf("User '%s' is not allowed to make a call to us.", r.Username)
			}
		}

		updatingMu.Lock()
		defer updatingMu.Unlock()

		if updating {
			return nil, errors.New("Updating klient. Can't accept any method.")
		}

		return true, nil
	})

	// Metrics, is used by Kloud to get usage so Kloud can stop free VMs
	k.PreHandleFunc(usg.Counter) // we measure every incoming request
	k.HandleFunc("klient.usage", usg.Current)

	// Collaboration, is used by our Koding.com browser client
	k.HandleFunc("klient.share", collab.Share)
	k.HandleFunc("klient.unshare", collab.Unshare)
	k.HandleFunc("klient.shared", collab.Shared)

	// Filesystem
	k.HandleFunc("fs.readDirectory", fs.ReadDirectory)
	k.HandleFunc("fs.glob", fs.Glob)
	k.HandleFunc("fs.readFile", fs.ReadFile)
	k.HandleFunc("fs.writeFile", fs.WriteFile)
	k.HandleFunc("fs.uniquePath", fs.UniquePath)
	k.HandleFunc("fs.getInfo", fs.GetInfo)
	k.HandleFunc("fs.setPermissions", fs.SetPermissions)
	k.HandleFunc("fs.remove", fs.Remove)
	k.HandleFunc("fs.rename", fs.Rename)
	k.HandleFunc("fs.createDirectory", fs.CreateDirectory)
	k.HandleFunc("fs.move", fs.Move)
	k.HandleFunc("fs.copy", fs.Copy)

	// Docker
	dock := docker.New("tcp")
	k.HandleFunc("docker.build", dock.Build)
	k.HandleFunc("docker.create", dock.Create)
	k.HandleFunc("docker.connect", dock.Connect)
	k.HandleFunc("docker.stop", dock.Stop)
	k.HandleFunc("docker.start", dock.Start)
	k.HandleFunc("docker.kill", dock.Kill)
	k.HandleFunc("docker.destroy", dock.Destroy)
	k.HandleFunc("docker.list", dock.List)

	// Execution
	k.HandleFunc("exec", command.Exec)

	// Terminal
	term := terminal.New(k.Log)
	term.InputHook = usg.Reset
	k.HandleFunc("webterm.getSessions", term.GetSessions)
	k.HandleFunc("webterm.connect", term.Connect)
	k.HandleFunc("webterm.killSession", term.KillSession)
	k.HandleFunc("webterm.killSessions", term.KillSessions)

	// Unshare collab users if the klient owner disconnects
	k.OnDisconnect(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is disconnected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		sharedUsers, err := collab.GetAll()
		if err != nil {
			k.Log.Warning("Couldn't unshare users: '%s'", err)
			return
		}

		if len(sharedUsers) == 0 {
			return // nothing to do ...
		}

		k.Log.Info("Unsharing users '%s'", sharedUsers)
		for _, user := range sharedUsers {
			if err := collab.Delete(user); err != nil {
				k.Log.Warning("Couldn't delete user from storage: '%s'", err)
			}

			// close all active sessions of the current
			term.CloseSessions(user)
		}
	})

	if err := register(k); err != nil {
		panic(err)
	}

	return k
}

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func HasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// Given a string of the form "host", "port", returns "host:port"
func AddPort(host, port string) string {
	if ok := HasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<commit_msg>docker: add docs of using UNIX socket and use it<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"koding/kite-handler/command"
	"koding/kite-handler/docker"
	"koding/kite-handler/fs"
	"koding/kite-handler/terminal"
	"koding/kites/klient/collaboration"
	"koding/kites/klient/protocol"
	"koding/kites/klient/usage"

	"github.com/koding/kite"
	"github.com/koding/kite/config"
)

var (
	flagIP          = flag.String("ip", "", "Change public ip")
	flagPort        = flag.Int("port", 56789, "Change running port")
	flagVersion     = flag.Bool("version", false, "Show version and exit")
	flagEnvironment = flag.String("env", protocol.Environment, "Change environment")
	flagRegion      = flag.String("region", protocol.Region, "Change region")
	flagRegisterURL = flag.String("register-url", "", "Change register URL to kontrol")
	flagDebug       = flag.Bool("debug", false, "Debug mode")

	// update paramters
	flagUpdateInterval = flag.Duration("update-interval", time.Minute*5,
		"Change interval for checking for new updates")
	flagUpdateURL = flag.String("update-url",
		"https://s3.amazonaws.com/koding-klient/"+protocol.Environment+"/latest-version.txt",
		"Change update endpoint for latest version")

	VERSION = protocol.Version
	NAME    = protocol.Name

	// this is our main reference to count and measure metrics for the klient
	// we count only those methods, please add/remove methods here that will
	// reset the timer of a klient.
	usg = usage.NewUsage(map[string]bool{
		"fs.readDirectory":    true,
		"fs.glob":             true,
		"fs.readFile":         true,
		"fs.writeFile":        true,
		"fs.uniquePath":       true,
		"fs.getInfo":          true,
		"fs.setPermissions":   true,
		"fs.remove":           true,
		"fs.rename":           true,
		"fs.createDirectory":  true,
		"fs.move":             true,
		"fs.copy":             true,
		"webterm.getSessions": true,
		"webterm.connect":     true,
		"webterm.killSession": true,
		"exec":                true,
		"klient.share":        true,
		"klient.unshare":      true,
		"klient.shared":       true,
	})

	// this is used to allow other users to call any klient method.
	collab = collaboration.New()

	// we also could use an atomic boolean this is simple for now.
	updating   = false
	updatingMu sync.Mutex // protects updating
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	k := newKite()

	// Close the klient.db in any case. Corrupt db would be catastrophic
	defer collab.Close()

	k.Log.Info("Running as version %s", VERSION)
	k.Run()
}

func newKite() *kite.Kite {
	k := kite.New(NAME, VERSION)

	if *flagDebug {
		k.SetLogLevel(kite.DEBUG)
	}

	conf := config.MustGet()
	k.Config = conf
	k.Config.Port = *flagPort
	k.Config.Environment = *flagEnvironment
	k.Config.Region = *flagRegion
	k.Id = conf.Id // always boot up with the same id in the kite.key

	// FIXME: It's ugly I know. It's a fix for Koding local development and is
	// needed
	if !strings.Contains(k.Config.KontrolURL, "ngrok") {
		// override current kontrolURL so it talks to port 3000, this is needed
		// because ELB can forward requests based on ports. The port 80 and 443 are
		// HTTP/HTTPS only so our kite can't connect it (we use websocket). However
		// We have a TCP proxy at 3000 which allows us to connect via WebSocket.
		u, _ := url.Parse(k.Config.KontrolURL)

		host := u.Host
		if HasPort(u.Host) {
			host, _, _ = net.SplitHostPort(u.Host)
		}

		u.Host = AddPort(host, "3000")
		u.Scheme = "http"
		k.Config.KontrolURL = u.String()
	}

	if *flagUpdateInterval < time.Minute {
		k.Log.Warning("Update interval can't be less than one minute. Setting to one minute.")
		*flagUpdateInterval = time.Minute
	}

	updater := &Updater{
		Endpoint: *flagUpdateURL,
		Interval: *flagUpdateInterval,
		Log:      k.Log,
	}

	// before we register check for latest update and re-update itself before
	// we continue
	k.Log.Info("Checking for new updates")
	if err := updater.checkAndUpdate(); err != nil {
		k.Log.Warning("Self-update: %s", err)
	}

	go updater.Run()

	userIn := func(user string, users ...string) bool {
		for _, u := range users {
			if u == user {
				return true
			}
		}
		return false
	}

	// don't pass any request if the caller is outside of our scope.
	// don't allow anyone to call a method if we are during an update.
	k.PreHandleFunc(func(r *kite.Request) (interface{}, error) {
		// only authenticated methods have correct username. For example
		// kite.ping has authentication disabled so username can be empty.
		if r.Auth != nil {
			k.Log.Info("Kite '%s/%s/%s' called method: '%s'",
				r.Username, r.Client.Environment, r.Client.Name, r.Method)

			// Allow these users by default
			allowedUsers := []string{k.Config.Username, "koding"}

			// Allow collaboration users as well
			sharedUsers, err := collab.GetAll()
			if err != nil {
				return nil, fmt.Errorf("Can't read shared users from the storage. Err: %v", err)
			}
			allowedUsers = append(allowedUsers, sharedUsers...)

			if !userIn(r.Username, allowedUsers...) {
				return nil, fmt.Errorf("User '%s' is not allowed to make a call to us.", r.Username)
			}
		}

		updatingMu.Lock()
		defer updatingMu.Unlock()

		if updating {
			return nil, errors.New("Updating klient. Can't accept any method.")
		}

		return true, nil
	})

	// Metrics, is used by Kloud to get usage so Kloud can stop free VMs
	k.PreHandleFunc(usg.Counter) // we measure every incoming request
	k.HandleFunc("klient.usage", usg.Current)

	// Collaboration, is used by our Koding.com browser client
	k.HandleFunc("klient.share", collab.Share)
	k.HandleFunc("klient.unshare", collab.Unshare)
	k.HandleFunc("klient.shared", collab.Shared)

	// Filesystem
	k.HandleFunc("fs.readDirectory", fs.ReadDirectory)
	k.HandleFunc("fs.glob", fs.Glob)
	k.HandleFunc("fs.readFile", fs.ReadFile)
	k.HandleFunc("fs.writeFile", fs.WriteFile)
	k.HandleFunc("fs.uniquePath", fs.UniquePath)
	k.HandleFunc("fs.getInfo", fs.GetInfo)
	k.HandleFunc("fs.setPermissions", fs.SetPermissions)
	k.HandleFunc("fs.remove", fs.Remove)
	k.HandleFunc("fs.rename", fs.Rename)
	k.HandleFunc("fs.createDirectory", fs.CreateDirectory)
	k.HandleFunc("fs.move", fs.Move)
	k.HandleFunc("fs.copy", fs.Copy)

	// Docker
	dock := docker.New("unix:///var/run/docker.sock")
	k.HandleFunc("docker.build", dock.Build)
	k.HandleFunc("docker.create", dock.Create)
	k.HandleFunc("docker.connect", dock.Connect)
	k.HandleFunc("docker.stop", dock.Stop)
	k.HandleFunc("docker.start", dock.Start)
	k.HandleFunc("docker.kill", dock.Kill)
	k.HandleFunc("docker.destroy", dock.Destroy)
	k.HandleFunc("docker.list", dock.List)

	// Execution
	k.HandleFunc("exec", command.Exec)

	// Terminal
	term := terminal.New(k.Log)
	term.InputHook = usg.Reset
	k.HandleFunc("webterm.getSessions", term.GetSessions)
	k.HandleFunc("webterm.connect", term.Connect)
	k.HandleFunc("webterm.killSession", term.KillSession)
	k.HandleFunc("webterm.killSessions", term.KillSessions)

	// Unshare collab users if the klient owner disconnects
	k.OnDisconnect(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is disconnected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		sharedUsers, err := collab.GetAll()
		if err != nil {
			k.Log.Warning("Couldn't unshare users: '%s'", err)
			return
		}

		if len(sharedUsers) == 0 {
			return // nothing to do ...
		}

		k.Log.Info("Unsharing users '%s'", sharedUsers)
		for _, user := range sharedUsers {
			if err := collab.Delete(user); err != nil {
				k.Log.Warning("Couldn't delete user from storage: '%s'", err)
			}

			// close all active sessions of the current
			term.CloseSessions(user)
		}
	})

	if err := register(k); err != nil {
		panic(err)
	}

	return k
}

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func HasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// Given a string of the form "host", "port", returns "host:port"
func AddPort(host, port string) string {
	if ok := HasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<|endoftext|>


<commit_before>package pq

import (
	"database/sql/driver"
	"encoding/hex"
	"encoding/json"
	"fmt"

	"github.com/oursky/skygear/skydb"
	"github.com/paulmach/go.geo"
)

// This file implements Record related operations of the
// skydb/pq implementation.

// Different data types that can be saved in and loaded from postgreSQL
// NOTE(limouren): varchar is missing because text can replace them,
// see the docs here: http://www.postgresql.org/docs/9.4/static/datatype-character.html
const (
	TypeString    = "text"
	TypeNumber    = "double precision"
	TypeBoolean   = "boolean"
	TypeJSON      = "jsonb"
	TypeTimestamp = "timestamp without time zone"
	TypeLocation  = "geometry(Point)"
	TypeInteger   = "integer"
	TypeSerial    = "serial UNIQUE"
)

type nullJSON struct {
	JSON  interface{}
	Valid bool
}

func (nj *nullJSON) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if value == nil || !ok {
		nj.JSON = nil
		nj.Valid = false
		return nil
	}

	err := json.Unmarshal(data, &nj.JSON)
	nj.Valid = err == nil

	return err
}

type assetValue skydb.Asset

func (asset assetValue) Value() (driver.Value, error) {
	return asset.Name, nil
}

type nullAsset struct {
	Asset *skydb.Asset
	Valid bool
}

func (na *nullAsset) Scan(value interface{}) error {
	if value == nil {
		na.Asset = &skydb.Asset{}
		na.Valid = false
		return nil
	}

	assetName, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("failed to scan Asset: got type(value) = %T, expect []byte", value)
	}

	na.Asset = &skydb.Asset{
		Name: string(assetName),
	}
	na.Valid = true

	return nil
}

type nullLocation struct {
	Location skydb.Location
	Valid    bool
}

func (nl *nullLocation) Scan(value interface{}) error {
	if value == nil {
		nl.Location = skydb.Location{}
		nl.Valid = false
		return nil
	}

	src, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("failed to scan Location: got type(value) = %T, expect []byte", value)
	}

	// TODO(limouren): instead of decoding a str-encoded hex, we should utilize
	// ST_AsBinary to perform the SELECT
	decoded := make([]byte, hex.DecodedLen(len(src)))
	_, err := hex.Decode(decoded, src)
	if err != nil {
		return fmt.Errorf("failed to scan Location: malformed wkb")
	}

	err = (*geo.Point)(&nl.Location).Scan(decoded)
	nl.Valid = err == nil
	return err
}

type referenceValue skydb.Reference

func (ref referenceValue) Value() (driver.Value, error) {
	return ref.ID.Key, nil
}

type jsonSliceValue []interface{}

func (s jsonSliceValue) Value() (driver.Value, error) {
	return json.Marshal([]interface{}(s))
}

type jsonMapValue map[string]interface{}

func (m jsonMapValue) Value() (driver.Value, error) {
	return json.Marshal(map[string]interface{}(m))
}

type aclValue skydb.RecordACL

func (acl aclValue) Value() (driver.Value, error) {
	if acl == nil {
		return nil, nil
	}
	return json.Marshal(acl)
}

type locationValue skydb.Location

func (loc locationValue) Value() (driver.Value, error) {
	return geo.Point(loc).ToWKT(), nil
}
<commit_msg>Add type nullJSONStringSlice for reading json array from pq<commit_after>package pq

import (
	"database/sql/driver"
	"encoding/hex"
	"encoding/json"
	"fmt"

	"github.com/oursky/skygear/skydb"
	"github.com/paulmach/go.geo"
)

// This file implements Record related operations of the
// skydb/pq implementation.

// Different data types that can be saved in and loaded from postgreSQL
// NOTE(limouren): varchar is missing because text can replace them,
// see the docs here: http://www.postgresql.org/docs/9.4/static/datatype-character.html
const (
	TypeString    = "text"
	TypeNumber    = "double precision"
	TypeBoolean   = "boolean"
	TypeJSON      = "jsonb"
	TypeTimestamp = "timestamp without time zone"
	TypeLocation  = "geometry(Point)"
	TypeInteger   = "integer"
	TypeSerial    = "serial UNIQUE"
)

type nullJSON struct {
	JSON  interface{}
	Valid bool
}

func (nj *nullJSON) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if value == nil || !ok {
		nj.JSON = nil
		nj.Valid = false
		return nil
	}

	err := json.Unmarshal(data, &nj.JSON)
	nj.Valid = err == nil

	return err
}

type nullJSONStringSlice struct {
	slice []string
	Valid bool
}

func (njss *nullJSONStringSlice) Scan(value interface{}) error {
	data, ok := value.([]byte)
	if value == nil || !ok {
		njss.slice = nil
		njss.Valid = false
		return nil
	}

	err := json.Unmarshal(data, &njss.slice)
	njss.Valid = err == nil
	return err
}

type assetValue skydb.Asset

func (asset assetValue) Value() (driver.Value, error) {
	return asset.Name, nil
}

type nullAsset struct {
	Asset *skydb.Asset
	Valid bool
}

func (na *nullAsset) Scan(value interface{}) error {
	if value == nil {
		na.Asset = &skydb.Asset{}
		na.Valid = false
		return nil
	}

	assetName, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("failed to scan Asset: got type(value) = %T, expect []byte", value)
	}

	na.Asset = &skydb.Asset{
		Name: string(assetName),
	}
	na.Valid = true

	return nil
}

type nullLocation struct {
	Location skydb.Location
	Valid    bool
}

func (nl *nullLocation) Scan(value interface{}) error {
	if value == nil {
		nl.Location = skydb.Location{}
		nl.Valid = false
		return nil
	}

	src, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("failed to scan Location: got type(value) = %T, expect []byte", value)
	}

	// TODO(limouren): instead of decoding a str-encoded hex, we should utilize
	// ST_AsBinary to perform the SELECT
	decoded := make([]byte, hex.DecodedLen(len(src)))
	_, err := hex.Decode(decoded, src)
	if err != nil {
		return fmt.Errorf("failed to scan Location: malformed wkb")
	}

	err = (*geo.Point)(&nl.Location).Scan(decoded)
	nl.Valid = err == nil
	return err
}

type referenceValue skydb.Reference

func (ref referenceValue) Value() (driver.Value, error) {
	return ref.ID.Key, nil
}

type jsonSliceValue []interface{}

func (s jsonSliceValue) Value() (driver.Value, error) {
	return json.Marshal([]interface{}(s))
}

type jsonMapValue map[string]interface{}

func (m jsonMapValue) Value() (driver.Value, error) {
	return json.Marshal(map[string]interface{}(m))
}

type aclValue skydb.RecordACL

func (acl aclValue) Value() (driver.Value, error) {
	if acl == nil {
		return nil, nil
	}
	return json.Marshal(acl)
}

type locationValue skydb.Location

func (loc locationValue) Value() (driver.Value, error) {
	return geo.Point(loc).ToWKT(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	"github.com/ashwanthkumar/slack-go-webhook"
)

type Slack struct {
	Webhook string
	Channel string
	Owners  string
}

func (s *Slack) Notify(check AppCheck) {
	attachment := slack.Attachment{
		Text:  &check.Message,
		Color: s.resultToColor(check),
	}
	attachment.
		AddField(slack.Field{Title: "App", Value: check.App, Short: true}).
		AddField(slack.Field{Title: "Check", Value: check.CheckName, Short: true}).
		AddField(slack.Field{Title: "Result", Value: s.resultToString(check), Short: true})

	destination := GetString(check.Labels, "alerts.slack.channel", s.Channel)

	appSpecificOwners := GetString(check.Labels, "alerts.slack.owners", s.Owners)
	var owners []string
	if appSpecificOwners != "" {
		owners = strings.Split(appSpecificOwners, ",")
	} else {
		owners = []string{"@here"}
	}

	alertSuffix := "Please check!"
	if check.Result == Pass {
		alertSuffix = "Check Resolved, thanks!"
	}
	mainText := fmt.Sprintf("%s, %s", s.parseOwners(owners), alertSuffix)

	payload := slack.Payload(mainText,
		"marathon-alerts",
		"",
		destination,
		[]slack.Attachment{attachment})

	webhooks := strings.Split(GetString(check.Labels, "alerts.slack.webhook", s.Webhook), ",")

	for _, webhook := range webhooks {
		err := slack.Send(webhook, payload)
		if err != nil {
			fmt.Printf("Unexpected Error - %v", err)
		}
	}
}

func (s *Slack) resultToColor(check AppCheck) *string {
	color := "black"
	switch check.Result {
	case Pass:
		color = "good"
	case Warning:
		color = "warning"
	case Critical:
		color = "danger"
	}

	return &color
}

func (s *Slack) resultToString(check AppCheck) string {
	value := "Unknown"
	switch check.Result {
	case Pass:
		value = "Passed"
	case Warning:
		value = "Warning"
	case Critical:
		value = "Failed"
	}

	return value
}

func (s *Slack) parseOwners(owners []string) string {
	parsedOwners := []string{}
	for _, owner := range owners {
		if owner != "@here" {
			owner = fmt.Sprintf("@%s", owner)
		}
		parsedOwners = append(parsedOwners, owner)
	}

	return strings.Join(parsedOwners, ", ")
}
<commit_msg>Fixing the build because of #1 on ashwanthkumar/slack-go-webhook<commit_after>package main

import (
	"fmt"
	"strings"

	"github.com/ashwanthkumar/slack-go-webhook"
)

type Slack struct {
	Webhook string
	Channel string
	Owners  string
}

func (s *Slack) Notify(check AppCheck) {
	attachment := slack.Attachment{
		Text:  &check.Message,
		Color: s.resultToColor(check),
	}
	attachment.
		AddField(slack.Field{Title: "App", Value: check.App, Short: true}).
		AddField(slack.Field{Title: "Check", Value: check.CheckName, Short: true}).
		AddField(slack.Field{Title: "Result", Value: s.resultToString(check), Short: true})

	destination := GetString(check.Labels, "alerts.slack.channel", s.Channel)

	appSpecificOwners := GetString(check.Labels, "alerts.slack.owners", s.Owners)
	var owners []string
	if appSpecificOwners != "" {
		owners = strings.Split(appSpecificOwners, ",")
	} else {
		owners = []string{"@here"}
	}

	alertSuffix := "Please check!"
	if check.Result == Pass {
		alertSuffix = "Check Resolved, thanks!"
	}
	mainText := fmt.Sprintf("%s, %s", s.parseOwners(owners), alertSuffix)

	payload := slack.Payload(mainText,
		"marathon-alerts",
		"",
		destination,
		[]slack.Attachment{attachment})

	webhooks := strings.Split(GetString(check.Labels, "alerts.slack.webhook", s.Webhook), ",")

	for _, webhook := range webhooks {
		err := slack.Send(webhook, "", payload)
		if err != nil {
			fmt.Printf("Unexpected Error - %v", err)
		}
	}
}

func (s *Slack) resultToColor(check AppCheck) *string {
	color := "black"
	switch check.Result {
	case Pass:
		color = "good"
	case Warning:
		color = "warning"
	case Critical:
		color = "danger"
	}

	return &color
}

func (s *Slack) resultToString(check AppCheck) string {
	value := "Unknown"
	switch check.Result {
	case Pass:
		value = "Passed"
	case Warning:
		value = "Warning"
	case Critical:
		value = "Failed"
	}

	return value
}

func (s *Slack) parseOwners(owners []string) string {
	parsedOwners := []string{}
	for _, owner := range owners {
		if owner != "@here" {
			owner = fmt.Sprintf("@%s", owner)
		}
		parsedOwners = append(parsedOwners, owner)
	}

	return strings.Join(parsedOwners, ", ")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func TestReadConfigFile(t *testing.T) {
	filename := "config.toml"
	ReadConfigFile(filename)

	if config.Server.RrdPath != "sample/" {
		t.Fatalf("Error reading config file %s", filename)
	}

	err := ReadConfigFile("fugahoge.toml")
	if err == nil {
		t.Fatalf("The file %s is invalid but error didn't happen.", err)
	}
}

func TestHello(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(hello))
	defer ts.Close()

	r, err := http.Get(ts.URL)
	if err != nil {
		t.Fatalf("Error by http.Get(). %v", err)
	}

	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Fatalf("Error by ioutil.ReadAll(). %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if "{\"message\":\"hello\"}" != string(data) {
		t.Fatalf("Data Error. %v", string(data))
	}
}

func TestSearch(t *testing.T) {
	requestJSON := `{"target":"hoge"}`
	reader := strings.NewReader(requestJSON)

	ReadConfigFile("config.toml")

	ts := httptest.NewServer(http.HandlerFunc(search))
	defer ts.Close()

	r, err := http.Post(ts.URL, "application/json", reader)
	if err != nil {
		t.Fatalf("Error at a GET request. %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	decoder := json.NewDecoder(r.Body)
	var searchResponse []string
	decoder.Decode(&searchResponse)

	if len(searchResponse) <= 0 {
		t.Fatalf("Data Error. %v", searchResponse)
	} else {
		t.Log(searchResponse)
	}
}

func TestQuery(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(query))
	defer ts.Close()
	client := &http.Client{}

	// Test for an OPTIONS request
	reqOptions, err := http.NewRequest("OPTIONS", ts.URL, nil)
	if err != nil {
		t.Fatalf("Error at an OPTIONS request. %v", err)
	}
	r, err := client.Do(reqOptions)

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if r.Header.Get("Access-Control-Allow-Origin") != "*" {
		t.Fatalf("Header Access-Control-Allow-Origin is invalid. %s", r.Header.Get("Access-Control-Allow-Origin"))
	}
	if r.Header.Get("Access-Control-Allow-Headers") != "accept, content-type" {
		t.Fatalf("Header Access-Control-Allow-Headers is invalid. %s", r.Header.Get("Access-Control-Allow-Headers"))
	}
	if r.Header.Get("Access-Control-Allow-Methods") != "GET,POST,HEAD,OPTIONS" {
		t.Fatalf("Header Access-Control-Allow-Methods is invalid. %s", r.Header.Get("Access-Control-Allow-Methods"))
	}

	// Test for a POST request
	requestJSON := `{
	  "panelId":1,
	  "range":{
	    "from":"2017-01-17T05:14:42.237Z",
	    "to":"2017-01-18T05:14:42.237Z",
	    "raw":{
	      "from":"now-24h",
	      "to":"now"
	    }
	  },
	  "rangeRaw":{
	    "from":"now-24h",
	    "to":"now"
	  },
	  "interval":"1m",
	  "intervalMs":60000,
	  "targets":[
	    {"target":"sample:ClientJobsIdle","refId":"A","hide":false,"type":"timeserie"},
	    {"target":"sample:ClientJobsRunning","refId":"B","hide":false,"type":"timeserie"}
	  ],
	  "format":"json",
	  "maxDataPoints":1812
	}`

	reader := strings.NewReader(requestJSON)
	r, err = http.Post(ts.URL, "application/json; charset=utf-8", reader)
	if err != nil {
		t.Fatalf("Error at an POST request. %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if r.Header.Get("Access-Control-Allow-Origin") != "*" {
		t.Fatalf("Header Access-Control-Allow-Origin is invalid. %s", r.Header.Get("Access-Control-Allow-Origin"))
	}
	if r.Header.Get("Access-Control-Allow-Headers") != "accept, content-type" {
		t.Fatalf("Header Access-Control-Allow-Headers is invalid. %s", r.Header.Get("Access-Control-Allow-Headers"))
	}
	if r.Header.Get("Access-Control-Allow-Methods") != "GET,POST,HEAD,OPTIONS" {
		t.Fatalf("Header Access-Control-Allow-Methods is invalid. %s", r.Header.Get("Access-Control-Allow-Methods"))
	}

	decoder := json.NewDecoder(r.Body)
	var queryRequest QueryRequest
	err = decoder.Decode(&queryRequest)
	if err != nil {
		fmt.Println("error in query 1")
		fmt.Println(err)
	}

	if len(queryRequest.Targets) < 1 {
		t.Fatalf("Response is empty.")
	}
}

func TestAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(annotations))
	defer ts.Close()

	r, err := http.Get(ts.URL)
	if err != nil {
		t.Fatalf("Error at a GET request. %v", err)
	}

	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Fatalf("Error by ioutil.ReadAll(). %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if "{\"message\":\"annotations\"}" != string(data) {
		t.Fatalf("Data Error. %v", string(data))
	}
}
<commit_msg>Fix TestQuery<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
)

func TestReadConfigFile(t *testing.T) {
	filename := "config.toml"
	ReadConfigFile(filename)

	if config.Server.RrdPath != "sample/" {
		t.Fatalf("Error reading config file %s", filename)
	}

	err := ReadConfigFile("fugahoge.toml")
	if err == nil {
		t.Fatalf("The file %s is invalid but error didn't happen.", err)
	}
}

func TestHello(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(hello))
	defer ts.Close()

	r, err := http.Get(ts.URL)
	if err != nil {
		t.Fatalf("Error by http.Get(). %v", err)
	}

	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Fatalf("Error by ioutil.ReadAll(). %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if "{\"message\":\"hello\"}" != string(data) {
		t.Fatalf("Data Error. %v", string(data))
	}
}

func TestSearch(t *testing.T) {
	requestJSON := `{"target":"hoge"}`
	reader := strings.NewReader(requestJSON)

	ReadConfigFile("config.toml")

	ts := httptest.NewServer(http.HandlerFunc(search))
	defer ts.Close()

	r, err := http.Post(ts.URL, "application/json", reader)
	if err != nil {
		t.Fatalf("Error at a GET request. %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	decoder := json.NewDecoder(r.Body)
	var searchResponse []string
	decoder.Decode(&searchResponse)

	if len(searchResponse) <= 0 {
		t.Fatalf("Data Error. %v", searchResponse)
	} else {
		t.Log(searchResponse)
	}
}

func TestQuery(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(query))
	defer ts.Close()
	client := &http.Client{}

	// Test for an OPTIONS request
	reqOptions, err := http.NewRequest("OPTIONS", ts.URL, nil)
	if err != nil {
		t.Fatalf("Error at an OPTIONS request. %v", err)
	}
	r, err := client.Do(reqOptions)

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if r.Header.Get("Access-Control-Allow-Origin") != "*" {
		t.Fatalf("Header Access-Control-Allow-Origin is invalid. %s", r.Header.Get("Access-Control-Allow-Origin"))
	}
	if r.Header.Get("Access-Control-Allow-Headers") != "accept, content-type" {
		t.Fatalf("Header Access-Control-Allow-Headers is invalid. %s", r.Header.Get("Access-Control-Allow-Headers"))
	}
	if r.Header.Get("Access-Control-Allow-Methods") != "GET,POST,HEAD,OPTIONS" {
		t.Fatalf("Header Access-Control-Allow-Methods is invalid. %s", r.Header.Get("Access-Control-Allow-Methods"))
	}

	// Test for a POST request
	requestJSON := `{
	  "panelId":1,
	  "range":{
	    "from":"2017-01-17T05:14:42.237Z",
	    "to":"2017-01-18T05:14:42.237Z",
	    "raw":{
	      "from":"now-24h",
	      "to":"now"
	    }
	  },
	  "rangeRaw":{
	    "from":"now-24h",
	    "to":"now"
	  },
	  "interval":"1m",
	  "intervalMs":60000,
	  "targets":[
	    {"target":"sample:ClientJobsIdle","refId":"A","hide":false,"type":"timeserie"},
	    {"target":"sample:ClientJobsRunning","refId":"B","hide":false,"type":"timeserie"}
	  ],
	  "format":"json",
	  "maxDataPoints":1812
	}`

	reader := strings.NewReader(requestJSON)
	r, err = http.Post(ts.URL, "application/json; charset=utf-8", reader)
	if err != nil {
		t.Fatalf("Error at an POST request. %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if r.Header.Get("Access-Control-Allow-Origin") != "*" {
		t.Fatalf("Header Access-Control-Allow-Origin is invalid. %s", r.Header.Get("Access-Control-Allow-Origin"))
	}
	if r.Header.Get("Access-Control-Allow-Headers") != "accept, content-type" {
		t.Fatalf("Header Access-Control-Allow-Headers is invalid. %s", r.Header.Get("Access-Control-Allow-Headers"))
	}
	if r.Header.Get("Access-Control-Allow-Methods") != "GET,POST,HEAD,OPTIONS" {
		t.Fatalf("Header Access-Control-Allow-Methods is invalid. %s", r.Header.Get("Access-Control-Allow-Methods"))
	}

	decoder := json.NewDecoder(r.Body)
	var qrs = []QueryResponse{}
	err = decoder.Decode(&qrs)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error in query 1: %v", err)
	}

	for _, v := range qrs {
		if len(v.Target) < 0 {
			t.Errorf("Response is empty.")
		}
	}
}

func TestAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(annotations))
	defer ts.Close()

	r, err := http.Get(ts.URL)
	if err != nil {
		t.Fatalf("Error at a GET request. %v", err)
	}

	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Fatalf("Error by ioutil.ReadAll(). %v", err)
	}

	if r.StatusCode != 200 {
		t.Fatalf("Status code is not 200 but %d.", r.StatusCode)
		return
	}

	if "{\"message\":\"annotations\"}" != string(data) {
		t.Fatalf("Data Error. %v", string(data))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"github.com/weaveworks/weave/ipam"
	"github.com/weaveworks/weave/nameserver"
	"github.com/weaveworks/weave/net/address"
	weave "github.com/weaveworks/weave/router"
)

func metricsHandler(router *weave.NetworkRouter, allocator *ipam.Allocator, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) http.Handler {
	reg := prometheus.NewRegistry()
	reg.MustRegister(prometheus.NewProcessCollector(os.Getpid(), ""))
	reg.MustRegister(newMetrics(router, allocator, ns, dnsserver))
	return promhttp.HandlerFor(reg, promhttp.HandlerOpts{})
}

type collector struct {
	router    *weave.NetworkRouter
	allocator *ipam.Allocator
	ns        *nameserver.Nameserver
	dnsserver *nameserver.DNSServer
}

type metric struct {
	*prometheus.Desc
	Collect func(WeaveStatus, *prometheus.Desc, chan<- prometheus.Metric)
}

func desc(fqName, help string, variableLabels ...string) *prometheus.Desc {
	return prometheus.NewDesc(fqName, help, variableLabels, prometheus.Labels{})
}

func intGauge(desc *prometheus.Desc, val int, labels ...string) prometheus.Metric {
	return prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(val), labels...)
}
func uint64Counter(desc *prometheus.Desc, val uint64, labels ...string) prometheus.Metric {
	return prometheus.MustNewConstMetric(desc, prometheus.CounterValue, float64(val), labels...)
}

var metrics = []metric{
	{desc("weave_connections", "Number of peer-to-peer connections.", "state", "type"),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			counts := make(map[string]map[string]int)
			for _, conn := range s.Router.Connections {
				t, ok := conn.Attrs["name"].(string)
				if !ok {
					// TODO: some kind of log statement here may be useful here?
					t = "unknown"
				}
				counts[t][conn.State]++
			}
			for connType, stateCounts := range counts {
				for state, count := range stateCounts {
					ch <- intGauge(desc, count, state, connType)
				}
			}
		}},
	{desc("weave_connection_terminations_total", "Number of peer-to-peer connections terminated."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			ch <- uint64Counter(desc, uint64(s.Router.TerminationCount))
		}},
	{desc("weave_ips", "Number of IP addresses.", "state"),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, s.IPAM.ActiveIPs, "local-used")
			}
		}},
	{desc("weave_max_ips", "Size of IP address space used by allocator."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, s.IPAM.RangeNumIPs)
			}
		}},
	{desc("weave_dns_entries", "Number of DNS entries."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.DNS != nil {
				ch <- intGauge(desc, countDNSEntriesForPeer(s.Router.Name, s.DNS.Entries))
			}
		}},
	{desc("weave_flows", "Number of FastDP flows."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if metrics := fastDPMetrics(s); metrics != nil {
				ch <- intGauge(desc, metrics.Flows)
			}
		}},
	{desc("weave_ipam_unreachable_count", "Number of unreachable peers."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			var count int
			for _, entry := range summariseIpamStats(s.IPAM) {
				if !entry.reachable {
					count++
				}
			}
			ch <- intGauge(desc, count)
		}},
	{desc("weave_ipam_unreachable_percentage", "Percentage of IP addresses owned  by unreachable peers."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			var totalUnreachable uint32
			for _, entry := range summariseIpamStats(s.IPAM) {
				if !entry.reachable {
					totalUnreachable += entry.ips
				}
			}
			percentage := float64(totalUnreachable) * 100.0 / float64(s.IPAM.RangeNumIPs)
			ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, percentage)
		}},
	{desc("weave_ipam_pending_allocates", "Number of pending allocates."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, len(s.IPAM.PendingAllocates))
			}
		}},
	{desc("weave_ipam_pending_claims", "Number of pending claims."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, len(s.IPAM.PendingClaims))
			}
		}},
}

func fastDPMetrics(s WeaveStatus) *weave.FastDPMetrics {
	if diagMap, ok := s.Router.OverlayDiagnostics.(map[string]interface{}); ok {
		if diag, ok := diagMap["fastdp"]; ok {
			if fastDPStats, ok := diag.(weave.FastDPStatus); ok {
				return fastDPStats.Metrics().(*weave.FastDPMetrics)
			}
		}
	}
	return nil
}

func newMetrics(router *weave.NetworkRouter, allocator *ipam.Allocator, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) *collector {
	return &collector{
		router:    router,
		allocator: allocator,
		ns:        ns,
		dnsserver: dnsserver,
	}
}

func (m *collector) Collect(ch chan<- prometheus.Metric) {

	status := WeaveStatus{
		Router: weave.NewNetworkRouterStatus(m.router),
		IPAM:   ipam.NewStatus(m.allocator, address.CIDR{}),
		DNS:    nameserver.NewStatus(m.ns, m.dnsserver)}

	for _, metric := range metrics {
		metric.Collect(status, metric.Desc, ch)
	}
}

func (m *collector) Describe(ch chan<- *prometheus.Desc) {
	for _, metric := range metrics {
		ch <- metric.Desc
	}
}
<commit_msg>Ensure maps for connection counts are created before use<commit_after>package main

import (
	"net/http"
	"os"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"github.com/weaveworks/weave/ipam"
	"github.com/weaveworks/weave/nameserver"
	"github.com/weaveworks/weave/net/address"
	weave "github.com/weaveworks/weave/router"
)

func metricsHandler(router *weave.NetworkRouter, allocator *ipam.Allocator, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) http.Handler {
	reg := prometheus.NewRegistry()
	reg.MustRegister(prometheus.NewProcessCollector(os.Getpid(), ""))
	reg.MustRegister(newMetrics(router, allocator, ns, dnsserver))
	return promhttp.HandlerFor(reg, promhttp.HandlerOpts{})
}

type collector struct {
	router    *weave.NetworkRouter
	allocator *ipam.Allocator
	ns        *nameserver.Nameserver
	dnsserver *nameserver.DNSServer
}

type metric struct {
	*prometheus.Desc
	Collect func(WeaveStatus, *prometheus.Desc, chan<- prometheus.Metric)
}

func desc(fqName, help string, variableLabels ...string) *prometheus.Desc {
	return prometheus.NewDesc(fqName, help, variableLabels, prometheus.Labels{})
}

func intGauge(desc *prometheus.Desc, val int, labels ...string) prometheus.Metric {
	return prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(val), labels...)
}
func uint64Counter(desc *prometheus.Desc, val uint64, labels ...string) prometheus.Metric {
	return prometheus.MustNewConstMetric(desc, prometheus.CounterValue, float64(val), labels...)
}

var metrics = []metric{
	{desc("weave_connections", "Number of peer-to-peer connections.", "state", "type"),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			counts := make(map[ /*state*/ string]map[ /*type*/ string]int)
			for _, state := range allConnectionStates {
				counts[state] = make(map[string]int)
			}
			for _, conn := range s.Router.Connections {
				typeName := "unknown"
				if t, ok := conn.Attrs["name"]; ok {
					typeName = t.(string)
				}
				counts[conn.State][typeName]++
			}
			for state, stateCounts := range counts {
				for connType, count := range stateCounts {
					ch <- intGauge(desc, count, state, connType)
				}
			}
		}},
	{desc("weave_connection_terminations_total", "Number of peer-to-peer connections terminated."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			ch <- uint64Counter(desc, uint64(s.Router.TerminationCount))
		}},
	{desc("weave_ips", "Number of IP addresses.", "state"),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, s.IPAM.ActiveIPs, "local-used")
			}
		}},
	{desc("weave_max_ips", "Size of IP address space used by allocator."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, s.IPAM.RangeNumIPs)
			}
		}},
	{desc("weave_dns_entries", "Number of DNS entries."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.DNS != nil {
				ch <- intGauge(desc, countDNSEntriesForPeer(s.Router.Name, s.DNS.Entries))
			}
		}},
	{desc("weave_flows", "Number of FastDP flows."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if metrics := fastDPMetrics(s); metrics != nil {
				ch <- intGauge(desc, metrics.Flows)
			}
		}},
	{desc("weave_ipam_unreachable_count", "Number of unreachable peers."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			var count int
			for _, entry := range summariseIpamStats(s.IPAM) {
				if !entry.reachable {
					count++
				}
			}
			ch <- intGauge(desc, count)
		}},
	{desc("weave_ipam_unreachable_percentage", "Percentage of IP addresses owned  by unreachable peers."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			var totalUnreachable uint32
			for _, entry := range summariseIpamStats(s.IPAM) {
				if !entry.reachable {
					totalUnreachable += entry.ips
				}
			}
			percentage := float64(totalUnreachable) * 100.0 / float64(s.IPAM.RangeNumIPs)
			ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, percentage)
		}},
	{desc("weave_ipam_pending_allocates", "Number of pending allocates."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, len(s.IPAM.PendingAllocates))
			}
		}},
	{desc("weave_ipam_pending_claims", "Number of pending claims."),
		func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
			if s.IPAM != nil {
				ch <- intGauge(desc, len(s.IPAM.PendingClaims))
			}
		}},
}

func fastDPMetrics(s WeaveStatus) *weave.FastDPMetrics {
	if diagMap, ok := s.Router.OverlayDiagnostics.(map[string]interface{}); ok {
		if diag, ok := diagMap["fastdp"]; ok {
			if fastDPStats, ok := diag.(weave.FastDPStatus); ok {
				return fastDPStats.Metrics().(*weave.FastDPMetrics)
			}
		}
	}
	return nil
}

func newMetrics(router *weave.NetworkRouter, allocator *ipam.Allocator, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) *collector {
	return &collector{
		router:    router,
		allocator: allocator,
		ns:        ns,
		dnsserver: dnsserver,
	}
}

func (m *collector) Collect(ch chan<- prometheus.Metric) {

	status := WeaveStatus{
		Router: weave.NewNetworkRouterStatus(m.router),
		IPAM:   ipam.NewStatus(m.allocator, address.CIDR{}),
		DNS:    nameserver.NewStatus(m.ns, m.dnsserver)}

	for _, metric := range metrics {
		metric.Collect(status, metric.Desc, ch)
	}
}

func (m *collector) Describe(ch chan<- *prometheus.Desc) {
	for _, metric := range metrics {
		ch <- metric.Desc
	}
}
<|endoftext|>


<commit_before>package mysql

const (
	passwordQuery     = "SELECT passwordHash FROM User WHERE username = ?"
	insertIntoData    = "INSERT INTO Data (device, timestamp) VALUES (?, ?);"
	insertIntoBattery = "INSERT INTO BatteryStatus VALUES (?, ?);"
	getAllBattery     = "SELECT d.timestamp, b.batteryPercentage " +
		"FROM Data d, BatteryStatus b, Device dev, User u " +
		"WHERE u.apiKey = ? AND u.id = dev.user AND dev.id = d.device " +
		"AND d.id = b.id;"
)
<commit_msg>fix bug in sql query<commit_after>package mysql

const (
	passwordQuery     = "SELECT passwordHash FROM User WHERE username = ?"
	insertIntoData    = "INSERT INTO Data (device, timestamp) VALUES (?, ?);"
	insertIntoBattery = "INSERT INTO BatteryStatus VALUES (?, ?);"
	getAllBattery     = "SELECT d.timestamp, b.batteryPercentage " +
		"FROM Data d, BatteryStatus b, Device dev, User u " +
		"WHERE u.apiKey = ? AND u.uid = dev.user AND dev.id = d.device " +
		"AND d.id = b.id;"
)
<|endoftext|>


<commit_before>package putio

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	defaultUserAgent = "go-putio"
	defaultMediaType = "application/json"
	defaultBaseURL   = "https://api.put.io"
	defaultUploadURL = "https://upload.put.io"
)

// Client manages communication with Put.io v2 API.
type Client struct {
	// HTTP client used to communicate with Put.io API
	client *http.Client

	// Base URL for API requests
	BaseURL *url.URL

	// base url for upload requests
	uploadURL *url.URL

	// User agent for client
	UserAgent string

	// ExtraHeaders are passed to the API server on every request.
	ExtraHeaders http.Header

	// Services used for communicating with the API
	Account   *AccountService
	Files     *FilesService
	Transfers *TransfersService
	Zips      *ZipsService
	Friends   *FriendsService
	Events    *EventsService
}

// NewClient returns a new Put.io API client, using the htttpClient, which must
// be a new Oauth2 enabled http.Client. If httpClient is not defined, default
// HTTP client is used.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	baseURL, _ := url.Parse(defaultBaseURL)
	uploadURL, _ := url.Parse(defaultUploadURL)
	c := &Client{
		client:       httpClient,
		BaseURL:      baseURL,
		uploadURL:    uploadURL,
		UserAgent:    defaultUserAgent,
		ExtraHeaders: make(http.Header),
	}

	c.Account = &AccountService{client: c}
	c.Files = &FilesService{client: c}
	c.Transfers = &TransfersService{client: c}
	c.Zips = &ZipsService{client: c}
	c.Friends = &FriendsService{client: c}
	c.Events = &EventsService{client: c}

	return c
}

func (c *Client) ValidateToken(ctx context.Context) (userID *int64, err error) {
	req, err := c.NewRequest(ctx, "GET", "/v2/oauth2/validate", nil)
	if err != nil {
		return
	}
	var r struct {
		UserID *int64 `json:"user_id"`
	}
	_, err = c.Do(req, &r)
	return r.UserID, err
}

// NewRequest creates an API request. A relative URL can be provided via
// relURL, which will be resolved to the BaseURL of the Client.
func (c *Client) NewRequest(ctx context.Context, method, relURL string, body io.Reader) (*http.Request, error) {
	rel, err := url.Parse(relURL)
	if err != nil {
		return nil, err
	}

	var u *url.URL
	// XXX: workaroud for upload endpoint. upload method has a different base url,
	// so we've a special case for testing purposes.
	if relURL == "/v2/files/upload" {
		u = c.uploadURL.ResolveReference(rel)
	} else {
		u = c.BaseURL.ResolveReference(rel)
	}

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req = req.WithContext(ctx)
	req.Header.Set("Accept", defaultMediaType)
	req.Header.Set("User-Agent", c.UserAgent)

	// merge headers with extra headers
	for header, values := range c.ExtraHeaders {
		for _, value := range values {
			req.Header.Add(header, value)
		}
	}

	return req, nil
}

// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. Response body is closed at all cases except
// v is nil. If v is nil, response body is not closed and the body can be used
// for streaming.
func (c *Client) Do(r *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(r)
	if err != nil {
		return nil, err
	}

	err = checkResponse(resp)
	if err != nil {
		// close the body at all times if there is an http error
		resp.Body.Close()
		return resp, err
	}

	if v == nil {
		return resp, nil
	}

	// close the body for all cases from here
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(v)
	if err != nil {
		return resp, err
	}

	return resp, nil
}

// checkResponse is the entrypoint to reading the API response. If the response
// status code is not in success range, it will try to return a structured
// error.
func checkResponse(r *http.Response) error {
	status := r.StatusCode
	switch {
	case status >= 200 && status <= 399:
		return nil
	case status >= 400 && status <= 599:
		// server returns json
	default:
		return fmt.Errorf("unexpected status code: %d", status)
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return fmt.Errorf("body read error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
	}
	if len(data) > 0 {
		err = json.Unmarshal(data, errorResponse)
		if err != nil {
			return fmt.Errorf("json decod error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
		}
	}
	return errorResponse
}
<commit_msg>fix typo in error message<commit_after>package putio

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	defaultUserAgent = "go-putio"
	defaultMediaType = "application/json"
	defaultBaseURL   = "https://api.put.io"
	defaultUploadURL = "https://upload.put.io"
)

// Client manages communication with Put.io v2 API.
type Client struct {
	// HTTP client used to communicate with Put.io API
	client *http.Client

	// Base URL for API requests
	BaseURL *url.URL

	// base url for upload requests
	uploadURL *url.URL

	// User agent for client
	UserAgent string

	// ExtraHeaders are passed to the API server on every request.
	ExtraHeaders http.Header

	// Services used for communicating with the API
	Account   *AccountService
	Files     *FilesService
	Transfers *TransfersService
	Zips      *ZipsService
	Friends   *FriendsService
	Events    *EventsService
}

// NewClient returns a new Put.io API client, using the htttpClient, which must
// be a new Oauth2 enabled http.Client. If httpClient is not defined, default
// HTTP client is used.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	baseURL, _ := url.Parse(defaultBaseURL)
	uploadURL, _ := url.Parse(defaultUploadURL)
	c := &Client{
		client:       httpClient,
		BaseURL:      baseURL,
		uploadURL:    uploadURL,
		UserAgent:    defaultUserAgent,
		ExtraHeaders: make(http.Header),
	}

	c.Account = &AccountService{client: c}
	c.Files = &FilesService{client: c}
	c.Transfers = &TransfersService{client: c}
	c.Zips = &ZipsService{client: c}
	c.Friends = &FriendsService{client: c}
	c.Events = &EventsService{client: c}

	return c
}

func (c *Client) ValidateToken(ctx context.Context) (userID *int64, err error) {
	req, err := c.NewRequest(ctx, "GET", "/v2/oauth2/validate", nil)
	if err != nil {
		return
	}
	var r struct {
		UserID *int64 `json:"user_id"`
	}
	_, err = c.Do(req, &r)
	return r.UserID, err
}

// NewRequest creates an API request. A relative URL can be provided via
// relURL, which will be resolved to the BaseURL of the Client.
func (c *Client) NewRequest(ctx context.Context, method, relURL string, body io.Reader) (*http.Request, error) {
	rel, err := url.Parse(relURL)
	if err != nil {
		return nil, err
	}

	var u *url.URL
	// XXX: workaroud for upload endpoint. upload method has a different base url,
	// so we've a special case for testing purposes.
	if relURL == "/v2/files/upload" {
		u = c.uploadURL.ResolveReference(rel)
	} else {
		u = c.BaseURL.ResolveReference(rel)
	}

	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return nil, err
	}

	req = req.WithContext(ctx)
	req.Header.Set("Accept", defaultMediaType)
	req.Header.Set("User-Agent", c.UserAgent)

	// merge headers with extra headers
	for header, values := range c.ExtraHeaders {
		for _, value := range values {
			req.Header.Add(header, value)
		}
	}

	return req, nil
}

// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. Response body is closed at all cases except
// v is nil. If v is nil, response body is not closed and the body can be used
// for streaming.
func (c *Client) Do(r *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(r)
	if err != nil {
		return nil, err
	}

	err = checkResponse(resp)
	if err != nil {
		// close the body at all times if there is an http error
		resp.Body.Close()
		return resp, err
	}

	if v == nil {
		return resp, nil
	}

	// close the body for all cases from here
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(v)
	if err != nil {
		return resp, err
	}

	return resp, nil
}

// checkResponse is the entrypoint to reading the API response. If the response
// status code is not in success range, it will try to return a structured
// error.
func checkResponse(r *http.Response) error {
	status := r.StatusCode
	switch {
	case status >= 200 && status <= 399:
		return nil
	case status >= 400 && status <= 599:
		// server returns json
	default:
		return fmt.Errorf("unexpected status code: %d", status)
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return fmt.Errorf("body read error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
	}
	if len(data) > 0 {
		err = json.Unmarshal(data, errorResponse)
		if err != nil {
			return fmt.Errorf("json decode error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
		}
	}
	return errorResponse
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package controller

import (
	"fmt"
	"time"

	"github.com/golang/glog"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"

	schedcache "github.com/kubernetes-incubator/kube-arbitrator/pkg/cache"
	"github.com/kubernetes-incubator/kube-arbitrator/pkg/client/clientset"
	"github.com/kubernetes-incubator/kube-arbitrator/pkg/policy"
)

type PolicyController struct {
	config     *rest.Config
	clientset  *clientset.Clientset
	kubeclient *kubernetes.Clientset
	cache      schedcache.Cache
	allocator  policy.Interface
	podSets    *cache.FIFO
}

func podSetKey(obj interface{}) (string, error) {
	podSet, ok := obj.(*schedcache.PodSet)
	if !ok {
		return "", fmt.Errorf("not a PodSet")
	}

	return fmt.Sprintf("%s/%s", podSet.Namespace, podSet.Name), nil
}

func NewPolicyController(config *rest.Config, policyName string) (*PolicyController, error) {
	cs, err := clientset.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("fail to create client for PolicyController: %#v", err)
	}

	kc, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("failed to create kube client for PolicyController: %#v", err)
	}

	alloc, err := policy.New(policyName)
	if err != nil {
		return nil, fmt.Errorf("failed to create allocator: %#v", err)
	}

	queueController := &PolicyController{
		config:     config,
		clientset:  cs,
		kubeclient: kc,
		cache:      schedcache.New(config),
		allocator:  alloc,
		podSets:    cache.NewFIFO(podSetKey),
	}

	return queueController, nil
}

func (pc *PolicyController) Run(stopCh <-chan struct{}) {
	// Start cache for policy.
	go pc.cache.Run(stopCh)
	pc.cache.WaitForCacheSync(stopCh)

	go wait.Until(pc.runOnce, 2*time.Second, stopCh)
	go wait.Until(pc.processAllocDecision, 0, stopCh)
}

func (pc *PolicyController) runOnce() {
	glog.V(4).Infof("Start scheduling ...")
	defer glog.V(4).Infof("End scheduling ...")

	pc.resetPodSets()

	snapshot := pc.cache.Snapshot()

	consumers := pc.allocator.Allocate(snapshot.Consumers, snapshot.Nodes)

	pc.enqueue(consumers)
}

func (pc *PolicyController) enqueue(consumers []*schedcache.ConsumerInfo) {
	for _, c := range consumers {
		for _, ps := range c.PodSets {
			pc.podSets.Add(ps)
		}
	}
}

func (pc *PolicyController) resetPodSets() {
	// clean up FIFO Queue podSets
	err := pc.podSets.Replace([]interface{}{}, "")
	if err != nil {
		glog.V(4).Infof("Reset podSets error %v", err)
	}
}

func (pc *PolicyController) processAllocDecision() {
	pc.podSets.Pop(func(obj interface{}) error {
		ps, ok := obj.(*schedcache.PodSet)
		if !ok {
			return fmt.Errorf("not a PodSet")
		}

		for _, p := range ps.Pending {
			if len(p.NodeName) != 0 {
				if err := pc.kubeclient.CoreV1().Pods(p.Namespace).Bind(&v1.Binding{
					ObjectMeta: metav1.ObjectMeta{Namespace: p.Namespace, Name: p.Name, UID: p.UID},
					Target: v1.ObjectReference{
						Kind: "Node",
						Name: p.NodeName,
					},
				}); err != nil {
					glog.Infof("Failed to bind pod <%v/%v>: %#v", p.Namespace, p.Name, err)
					return err
				}
			}
		}

		for _, p := range ps.Running {
			if len(p.NodeName) == 0 {
				// TODO(k82cn): it's better to use /eviction instead of delete to avoid race-condition.
				if err := pc.kubeclient.CoreV1().Pods(p.Namespace).Delete(p.Name, &metav1.DeleteOptions{}); err != nil {
					glog.Infof("Failed to preempt pod <%v/%v>: %#v", p.Namespace, p.Name, err)
					return err
				}
			}
		}

		return nil
	})
}
<commit_msg>cancel all alloc decision processing before policy run<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package controller

import (
	"fmt"
	"time"

	"github.com/golang/glog"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"

	schedcache "github.com/kubernetes-incubator/kube-arbitrator/pkg/cache"
	"github.com/kubernetes-incubator/kube-arbitrator/pkg/client/clientset"
	"github.com/kubernetes-incubator/kube-arbitrator/pkg/policy"
)

type PolicyController struct {
	config     *rest.Config
	clientset  *clientset.Clientset
	kubeclient *kubernetes.Clientset
	cache      schedcache.Cache
	allocator  policy.Interface
	podSets    *cache.FIFO
}

func podSetKey(obj interface{}) (string, error) {
	podSet, ok := obj.(*schedcache.PodSet)
	if !ok {
		return "", fmt.Errorf("not a PodSet")
	}

	return fmt.Sprintf("%s/%s", podSet.Namespace, podSet.Name), nil
}

func NewPolicyController(config *rest.Config, policyName string) (*PolicyController, error) {
	cs, err := clientset.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("fail to create client for PolicyController: %#v", err)
	}

	kc, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("failed to create kube client for PolicyController: %#v", err)
	}

	alloc, err := policy.New(policyName)
	if err != nil {
		return nil, fmt.Errorf("failed to create allocator: %#v", err)
	}

	queueController := &PolicyController{
		config:     config,
		clientset:  cs,
		kubeclient: kc,
		cache:      schedcache.New(config),
		allocator:  alloc,
		podSets:    cache.NewFIFO(podSetKey),
	}

	return queueController, nil
}

func (pc *PolicyController) Run(stopCh <-chan struct{}) {
	// Start cache for policy.
	go pc.cache.Run(stopCh)
	pc.cache.WaitForCacheSync(stopCh)

	go wait.Until(pc.runOnce, 2*time.Second, stopCh)
	go wait.Until(pc.processAllocDecision, 0, stopCh)
}

func (pc *PolicyController) runOnce() {
	glog.V(4).Infof("Start scheduling ...")
	defer glog.V(4).Infof("End scheduling ...")

	pc.cancelAllocDecisionProcessing()

	snapshot := pc.cache.Snapshot()

	consumers := pc.allocator.Allocate(snapshot.Consumers, snapshot.Nodes)

	pc.enqueue(consumers)
}

func (pc *PolicyController) enqueue(consumers []*schedcache.ConsumerInfo) {
	for _, c := range consumers {
		for _, ps := range c.PodSets {
			pc.podSets.Add(ps)
		}
	}
}

func (pc *PolicyController) cancelAllocDecisionProcessing() {
	// clean up FIFO Queue podSets
	err := pc.podSets.Replace([]interface{}{}, "")
	if err != nil {
		glog.V(4).Infof("Reset podSets error %v", err)
	}
}

func (pc *PolicyController) processAllocDecision() {
	pc.podSets.Pop(func(obj interface{}) error {
		ps, ok := obj.(*schedcache.PodSet)
		if !ok {
			return fmt.Errorf("not a PodSet")
		}

		for _, p := range ps.Pending {
			if len(p.NodeName) != 0 {
				if err := pc.kubeclient.CoreV1().Pods(p.Namespace).Bind(&v1.Binding{
					ObjectMeta: metav1.ObjectMeta{Namespace: p.Namespace, Name: p.Name, UID: p.UID},
					Target: v1.ObjectReference{
						Kind: "Node",
						Name: p.NodeName,
					},
				}); err != nil {
					glog.Infof("Failed to bind pod <%v/%v>: %#v", p.Namespace, p.Name, err)
					return err
				}
			}
		}

		for _, p := range ps.Running {
			if len(p.NodeName) == 0 {
				// TODO(k82cn): it's better to use /eviction instead of delete to avoid race-condition.
				if err := pc.kubeclient.CoreV1().Pods(p.Namespace).Delete(p.Name, &metav1.DeleteOptions{}); err != nil {
					glog.Infof("Failed to preempt pod <%v/%v>: %#v", p.Namespace, p.Name, err)
					return err
				}
			}
		}

		return nil
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative 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 generator

import (
	"context"
	"fmt"
	"time"

	v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
	endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
	route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/types"
	envoy "knative.dev/net-kourier/pkg/envoy/api"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/pkg/kmeta"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/tracker"
)

type translatedIngress struct {
	name                    types.NamespacedName
	sniMatches              []*envoy.SNIMatch
	clusters                []*v3.Cluster
	externalVirtualHosts    []*route.VirtualHost
	externalTLSVirtualHosts []*route.VirtualHost
	internalVirtualHosts    []*route.VirtualHost
}

type IngressTranslator struct {
	secretGetter    func(ns, name string) (*corev1.Secret, error)
	endpointsGetter func(ns, name string) (*corev1.Endpoints, error)
	serviceGetter   func(ns, name string) (*corev1.Service, error)
	tracker         tracker.Interface
}

func NewIngressTranslator(
	secretGetter func(ns, name string) (*corev1.Secret, error),
	endpointsGetter func(ns, name string) (*corev1.Endpoints, error),
	serviceGetter func(ns, name string) (*corev1.Service, error),
	tracker tracker.Interface) IngressTranslator {
	return IngressTranslator{
		secretGetter:    secretGetter,
		endpointsGetter: endpointsGetter,
		serviceGetter:   serviceGetter,
		tracker:         tracker,
	}
}

func (translator *IngressTranslator) translateIngress(ctx context.Context, ingress *v1alpha1.Ingress, extAuthzEnabled bool) (*translatedIngress, error) {
	logger := logging.FromContext(ctx)

	sniMatches := make([]*envoy.SNIMatch, 0, len(ingress.Spec.TLS))
	for _, ingressTLS := range ingress.Spec.TLS {
		if err := trackSecret(translator.tracker, ingressTLS.SecretNamespace, ingressTLS.SecretName, ingress); err != nil {
			return nil, err
		}

		secret, err := translator.secretGetter(ingressTLS.SecretNamespace, ingressTLS.SecretName)
		if err != nil {
			return nil, fmt.Errorf("failed to fetch secret: %w", err)
		}

		secretRef := types.NamespacedName{
			Namespace: ingressTLS.SecretNamespace,
			Name:      ingressTLS.SecretName,
		}
		sniMatches = append(sniMatches, &envoy.SNIMatch{
			Hosts:            ingressTLS.Hosts,
			CertSource:       secretRef,
			CertificateChain: secret.Data[certFieldInSecret],
			PrivateKey:       secret.Data[keyFieldInSecret]})
	}

	internalHosts := make([]*route.VirtualHost, 0, len(ingress.Spec.Rules))
	externalHosts := make([]*route.VirtualHost, 0, len(ingress.Spec.Rules))
	externalTLSHosts := make([]*route.VirtualHost, 0, len(ingress.Spec.Rules))
	clusters := make([]*v3.Cluster, 0, len(ingress.Spec.Rules))

	for i, rule := range ingress.Spec.Rules {
		ruleName := fmt.Sprintf("(%s/%s).Rules[%d]", ingress.Namespace, ingress.Name, i)

		routes := make([]*route.Route, 0, len(rule.HTTP.Paths))
		tlsRoutes := make([]*route.Route, 0, len(rule.HTTP.Paths))
		for _, httpPath := range rule.HTTP.Paths {
			// Default the path to "/" if none is passed.
			path := httpPath.Path
			if path == "" {
				path = "/"
			}

			pathName := fmt.Sprintf("%s.Paths[%s]", ruleName, path)

			wrs := make([]*route.WeightedCluster_ClusterWeight, 0, len(httpPath.Splits))
			for _, split := range httpPath.Splits {
				// The FQN of the service is sufficient here, as clusters towards the
				// same service are supposed to be deduplicated anyway.
				splitName := fmt.Sprintf("%s/%s", split.ServiceNamespace, split.ServiceName)

				if err := trackService(translator.tracker, split.ServiceNamespace, split.ServiceName, ingress); err != nil {
					return nil, err
				}

				service, err := translator.serviceGetter(split.ServiceNamespace, split.ServiceName)
				if apierrors.IsNotFound(err) {
					logger.Warnf("Service '%s/%s' not yet created", split.ServiceNamespace, split.ServiceName)
					// TODO(markusthoemmes): Find out if we should actually `continue` here.
					return nil, nil
				} else if err != nil {
					return nil, fmt.Errorf("failed to fetch service '%s/%s': %w", split.ServiceNamespace, split.ServiceName, err)
				}

				// Match the ingress' port with a port on the Service to find the target.
				// Also find out if the target supports HTTP2.
				var (
					externalPort int32
					targetPort   int32
					http2        bool
				)
				for _, port := range service.Spec.Ports {
					if port.Port == split.ServicePort.IntVal || port.Name == split.ServicePort.StrVal {
						externalPort = port.Port
						targetPort = port.TargetPort.IntVal
						http2 = port.Name == "http2" || port.Name == "h2c"
					}
				}

				var (
					publicLbEndpoints []*endpoint.LbEndpoint
					typ               v3.Cluster_DiscoveryType
				)
				if service.Spec.Type == corev1.ServiceTypeExternalName {
					// If the service is of type ExternalName, we add a single endpoint.
					typ = v3.Cluster_LOGICAL_DNS
					publicLbEndpoints = []*endpoint.LbEndpoint{
						envoy.NewLBEndpoint(service.Spec.ExternalName, uint32(externalPort)),
					}
				} else {
					// For all other types, fetch the endpoints object.
					endpoints, err := translator.endpointsGetter(split.ServiceNamespace, split.ServiceName)
					if apierrors.IsNotFound(err) {
						logger.Warnf("Endpoints '%s/%s' not yet created", split.ServiceNamespace, split.ServiceName)
						// TODO(markusthoemmes): Find out if we should actually `continue` here.
						return nil, nil
					} else if err != nil {
						return nil, fmt.Errorf("failed to fetch endpoints '%s/%s': %w", split.ServiceNamespace, split.ServiceName, err)
					}

					typ = v3.Cluster_STATIC
					publicLbEndpoints = lbEndpointsForKubeEndpoints(endpoints, targetPort)
				}

				connectTimeout := 5 * time.Second
				cluster := envoy.NewCluster(splitName, connectTimeout, publicLbEndpoints, http2, typ)
				clusters = append(clusters, cluster)

				weightedCluster := envoy.NewWeightedCluster(splitName, uint32(split.Percent), split.AppendHeaders)
				wrs = append(wrs, weightedCluster)
			}

			if len(wrs) != 0 {
				if ingress.Spec.HTTPOption == v1alpha1.HTTPOptionRedirected && rule.Visibility == v1alpha1.IngressVisibilityExternalIP {
					routes = append(routes, envoy.NewRedirectRoute(
						pathName, matchHeadersFromHTTPPath(httpPath), path))
				} else {
					routes = append(routes, envoy.NewRoute(
						pathName, matchHeadersFromHTTPPath(httpPath), path, wrs, 0, httpPath.AppendHeaders, httpPath.RewriteHost))
				}
				if len(ingress.Spec.TLS) != 0 {
					tlsRoutes = append(tlsRoutes, envoy.NewRoute(
						pathName, matchHeadersFromHTTPPath(httpPath), path, wrs, 0, httpPath.AppendHeaders, httpPath.RewriteHost))
				}
			}
		}

		if len(routes) == 0 {
			// Return nothing if there are not routes to generate.
			return nil, nil
		}

		var virtualHost, virtualTLSHost *route.VirtualHost
		if extAuthzEnabled {
			contextExtensions := kmeta.UnionMaps(map[string]string{
				"client":     "kourier",
				"visibility": string(rule.Visibility),
			}, ingress.GetLabels())
			virtualHost = envoy.NewVirtualHostWithExtAuthz(ruleName, contextExtensions, domainsForRule(rule), routes)
			if len(tlsRoutes) != 0 {
				virtualTLSHost = envoy.NewVirtualHostWithExtAuthz(ruleName, contextExtensions, domainsForRule(rule), tlsRoutes)
			}
		} else {
			virtualHost = envoy.NewVirtualHost(ruleName, domainsForRule(rule), routes)
			if len(tlsRoutes) != 0 {
				virtualTLSHost = envoy.NewVirtualHost(ruleName, domainsForRule(rule), tlsRoutes)
			}
		}

		internalHosts = append(internalHosts, virtualHost)
		if rule.Visibility == v1alpha1.IngressVisibilityExternalIP {
			externalHosts = append(externalHosts, virtualHost)
			if virtualTLSHost != nil {
				externalTLSHosts = append(externalTLSHosts, virtualTLSHost)
			}
		}
	}

	return &translatedIngress{
		name: types.NamespacedName{
			Namespace: ingress.Namespace,
			Name:      ingress.Name,
		},
		sniMatches:              sniMatches,
		clusters:                clusters,
		externalVirtualHosts:    externalHosts,
		externalTLSVirtualHosts: externalTLSHosts,
		internalVirtualHosts:    internalHosts,
	}, nil
}

func trackSecret(t tracker.Interface, ns, name string, ingress *v1alpha1.Ingress) error {
	return t.TrackReference(tracker.Reference{
		Kind:       "Secret",
		APIVersion: "v1",
		Namespace:  ns,
		Name:       name,
	}, ingress)
}

func trackService(t tracker.Interface, svcNs, svcName string, ingress *v1alpha1.Ingress) error {
	if err := t.TrackReference(tracker.Reference{
		Kind:       "Service",
		APIVersion: "v1",
		Namespace:  svcNs,
		Name:       svcName,
	}, ingress); err != nil {
		return fmt.Errorf("could not track service reference: %w", err)
	}

	if err := t.TrackReference(tracker.Reference{
		Kind:       "Endpoints",
		APIVersion: "v1",
		Namespace:  svcNs,
		Name:       svcName,
	}, ingress); err != nil {
		return fmt.Errorf("could not track endpoints reference: %w", err)
	}
	return nil
}

func lbEndpointsForKubeEndpoints(kubeEndpoints *corev1.Endpoints, targetPort int32) []*endpoint.LbEndpoint {
	var readyAddressCount int
	for _, subset := range kubeEndpoints.Subsets {
		readyAddressCount += len(subset.Addresses)
	}

	if readyAddressCount == 0 {
		return nil
	}

	eps := make([]*endpoint.LbEndpoint, 0, readyAddressCount)
	for _, subset := range kubeEndpoints.Subsets {
		for _, address := range subset.Addresses {
			eps = append(eps, envoy.NewLBEndpoint(address.IP, uint32(targetPort)))
		}
	}

	return eps
}

func matchHeadersFromHTTPPath(httpPath v1alpha1.HTTPIngressPath) []*route.HeaderMatcher {
	matchHeaders := make([]*route.HeaderMatcher, 0, len(httpPath.Headers))

	for header, matchType := range httpPath.Headers {
		matchHeader := &route.HeaderMatcher{
			Name: header,
		}
		if matchType.Exact != "" {
			matchHeader.HeaderMatchSpecifier = &route.HeaderMatcher_ExactMatch{
				ExactMatch: matchType.Exact,
			}
		}
		matchHeaders = append(matchHeaders, matchHeader)
	}
	return matchHeaders
}

// domainsForRule returns all domains for the given rule.
//
// For example, external domains returns domains with the following formats:
// 	- sub-route_host.namespace.example.com
// 	- sub-route_host.namespace.example.com:*
//
// Somehow envoy doesn't match properly gRPC authorities with ports.
// The fix is to include ":*" in the domains.
// This applies both for internal and external domains.
// More info https://github.com/envoyproxy/envoy/issues/886
func domainsForRule(rule v1alpha1.IngressRule) []string {
	domains := make([]string, 0, 2*len(rule.Hosts))
	for _, host := range rule.Hosts {
		domains = append(domains, host, host+":*")
	}
	return domains
}
<commit_msg>create tls route when using one cert via environment value. (#667)<commit_after>/*
Copyright 2020 The Knative 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 generator

import (
	"context"
	"fmt"
	"time"

	v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
	endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
	route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/types"
	envoy "knative.dev/net-kourier/pkg/envoy/api"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/pkg/kmeta"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/tracker"
)

type translatedIngress struct {
	name                    types.NamespacedName
	sniMatches              []*envoy.SNIMatch
	clusters                []*v3.Cluster
	externalVirtualHosts    []*route.VirtualHost
	externalTLSVirtualHosts []*route.VirtualHost
	internalVirtualHosts    []*route.VirtualHost
}

type IngressTranslator struct {
	secretGetter    func(ns, name string) (*corev1.Secret, error)
	endpointsGetter func(ns, name string) (*corev1.Endpoints, error)
	serviceGetter   func(ns, name string) (*corev1.Service, error)
	tracker         tracker.Interface
}

func NewIngressTranslator(
	secretGetter func(ns, name string) (*corev1.Secret, error),
	endpointsGetter func(ns, name string) (*corev1.Endpoints, error),
	serviceGetter func(ns, name string) (*corev1.Service, error),
	tracker tracker.Interface) IngressTranslator {
	return IngressTranslator{
		secretGetter:    secretGetter,
		endpointsGetter: endpointsGetter,
		serviceGetter:   serviceGetter,
		tracker:         tracker,
	}
}

func (translator *IngressTranslator) translateIngress(ctx context.Context, ingress *v1alpha1.Ingress, extAuthzEnabled bool) (*translatedIngress, error) {
	logger := logging.FromContext(ctx)

	sniMatches := make([]*envoy.SNIMatch, 0, len(ingress.Spec.TLS))
	for _, ingressTLS := range ingress.Spec.TLS {
		if err := trackSecret(translator.tracker, ingressTLS.SecretNamespace, ingressTLS.SecretName, ingress); err != nil {
			return nil, err
		}

		secret, err := translator.secretGetter(ingressTLS.SecretNamespace, ingressTLS.SecretName)
		if err != nil {
			return nil, fmt.Errorf("failed to fetch secret: %w", err)
		}

		secretRef := types.NamespacedName{
			Namespace: ingressTLS.SecretNamespace,
			Name:      ingressTLS.SecretName,
		}
		sniMatches = append(sniMatches, &envoy.SNIMatch{
			Hosts:            ingressTLS.Hosts,
			CertSource:       secretRef,
			CertificateChain: secret.Data[certFieldInSecret],
			PrivateKey:       secret.Data[keyFieldInSecret]})
	}

	internalHosts := make([]*route.VirtualHost, 0, len(ingress.Spec.Rules))
	externalHosts := make([]*route.VirtualHost, 0, len(ingress.Spec.Rules))
	externalTLSHosts := make([]*route.VirtualHost, 0, len(ingress.Spec.Rules))
	clusters := make([]*v3.Cluster, 0, len(ingress.Spec.Rules))

	for i, rule := range ingress.Spec.Rules {
		ruleName := fmt.Sprintf("(%s/%s).Rules[%d]", ingress.Namespace, ingress.Name, i)

		routes := make([]*route.Route, 0, len(rule.HTTP.Paths))
		tlsRoutes := make([]*route.Route, 0, len(rule.HTTP.Paths))
		for _, httpPath := range rule.HTTP.Paths {
			// Default the path to "/" if none is passed.
			path := httpPath.Path
			if path == "" {
				path = "/"
			}

			pathName := fmt.Sprintf("%s.Paths[%s]", ruleName, path)

			wrs := make([]*route.WeightedCluster_ClusterWeight, 0, len(httpPath.Splits))
			for _, split := range httpPath.Splits {
				// The FQN of the service is sufficient here, as clusters towards the
				// same service are supposed to be deduplicated anyway.
				splitName := fmt.Sprintf("%s/%s", split.ServiceNamespace, split.ServiceName)

				if err := trackService(translator.tracker, split.ServiceNamespace, split.ServiceName, ingress); err != nil {
					return nil, err
				}

				service, err := translator.serviceGetter(split.ServiceNamespace, split.ServiceName)
				if apierrors.IsNotFound(err) {
					logger.Warnf("Service '%s/%s' not yet created", split.ServiceNamespace, split.ServiceName)
					// TODO(markusthoemmes): Find out if we should actually `continue` here.
					return nil, nil
				} else if err != nil {
					return nil, fmt.Errorf("failed to fetch service '%s/%s': %w", split.ServiceNamespace, split.ServiceName, err)
				}

				// Match the ingress' port with a port on the Service to find the target.
				// Also find out if the target supports HTTP2.
				var (
					externalPort int32
					targetPort   int32
					http2        bool
				)
				for _, port := range service.Spec.Ports {
					if port.Port == split.ServicePort.IntVal || port.Name == split.ServicePort.StrVal {
						externalPort = port.Port
						targetPort = port.TargetPort.IntVal
						http2 = port.Name == "http2" || port.Name == "h2c"
					}
				}

				var (
					publicLbEndpoints []*endpoint.LbEndpoint
					typ               v3.Cluster_DiscoveryType
				)
				if service.Spec.Type == corev1.ServiceTypeExternalName {
					// If the service is of type ExternalName, we add a single endpoint.
					typ = v3.Cluster_LOGICAL_DNS
					publicLbEndpoints = []*endpoint.LbEndpoint{
						envoy.NewLBEndpoint(service.Spec.ExternalName, uint32(externalPort)),
					}
				} else {
					// For all other types, fetch the endpoints object.
					endpoints, err := translator.endpointsGetter(split.ServiceNamespace, split.ServiceName)
					if apierrors.IsNotFound(err) {
						logger.Warnf("Endpoints '%s/%s' not yet created", split.ServiceNamespace, split.ServiceName)
						// TODO(markusthoemmes): Find out if we should actually `continue` here.
						return nil, nil
					} else if err != nil {
						return nil, fmt.Errorf("failed to fetch endpoints '%s/%s': %w", split.ServiceNamespace, split.ServiceName, err)
					}

					typ = v3.Cluster_STATIC
					publicLbEndpoints = lbEndpointsForKubeEndpoints(endpoints, targetPort)
				}

				connectTimeout := 5 * time.Second
				cluster := envoy.NewCluster(splitName, connectTimeout, publicLbEndpoints, http2, typ)
				clusters = append(clusters, cluster)

				weightedCluster := envoy.NewWeightedCluster(splitName, uint32(split.Percent), split.AppendHeaders)
				wrs = append(wrs, weightedCluster)
			}

			if len(wrs) != 0 {
				if ingress.Spec.HTTPOption == v1alpha1.HTTPOptionRedirected && rule.Visibility == v1alpha1.IngressVisibilityExternalIP {
					routes = append(routes, envoy.NewRedirectRoute(
						pathName, matchHeadersFromHTTPPath(httpPath), path))
				} else {
					routes = append(routes, envoy.NewRoute(
						pathName, matchHeadersFromHTTPPath(httpPath), path, wrs, 0, httpPath.AppendHeaders, httpPath.RewriteHost))
				}
				if len(ingress.Spec.TLS) != 0 || useHTTPSListenerWithOneCert() {
					tlsRoutes = append(tlsRoutes, envoy.NewRoute(
						pathName, matchHeadersFromHTTPPath(httpPath), path, wrs, 0, httpPath.AppendHeaders, httpPath.RewriteHost))
				}
			}
		}

		if len(routes) == 0 {
			// Return nothing if there are not routes to generate.
			return nil, nil
		}

		var virtualHost, virtualTLSHost *route.VirtualHost
		if extAuthzEnabled {
			contextExtensions := kmeta.UnionMaps(map[string]string{
				"client":     "kourier",
				"visibility": string(rule.Visibility),
			}, ingress.GetLabels())
			virtualHost = envoy.NewVirtualHostWithExtAuthz(ruleName, contextExtensions, domainsForRule(rule), routes)
			if len(tlsRoutes) != 0 {
				virtualTLSHost = envoy.NewVirtualHostWithExtAuthz(ruleName, contextExtensions, domainsForRule(rule), tlsRoutes)
			}
		} else {
			virtualHost = envoy.NewVirtualHost(ruleName, domainsForRule(rule), routes)
			if len(tlsRoutes) != 0 {
				virtualTLSHost = envoy.NewVirtualHost(ruleName, domainsForRule(rule), tlsRoutes)
			}
		}

		internalHosts = append(internalHosts, virtualHost)
		if rule.Visibility == v1alpha1.IngressVisibilityExternalIP {
			externalHosts = append(externalHosts, virtualHost)
			if virtualTLSHost != nil {
				externalTLSHosts = append(externalTLSHosts, virtualTLSHost)
			}
		}
	}

	return &translatedIngress{
		name: types.NamespacedName{
			Namespace: ingress.Namespace,
			Name:      ingress.Name,
		},
		sniMatches:              sniMatches,
		clusters:                clusters,
		externalVirtualHosts:    externalHosts,
		externalTLSVirtualHosts: externalTLSHosts,
		internalVirtualHosts:    internalHosts,
	}, nil
}

func trackSecret(t tracker.Interface, ns, name string, ingress *v1alpha1.Ingress) error {
	return t.TrackReference(tracker.Reference{
		Kind:       "Secret",
		APIVersion: "v1",
		Namespace:  ns,
		Name:       name,
	}, ingress)
}

func trackService(t tracker.Interface, svcNs, svcName string, ingress *v1alpha1.Ingress) error {
	if err := t.TrackReference(tracker.Reference{
		Kind:       "Service",
		APIVersion: "v1",
		Namespace:  svcNs,
		Name:       svcName,
	}, ingress); err != nil {
		return fmt.Errorf("could not track service reference: %w", err)
	}

	if err := t.TrackReference(tracker.Reference{
		Kind:       "Endpoints",
		APIVersion: "v1",
		Namespace:  svcNs,
		Name:       svcName,
	}, ingress); err != nil {
		return fmt.Errorf("could not track endpoints reference: %w", err)
	}
	return nil
}

func lbEndpointsForKubeEndpoints(kubeEndpoints *corev1.Endpoints, targetPort int32) []*endpoint.LbEndpoint {
	var readyAddressCount int
	for _, subset := range kubeEndpoints.Subsets {
		readyAddressCount += len(subset.Addresses)
	}

	if readyAddressCount == 0 {
		return nil
	}

	eps := make([]*endpoint.LbEndpoint, 0, readyAddressCount)
	for _, subset := range kubeEndpoints.Subsets {
		for _, address := range subset.Addresses {
			eps = append(eps, envoy.NewLBEndpoint(address.IP, uint32(targetPort)))
		}
	}

	return eps
}

func matchHeadersFromHTTPPath(httpPath v1alpha1.HTTPIngressPath) []*route.HeaderMatcher {
	matchHeaders := make([]*route.HeaderMatcher, 0, len(httpPath.Headers))

	for header, matchType := range httpPath.Headers {
		matchHeader := &route.HeaderMatcher{
			Name: header,
		}
		if matchType.Exact != "" {
			matchHeader.HeaderMatchSpecifier = &route.HeaderMatcher_ExactMatch{
				ExactMatch: matchType.Exact,
			}
		}
		matchHeaders = append(matchHeaders, matchHeader)
	}
	return matchHeaders
}

// domainsForRule returns all domains for the given rule.
//
// For example, external domains returns domains with the following formats:
// 	- sub-route_host.namespace.example.com
// 	- sub-route_host.namespace.example.com:*
//
// Somehow envoy doesn't match properly gRPC authorities with ports.
// The fix is to include ":*" in the domains.
// This applies both for internal and external domains.
// More info https://github.com/envoyproxy/envoy/issues/886
func domainsForRule(rule v1alpha1.IngressRule) []string {
	domains := make([]string, 0, 2*len(rule.Hosts))
	for _, host := range rule.Hosts {
		domains = append(domains, host, host+":*")
	}
	return domains
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru 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 main

import (
	"flag"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/app"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	_ "github.com/globocom/tsuru/provision/docker"
	_ "github.com/globocom/tsuru/provision/juju"
	_ "github.com/globocom/tsuru/provision/local"
	stdlog "log"
	"log/syslog"
	"os"
	"time"
)

func collect(ticker <-chan time.Time) {
	for _ = range ticker {
		units, err := app.Provisioner.CollectStatus()
		if err != nil {
			log.Printf("Failed to collect status within the provisioner: %s.", err)
		}
		update(units)
	}
}

func fatal(err error) {
	fmt.Fprintln(os.Stderr, err)
	log.Fatal(err)
}

func main() {
	var (
		configFile string
		dry        bool
	)
	logger, err := syslog.NewLogger(syslog.LOG_INFO, stdlog.LstdFlags)
	if err != nil {
		stdlog.Fatal(err)
	}
	log.SetLogger(logger)
	flag.StringVar(&configFile, "config", "/etc/tsuru/tsuru.conf", "tsuru config file")
	flag.BoolVar(&dry, "dry", false, "dry-run: does not start the agent (for testing purposes)")
	flag.Parse()
	err = config.ReadAndWatchConfigFile(configFile)
	if err != nil {
		fatal(err)
	}
	connString, err := config.GetString("database:url")
	if err != nil {
		fatal(err)
	}
	dbName, err := config.GetString("database:name")
	if err != nil {
		fatal(err)
	}
	fmt.Printf("Using the database %q from the server %q.\n\n", dbName, connString)

	if !dry {
		provisioner, err := config.GetString("provisioner")
		if err != nil {
			fmt.Printf("Warning: %q didn't declare a provisioner, using default provisioner.\n", configFile)
			provisioner = "juju"
		}
		app.Provisioner, err = provision.Get(provisioner)
		if err != nil {
			fatal(err)
		}
		fmt.Printf("Using %q provisioner.\n\n", provisioner)

		ticker := time.Tick(time.Minute)
		fmt.Println("tsuru collector agent started...")
		collect(ticker)
	}
}
<commit_msg>fixed lxc import.<commit_after>// Copyright 2013 tsuru 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 main

import (
	"flag"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/app"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	_ "github.com/globocom/tsuru/provision/docker"
	_ "github.com/globocom/tsuru/provision/juju"
	_ "github.com/globocom/tsuru/provision/lxc"
	stdlog "log"
	"log/syslog"
	"os"
	"time"
)

func collect(ticker <-chan time.Time) {
	for _ = range ticker {
		units, err := app.Provisioner.CollectStatus()
		if err != nil {
			log.Printf("Failed to collect status within the provisioner: %s.", err)
		}
		update(units)
	}
}

func fatal(err error) {
	fmt.Fprintln(os.Stderr, err)
	log.Fatal(err)
}

func main() {
	var (
		configFile string
		dry        bool
	)
	logger, err := syslog.NewLogger(syslog.LOG_INFO, stdlog.LstdFlags)
	if err != nil {
		stdlog.Fatal(err)
	}
	log.SetLogger(logger)
	flag.StringVar(&configFile, "config", "/etc/tsuru/tsuru.conf", "tsuru config file")
	flag.BoolVar(&dry, "dry", false, "dry-run: does not start the agent (for testing purposes)")
	flag.Parse()
	err = config.ReadAndWatchConfigFile(configFile)
	if err != nil {
		fatal(err)
	}
	connString, err := config.GetString("database:url")
	if err != nil {
		fatal(err)
	}
	dbName, err := config.GetString("database:name")
	if err != nil {
		fatal(err)
	}
	fmt.Printf("Using the database %q from the server %q.\n\n", dbName, connString)

	if !dry {
		provisioner, err := config.GetString("provisioner")
		if err != nil {
			fmt.Printf("Warning: %q didn't declare a provisioner, using default provisioner.\n", configFile)
			provisioner = "juju"
		}
		app.Provisioner, err = provision.Get(provisioner)
		if err != nil {
			fatal(err)
		}
		fmt.Printf("Using %q provisioner.\n\n", provisioner)

		ticker := time.Tick(time.Minute)
		fmt.Println("tsuru collector agent started...")
		collect(ticker)
	}
}
<|endoftext|>


<commit_before>package command

import (
	"github.com/mitchellh/go-homedir"
	"log"
	"path"
)

// BaseURL is the base url of gost api services
var BaseURL = "http://localhost:8000/"

// WebURL is the base url of gost web services
var WebURL = "http://localhost:3000/"

const config = ".gostrc"

// ConfigFile is the true path of config file `.gostrc`
var ConfigFile string

func init() {
	home, err := homedir.Dir()
	if err != nil {
		log.Fatal("An error occured when get user home!")
	}
	ConfigFile = path.Join(home, config)
}
<commit_msg>fix misspelling<commit_after>package command

import (
	"github.com/mitchellh/go-homedir"
	"log"
	"path"
)

// BaseURL is the base url of gost api services
var BaseURL = "http://localhost:8000/"

// WebURL is the base url of gost web services
var WebURL = "http://localhost:3000/"

const config = ".gostrc"

// ConfigFile is the true path of config file `.gostrc`
var ConfigFile string

func init() {
	home, err := homedir.Dir()
	if err != nil {
		log.Fatal("An error occurred when get user home!")
	}
	ConfigFile = path.Join(home, config)
}
<|endoftext|>


<commit_before>package command

import (
	"flag"
	"fmt"
	"strings"
)

// OutputCommand is a Command implementation that reads an output
// from a Terraform state and prints it.
type OutputCommand struct {
	Meta
}

func (c *OutputCommand) Run(args []string) int {
	args = c.Meta.process(args, false)

	var module string
	cmdFlags := flag.NewFlagSet("output", flag.ContinueOnError)
	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&module, "module", "", "module")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }

	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) != 1 || args[0] == "" {
		c.Ui.Error(
			"The output command expects exactly one argument with the name\n" +
				"of an output variable.\n")
		cmdFlags.Usage()
		return 1
	}
	name := args[0]

	stateStore, err := c.Meta.State()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error reading state: %s", err))
		return 1
	}

	if module == "" {
		module = "root"
	} else {
		module = "root." + module
	}

	// Get the proper module we want to get outputs for
	modPath := strings.Split(module, ".")

	state := stateStore.State()
	mod := state.ModuleByPath(modPath)

	if mod == nil {
		c.Ui.Error(fmt.Sprintf(
			"The module %s could not be found. There is nothing to taint.",
			module))
		return 1
	}

	if state.Empty() || len(mod.Outputs) == 0 {
		c.Ui.Error(fmt.Sprintf(
			"The state file has no outputs defined. Define an output\n" +
				"in your configuration with the `output` directive and re-run\n" +
				"`terraform apply` for it to become available."))
		return 1
	}

	v, ok := mod.Outputs[name]
	if !ok {
		c.Ui.Error(fmt.Sprintf(
			"The output variable requested could not be found in the state\n" +
				"file. If you recently added this to your configuration, be\n" +
				"sure to run `terraform apply`, since the state won't be updated\n" +
				"with new output variables until that command is run."))
		return 1
	}

	c.Ui.Output(v)
	return 0
}

func (c *OutputCommand) Help() string {
	helpText := `
Usage: terraform output [options] NAME

  Reads an output variable from a Terraform state file and prints
  the value.

Options:

  -state=path      Path to the state file to read. Defaults to
                   "terraform.tfstate".

`
	return strings.TrimSpace(helpText)
}

func (c *OutputCommand) Synopsis() string {
	return "Read an output from a state file"
}
<commit_msg>command/output: fix error msg typo<commit_after>package command

import (
	"flag"
	"fmt"
	"strings"
)

// OutputCommand is a Command implementation that reads an output
// from a Terraform state and prints it.
type OutputCommand struct {
	Meta
}

func (c *OutputCommand) Run(args []string) int {
	args = c.Meta.process(args, false)

	var module string
	cmdFlags := flag.NewFlagSet("output", flag.ContinueOnError)
	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&module, "module", "", "module")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }

	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) != 1 || args[0] == "" {
		c.Ui.Error(
			"The output command expects exactly one argument with the name\n" +
				"of an output variable.\n")
		cmdFlags.Usage()
		return 1
	}
	name := args[0]

	stateStore, err := c.Meta.State()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error reading state: %s", err))
		return 1
	}

	if module == "" {
		module = "root"
	} else {
		module = "root." + module
	}

	// Get the proper module we want to get outputs for
	modPath := strings.Split(module, ".")

	state := stateStore.State()
	mod := state.ModuleByPath(modPath)

	if mod == nil {
		c.Ui.Error(fmt.Sprintf(
			"The module %s could not be found. There is nothing to output.",
			module))
		return 1
	}

	if state.Empty() || len(mod.Outputs) == 0 {
		c.Ui.Error(fmt.Sprintf(
			"The state file has no outputs defined. Define an output\n" +
				"in your configuration with the `output` directive and re-run\n" +
				"`terraform apply` for it to become available."))
		return 1
	}

	v, ok := mod.Outputs[name]
	if !ok {
		c.Ui.Error(fmt.Sprintf(
			"The output variable requested could not be found in the state\n" +
				"file. If you recently added this to your configuration, be\n" +
				"sure to run `terraform apply`, since the state won't be updated\n" +
				"with new output variables until that command is run."))
		return 1
	}

	c.Ui.Output(v)
	return 0
}

func (c *OutputCommand) Help() string {
	helpText := `
Usage: terraform output [options] NAME

  Reads an output variable from a Terraform state file and prints
  the value.

Options:

  -state=path      Path to the state file to read. Defaults to
                   "terraform.tfstate".

`
	return strings.TrimSpace(helpText)
}

func (c *OutputCommand) Synopsis() string {
	return "Read an output from a state file"
}
<|endoftext|>