<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"io"
	"os"

	"github.com/juju/juju/cloudconfig/instancecfg"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/tools"
)

// BootstrapParams holds the parameters for bootstrapping an environment.
type BootstrapParams struct {
	// Constraints are used to choose the initial instance specification,
	// and will be stored in the new environment's state.
	Constraints constraints.Value

	// Placement, if non-empty, holds an environment-specific placement
	// directive used to choose the initial instance.
	Placement string

	// AvailableTools is a collection of tools which the Bootstrap method
	// may use to decide which architecture/series to instantiate.
	AvailableTools tools.List

	// ContainerBridgeName, if non-empty, overrides the default
	// network bridge device to use for LXC and KVM containers. See
	// also instancecfg.DefaultBridgeName.
	ContainerBridgeName string
}

// BootstrapFinalizer is a function returned from Environ.Bootstrap.
// The caller must pass a InstanceConfig with the Tools field set.
type BootstrapFinalizer func(BootstrapContext, *instancecfg.InstanceConfig) error

// BootstrapContext is an interface that is passed to
// Environ.Bootstrap, providing a means of obtaining
// information about and manipulating the context in which
// it is being invoked.
type BootstrapContext interface {
	GetStdin() io.Reader
	GetStdout() io.Writer
	GetStderr() io.Writer
	Infof(format string, params ...interface{})
	Verbosef(format string, params ...interface{})

	// InterruptNotify starts watching for interrupt signals
	// on behalf of the caller, sending them to the supplied
	// channel.
	InterruptNotify(sig chan<- os.Signal)

	// StopInterruptNotify undoes the effects of a previous
	// call to InterruptNotify with the same channel. After
	// StopInterruptNotify returns, no more signals will be
	// delivered to the channel.
	StopInterruptNotify(chan<- os.Signal)

	// ShouldVerifyCredentials indicates whether the caller's cloud
	// credentials should be verified.
	ShouldVerifyCredentials() bool
}
<commit_msg>Add environs.BootstrapResult.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"io"
	"os"

	"github.com/juju/juju/cloudconfig/instancecfg"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/tools"
)

// BootstrapParams holds the parameters for bootstrapping an environment.
type BootstrapParams struct {
	// Constraints are used to choose the initial instance specification,
	// and will be stored in the new environment's state.
	Constraints constraints.Value

	// Placement, if non-empty, holds an environment-specific placement
	// directive used to choose the initial instance.
	Placement string

	// AvailableTools is a collection of tools which the Bootstrap method
	// may use to decide which architecture/series to instantiate.
	AvailableTools tools.List

	// ContainerBridgeName, if non-empty, overrides the default
	// network bridge device to use for LXC and KVM containers. See
	// also instancecfg.DefaultBridgeName.
	ContainerBridgeName string
}

// BootstrapFinalizer is a function returned from Environ.Bootstrap.
// The caller must pass a InstanceConfig with the Tools field set.
type BootstrapFinalizer func(BootstrapContext, *instancecfg.InstanceConfig) error

// BootstrapResult holds the data returned by calls to Environ.Bootstrap.
type BootstrapResult struct {
	// Arch is the instance's architecture.
	Arch string

	// Series is the instance's series.
	Series string

	// Finalize is a function that must be called to finalize the
	// bootstrap process by transferring the tools and installing the
	// initial Juju state server.
	Finalize BootstrapFinalizer
}

// BootstrapContext is an interface that is passed to
// Environ.Bootstrap, providing a means of obtaining
// information about and manipulating the context in which
// it is being invoked.
type BootstrapContext interface {
	GetStdin() io.Reader
	GetStdout() io.Writer
	GetStderr() io.Writer
	Infof(format string, params ...interface{})
	Verbosef(format string, params ...interface{})

	// InterruptNotify starts watching for interrupt signals
	// on behalf of the caller, sending them to the supplied
	// channel.
	InterruptNotify(sig chan<- os.Signal)

	// StopInterruptNotify undoes the effects of a previous
	// call to InterruptNotify with the same channel. After
	// StopInterruptNotify returns, no more signals will be
	// delivered to the channel.
	StopInterruptNotify(chan<- os.Signal)

	// ShouldVerifyCredentials indicates whether the caller's cloud
	// credentials should be verified.
	ShouldVerifyCredentials() bool
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
)

func largestRectangleArea(heights []int) int {
	n := len(heights)
	// minHeight[i][j] means the minimum height between [i, j)
	// so area[i][j] = (j-i)*minHeight[i][j]
	minHeight := make([][]int, n+1)
	for i := 0; i <= n; i++ {
		minHeight[i] = make([]int, n+1)
	}
	var maxArea int
	for i := 0; i < n; i++ {
		for j := i + 1; j <= n; j++ {
			if j == i+1 {
				minHeight[i][j] = heights[i]
			} else {
				minHeight[i][j] = int(math.Min(float64(minHeight[i][j-1]), float64(heights[j-1])))
			}
			if (j-i)*minHeight[i][j] > maxArea {
				maxArea = (j - i) * minHeight[i][j]
			}
		}
	}
	return maxArea
}

func main() {
	var h []int
	var expected int
	h, expected = []int{2, 1, 5, 6, 2, 3}, 10
	fmt.Printf("h: %v, expected: %d, actual: %d\n", h, expected, largestRectangleArea(h))
}
<commit_msg>solution(Time Limit Exceed): largest-rectangle-in-histogram<commit_after>package main

import (
	"fmt"
	"math"
)

func largestRectangleArea(heights []int) int {
	n := len(heights)
	// minHeight[i][j] means the minimum height between [i, j)
	// so area[i][j] = (j-i)*minHeight[i][j]
	var maxArea int
	for i := 0; i < n; i++ {
		min := heights[i]
		for j := i + 1; j <= n; j++ {
			min = int(math.Min(float64(min), float64(heights[j-1])))
			if (j-i)*min > maxArea {
				maxArea = (j - i) * min
			}
		}
	}
	return maxArea
}

func main() {
	var h []int
	var expected int
	h, expected = []int{2, 1, 5, 6, 2, 3}, 10
	fmt.Printf("h: %v, expected: %d, actual: %d\n", h, expected, largestRectangleArea(h))
}
<|endoftext|>


<commit_before>package kite

import (
	"errors"
	"fmt"
	"koding/newkite/protocol"
	"net"
	"sync"
	"time"
)

var ErrNoKitesAvailable = errors.New("no kites availabile")

// Kontrol embeds RemoteKite which has additional special helper methods.
type Kontrol struct {
	*RemoteKite

	// used for synchronizing methods that needs to be called after
	// successful connection.
	ready chan bool
}

// NewKontrol returns a pointer to new Kontrol instance.
func (k *Kite) NewKontrol(addr string) *Kontrol {
	// Only the address is required to connect Kontrol
	host, port, _ := net.SplitHostPort(addr)
	kite := protocol.Kite{
		PublicIP: host,
		Port:     port,
		Name:     "kontrol", // for logging purposes
	}

	auth := callAuthentication{
		Type: "kodingKey",
		Key:  k.KodingKey,
	}

	remoteKite := k.NewRemoteKite(kite, auth)
	remoteKite.client.Reconnect = true

	var once sync.Once
	ready := make(chan bool)

	remoteKite.OnConnect(func() {
		k.Log.Info("Connected to Kontrol ")

		// signal all other methods that are listening on this channel, that we
		// are ready.
		once.Do(func() { close(ready) })
	})

	remoteKite.OnDisconnect(func() { k.Log.Warning("Disconnected from Kontrol. I will retry in background...") })

	return &Kontrol{
		RemoteKite: remoteKite,
		ready:      ready,
	}
}

// Register registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() method.
func (k *Kontrol) Register() error {
	response, err := k.RemoteKite.Call("register", nil)
	if err != nil {
		return err
	}

	var rr protocol.RegisterResult
	err = response.Unmarshal(&rr)
	if err != nil {
		return err
	}

	switch rr.Result {
	case protocol.AllowKite:
		kite := &k.localKite.Kite

		// we know now which user that is after authentication
		kite.Username = rr.Username

		// Set the correct PublicIP if left empty in options.
		if kite.PublicIP == "" {
			kite.PublicIP = rr.PublicIP
		}

		k.Log.Info("Registered to kontrol with addr: %s version: %s uuid: %s",
			kite.Addr(), kite.Version, kite.ID)
	case protocol.RejectKite:
		return errors.New("Kite rejected")
	default:
		return fmt.Errorf("Invalid result: %s", rr.Result)
	}

	return nil
}

// WatchKites watches for Kites that matches the query. The onEvent functions
// is called for current kites and every new kite event.
func (k *Kontrol) WatchKites(query protocol.KontrolQuery, onEvent func(*protocol.KiteEvent)) error {
	<-k.ready

	queueEvents := func(r *Request) {
		args := r.Args.MustSliceOfLength(1)

		var event protocol.KiteEvent
		err := args[0].Unmarshal(&event)
		if err != nil {
			k.Log.Error(err.Error())
			return
		}

		onEvent(&event)
	}

	args := []interface{}{query, Callback(queueEvents)}
	remoteKites, err := k.getKites(args...)
	if err != nil && err != ErrNoKitesAvailable {
		return err // return only when something really happened
	}

	// also put the current kites to the eventChan.
	for _, remoteKite := range remoteKites {
		event := protocol.KiteEvent{
			Action: protocol.Register,
			Kite:   remoteKite.Kite,
			Token: &protocol.Token{
				Key: remoteKite.Authentication.Key,
				TTL: int(remoteKite.Authentication.ValidUntil.Sub(time.Now().UTC()) / time.Second),
			},
		}

		onEvent(&event)
	}

	return nil
}

// GetKites returns the list of Kites matching the query. The returned list
// contains ready to connect RemoteKite instances. The caller must connect
// with RemoteKite.Dial() before using each Kite. An error is returned when no
// kites are available.
func (k *Kontrol) GetKites(query protocol.KontrolQuery) ([]*RemoteKite, error) {
	return k.getKites(query)
}

// used internally for GetKites() and WatchKites()
func (k *Kontrol) getKites(args ...interface{}) ([]*RemoteKite, error) {
	<-k.ready

	response, err := k.RemoteKite.Call("getKites", args)
	if err != nil {
		return nil, err
	}

	var kites []protocol.KiteWithToken
	err = response.Unmarshal(&kites)
	if err != nil {
		return nil, err
	}

	if len(kites) == 0 {
		return nil, ErrNoKitesAvailable
	}

	remoteKites := make([]*RemoteKite, len(kites))
	for i, kite := range kites {
		validUntil := time.Now().UTC().Add(time.Duration(kite.Token.TTL) * time.Second)
		auth := callAuthentication{
			Type:       "token",
			Key:        kite.Token.Key,
			ValidUntil: &validUntil,
		}

		remoteKites[i] = k.localKite.NewRemoteKite(kite.Kite, auth)
	}

	return remoteKites, nil
}

// GetToken is used to get a new token for a single Kite.
func (k *Kontrol) GetToken(kite *protocol.Kite) (*protocol.Token, error) {
	<-k.ready

	result, err := k.RemoteKite.Call("getToken", kite)
	if err != nil {
		return nil, err
	}

	var tkn *protocol.Token
	err = result.Unmarshal(&tkn)
	if err != nil {
		return nil, err
	}

	return tkn, nil
}
<commit_msg>kite: code style<commit_after>package kite

import (
	"errors"
	"fmt"
	"koding/newkite/protocol"
	"net"
	"sync"
	"time"
)

var ErrNoKitesAvailable = errors.New("no kites availabile")

// Kontrol embeds RemoteKite which has additional special helper methods.
type Kontrol struct {
	*RemoteKite

	// used for synchronizing methods that needs to be called after
	// successful connection.
	ready chan bool
}

// NewKontrol returns a pointer to new Kontrol instance.
func (k *Kite) NewKontrol(addr string) *Kontrol {
	// Only the address is required to connect Kontrol
	host, port, _ := net.SplitHostPort(addr)
	kite := protocol.Kite{
		PublicIP: host,
		Port:     port,
		Name:     "kontrol", // for logging purposes
	}

	auth := callAuthentication{
		Type: "kodingKey",
		Key:  k.KodingKey,
	}

	remoteKite := k.NewRemoteKite(kite, auth)
	remoteKite.client.Reconnect = true

	var once sync.Once
	ready := make(chan bool)

	remoteKite.OnConnect(func() {
		k.Log.Info("Connected to Kontrol ")

		// signal all other methods that are listening on this channel, that we
		// are ready.
		once.Do(func() { close(ready) })
	})

	remoteKite.OnDisconnect(func() { k.Log.Warning("Disconnected from Kontrol. I will retry in background...") })

	return &Kontrol{
		RemoteKite: remoteKite,
		ready:      ready,
	}
}

// Register registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() method.
func (k *Kontrol) Register() error {
	response, err := k.RemoteKite.Call("register", nil)
	if err != nil {
		return err
	}

	var rr protocol.RegisterResult
	err = response.Unmarshal(&rr)
	if err != nil {
		return err
	}

	switch rr.Result {
	case protocol.AllowKite:
		kite := &k.localKite.Kite

		// we know now which user that is after authentication
		kite.Username = rr.Username

		// Set the correct PublicIP if left empty in options.
		if kite.PublicIP == "" {
			kite.PublicIP = rr.PublicIP
		}

		k.Log.Info("Registered to kontrol with addr: %s version: %s uuid: %s",
			kite.Addr(), kite.Version, kite.ID)
	case protocol.RejectKite:
		return errors.New("Kite rejected")
	default:
		return fmt.Errorf("Invalid result: %s", rr.Result)
	}

	return nil
}

// WatchKites watches for Kites that matches the query. The onEvent functions
// is called for current kites and every new kite event.
func (k *Kontrol) WatchKites(query protocol.KontrolQuery, onEvent func(*protocol.KiteEvent)) error {
	<-k.ready

	queueEvents := func(r *Request) {
		var event protocol.KiteEvent
		err := r.Args.MustSliceOfLength(1)[0].Unmarshal(&event)
		if err != nil {
			k.Log.Error(err.Error())
			return
		}

		onEvent(&event)
	}

	args := []interface{}{query, Callback(queueEvents)}
	remoteKites, err := k.getKites(args...)
	if err != nil && err != ErrNoKitesAvailable {
		return err // return only when something really happened
	}

	// also put the current kites to the eventChan.
	for _, remoteKite := range remoteKites {
		event := protocol.KiteEvent{
			Action: protocol.Register,
			Kite:   remoteKite.Kite,
			Token: &protocol.Token{
				Key: remoteKite.Authentication.Key,
				TTL: int(remoteKite.Authentication.ValidUntil.Sub(time.Now().UTC()) / time.Second),
			},
		}

		onEvent(&event)
	}

	return nil
}

// GetKites returns the list of Kites matching the query. The returned list
// contains ready to connect RemoteKite instances. The caller must connect
// with RemoteKite.Dial() before using each Kite. An error is returned when no
// kites are available.
func (k *Kontrol) GetKites(query protocol.KontrolQuery) ([]*RemoteKite, error) {
	return k.getKites(query)
}

// used internally for GetKites() and WatchKites()
func (k *Kontrol) getKites(args ...interface{}) ([]*RemoteKite, error) {
	<-k.ready

	response, err := k.RemoteKite.Call("getKites", args)
	if err != nil {
		return nil, err
	}

	var kites []protocol.KiteWithToken
	err = response.Unmarshal(&kites)
	if err != nil {
		return nil, err
	}

	if len(kites) == 0 {
		return nil, ErrNoKitesAvailable
	}

	remoteKites := make([]*RemoteKite, len(kites))
	for i, kite := range kites {
		validUntil := time.Now().UTC().Add(time.Duration(kite.Token.TTL) * time.Second)
		auth := callAuthentication{
			Type:       "token",
			Key:        kite.Token.Key,
			ValidUntil: &validUntil,
		}

		remoteKites[i] = k.localKite.NewRemoteKite(kite.Kite, auth)
	}

	return remoteKites, nil
}

// GetToken is used to get a new token for a single Kite.
func (k *Kontrol) GetToken(kite *protocol.Kite) (*protocol.Token, error) {
	<-k.ready

	result, err := k.RemoteKite.Call("getToken", kite)
	if err != nil {
		return nil, err
	}

	var tkn *protocol.Token
	err = result.Unmarshal(&tkn)
	if err != nil {
		return nil, err
	}

	return tkn, nil
}
<|endoftext|>


<commit_before>package server_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/juju/go/cmd/jujuc/server"
	"launchpad.net/juju/go/log"
	stdlog "log"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"text/template"
)

func Test(t *testing.T) { TestingT(t) }

type LogSuite struct{}

var _ = Suite(&LogSuite{})

func pushLog(debug bool) (buf *bytes.Buffer, pop func()) {
	oldTarget, oldDebug := log.Target, log.Debug
	buf = new(bytes.Buffer)
	log.Target, log.Debug = stdlog.New(buf, "", 0), debug
	return buf, func() {
		log.Target, log.Debug = oldTarget, oldDebug
	}
}

func AssertLog(c *C, ctx *server.Context, badge string, logDebug, callDebug, expectMsg bool) {
	buf, pop := pushLog(logDebug)
	defer pop()
	msg := "the chickens are restless"
	ctx.Log(callDebug, msg)
	expect := ""
	if expectMsg {
		var logBadge string
		if callDebug {
			logBadge = "JUJU:DEBUG"
		} else {
			logBadge = "JUJU"
		}
		expect = fmt.Sprintf("%s %s: %s\n", logBadge, badge, msg)
	}
	c.Assert(buf.String(), Equals, expect)
}

func AssertLogs(c *C, ctx *server.Context, badge string) {
	AssertLog(c, ctx, badge, true, true, true)
	AssertLog(c, ctx, badge, true, false, true)
	AssertLog(c, ctx, badge, false, true, false)
	AssertLog(c, ctx, badge, false, false, true)
}

func (s *LogSuite) TestLog(c *C) {
	local := &server.Context{LocalUnitName: "minecraft/0"}
	AssertLogs(c, local, "minecraft/0")
	relation := &server.Context{LocalUnitName: "minecraft/0", RelationName: "bot"}
	AssertLogs(c, relation, "minecraft/0 bot")
}

type ExecSuite struct {
	outPath string
}

var _ = Suite(&ExecSuite{})

var (
	hookTemplate = template.Must(template.New("").Parse(
		`#!/bin/bash
printenv > {{.OutPath}}
exit {{.ExitCode}}
`))
)

type hookArgs struct {
	OutPath  string
	ExitCode int
}

// makeCharm constructs a fake charm dir containing a single named hook with
// permissions perm and exit code code. It returns the charm directory and the
// path to which the hook script will write environment variables.
func makeCharm(c *C, hookName string, perm os.FileMode, code int) (charmDir, outPath string) {
	charmDir = c.MkDir()
	hooksDir := filepath.Join(charmDir, "hooks")
	err := os.Mkdir(hooksDir, 0755)
	c.Assert(err, IsNil)
	hook, err := os.OpenFile(filepath.Join(hooksDir, hookName), os.O_CREATE|os.O_WRONLY, perm)
	c.Assert(err, IsNil)
	defer hook.Close()
	outPath = filepath.Join(c.MkDir(), "hook.out")
	err = hookTemplate.Execute(hook, hookArgs{outPath, code})
	c.Assert(err, IsNil)
	return charmDir, outPath
}

func AssertEnvContains(c *C, lines []string, env map[string]string) {
	for k, v := range env {
		sought := k + "=" + v
		found := false
		for _, line := range lines {
			if line == sought {
				found = true
				continue
			}
		}
		comment := Commentf("expected to find %v among %v", sought, lines)
		c.Assert(found, Equals, true, comment)
	}
}

func AssertEnv(c *C, outPath string, env map[string]string) {
	out, err := ioutil.ReadFile(outPath)
	c.Assert(err, IsNil)
	lines := strings.Split(string(out), "\n")
	AssertEnvContains(c, lines, env)
	AssertEnvContains(c, lines, map[string]string{
		"PATH":                     os.Getenv("PATH"),
		"DEBIAN_FRONTEND":          "noninteractive",
		"APT_LISTCHANGES_FRONTEND": "none",
	})
}

func (s *ExecSuite) TestNoHook(c *C) {
	ctx := &server.Context{}
	err := ctx.RunHook("tree-fell-in-forest", c.MkDir(), "")
	c.Assert(err, IsNil)
}

func (s *ExecSuite) TestNonExecutableHook(c *C) {
	ctx := &server.Context{}
	charmDir, _ := makeCharm(c, "something-happened", 0600, 0)
	err := ctx.RunHook("something-happened", charmDir, "")
	c.Assert(err, ErrorMatches, `exec: ".*/something-happened": permission denied`)
}

func (s *ExecSuite) TestBadHook(c *C) {
	ctx := &server.Context{Id: "ctx-id"}
	charmDir, outPath := makeCharm(c, "occurrence-occurred", 0700, 99)
	socketPath := "/path/to/socket"
	err := ctx.RunHook("occurrence-occurred", charmDir, socketPath)
	c.Assert(err, ErrorMatches, "exit status 99")
	AssertEnv(c, outPath, map[string]string{
		"CHARM_DIR":         charmDir,
		"JUJU_AGENT_SOCKET": socketPath,
		"JUJU_CONTEXT_ID":   "ctx-id",
	})
}

func (s *ExecSuite) TestGoodHookWithVars(c *C) {
	ctx := &server.Context{
		Id:             "some-id",
		LocalUnitName:  "local/99",
		RemoteUnitName: "remote/123",
		RelationName:   "rel",
	}
	charmDir, outPath := makeCharm(c, "something-happened", 0700, 0)
	socketPath := "/path/to/socket"
	err := ctx.RunHook("something-happened", charmDir, socketPath)
	c.Assert(err, IsNil)
	AssertEnv(c, outPath, map[string]string{
		"CHARM_DIR":         charmDir,
		"JUJU_AGENT_SOCKET": socketPath,
		"JUJU_CONTEXT_ID":   "some-id",
		"JUJU_UNIT_NAME":    "local/99",
		"JUJU_REMOTE_UNIT":  "remote/123",
		"JUJU_RELATION":     "rel",
	})
}
<commit_msg>simplify test<commit_after>package server_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/juju/go/cmd/jujuc/server"
	"launchpad.net/juju/go/log"
	stdlog "log"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func Test(t *testing.T) { TestingT(t) }

type LogSuite struct{}

var _ = Suite(&LogSuite{})

func pushLog(debug bool) (buf *bytes.Buffer, pop func()) {
	oldTarget, oldDebug := log.Target, log.Debug
	buf = new(bytes.Buffer)
	log.Target, log.Debug = stdlog.New(buf, "", 0), debug
	return buf, func() {
		log.Target, log.Debug = oldTarget, oldDebug
	}
}

func AssertLog(c *C, ctx *server.Context, badge string, logDebug, callDebug, expectMsg bool) {
	buf, pop := pushLog(logDebug)
	defer pop()
	msg := "the chickens are restless"
	ctx.Log(callDebug, msg)
	expect := ""
	if expectMsg {
		var logBadge string
		if callDebug {
			logBadge = "JUJU:DEBUG"
		} else {
			logBadge = "JUJU"
		}
		expect = fmt.Sprintf("%s %s: %s\n", logBadge, badge, msg)
	}
	c.Assert(buf.String(), Equals, expect)
}

func AssertLogs(c *C, ctx *server.Context, badge string) {
	AssertLog(c, ctx, badge, true, true, true)
	AssertLog(c, ctx, badge, true, false, true)
	AssertLog(c, ctx, badge, false, true, false)
	AssertLog(c, ctx, badge, false, false, true)
}

func (s *LogSuite) TestLog(c *C) {
	local := &server.Context{LocalUnitName: "minecraft/0"}
	AssertLogs(c, local, "minecraft/0")
	relation := &server.Context{LocalUnitName: "minecraft/0", RelationName: "bot"}
	AssertLogs(c, relation, "minecraft/0 bot")
}

type ExecSuite struct {
	outPath string
}

var _ = Suite(&ExecSuite{})

// makeCharm constructs a fake charm dir containing a single named hook with
// permissions perm and exit code code. It returns the charm directory and the
// path to which the hook script will write environment variables.
func makeCharm(c *C, hookName string, perm os.FileMode, code int) (charmDir, outPath string) {
	charmDir = c.MkDir()
	hooksDir := filepath.Join(charmDir, "hooks")
	err := os.Mkdir(hooksDir, 0755)
	c.Assert(err, IsNil)
	hook, err := os.OpenFile(filepath.Join(hooksDir, hookName), os.O_CREATE|os.O_WRONLY, perm)
	c.Assert(err, IsNil)
	defer hook.Close()
	outPath = filepath.Join(c.MkDir(), "hook.out")
	_, err = fmt.Fprintf(hook, "#!/bin/bash\nenv > %s\nexit %d", outPath, code)
	c.Assert(err, IsNil)
	return charmDir, outPath
}

func AssertEnvContains(c *C, lines []string, env map[string]string) {
	for k, v := range env {
		sought := k + "=" + v
		found := false
		for _, line := range lines {
			if line == sought {
				found = true
				continue
			}
		}
		comment := Commentf("expected to find %v among %v", sought, lines)
		c.Assert(found, Equals, true, comment)
	}
}

func AssertEnv(c *C, outPath string, env map[string]string) {
	out, err := ioutil.ReadFile(outPath)
	c.Assert(err, IsNil)
	lines := strings.Split(string(out), "\n")
	AssertEnvContains(c, lines, env)
	AssertEnvContains(c, lines, map[string]string{
		"PATH":                     os.Getenv("PATH"),
		"DEBIAN_FRONTEND":          "noninteractive",
		"APT_LISTCHANGES_FRONTEND": "none",
	})
}

func (s *ExecSuite) TestNoHook(c *C) {
	ctx := &server.Context{}
	err := ctx.RunHook("tree-fell-in-forest", c.MkDir(), "")
	c.Assert(err, IsNil)
}

func (s *ExecSuite) TestNonExecutableHook(c *C) {
	ctx := &server.Context{}
	charmDir, _ := makeCharm(c, "something-happened", 0600, 0)
	err := ctx.RunHook("something-happened", charmDir, "")
	c.Assert(err, ErrorMatches, `exec: ".*/something-happened": permission denied`)
}

func (s *ExecSuite) TestBadHook(c *C) {
	ctx := &server.Context{Id: "ctx-id"}
	charmDir, outPath := makeCharm(c, "occurrence-occurred", 0700, 99)
	socketPath := "/path/to/socket"
	err := ctx.RunHook("occurrence-occurred", charmDir, socketPath)
	c.Assert(err, ErrorMatches, "exit status 99")
	AssertEnv(c, outPath, map[string]string{
		"CHARM_DIR":         charmDir,
		"JUJU_AGENT_SOCKET": socketPath,
		"JUJU_CONTEXT_ID":   "ctx-id",
	})
}

func (s *ExecSuite) TestGoodHookWithVars(c *C) {
	ctx := &server.Context{
		Id:             "some-id",
		LocalUnitName:  "local/99",
		RemoteUnitName: "remote/123",
		RelationName:   "rel",
	}
	charmDir, outPath := makeCharm(c, "something-happened", 0700, 0)
	socketPath := "/path/to/socket"
	err := ctx.RunHook("something-happened", charmDir, socketPath)
	c.Assert(err, IsNil)
	AssertEnv(c, outPath, map[string]string{
		"CHARM_DIR":         charmDir,
		"JUJU_AGENT_SOCKET": socketPath,
		"JUJU_CONTEXT_ID":   "some-id",
		"JUJU_UNIT_NAME":    "local/99",
		"JUJU_REMOTE_UNIT":  "remote/123",
		"JUJU_RELATION":     "rel",
	})
}
<|endoftext|>


<commit_before>package request

import (
	"net"
	"net/url"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
)

// Retryer provides the interface drive the SDK's request retry behavior. The
// Retryer implementation is responsible for implementing exponential backoff,
// and determine if a request API error should be retried.
//
// client.DefaultRetryer is the SDK's default implementation of the Retryer. It
// uses the which uses the Request.IsErrorRetryable and Request.IsErrorThrottle
// methods to determine if the request is retried.
type Retryer interface {
	// RetryRules return the retry delay that should be used by the SDK before
	// making another request attempt for the failed request.
	RetryRules(*Request) time.Duration

	// ShouldRetry returns if the failed request is retryable.
	//
	// Implementations may consider request attempt count when determining if a
	// request is retryable, but the SDK will use MaxRetries to limit the
	// number of attempts a request are made.
	ShouldRetry(*Request) bool

	// MaxRetries is the number of times a request may be retried before
	// failing.
	MaxRetries() int
}

// WithRetryer sets a Retryer value to the given Config returning the Config
// value for chaining. The value must not be nil.
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
	if retryer == nil {
		if cfg.Logger != nil {
			cfg.Logger.Log("ERROR: Request.WithRetryer called with nil retryer. Replacing with retry disabled Retryer.")
		}
		retryer = noOpRetryer{}
	}
	cfg.Retryer = retryer
	return cfg

}

// noOpRetryer is a internal no op retryer used when a request is created
// without a retryer.
//
// Provides a retryer that performs no retries.
// It should be used when we do not want retries to be performed.
type noOpRetryer struct{}

// MaxRetries returns the number of maximum returns the service will use to make
// an individual API; For NoOpRetryer the MaxRetries will always be zero.
func (d noOpRetryer) MaxRetries() int {
	return 0
}

// ShouldRetry will always return false for NoOpRetryer, as it should never retry.
func (d noOpRetryer) ShouldRetry(_ *Request) bool {
	return false
}

// RetryRules returns the delay duration before retrying this request again;
// since NoOpRetryer does not retry, RetryRules always returns 0.
func (d noOpRetryer) RetryRules(_ *Request) time.Duration {
	return 0
}

// retryableCodes is a collection of service response codes which are retry-able
// without any further action.
var retryableCodes = map[string]struct{}{
	ErrCodeRequestError:       {},
	"RequestTimeout":          {},
	ErrCodeResponseTimeout:    {},
	"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
}

var throttleCodes = map[string]struct{}{
	"ProvisionedThroughputExceededException": {},
	"ThrottledException":                     {}, // SNS, XRay, ResourceGroupsTagging API
	"Throttling":                             {},
	"ThrottlingException":                    {},
	"RequestLimitExceeded":                   {},
	"RequestThrottled":                       {},
	"RequestThrottledException":              {},
	"TooManyRequestsException":               {}, // Lambda functions
	"PriorRequestNotComplete":                {}, // Route53
	"TransactionInProgressException":         {},
	"EC2ThrottledException":                  {}, // EC2
}

// credsExpiredCodes is a collection of error codes which signify the credentials
// need to be refreshed. Expired tokens require refreshing of credentials, and
// resigning before the request can be retried.
var credsExpiredCodes = map[string]struct{}{
	"ExpiredToken":          {},
	"ExpiredTokenException": {},
	"RequestExpired":        {}, // EC2 Only
}

func isCodeThrottle(code string) bool {
	_, ok := throttleCodes[code]
	return ok
}

func isCodeRetryable(code string) bool {
	if _, ok := retryableCodes[code]; ok {
		return true
	}

	return isCodeExpiredCreds(code)
}

func isCodeExpiredCreds(code string) bool {
	_, ok := credsExpiredCodes[code]
	return ok
}

var validParentCodes = map[string]struct{}{
	ErrCodeSerialization: {},
	ErrCodeRead:          {},
}

func isNestedErrorRetryable(parentErr awserr.Error) bool {
	if parentErr == nil {
		return false
	}

	if _, ok := validParentCodes[parentErr.Code()]; !ok {
		return false
	}

	err := parentErr.OrigErr()
	if err == nil {
		return false
	}

	if aerr, ok := err.(awserr.Error); ok {
		return isCodeRetryable(aerr.Code())
	}

	if t, ok := err.(temporary); ok {
		return t.Temporary() || isErrConnectionReset(err)
	}

	return isErrConnectionReset(err)
}

// IsErrorRetryable returns whether the error is retryable, based on its Code.
// Returns false if error is nil.
func IsErrorRetryable(err error) bool {
	if err == nil {
		return false
	}
	return shouldRetryError(err)
}

type temporary interface {
	Temporary() bool
}

func shouldRetryError(origErr error) bool {
	switch err := origErr.(type) {
	case awserr.Error:
		if err.Code() == CanceledErrorCode {
			return false
		}
		if isNestedErrorRetryable(err) {
			return true
		}

		origErr := err.OrigErr()
		var shouldRetry bool
		if origErr != nil {
			shouldRetry = shouldRetryError(origErr)
			if err.Code() == ErrCodeRequestError && !shouldRetry {
				return false
			}
		}
		if isCodeRetryable(err.Code()) {
			return true
		}
		return shouldRetry

	case *url.Error:
		if strings.Contains(err.Error(), "connection refused") {
			// Refused connections should be retried as the service may not yet
			// be running on the port. Go TCP dial considers refused
			// connections as not temporary.
			return true
		}
		// *url.Error only implements Temporary after golang 1.6 but since
		// url.Error only wraps the error:
		return shouldRetryError(err.Err)

	case temporary:
		if netErr, ok := err.(*net.OpError); ok && netErr.Op == "dial" {
			return true
		}
		// If the error is temporary, we want to allow continuation of the
		// retry process
		return err.Temporary() || isErrConnectionReset(origErr)

	case nil:
		// `awserr.Error.OrigErr()` can be nil, meaning there was an error but
		// because we don't know the cause, it is marked as retryable. See
		// TestRequest4xxUnretryable for an example.
		return true

	default:
		switch err.Error() {
		case "net/http: request canceled",
			"net/http: request canceled while waiting for connection":
			// known 1.5 error case when an http request is cancelled
			return false
		}
		// here we don't know the error; so we allow a retry.
		return true
	}
}

// IsErrorThrottle returns whether the error is to be throttled based on its code.
// Returns false if error is nil.
func IsErrorThrottle(err error) bool {
	if aerr, ok := err.(awserr.Error); ok && aerr != nil {
		return isCodeThrottle(aerr.Code())
	}
	return false
}

// IsErrorExpiredCreds returns whether the error code is a credential expiry
// error. Returns false if error is nil.
func IsErrorExpiredCreds(err error) bool {
	if aerr, ok := err.(awserr.Error); ok && aerr != nil {
		return isCodeExpiredCreds(aerr.Code())
	}
	return false
}

// IsErrorRetryable returns whether the error is retryable, based on its Code.
// Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorRetryable
func (r *Request) IsErrorRetryable() bool {
	if isErrCode(r.Error, r.RetryErrorCodes) {
		return true
	}

	// HTTP response status code 501 should not be retried.
	// 501 represents Not Implemented which means the request method is not
	// supported by the server and cannot be handled.
	if r.HTTPResponse != nil {
		// HTTP response status code 500 represents internal server error and
		// should be retried without any throttle.
		if r.HTTPResponse.StatusCode == 500 {
			return true
		}
	}
	return IsErrorRetryable(r.Error)
}

// IsErrorThrottle returns whether the error is to be throttled based on its
// code. Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorThrottle
func (r *Request) IsErrorThrottle() bool {
	if isErrCode(r.Error, r.ThrottleErrorCodes) {
		return true
	}

	if r.HTTPResponse != nil {
		switch r.HTTPResponse.StatusCode {
		case
			429, // error caused due to too many requests
			502, // Bad Gateway error should be throttled
			503, // caused when service is unavailable
			504: // error occurred due to gateway timeout
			return true
		}
	}

	return IsErrorThrottle(r.Error)
}

func isErrCode(err error, codes []string) bool {
	if aerr, ok := err.(awserr.Error); ok && aerr != nil {
		for _, code := range codes {
			if code == aerr.Code() {
				return true
			}
		}
	}

	return false
}

// IsErrorExpired returns whether the error code is a credential expiry error.
// Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorExpiredCreds
func (r *Request) IsErrorExpired() bool {
	return IsErrorExpiredCreds(r.Error)
}
<commit_msg>Fix word repetition in comment (#4304)<commit_after>package request

import (
	"net"
	"net/url"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
)

// Retryer provides the interface drive the SDK's request retry behavior. The
// Retryer implementation is responsible for implementing exponential backoff,
// and determine if a request API error should be retried.
//
// client.DefaultRetryer is the SDK's default implementation of the Retryer. It
// uses the Request.IsErrorRetryable and Request.IsErrorThrottle methods to
// determine if the request is retried.
type Retryer interface {
	// RetryRules return the retry delay that should be used by the SDK before
	// making another request attempt for the failed request.
	RetryRules(*Request) time.Duration

	// ShouldRetry returns if the failed request is retryable.
	//
	// Implementations may consider request attempt count when determining if a
	// request is retryable, but the SDK will use MaxRetries to limit the
	// number of attempts a request are made.
	ShouldRetry(*Request) bool

	// MaxRetries is the number of times a request may be retried before
	// failing.
	MaxRetries() int
}

// WithRetryer sets a Retryer value to the given Config returning the Config
// value for chaining. The value must not be nil.
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
	if retryer == nil {
		if cfg.Logger != nil {
			cfg.Logger.Log("ERROR: Request.WithRetryer called with nil retryer. Replacing with retry disabled Retryer.")
		}
		retryer = noOpRetryer{}
	}
	cfg.Retryer = retryer
	return cfg

}

// noOpRetryer is a internal no op retryer used when a request is created
// without a retryer.
//
// Provides a retryer that performs no retries.
// It should be used when we do not want retries to be performed.
type noOpRetryer struct{}

// MaxRetries returns the number of maximum returns the service will use to make
// an individual API; For NoOpRetryer the MaxRetries will always be zero.
func (d noOpRetryer) MaxRetries() int {
	return 0
}

// ShouldRetry will always return false for NoOpRetryer, as it should never retry.
func (d noOpRetryer) ShouldRetry(_ *Request) bool {
	return false
}

// RetryRules returns the delay duration before retrying this request again;
// since NoOpRetryer does not retry, RetryRules always returns 0.
func (d noOpRetryer) RetryRules(_ *Request) time.Duration {
	return 0
}

// retryableCodes is a collection of service response codes which are retry-able
// without any further action.
var retryableCodes = map[string]struct{}{
	ErrCodeRequestError:       {},
	"RequestTimeout":          {},
	ErrCodeResponseTimeout:    {},
	"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
}

var throttleCodes = map[string]struct{}{
	"ProvisionedThroughputExceededException": {},
	"ThrottledException":                     {}, // SNS, XRay, ResourceGroupsTagging API
	"Throttling":                             {},
	"ThrottlingException":                    {},
	"RequestLimitExceeded":                   {},
	"RequestThrottled":                       {},
	"RequestThrottledException":              {},
	"TooManyRequestsException":               {}, // Lambda functions
	"PriorRequestNotComplete":                {}, // Route53
	"TransactionInProgressException":         {},
	"EC2ThrottledException":                  {}, // EC2
}

// credsExpiredCodes is a collection of error codes which signify the credentials
// need to be refreshed. Expired tokens require refreshing of credentials, and
// resigning before the request can be retried.
var credsExpiredCodes = map[string]struct{}{
	"ExpiredToken":          {},
	"ExpiredTokenException": {},
	"RequestExpired":        {}, // EC2 Only
}

func isCodeThrottle(code string) bool {
	_, ok := throttleCodes[code]
	return ok
}

func isCodeRetryable(code string) bool {
	if _, ok := retryableCodes[code]; ok {
		return true
	}

	return isCodeExpiredCreds(code)
}

func isCodeExpiredCreds(code string) bool {
	_, ok := credsExpiredCodes[code]
	return ok
}

var validParentCodes = map[string]struct{}{
	ErrCodeSerialization: {},
	ErrCodeRead:          {},
}

func isNestedErrorRetryable(parentErr awserr.Error) bool {
	if parentErr == nil {
		return false
	}

	if _, ok := validParentCodes[parentErr.Code()]; !ok {
		return false
	}

	err := parentErr.OrigErr()
	if err == nil {
		return false
	}

	if aerr, ok := err.(awserr.Error); ok {
		return isCodeRetryable(aerr.Code())
	}

	if t, ok := err.(temporary); ok {
		return t.Temporary() || isErrConnectionReset(err)
	}

	return isErrConnectionReset(err)
}

// IsErrorRetryable returns whether the error is retryable, based on its Code.
// Returns false if error is nil.
func IsErrorRetryable(err error) bool {
	if err == nil {
		return false
	}
	return shouldRetryError(err)
}

type temporary interface {
	Temporary() bool
}

func shouldRetryError(origErr error) bool {
	switch err := origErr.(type) {
	case awserr.Error:
		if err.Code() == CanceledErrorCode {
			return false
		}
		if isNestedErrorRetryable(err) {
			return true
		}

		origErr := err.OrigErr()
		var shouldRetry bool
		if origErr != nil {
			shouldRetry = shouldRetryError(origErr)
			if err.Code() == ErrCodeRequestError && !shouldRetry {
				return false
			}
		}
		if isCodeRetryable(err.Code()) {
			return true
		}
		return shouldRetry

	case *url.Error:
		if strings.Contains(err.Error(), "connection refused") {
			// Refused connections should be retried as the service may not yet
			// be running on the port. Go TCP dial considers refused
			// connections as not temporary.
			return true
		}
		// *url.Error only implements Temporary after golang 1.6 but since
		// url.Error only wraps the error:
		return shouldRetryError(err.Err)

	case temporary:
		if netErr, ok := err.(*net.OpError); ok && netErr.Op == "dial" {
			return true
		}
		// If the error is temporary, we want to allow continuation of the
		// retry process
		return err.Temporary() || isErrConnectionReset(origErr)

	case nil:
		// `awserr.Error.OrigErr()` can be nil, meaning there was an error but
		// because we don't know the cause, it is marked as retryable. See
		// TestRequest4xxUnretryable for an example.
		return true

	default:
		switch err.Error() {
		case "net/http: request canceled",
			"net/http: request canceled while waiting for connection":
			// known 1.5 error case when an http request is cancelled
			return false
		}
		// here we don't know the error; so we allow a retry.
		return true
	}
}

// IsErrorThrottle returns whether the error is to be throttled based on its code.
// Returns false if error is nil.
func IsErrorThrottle(err error) bool {
	if aerr, ok := err.(awserr.Error); ok && aerr != nil {
		return isCodeThrottle(aerr.Code())
	}
	return false
}

// IsErrorExpiredCreds returns whether the error code is a credential expiry
// error. Returns false if error is nil.
func IsErrorExpiredCreds(err error) bool {
	if aerr, ok := err.(awserr.Error); ok && aerr != nil {
		return isCodeExpiredCreds(aerr.Code())
	}
	return false
}

// IsErrorRetryable returns whether the error is retryable, based on its Code.
// Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorRetryable
func (r *Request) IsErrorRetryable() bool {
	if isErrCode(r.Error, r.RetryErrorCodes) {
		return true
	}

	// HTTP response status code 501 should not be retried.
	// 501 represents Not Implemented which means the request method is not
	// supported by the server and cannot be handled.
	if r.HTTPResponse != nil {
		// HTTP response status code 500 represents internal server error and
		// should be retried without any throttle.
		if r.HTTPResponse.StatusCode == 500 {
			return true
		}
	}
	return IsErrorRetryable(r.Error)
}

// IsErrorThrottle returns whether the error is to be throttled based on its
// code. Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorThrottle
func (r *Request) IsErrorThrottle() bool {
	if isErrCode(r.Error, r.ThrottleErrorCodes) {
		return true
	}

	if r.HTTPResponse != nil {
		switch r.HTTPResponse.StatusCode {
		case
			429, // error caused due to too many requests
			502, // Bad Gateway error should be throttled
			503, // caused when service is unavailable
			504: // error occurred due to gateway timeout
			return true
		}
	}

	return IsErrorThrottle(r.Error)
}

func isErrCode(err error, codes []string) bool {
	if aerr, ok := err.(awserr.Error); ok && aerr != nil {
		for _, code := range codes {
			if code == aerr.Code() {
				return true
			}
		}
	}

	return false
}

// IsErrorExpired returns whether the error code is a credential expiry error.
// Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorExpiredCreds
func (r *Request) IsErrorExpired() bool {
	return IsErrorExpiredCreds(r.Error)
}
<|endoftext|>


<commit_before>package models

import "time"

type Permission struct {
	// unique identifier of the channel
	Id int64 `json:"id,string"`

	// name of the permission
	Name string `json:"name"`

	// admin, moderator, member, guest
	RoleConstant string `json:"roleConstant"`

	// Id of the channel
	ChannelId int64 `json:"channelId,string"       sql:"NOT NULL"`

	// Status of the permission in the channel
	// Allowed/Disallowed
	StatusConstant string `json:"statusConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation date of permission
	CreatedAt time.Time `json:"createdAt"          sql:"NOT NULL"`

	// Modification date of the permission
	UpdatedAt time.Time `json:"updatedAt"          sql:"NOT NULL"`
}
<commit_msg>Social: added new constants for permission table<commit_after>package models

import "time"
var (
	Permission_ROLE_SUPERADMIN = "superadmin"
	Permission_ROLE_ADMIN      = "admin"
	Permission_ROLE_MODERATOR  = "moderator"
	Permission_ROLE_MEMBER     = "member"
	Permission_ROLE_GUEST      = "guest"
)

var (
	Permission_STATUS_ALLOWED    = "allowed"
	Permission_STATUS_DISALLOWED = "disallowed"
)

type Permission struct {
	// unique identifier of the channel
	Id int64 `json:"id,string"`

	// name of the permission
	Name string `json:"name"`

	// admin, moderator, member, guest
	RoleConstant string `json:"roleConstant"`

	// Id of the channel
	ChannelId int64 `json:"channelId,string"       sql:"NOT NULL"`

	// Status of the permission in the channel
	// Allowed/Disallowed
	StatusConstant string `json:"statusConstant"   sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation date of permission
	CreatedAt time.Time `json:"createdAt"          sql:"NOT NULL"`

	// Modification date of the permission
	UpdatedAt time.Time `json:"updatedAt"          sql:"NOT NULL"`
}
<|endoftext|>


<commit_before>// +build heroku

package main

import (
	"log"
	"net/http"
	"os"

	_ "github.com/lib/pq"

	"github.com/psimika/secure-web-app/petfind/postgres"
	"github.com/psimika/secure-web-app/web"
)

// This is an implementation of make.go that is specific to Heroku as indicated
// by the build tag. The build tag means that on Heroku the main_heroku.go will
// be built and on any other case main.go will be built instead.
//
// In order to deploy to Heroku for the first time we need these steps:
//
//     heroku login
//
//     heroku create
//
//     heroku addons:create heroku-postgresql:hobby-dev
//
// After that and each time we make a change on master branch:
//
//     git push heroku master
//
// Or when working on a different branch:
//
//     git push heroku somebranch:master

func main() {
	// Heroku uses the environment variables DATABASE_URL and PORT so that the
	// app knows on which database to connect and on which port to listen on.
	// Heroku deploys the application under /app.
	var (
		databaseURL = setDefaultIfEmpty("", os.Getenv("DATABASE_URL"))
		port        = setDefaultIfEmpty("8080", os.Getenv("PORT"))
		tmplPath    = setDefaultIfEmpty("/app/web", os.Getenv("TMPL_PATH"))
	)

	if databaseURL == "" {
		log.Fatal("No database URL provided, exiting...")
	}

	store, err := postgres.NewStore(databaseURL)
	if err != nil {
		log.Println("NewStore failed:", err)
		return
	}

	handlers, err := web.NewServer(tmplPath, store, true)
	if err != nil {
		log.Println("NewServer failed:", err)
		return
	}

	//log.Fatal(http.ListenAndServe(":"+port, handlers))
	log.Fatal(http.ListenAndServe(":"+port, redirectHTTP(handlers)))
}

func setDefaultIfEmpty(defaultValue, value string) string {
	if value == "" {
		return defaultValue
	}
	return value
}

func redirectHTTP(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.TLS != nil || r.Host == "" {
			http.NotFound(w, r)
			return
		}

		u := r.URL
		u.Host = r.Host
		u.Scheme = "https"
		http.Redirect(w, r, u.String(), http.StatusFound)
		//h.ServeHTTP(w, r)
	})
}
<commit_msg>Debug heroku forwarded port<commit_after>// +build heroku

package main

import (
	"log"
	"net/http"
	"os"

	_ "github.com/lib/pq"

	"github.com/psimika/secure-web-app/petfind/postgres"
	"github.com/psimika/secure-web-app/web"
)

// This is an implementation of make.go that is specific to Heroku as indicated
// by the build tag. The build tag means that on Heroku the main_heroku.go will
// be built and on any other case main.go will be built instead.
//
// In order to deploy to Heroku for the first time we need these steps:
//
//     heroku login
//
//     heroku create
//
//     heroku addons:create heroku-postgresql:hobby-dev
//
// After that and each time we make a change on master branch:
//
//     git push heroku master
//
// Or when working on a different branch:
//
//     git push heroku somebranch:master

func main() {
	// Heroku uses the environment variables DATABASE_URL and PORT so that the
	// app knows on which database to connect and on which port to listen on.
	// Heroku deploys the application under /app.
	var (
		databaseURL = setDefaultIfEmpty("", os.Getenv("DATABASE_URL"))
		port        = setDefaultIfEmpty("8080", os.Getenv("PORT"))
		tmplPath    = setDefaultIfEmpty("/app/web", os.Getenv("TMPL_PATH"))
	)

	if databaseURL == "" {
		log.Fatal("No database URL provided, exiting...")
	}

	store, err := postgres.NewStore(databaseURL)
	if err != nil {
		log.Println("NewStore failed:", err)
		return
	}

	handlers, err := web.NewServer(tmplPath, store, true)
	if err != nil {
		log.Println("NewServer failed:", err)
		return
	}

	//log.Fatal(http.ListenAndServe(":"+port, handlers))
	log.Fatal(http.ListenAndServe(":"+port, redirectHTTP(handlers)))
}

func setDefaultIfEmpty(defaultValue, value string) string {
	if value == "" {
		return defaultValue
	}
	return value
}

func redirectHTTP(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Println("heroku forwarded port:", r.Header.Get("X-Forwarded-Port"))
		if r.TLS != nil || r.Host == "" {
			http.NotFound(w, r)
			return
		}

		u := r.URL
		u.Host = r.Host
		u.Scheme = "https"
		http.Redirect(w, r, u.String(), http.StatusFound)
		//h.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2017 Red Hat, Inc.
 *
 */

package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"

	"time"

	"github.com/emicklei/go-restful"
	"github.com/libvirt/libvirt-go"
	"github.com/spf13/pflag"
	k8sv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/kubernetes/scheme"
	k8coresv1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/record"

	"kubevirt.io/kubevirt/pkg/api/v1"
	cloudinit "kubevirt.io/kubevirt/pkg/cloud-init"
	configdisk "kubevirt.io/kubevirt/pkg/config-disk"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/pkg/logging"
	"kubevirt.io/kubevirt/pkg/service"
	"kubevirt.io/kubevirt/pkg/virt-handler"
	"kubevirt.io/kubevirt/pkg/virt-handler/rest"
	"kubevirt.io/kubevirt/pkg/virt-handler/virtwrap"
	virt_api "kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/api"
	virtcache "kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/cache"
	virtcli "kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/cli"
	"kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/isolation"
)

type virtHandlerApp struct {
	Service      *service.Service
	HostOverride string
	LibvirtUri   string
	SocketDir    string
	CloudInitDir string
}

func newVirtHandlerApp(host *string, port *int, hostOverride *string, libvirtUri *string, socketDir *string, cloudInitDir *string) *virtHandlerApp {
	if *hostOverride == "" {
		defaultHostName, err := os.Hostname()
		if err != nil {
			panic(err)
		}
		*hostOverride = defaultHostName
	}

	return &virtHandlerApp{
		Service:      service.NewService("virt-handler", host, port),
		HostOverride: *hostOverride,
		LibvirtUri:   *libvirtUri,
		SocketDir:    *socketDir,
		CloudInitDir: *cloudInitDir,
	}
}

func main() {
	logging.InitializeLogging("virt-handler")
	libvirt.EventRegisterDefaultImpl()
	libvirtUri := flag.String("libvirt-uri", "qemu:///system", "Libvirt connection string.")
	host := flag.String("listen", "0.0.0.0", "Address where to listen on")
	port := flag.Int("port", 8185, "Port to listen on")
	hostOverride := flag.String("hostname-override", "", "Kubernetes Pod to monitor for changes")
	socketDir := flag.String("socket-dir", "/var/run/kubevirt", "Directory where to look for sockets for cgroup detection")
	cloudInitDir := flag.String("cloud-init-dir", "/var/run/libvirt/cloud-init-dir", "Base directory for ephemeral cloud init data")
	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
	pflag.Parse()

	app := newVirtHandlerApp(host, port, hostOverride, libvirtUri, socketDir, cloudInitDir)

	log := logging.DefaultLogger()
	log.Info().V(1).Log("hostname", app.HostOverride)

	err := cloudinit.SetLocalDirectory(app.CloudInitDir)
	if err != nil {
		panic(err)
	}

	go func() {
		for {
			if res := libvirt.EventRunDefaultImpl(); res != nil {
				// Report the error somehow or break the loop.
				log.Error().Reason(res).Msg("Listening to libvirt events failed.")
			}
		}
	}()
	domainConn, err := virtcli.NewConnection(app.LibvirtUri, "", "", 10*time.Second)
	if err != nil {
		panic(fmt.Sprintf("failed to connect to libvirtd: %v", err))
	}
	defer domainConn.Close()

	// Create event recorder
	virtCli, err := kubecli.GetKubevirtClient()
	if err != nil {
		panic(err)
	}
	broadcaster := record.NewBroadcaster()
	broadcaster.StartRecordingToSink(&k8coresv1.EventSinkImpl{Interface: virtCli.CoreV1().Events(k8sv1.NamespaceAll)})
	// TODO what is scheme used for in Recorder?
	recorder := broadcaster.NewRecorder(scheme.Scheme, k8sv1.EventSource{Component: "virt-handler", Host: app.HostOverride})

	domainManager, err := virtwrap.NewLibvirtDomainManager(domainConn,
		recorder,
		isolation.NewSocketBasedIsolationDetector(app.SocketDir),
	)
	if err != nil {
		panic(err)
	}

	l, err := labels.Parse(fmt.Sprintf(v1.NodeNameLabel+" in (%s)", app.HostOverride))
	if err != nil {
		panic(err)
	}

	configDiskClient := configdisk.NewConfigDiskClient()

	// Wire VM controller
	vmListWatcher := kubecli.NewListWatchFromClient(virtCli.RestClient(), "vms", k8sv1.NamespaceAll, fields.Everything(), l)
	vmStore, vmQueue, vmController := virthandler.NewVMController(vmListWatcher, domainManager, recorder, *virtCli.RestClient(), virtCli, app.HostOverride, configDiskClient)

	// Wire Domain controller
	domainSharedInformer, err := virtcache.NewSharedInformer(domainConn)
	if err != nil {
		panic(err)
	}
	domainStore, domainController := virthandler.NewDomainController(vmQueue, vmStore, domainSharedInformer, *virtCli.RestClient(), recorder)

	if err != nil {
		panic(err)
	}

	// Bootstrapping. From here on the startup order matters
	stop := make(chan struct{})
	defer close(stop)

	// Start domain controller and wait for Domain cache sync
	domainController.StartInformer(stop)
	domainController.WaitForSync(stop)

	// Poplulate the VM store with known Domains on the host, to get deletes since the last run
	for _, domain := range domainStore.List() {
		d := domain.(*virt_api.Domain)
		vmStore.Add(v1.NewVMReferenceFromNameWithNS(d.ObjectMeta.Namespace, d.ObjectMeta.Name))
	}

	// Watch for VM changes
	vmController.StartInformer(stop)
	vmController.WaitForSync(stop)

	err = configDiskClient.UndefineUnseen(vmStore)
	if err != nil {
		panic(err)
	}

	go domainController.Run(3, stop)
	go vmController.Run(3, stop)

	// TODO add a http handler which provides health check

	// Add websocket route to access consoles remotely
	console := rest.NewConsoleResource(domainConn)
	migrationHostInfo := rest.NewMigrationHostInfo(isolation.NewSocketBasedIsolationDetector(app.SocketDir))
	ws := new(restful.WebService)
	ws.Route(ws.GET("/api/v1/namespaces/{namespace}/vms/{name}/console").To(console.Console))
	ws.Route(ws.GET("/api/v1/namespaces/{namespace}/vms/{name}/migrationHostInfo").To(migrationHostInfo.MigrationHostInfo))
	restful.DefaultContainer.Add(ws)
	server := &http.Server{Addr: app.Service.Address(), Handler: restful.DefaultContainer}
	server.ListenAndServe()
}
<commit_msg>move virt-handler core functionality to the it's app structure<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2017 Red Hat, Inc.
 *
 */

package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"

	"time"

	"github.com/emicklei/go-restful"
	"github.com/libvirt/libvirt-go"
	"github.com/spf13/pflag"
	k8sv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/kubernetes/scheme"
	k8coresv1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/record"

	"kubevirt.io/kubevirt/pkg/api/v1"
	cloudinit "kubevirt.io/kubevirt/pkg/cloud-init"
	configdisk "kubevirt.io/kubevirt/pkg/config-disk"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/pkg/logging"
	"kubevirt.io/kubevirt/pkg/service"
	"kubevirt.io/kubevirt/pkg/virt-handler"
	"kubevirt.io/kubevirt/pkg/virt-handler/rest"
	"kubevirt.io/kubevirt/pkg/virt-handler/virtwrap"
	virt_api "kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/api"
	virtcache "kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/cache"
	virtcli "kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/cli"
	"kubevirt.io/kubevirt/pkg/virt-handler/virtwrap/isolation"
)

type virtHandlerApp struct {
	Service      *service.Service
	HostOverride string
	LibvirtUri   string
	SocketDir    string
	CloudInitDir string
}

func newVirtHandlerApp(host *string, port *int, hostOverride *string, libvirtUri *string, socketDir *string, cloudInitDir *string) *virtHandlerApp {
	if *hostOverride == "" {
		defaultHostName, err := os.Hostname()
		if err != nil {
			panic(err)
		}
		*hostOverride = defaultHostName
	}

	return &virtHandlerApp{
		Service:      service.NewService("virt-handler", host, port),
		HostOverride: *hostOverride,
		LibvirtUri:   *libvirtUri,
		SocketDir:    *socketDir,
		CloudInitDir: *cloudInitDir,
	}
}

func (app *virtHandlerApp) Run() {
	log := logging.DefaultLogger()
	log.Info().V(1).Log("hostname", app.HostOverride)

	err := cloudinit.SetLocalDirectory(app.CloudInitDir)
	if err != nil {
		panic(err)
	}

	go func() {
		for {
			if res := libvirt.EventRunDefaultImpl(); res != nil {
				// Report the error somehow or break the loop.
				log.Error().Reason(res).Msg("Listening to libvirt events failed.")
			}
		}
	}()
	domainConn, err := virtcli.NewConnection(app.LibvirtUri, "", "", 10*time.Second)
	if err != nil {
		panic(fmt.Sprintf("failed to connect to libvirtd: %v", err))
	}
	defer domainConn.Close()

	// Create event recorder
	virtCli, err := kubecli.GetKubevirtClient()
	if err != nil {
		panic(err)
	}
	broadcaster := record.NewBroadcaster()
	broadcaster.StartRecordingToSink(&k8coresv1.EventSinkImpl{Interface: virtCli.CoreV1().Events(k8sv1.NamespaceAll)})
	// TODO what is scheme used for in Recorder?
	recorder := broadcaster.NewRecorder(scheme.Scheme, k8sv1.EventSource{Component: "virt-handler", Host: app.HostOverride})

	domainManager, err := virtwrap.NewLibvirtDomainManager(domainConn,
		recorder,
		isolation.NewSocketBasedIsolationDetector(app.SocketDir),
	)
	if err != nil {
		panic(err)
	}

	l, err := labels.Parse(fmt.Sprintf(v1.NodeNameLabel+" in (%s)", app.HostOverride))
	if err != nil {
		panic(err)
	}

	configDiskClient := configdisk.NewConfigDiskClient()

	// Wire VM controller
	vmListWatcher := kubecli.NewListWatchFromClient(virtCli.RestClient(), "vms", k8sv1.NamespaceAll, fields.Everything(), l)
	vmStore, vmQueue, vmController := virthandler.NewVMController(vmListWatcher, domainManager, recorder, *virtCli.RestClient(), virtCli, app.HostOverride, configDiskClient)

	// Wire Domain controller
	domainSharedInformer, err := virtcache.NewSharedInformer(domainConn)
	if err != nil {
		panic(err)
	}
	domainStore, domainController := virthandler.NewDomainController(vmQueue, vmStore, domainSharedInformer, *virtCli.RestClient(), recorder)

	if err != nil {
		panic(err)
	}

	// Bootstrapping. From here on the startup order matters
	stop := make(chan struct{})
	defer close(stop)

	// Start domain controller and wait for Domain cache sync
	domainController.StartInformer(stop)
	domainController.WaitForSync(stop)

	// Poplulate the VM store with known Domains on the host, to get deletes since the last run
	for _, domain := range domainStore.List() {
		d := domain.(*virt_api.Domain)
		vmStore.Add(v1.NewVMReferenceFromNameWithNS(d.ObjectMeta.Namespace, d.ObjectMeta.Name))
	}

	// Watch for VM changes
	vmController.StartInformer(stop)
	vmController.WaitForSync(stop)

	err = configDiskClient.UndefineUnseen(vmStore)
	if err != nil {
		panic(err)
	}

	go domainController.Run(3, stop)
	go vmController.Run(3, stop)

	// TODO add a http handler which provides health check

	// Add websocket route to access consoles remotely
	console := rest.NewConsoleResource(domainConn)
	migrationHostInfo := rest.NewMigrationHostInfo(isolation.NewSocketBasedIsolationDetector(app.SocketDir))
	ws := new(restful.WebService)
	ws.Route(ws.GET("/api/v1/namespaces/{namespace}/vms/{name}/console").To(console.Console))
	ws.Route(ws.GET("/api/v1/namespaces/{namespace}/vms/{name}/migrationHostInfo").To(migrationHostInfo.MigrationHostInfo))
	restful.DefaultContainer.Add(ws)
	server := &http.Server{Addr: app.Service.Address(), Handler: restful.DefaultContainer}
	server.ListenAndServe()
}

func main() {
	logging.InitializeLogging("virt-handler")
	libvirt.EventRegisterDefaultImpl()
	libvirtUri := flag.String("libvirt-uri", "qemu:///system", "Libvirt connection string.")
	host := flag.String("listen", "0.0.0.0", "Address where to listen on")
	port := flag.Int("port", 8185, "Port to listen on")
	hostOverride := flag.String("hostname-override", "", "Kubernetes Pod to monitor for changes")
	socketDir := flag.String("socket-dir", "/var/run/kubevirt", "Directory where to look for sockets for cgroup detection")
	cloudInitDir := flag.String("cloud-init-dir", "/var/run/libvirt/cloud-init-dir", "Base directory for ephemeral cloud init data")
	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
	pflag.Parse()

	app := newVirtHandlerApp(host, port, hostOverride, libvirtUri, socketDir, cloudInitDir)
	app.Run()
}
<|endoftext|>


<commit_before>// Package jwts is authentication by JWT
package jwts

import (
	"crypto/rsa"
	"io/ioutil"

	"github.com/dgrijalva/jwt-go"
	"github.com/pkg/errors"
)

const (
	// HMAC signing algorithm
	HMAC uint8 = 1
	// RSA signing algorithm
	RSA uint8 = 2
)

// CustomClaims is jwt claim
type CustomClaims struct {
	Option string `json:"option"`
	jwt.StandardClaims
}

// JWTer interface
type JWTer interface {
	CreateBasicToken(t int64, clientID, userName string) (string, error)
	CreateCustomToken(t int64, clientID, userName, option string) (string, error)
	ValidateToken(tokenString string) error
	ValidateTokenWithClaim(tokenString, clientID, userName string) error
	ValidateTokenWithCustomClaim(tokenString, clientID, userName, option string) error
}

// ----------------------------------------------------------------------------
// jwtee
// ----------------------------------------------------------------------------

type jwtee struct {
	audience string
	SigAlgoer
}

// NewJWT returns JWTer interface
func NewJWT(audience string, sigAlgoer SigAlgoer) JWTer {
	return &jwtee{
		audience:  audience,
		SigAlgoer: sigAlgoer,
	}
}

// CreateBasicToken returns basic claim
// - encode Header, Payload, Signature by Base64 and concatenate these with dot
func (j *jwtee) CreateBasicToken(t int64, clientID, userName string) (string, error) {
	token := jwt.NewWithClaims(
		j.SigAlgoer.GetMethod(),
		j.getClaims(t, clientID, userName),
	)
	return j.SigAlgoer.SignedString(token)
}

// CreateToken returns user defined claim
// - encode Header, Payload, Signature by Base64 and concatenate these with dot
func (j *jwtee) CreateCustomToken(t int64, clientID, userName, option string) (string, error) {
	claims := &CustomClaims{
		option,
		j.getClaims(t, clientID, userName),
	}
	token := jwt.NewWithClaims(j.SigAlgoer.GetMethod(), claims)
	return j.SigAlgoer.SignedString(token)
}

// Payload
func (j *jwtee) getClaims(t int64, clientID, userName string) jwt.StandardClaims {
	// Audience  string `json:"aud,omitempty"` // https://login.hiromaily.com
	// ExpiresAt int64  `json:"exp,omitempty"`
	// Id        string `json:"jti,omitempty"`
	// IssuedAt  int64  `json:"iat,omitempty"`
	// Issuer    string `json:"iss,omitempty"` // OAuth client_id
	// NotBefore int64  `json:"nbf,omitempty"`
	// Subject   string `json:"sub,omitempty"` // user name or email
	claims := jwt.StandardClaims{
		Audience: j.audience,
		// ExpiresAt: time.Now().Add(time.Second * 2).Unix(),
		ExpiresAt: t,
		Issuer:    clientID,
		Subject:   userName,
	}
	return claims
}

func (j *jwtee) keyFunc(token *jwt.Token) (interface{}, error) {
	if isValid := j.SigAlgoer.ValidateMethod(token); !isValid {
		return nil, errors.Errorf("unexpected signing method: %v", token.Header["alg"])
	}
	return j.SigAlgoer.GetKey(), nil
}

// ValidateToken validates token string, it may be too strict
func (j *jwtee) ValidateToken(tokenString string) error {
	// token
	token, err := jwt.Parse(tokenString, j.keyFunc)
	if err != nil {
		return err
	} else if !token.Valid {
		return errors.New("token is invalid")
	}
	return nil
}

// ValidateTokenWithClaim validates token by clientID and userName
// may be too strict to check
func (j *jwtee) ValidateTokenWithClaim(tokenString, clientID, userName string) error {
	token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, j.keyFunc)
	if err != nil {
		return err
	} else if !token.Valid {
		return errors.New("token is invalid")
	}

	// validate claim as well
	claims, ok := token.Claims.(*jwt.StandardClaims)
	if !ok {
		return errors.New("fail to validate claim: claims can't be retrieved")
	} else if claims.Issuer != clientID {
		return errors.New("fail to validate claim: issuer is invalid")
	} else if claims.Subject != userName {
		return errors.New("fail to validate claim: subject is invalid")
	}
	return nil
}

// ValidateTokenWithCustomClaim validates token by clientID and userName and option
// may be too strict to check
func (j *jwtee) ValidateTokenWithCustomClaim(tokenString, clientID, userName, option string) error {
	// token
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, j.keyFunc)
	if err != nil {
		return err
	} else if !token.Valid {
		return errors.New("token is invalid")
	}

	// check claim
	claims, ok := token.Claims.(*CustomClaims)
	if !ok {
		return errors.New("fail to validate claim: claims data can't be retrieved")
	} else if claims.Issuer != clientID {
		return errors.New("fail to validate claim: issuer is invalid")
	} else if claims.Subject != userName {
		return errors.New("fail to validate claim: subject is invalid")
	} else if claims.Option != option {
		return errors.New("fail to validate claim: option is invalid")
	}

	return nil
}

// ----------------------------------------------------------------------------
// SigAlgoer
// ----------------------------------------------------------------------------

// SigAlgoer interface
type SigAlgoer interface {
	GetMethod() jwt.SigningMethod
	SignedString(token *jwt.Token) (string, error)
	ValidateMethod(token *jwt.Token) bool
	GetKey() interface{}
}

// ----------------------------------------------------------------------------
// HMAC
// ----------------------------------------------------------------------------
type algoHMAC struct {
	encrypted uint8
	method    jwt.SigningMethod
	secret    string
}

// NewHMAC returns SigAlgoer
func NewHMAC(secret string) SigAlgoer {
	return &algoHMAC{
		encrypted: HMAC,
		method:    jwt.SigningMethodHS256,
		secret:    secret,
	}
}

// GetMethod returns method
func (a *algoHMAC) GetMethod() jwt.SigningMethod {
	return a.method
}

// SignedString returns signed string from toke
func (a *algoHMAC) SignedString(token *jwt.Token) (string, error) {
	return token.SignedString([]byte(a.secret))
}

// ValidateMethod validates method of token
func (a *algoHMAC) ValidateMethod(token *jwt.Token) bool {
	_, ok := token.Method.(*jwt.SigningMethodHMAC)
	return ok
}

// GetKey returns key
func (a *algoHMAC) GetKey() interface{} {
	return []byte(a.secret)
}

// ----------------------------------------------------------------------------
// RSA
// ----------------------------------------------------------------------------
type algoRSA struct {
	encrypted  uint8
	method     jwt.SigningMethod
	privateKey *rsa.PrivateKey
	publicKey  *rsa.PublicKey
}

// NewRSA returns SigAlgoer interface and error
func NewRSA(privKey, pubKey string) (SigAlgoer, error) {
	privKeyParsed, err := lookupPrivateKey(privKey)
	if err != nil {
		return nil, err
	}
	pubKeyParsed, err := lookupPublicKey(pubKey)
	if err != nil {
		return nil, err
	}

	return &algoRSA{
		encrypted:  RSA,
		method:     jwt.SigningMethodRS256,
		privateKey: privKeyParsed,
		publicKey:  pubKeyParsed,
	}, nil
}

func (a *algoRSA) GetMethod() jwt.SigningMethod {
	return a.method
}

func (a *algoRSA) SignedString(token *jwt.Token) (string, error) {
	return token.SignedString(a.privateKey)
}

func (a *algoRSA) ValidateMethod(token *jwt.Token) bool {
	_, ok := token.Method.(*jwt.SigningMethodRSA)
	return ok
}

func (a *algoRSA) GetKey() interface{} {
	return a.publicKey
}

// public key using ParseRSAPublicKeyFromPEM()
func lookupPublicKey(keyPath string) (*rsa.PublicKey, error) {
	key, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	parsedKey, err := jwt.ParseRSAPublicKeyFromPEM(key)
	return parsedKey, err
}

// private key using ParseRSAPrivateKeyFromPEM()
func lookupPrivateKey(keyPath string) (*rsa.PrivateKey, error) {
	key, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	return parsedKey, err
}
<commit_msg>refactoring jwt<commit_after>// Package jwts is authentication by JWT
package jwts

import (
	"crypto/rsa"
	"io/ioutil"

	"github.com/dgrijalva/jwt-go"
	"github.com/pkg/errors"
)

const (
	// HMAC signing algorithm
	HMAC uint8 = 1
	// RSA signing algorithm
	RSA uint8 = 2
)

// CustomClaims is jwt claim
type CustomClaims struct {
	Option string `json:"option"`
	jwt.StandardClaims
}

// JWTer interface
type JWTer interface {
	CreateBasicToken(t int64, clientID, userName string) (string, error)
	CreateCustomToken(t int64, clientID, userName, option string) (string, error)
	ValidateToken(tokenString string) error
	ValidateTokenWithClaim(tokenString, clientID, userName string) error
	ValidateTokenWithCustomClaim(tokenString, clientID, userName, option string) error
}

// ----------------------------------------------------------------------------
// jwtee
// ----------------------------------------------------------------------------

type jwtee struct {
	audience string
	SigAlgoer
}

// NewJWT returns JWTer interface
func NewJWT(audience string, sigAlgoer SigAlgoer) JWTer {
	return &jwtee{
		audience:  audience,
		SigAlgoer: sigAlgoer,
	}
}

// CreateBasicToken returns basic claim
// - encode Header, Payload, Signature by Base64 and concatenate these with dot
func (j *jwtee) CreateBasicToken(t int64, clientID, userName string) (string, error) {
	token := jwt.NewWithClaims(
		j.SigAlgoer.GetMethod(),
		j.getClaims(t, clientID, userName),
	)
	return j.SigAlgoer.SignedString(token)
}

// CreateToken returns user defined claim
// - encode Header, Payload, Signature by Base64 and concatenate these with dot
func (j *jwtee) CreateCustomToken(t int64, clientID, userName, option string) (string, error) {
	claims := &CustomClaims{
		option,
		j.getClaims(t, clientID, userName),
	}
	token := jwt.NewWithClaims(j.SigAlgoer.GetMethod(), claims)
	return j.SigAlgoer.SignedString(token)
}

// Payload
func (j *jwtee) getClaims(t int64, clientID, userName string) jwt.StandardClaims {
	// Audience  string `json:"aud,omitempty"` // https://login.hiromaily.com
	// ExpiresAt int64  `json:"exp,omitempty"`
	// Id        string `json:"jti,omitempty"`
	// IssuedAt  int64  `json:"iat,omitempty"`
	// Issuer    string `json:"iss,omitempty"` // OAuth client_id
	// NotBefore int64  `json:"nbf,omitempty"`
	// Subject   string `json:"sub,omitempty"` // user name or email
	claims := jwt.StandardClaims{
		Audience: j.audience,
		// ExpiresAt: time.Now().Add(time.Second * 2).Unix(),
		ExpiresAt: t,
		Issuer:    clientID,
		Subject:   userName,
	}
	return claims
}

func (j *jwtee) keyFunc(token *jwt.Token) (interface{}, error) {
	if isValid := j.SigAlgoer.ValidateMethod(token); !isValid {
		return nil, errors.Errorf("unexpected signing method: %v", token.Header["alg"])
	}
	return j.SigAlgoer.GetKey(), nil
}

// ValidateToken validates token string, it may be too strict
func (j *jwtee) ValidateToken(tokenString string) error {
	token, err := jwt.Parse(tokenString, j.keyFunc)
	if err != nil {
		return err
	}
	if !token.Valid {
		return errors.New("token is invalid")
	}
	return nil
}

// ValidateTokenWithClaim validates token by clientID and userName
// may be too strict to check
func (j *jwtee) ValidateTokenWithClaim(tokenString, clientID, userName string) error {
	token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, j.keyFunc)
	if err != nil {
		return err
	}
	if !token.Valid {
		return errors.New("token is invalid")
	}

	// validate claim
	claims, ok := token.Claims.(*jwt.StandardClaims)
	if !ok {
		return errors.New("fail to validate claim: claims can't be retrieved")
	}
	if claims.Issuer != clientID {
		return errors.New("fail to validate claim: issuer is invalid")
	}
	if claims.Subject != userName {
		return errors.New("fail to validate claim: subject is invalid")
	}
	return nil
}

// ValidateTokenWithCustomClaim validates token by clientID and userName and option
// may be too strict to check
func (j *jwtee) ValidateTokenWithCustomClaim(tokenString, clientID, userName, option string) error {
	// token
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, j.keyFunc)
	if err != nil {
		return err
	}
	if !token.Valid {
		return errors.New("token is invalid")
	}

	// validate claim
	claims, ok := token.Claims.(*CustomClaims)
	if !ok {
		return errors.New("fail to validate claim: claims data can't be retrieved")
	} else if claims.Issuer != clientID {
		return errors.New("fail to validate claim: issuer is invalid")
	} else if claims.Subject != userName {
		return errors.New("fail to validate claim: subject is invalid")
	} else if claims.Option != option {
		return errors.New("fail to validate claim: option is invalid")
	}

	return nil
}

// ----------------------------------------------------------------------------
// SigAlgoer
// ----------------------------------------------------------------------------

// SigAlgoer interface
type SigAlgoer interface {
	GetMethod() jwt.SigningMethod
	SignedString(token *jwt.Token) (string, error)
	ValidateMethod(token *jwt.Token) bool
	GetKey() interface{}
}

// ----------------------------------------------------------------------------
// HMAC
// ----------------------------------------------------------------------------
type algoHMAC struct {
	encrypted uint8
	method    jwt.SigningMethod
	secret    string
}

// NewHMAC returns SigAlgoer
func NewHMAC(secret string) SigAlgoer {
	return &algoHMAC{
		encrypted: HMAC,
		method:    jwt.SigningMethodHS256,
		secret:    secret,
	}
}

// GetMethod returns method
func (a *algoHMAC) GetMethod() jwt.SigningMethod {
	return a.method
}

// SignedString returns signed string from toke
func (a *algoHMAC) SignedString(token *jwt.Token) (string, error) {
	return token.SignedString([]byte(a.secret))
}

// ValidateMethod validates method of token
func (a *algoHMAC) ValidateMethod(token *jwt.Token) bool {
	_, ok := token.Method.(*jwt.SigningMethodHMAC)
	return ok
}

// GetKey returns key
func (a *algoHMAC) GetKey() interface{} {
	return []byte(a.secret)
}

// ----------------------------------------------------------------------------
// RSA
// ----------------------------------------------------------------------------
type algoRSA struct {
	encrypted  uint8
	method     jwt.SigningMethod
	privateKey *rsa.PrivateKey
	publicKey  *rsa.PublicKey
}

// NewRSA returns SigAlgoer interface and error
func NewRSA(privKey, pubKey string) (SigAlgoer, error) {
	privKeyParsed, err := lookupPrivateKey(privKey)
	if err != nil {
		return nil, err
	}
	pubKeyParsed, err := lookupPublicKey(pubKey)
	if err != nil {
		return nil, err
	}

	return &algoRSA{
		encrypted:  RSA,
		method:     jwt.SigningMethodRS256,
		privateKey: privKeyParsed,
		publicKey:  pubKeyParsed,
	}, nil
}

func (a *algoRSA) GetMethod() jwt.SigningMethod {
	return a.method
}

func (a *algoRSA) SignedString(token *jwt.Token) (string, error) {
	return token.SignedString(a.privateKey)
}

func (a *algoRSA) ValidateMethod(token *jwt.Token) bool {
	_, ok := token.Method.(*jwt.SigningMethodRSA)
	return ok
}

func (a *algoRSA) GetKey() interface{} {
	return a.publicKey
}

// public key using ParseRSAPublicKeyFromPEM()
func lookupPublicKey(keyPath string) (*rsa.PublicKey, error) {
	key, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	parsedKey, err := jwt.ParseRSAPublicKeyFromPEM(key)
	return parsedKey, err
}

// private key using ParseRSAPrivateKeyFromPEM()
func lookupPrivateKey(keyPath string) (*rsa.PrivateKey, error) {
	key, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	return parsedKey, err
}
<|endoftext|>


<commit_before>package chClient

import (
	"git.containerum.net/ch/kube-client/pkg/cherry"
	"git.containerum.net/ch/kube-client/pkg/cherry/auth"
	"git.containerum.net/ch/kube-client/pkg/cherry/kube-api"
	"github.com/containerum/chkit/pkg/model/service"
)

func (client *Client) GetService(namespace, serviceName string) (service.Service, error) {
	var gainedService service.Service
	err := retry(4, func() (bool, error) {
		kubeService, err := client.kubeAPIClient.GetService(namespace, serviceName)
		switch {
		case err == nil:
			gainedService = service.ServiceFromKube(kubeService)
			return false, err
		case cherry.In(err,
			autherr.ErrInvalidToken(),
			autherr.ErrTokenNotFound()):
			er := client.Auth()
			return true, er
		case cherry.In(err, kubeErrors.ErrAccessError()):
			return false, ErrYouDoNotHaveAccessToResource.Wrap(err)
		default:
			return true, ErrFatalError.Wrap(err)
		}
	})
	return gainedService, err
}
<commit_msg>add get service list method<commit_after>package chClient

import (
	"git.containerum.net/ch/kube-client/pkg/cherry"
	"git.containerum.net/ch/kube-client/pkg/cherry/auth"
	"git.containerum.net/ch/kube-client/pkg/cherry/kube-api"
	"github.com/containerum/chkit/pkg/model/service"
)

func (client *Client) GetService(namespace, serviceName string) (service.Service, error) {
	var gainedService service.Service
	err := retry(4, func() (bool, error) {
		kubeService, err := client.kubeAPIClient.GetService(namespace, serviceName)
		switch {
		case err == nil:
			gainedService = service.ServiceFromKube(kubeService)
			return false, err
		case cherry.In(err,
			autherr.ErrInvalidToken(),
			autherr.ErrTokenNotFound()):
			er := client.Auth()
			return true, er
		case cherry.In(err, kubeErrors.ErrAccessError()):
			return false, ErrYouDoNotHaveAccessToResource.Wrap(err)
		default:
			return true, ErrFatalError.Wrap(err)
		}
	})
	return gainedService, err
}

func (client *Client) GetServiceList(namespace string) (service.ServiceList, error) {
	var gainedList service.ServiceList
	err := retry(4, func() (bool, error) {
		kubeLsit, err := client.kubeAPIClient.GetServiceList(namespace)
		switch {
		case err == nil:
			gainedList = service.ServiceListFromKube(kubeLsit)
			return false, err
		case cherry.In(err,
			autherr.ErrInvalidToken(),
			autherr.ErrTokenNotFound()):
			er := client.Auth()
			return true, er
		case cherry.In(err, kubeErrors.ErrAccessError()):
			return false, ErrYouDoNotHaveAccessToResource.Wrap(err)
		default:
			return true, ErrFatalError.Wrap(err)
		}
	})
	return gainedList, err
}
<|endoftext|>


<commit_before>package data

import (
	"errors"
	"fmt"

	pb "rsprd.com/spread/pkg/spreadproto"
)

// AddParamToDoc adds the given parameter to the
func AddParamToDoc(doc *pb.Document, target *SRI, param *pb.Parameter) error {
	if !target.IsField() {
		return errors.New("passed SRI is not a field")
	}

	field, err := GetFieldFromDocument(doc, target.Field)
	if err != nil {
		return err
	}

	field.Param = param
	return nil
}

// ApplyArguments takes the given arguments and uses them to satisfy a field parameter.
func ApplyArguments(field *pb.Field, args ...*pb.Argument) error {
	if field == nil {
		return errors.New("field was nil")
	} else if field.GetParam() == nil {
		return fmt.Errorf("field %s does not have a parameter", field.Key)
	} else if len(args) < 1 {
		return errors.New("an argument must be specified")
	} else if len(args) == 1 && len(field.GetParam().Pattern) == 0 {
		return simpleArgApply(field, args[0])
	}
	// TODO: complete string formatting based apply
	return nil
}

// simpleArgApply is used when no formatting template string is given.
func simpleArgApply(field *pb.Field, arg *pb.Argument) error {
	switch val := arg.GetValue().(type) {
	case *pb.Argument_Number:
		field.Value = *pb.Field_Number{Number: val.Number}
	case *pb.Argument_Str:
		field.Value = *pb.Field_Str{Str: val.Str}
	case *pb.Argument_Boolean:
		field.Value = *pb.Field_Boolean{Boolean: val.Boolean}
	case *pb.Argument_Object:
		field.Value = *pb.Field_Object{Object: val.Object}
	case *pb.Argument_Array:
		field.Value = *pb.Field_Array{Array: val.Array}
	default:
		field.Value = nil
	}

	return nil
}
<commit_msg>changed indirect to dereference in simple parameter application<commit_after>package data

import (
	"errors"
	"fmt"

	pb "rsprd.com/spread/pkg/spreadproto"
)

// AddParamToDoc adds the given parameter to the
func AddParamToDoc(doc *pb.Document, target *SRI, param *pb.Parameter) error {
	if !target.IsField() {
		return errors.New("passed SRI is not a field")
	}

	field, err := GetFieldFromDocument(doc, target.Field)
	if err != nil {
		return err
	}

	field.Param = param
	return nil
}

// ApplyArguments takes the given arguments and uses them to satisfy a field parameter.
func ApplyArguments(field *pb.Field, args ...*pb.Argument) error {
	if field == nil {
		return errors.New("field was nil")
	} else if field.GetParam() == nil {
		return fmt.Errorf("field %s does not have a parameter", field.Key)
	} else if len(args) < 1 {
		return errors.New("an argument must be specified")
	} else if len(args) == 1 && len(field.GetParam().Pattern) == 0 {
		return simpleArgApply(field, args[0])
	}
	// TODO: complete string formatting based apply
	return nil
}

// simpleArgApply is used when no formatting template string is given.
func simpleArgApply(field *pb.Field, arg *pb.Argument) error {
	switch val := arg.GetValue().(type) {
	case *pb.Argument_Number:
		field.Value = &pb.Field_Number{Number: val.Number}
	case *pb.Argument_Str:
		field.Value = &pb.Field_Str{Str: val.Str}
	case *pb.Argument_Boolean:
		field.Value = &pb.Field_Boolean{Boolean: val.Boolean}
	case *pb.Argument_Object:
		field.Value = &pb.Field_Object{Object: val.Object}
	case *pb.Argument_Array:
		field.Value = &pb.Field_Array{Array: val.Array}
	default:
		field.Value = nil
	}

	return nil
}
<|endoftext|>


<commit_before>package ice

import (
	"testing"
	"time"

	"github.com/pions/transport/test"
)

func TestPairSearch(t *testing.T) {
	// Limit runtime in case of deadlocks
	lim := test.TimeOut(time.Second * 10)
	defer lim.Stop()

	var config AgentConfig
	a, err := NewAgent(&config)

	if err != nil {
		t.Fatalf("Error constructing ice.Agent")
	}

	if len(a.validPairs) != 0 {
		t.Fatalf("TestPairSearch is only a valid test if a.validPairs is empty on construction")
	}

	cp, err := a.getBestPair()

	if cp != nil {
		t.Fatalf("No Candidate pairs should exist")
	}

	if err == nil {
		t.Fatalf("An error should have been reported (with no available candidate pairs)")
	}

	err = a.Close()

	if err != nil {
		t.Fatalf("Close agent emits error %v", err)
	}
}
<commit_msg>Added test for handleNewPeerReflexiveCandidate<commit_after>package ice

import (
	"net"
	"testing"
	"time"

	"github.com/pions/transport/test"
)

func TestPairSearch(t *testing.T) {
	// Limit runtime in case of deadlocks
	lim := test.TimeOut(time.Second * 10)
	defer lim.Stop()

	var config AgentConfig
	a, err := NewAgent(&config)

	if err != nil {
		t.Fatalf("Error constructing ice.Agent")
	}

	if len(a.validPairs) != 0 {
		t.Fatalf("TestPairSearch is only a valid test if a.validPairs is empty on construction")
	}

	cp, err := a.getBestPair()

	if cp != nil {
		t.Fatalf("No Candidate pairs should exist")
	}

	if err == nil {
		t.Fatalf("An error should have been reported (with no available candidate pairs)")
	}

	err = a.Close()

	if err != nil {
		t.Fatalf("Close agent emits error %v", err)
	}
}

type BadAddr struct{}

func (ba *BadAddr) Network() string {
	return "xxx"
}
func (ba *BadAddr) String() string {
	return "yyy"
}

func TestHandlePeerReflexive(t *testing.T) {
	// Limit runtime in case of deadlocks
	lim := test.TimeOut(time.Second * 2)
	defer lim.Stop()

	t.Run("UDP pflx candidate from handleInboud()", func(t *testing.T) {
		var config AgentConfig
		a, err := NewAgent(&config)

		if err != nil {
			t.Fatalf("Error constructing ice.Agent")
		}

		ip := net.ParseIP("192.168.0.2")
		local, err := NewCandidateHost("udp", ip, 777)
		if err != nil {
			t.Fatalf("failed to create a new candidate: %v", err)
		}

		remote := &net.UDPAddr{IP: net.ParseIP("172.17.0.3"), Port: 999}

		a.handleInbound(nil, local, remote)

		// length of remote candidate list must be one now
		if len(a.remoteCandidates) != 1 {
			t.Fatal("failed to add a network type to the remote candidate list")
		}

		// length of remote candidate list for a network type must be 1
		set := a.remoteCandidates[local.NetworkType]
		if len(set) != 1 {
			t.Fatal("failed to add prflx candidate to remote candidate list")
		}

		c := set[0]

		if c.Type != CandidateTypePeerReflexive {
			t.Fatal("candidate type must be prflx")
		}

		if !c.IP.Equal(net.ParseIP("172.17.0.3")) {
			t.Fatal("IP address mismatch")
		}

		if c.Port != 999 {
			t.Fatal("Port number mismatch")
		}

		err = a.Close()
		if err != nil {
			t.Fatalf("Close agent emits error %v", err)
		}
	})

	t.Run("Bad network type with handleInbound()", func(t *testing.T) {
		var config AgentConfig
		a, err := NewAgent(&config)

		if err != nil {
			t.Fatal("Error constructing ice.Agent")
		}

		ip := net.ParseIP("192.168.0.2")
		local, err := NewCandidateHost("tcp", ip, 777)
		if err != nil {
			t.Fatalf("failed to create a new candidate: %v", err)
		}

		remote := &BadAddr{}

		a.handleInbound(nil, local, remote)

		if len(a.remoteCandidates) != 0 {
			t.Fatal("bad address should not be added to the remote candidate list")
		}

		err = a.Close()
		if err != nil {
			t.Fatalf("Close agent emits error %v", err)
		}
	})

	t.Run("TCP prflx with handleNewPeerReflexiveCandidate()", func(t *testing.T) {
		var config AgentConfig
		a, err := NewAgent(&config)

		if err != nil {
			t.Fatal("Error constructing ice.Agent")
		}

		ip := net.ParseIP("192.168.0.2")
		local, err := NewCandidateHost("tcp", ip, 777)
		if err != nil {
			t.Fatalf("failed to create a new candidate: %v", err)
		}

		remote := &net.TCPAddr{IP: net.ParseIP("172.17.0.3"), Port: 999}

		a.handleNewPeerReflexiveCandidate(local, remote)

		// length of remote candidate list must be one now
		if len(a.remoteCandidates) != 1 {
			t.Fatal("failed to add a network type to the remote candidate list")
		}

		// length of remote candidate list for a network type must be 1
		set := a.remoteCandidates[local.NetworkType]
		if len(set) != 1 {
			t.Fatal("failed to add prflx candidate to remote candidate list")
		}

		c := set[0]

		if c.Type != CandidateTypePeerReflexive {
			t.Fatal("candidate type must be prflx")
		}

		if !c.IP.Equal(net.ParseIP("172.17.0.3")) {
			t.Fatal("IP address mismatch")
		}

		if c.Port != 999 {
			t.Fatal("Port number mismatch")
		}

		err = a.Close()
		if err != nil {
			t.Fatalf("Close agent emits error %v", err)
		}
	})
}
<|endoftext|>


<commit_before>// Copyright 2018 Authors of Cilium
//
// 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 metrics

import (
	"time"

	clientPkg "github.com/cilium/cilium/pkg/client"
	healthClientPkg "github.com/cilium/cilium/pkg/health/client"

	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"
)

const (
	updateLatencyMetricsInterval = 30 * time.Second
)

type statusCollector struct {
	ciliumClient *clientPkg.Client
	healthClient *healthClientPkg.Client

	controllersFailingDesc         *prometheus.Desc
	ipAddressesDesc                *prometheus.Desc
	unreachableNodesDesc           *prometheus.Desc
	unreachableHealthEndpointsDesc *prometheus.Desc
}

func newStatusCollector() *statusCollector {
	ciliumClient, err := clientPkg.NewClient("")
	if err != nil {
		log.WithError(err).Fatal("Error while creating Cilium API client")
	}

	healthClient, err := healthClientPkg.NewClient("")
	if err != nil {
		log.WithError(err).Fatal("Error while creating cilium-health API client")
	}

	return &statusCollector{
		ciliumClient: ciliumClient,
		healthClient: healthClient,
		controllersFailingDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "controllers_failing"),
			"Number of failing controllers",
			nil, nil,
		),
		ipAddressesDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "ip_addresses"),
			"Number of allocated IP addresses",
			[]string{"family"}, nil,
		),
		unreachableNodesDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "unreachable_nodes"),
			"Number of nodes that cannot be reached",
			nil, nil,
		),
		unreachableHealthEndpointsDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "unreachable_health_endpoints"),
			"Number of health endpoints that cannot be reached",
			nil, nil,
		),
	}
}

func (s *statusCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- s.controllersFailingDesc
	ch <- s.ipAddressesDesc
	ch <- s.unreachableNodesDesc
	ch <- s.unreachableHealthEndpointsDesc
}

func (s *statusCollector) Collect(ch chan<- prometheus.Metric) {
	statusResponse, err := s.ciliumClient.Daemon.GetHealthz(nil)
	if err != nil {
		log.WithError(err).Error("Error while getting Cilium status")
		return
	}

	if statusResponse.Payload == nil {
		return
	}

	// Controllers failing
	controllersFailing := 0

	for _, ctrl := range statusResponse.Payload.Controllers {
		if ctrl.Status == nil {
			continue
		}
		if ctrl.Status.ConsecutiveFailureCount > 0 {
			controllersFailing++
		}
	}

	ch <- prometheus.MustNewConstMetric(
		s.controllersFailingDesc,
		prometheus.GaugeValue,
		float64(controllersFailing),
	)

	if statusResponse.Payload.Ipam != nil {
		// Address count
		ch <- prometheus.MustNewConstMetric(
			s.ipAddressesDesc,
			prometheus.GaugeValue,
			float64(len(statusResponse.Payload.Ipam.IPV4)),
			"ipv4",
		)

		ch <- prometheus.MustNewConstMetric(
			s.ipAddressesDesc,
			prometheus.GaugeValue,
			float64(len(statusResponse.Payload.Ipam.IPV6)),
			"ipv6",
		)
	}

	healthStatusResponse, err := s.healthClient.Connectivity.GetStatus(nil)
	if err != nil {
		log.WithError(err).Error("Error while getting cilium-health status")
		return
	}

	if healthStatusResponse.Payload == nil {
		return
	}

	// Nodes and endpoints healthStatusResponse
	var (
		unreachableNodes     int
		unreachableEndpoints int
	)

	for _, nodeStatus := range healthStatusResponse.Payload.Nodes {
		if !healthClientPkg.PathIsHealthy(healthClientPkg.GetHostPrimaryAddress(nodeStatus)) {
			unreachableNodes++
		}
		if nodeStatus.Endpoint != nil && !healthClientPkg.PathIsHealthy(nodeStatus.Endpoint) {
			unreachableEndpoints++
		}
	}

	ch <- prometheus.MustNewConstMetric(
		s.unreachableNodesDesc,
		prometheus.GaugeValue,
		float64(unreachableNodes),
	)

	ch <- prometheus.MustNewConstMetric(
		s.unreachableHealthEndpointsDesc,
		prometheus.GaugeValue,
		float64(unreachableEndpoints),
	)
}
<commit_msg>metrics: remove unused cons updateLatencyMetricsInterval<commit_after>// Copyright 2018 Authors of Cilium
//
// 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 metrics

import (
	clientPkg "github.com/cilium/cilium/pkg/client"
	healthClientPkg "github.com/cilium/cilium/pkg/health/client"

	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"
)

type statusCollector struct {
	ciliumClient *clientPkg.Client
	healthClient *healthClientPkg.Client

	controllersFailingDesc         *prometheus.Desc
	ipAddressesDesc                *prometheus.Desc
	unreachableNodesDesc           *prometheus.Desc
	unreachableHealthEndpointsDesc *prometheus.Desc
}

func newStatusCollector() *statusCollector {
	ciliumClient, err := clientPkg.NewClient("")
	if err != nil {
		log.WithError(err).Fatal("Error while creating Cilium API client")
	}

	healthClient, err := healthClientPkg.NewClient("")
	if err != nil {
		log.WithError(err).Fatal("Error while creating cilium-health API client")
	}

	return &statusCollector{
		ciliumClient: ciliumClient,
		healthClient: healthClient,
		controllersFailingDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "controllers_failing"),
			"Number of failing controllers",
			nil, nil,
		),
		ipAddressesDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "ip_addresses"),
			"Number of allocated IP addresses",
			[]string{"family"}, nil,
		),
		unreachableNodesDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "unreachable_nodes"),
			"Number of nodes that cannot be reached",
			nil, nil,
		),
		unreachableHealthEndpointsDesc: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "unreachable_health_endpoints"),
			"Number of health endpoints that cannot be reached",
			nil, nil,
		),
	}
}

func (s *statusCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- s.controllersFailingDesc
	ch <- s.ipAddressesDesc
	ch <- s.unreachableNodesDesc
	ch <- s.unreachableHealthEndpointsDesc
}

func (s *statusCollector) Collect(ch chan<- prometheus.Metric) {
	statusResponse, err := s.ciliumClient.Daemon.GetHealthz(nil)
	if err != nil {
		log.WithError(err).Error("Error while getting Cilium status")
		return
	}

	if statusResponse.Payload == nil {
		return
	}

	// Controllers failing
	controllersFailing := 0

	for _, ctrl := range statusResponse.Payload.Controllers {
		if ctrl.Status == nil {
			continue
		}
		if ctrl.Status.ConsecutiveFailureCount > 0 {
			controllersFailing++
		}
	}

	ch <- prometheus.MustNewConstMetric(
		s.controllersFailingDesc,
		prometheus.GaugeValue,
		float64(controllersFailing),
	)

	if statusResponse.Payload.Ipam != nil {
		// Address count
		ch <- prometheus.MustNewConstMetric(
			s.ipAddressesDesc,
			prometheus.GaugeValue,
			float64(len(statusResponse.Payload.Ipam.IPV4)),
			"ipv4",
		)

		ch <- prometheus.MustNewConstMetric(
			s.ipAddressesDesc,
			prometheus.GaugeValue,
			float64(len(statusResponse.Payload.Ipam.IPV6)),
			"ipv6",
		)
	}

	healthStatusResponse, err := s.healthClient.Connectivity.GetStatus(nil)
	if err != nil {
		log.WithError(err).Error("Error while getting cilium-health status")
		return
	}

	if healthStatusResponse.Payload == nil {
		return
	}

	// Nodes and endpoints healthStatusResponse
	var (
		unreachableNodes     int
		unreachableEndpoints int
	)

	for _, nodeStatus := range healthStatusResponse.Payload.Nodes {
		if !healthClientPkg.PathIsHealthy(healthClientPkg.GetHostPrimaryAddress(nodeStatus)) {
			unreachableNodes++
		}
		if nodeStatus.Endpoint != nil && !healthClientPkg.PathIsHealthy(nodeStatus.Endpoint) {
			unreachableEndpoints++
		}
	}

	ch <- prometheus.MustNewConstMetric(
		s.unreachableNodesDesc,
		prometheus.GaugeValue,
		float64(unreachableNodes),
	)

	ch <- prometheus.MustNewConstMetric(
		s.unreachableHealthEndpointsDesc,
		prometheus.GaugeValue,
		float64(unreachableEndpoints),
	)
}
<|endoftext|>