<commit_before>package master

import (
	"fmt"
	. "github.com/KIT-MAMID/mamid/model"
	"github.com/KIT-MAMID/mamid/msp"
	"github.com/Sirupsen/logrus"
	"github.com/jinzhu/gorm"
)

var deployerLog = logrus.WithField("module", "deployer")

/*
  Listens on the bus for state mismatches and tries to solve them by pushing the desired state to the Mongod
*/
type Deployer struct {
	DB             *DB
	MSPClient      msp.MSPClient
	BusReadChannel <-chan interface{}
}

func (d *Deployer) Run() {

	for {
		msg := <-d.BusReadChannel
		switch msg.(type) {
		case MongodMatchStatus:
			go d.handleMatchStatus(msg.(MongodMatchStatus))
		case ReplicaSetInitiationStatus:
			go d.handleReplicaSetInitiationStatus(msg.(ReplicaSetInitiationStatus))
		}

	}
}

func (d *Deployer) handleMatchStatus(m MongodMatchStatus) {
	if !m.Mismatch {
		return
	}
	d.pushMongodState(m.Mongod)
}

func (d *Deployer) handleReplicaSetInitiationStatus(s ReplicaSetInitiationStatus) {

	if s.Initiated {
		return
	}

	var msg msp.RsInitiateMessage
	var mspErr *msp.Error

	tx := d.DB.Begin()

	slave, initiator, err := d.findInitiatorForReplicaSet(tx, s.ReplicaSet)
	if err != nil {
		deployerLog.WithError(err).Errorf("could not find initiator for replica set `%s`", s.ReplicaSet.Name)
		goto rollbackAndReturn
	}

	msg = msp.RsInitiateMessage{
		Port: msp.PortNumber(initiator.Port),
	}

	msg.ReplicaSetConfig, err = d.replicaSetConfig(tx, s.ReplicaSet)
	if err != nil {
		deployerLog.WithError(err).Errorf("could not generate replica set config `%s`", s.ReplicaSet.Name)
		goto rollbackAndReturn
	}

	deployerLog.Debugf("initializing Replica Set `%s` from `%s` using message: %#v", s.ReplicaSet.Name, slave.Hostname, msg)

	mspErr = d.MSPClient.InitiateReplicaSet(msp.HostPort{slave.Hostname, msp.PortNumber(slave.Port)}, msg)

	if mspErr != nil {
		deployerLog.Errorf("error initializing Replica Set `%s` from `%s`: %s", s.ReplicaSet.Name, slave.Hostname, mspErr)
	} else {

		if err = tx.Model(&s.ReplicaSet).Update("Initiated", true).Error; err != nil {
			deployerLog.Errorf("error initializing Replica Set `%s` from `%s`: %s", s.ReplicaSet.Name, slave.Hostname, mspErr)
			goto rollbackAndReturn
		}
		tx.Commit()
	}

	return

rollbackAndReturn:
	tx.Rollback()
	return

}

// Find a Mongod of ReplicaSet r for `initiiating` the ReplicaSet
func (d *Deployer) findInitiatorForReplicaSet(tx *gorm.DB, r ReplicaSet) (s Slave, m Mongod, err error) {

	err = tx.Raw(`
		SELECT m.*
		FROM mongods m
		JOIN replica_sets r ON m.replica_set_id = r.id
		WHERE
			r.initialized = false
			AND
			m.replica_set_id = ?
		LIMIT 1
			`, r.ID).Scan(&m).Error
	if err != nil {
		return
	}

	if err = tx.Model(&m).Related(&s, "ParentSlaveID").Error; err != nil {
		return
	}

	return

}

func (d *Deployer) pushMongodState(mongod Mongod) {

	deployerLog.Debugf("fetch Mongod state representation: `%d` on slave `%d`", mongod.ID, mongod.ParentSlaveID)
	// Readonly tx
	tx := d.DB.Begin()

	hostPort, mspMongod, err := d.mspMongodStateRepresentation(tx, mongod)
	if err != nil {
		deployerLog.Println(err)
	}
	// Readonly tx
	tx.Rollback()
	deployerLog.Debugf("finish fetching Mongod state representation: `%d` on slave `%d`", mongod.ID, mongod.ParentSlaveID)

	deployerLog.Debugf("establishing Mongod state on `%s`", hostPort)

	mspError := d.MSPClient.EstablishMongodState(hostPort, mspMongod)
	if mspError != nil {
		deployerLog.Errorf("MSP error establishing mongod state on `%s` for Mongod `(%v(id=%d),%d,)` in Replica Set `%s`: %s",
			hostPort, mongod.ParentSlave, mongod.ParentSlaveID, mongod.Port, mongod.ReplSetName, mspError)
	} else {
		deployerLog.Debugf("finished establishing Mongod state on %s", hostPort)
	}

}

// Generate an MSP-compatible representation of the deisred Mongod state
// uses tx readonly
// When err != nil is returned, the tx. should be rolled back and the error be reported
func (d *Deployer) mspMongodStateRepresentation(tx *gorm.DB, mongod Mongod) (hostPort msp.HostPort, mspMongod msp.Mongod, err error) {

	var slave Slave
	var desiredState MongodState
	var mspMongodState msp.MongodState
	var replicaSetMembers []msp.ReplicaSetMember

	// Fetch master representation
	if err = tx.Model(&mongod).Related(&slave, "ParentSlave").Error; err != nil {
		return
	}
	if err = tx.Model(&mongod).Related(&desiredState, "DesiredState").Error; err != nil {
		return
	}
	mspMongodState, err = mspMongodStateFromExecutionState(desiredState.ExecutionState)
	if err != nil {
		return
	}

	// TODO use DesiredState once this is set
	if !mongod.ReplicaSetID.Valid {
		replicaSetMembers = make([]msp.ReplicaSetMember, 0, 0)
	} else {
		if replicaSetMembers, err = mspDesiredReplicaSetMembersForReplicaSetID(tx, mongod.ReplicaSetID.Int64); err != nil {
			return
		}
	}

	// Construct msp representation
	hostPort = msp.HostPort{
		Hostname: slave.Hostname,
		Port:     msp.PortNumber(slave.Port),
	}
	mspMongod = msp.Mongod{
		Port: msp.PortNumber(mongod.Port),
		ReplicaSetConfig: msp.ReplicaSetConfig{
			ReplicaSetName:       mongod.ReplSetName,
			ReplicaSetMembers:    replicaSetMembers,
			ShardingConfigServer: desiredState.IsShardingConfigServer,
		},
		State: mspMongodState,
	}

	return

}

func mspMongodStateFromExecutionState(s MongodExecutionState) (msp.MongodState, error) {
	switch s {
	case MongodExecutionStateDestroyed:
		return msp.MongodStateDestroyed, nil
	case MongodExecutionStateNotRunning:
		return msp.MongodStateNotRunning, nil
	case MongodExecutionStateRecovering:
		return msp.MongodStateRecovering, nil
	case MongodExecutionStateRunning:
		return msp.MongodStateRunning, nil
	default:
		return "", fmt.Errorf("deployer: unable to map `%v` from model.ExecutionState to msp.MongodState", s)
	}
}

// Generate a ReplicaSetConfig used to describe the ReplicaSet r
func (d *Deployer) replicaSetConfig(tx *gorm.DB, r ReplicaSet) (config msp.ReplicaSetConfig, err error) {

	config = msp.ReplicaSetConfig{
		ReplicaSetName:       r.Name,
		ReplicaSetMembers:    make([]msp.ReplicaSetMember, 0, 0),
		ShardingConfigServer: r.ConfigureAsShardingConfigServer,
	}

	config.ReplicaSetMembers, err = mspDesiredReplicaSetMembersForReplicaSetID(tx, r.ID)

	return
}

// Return the list of msp.HostPort a Mongod should have as members
// Includes the mongod passed as parameter m
func mspDesiredReplicaSetMembersForReplicaSetID(tx *gorm.DB, replicaSetID int64) (replicaSetMembers []msp.ReplicaSetMember, err error) {

	rows, err := tx.Raw(`SELECT s.hostname, m.port
		FROM mongods m
		JOIN replica_sets r ON m.replica_set_id = r.id
		JOIN mongod_states desired_state ON m.desired_state_id = desired_state.id
		JOIN slaves s ON m.parent_slave_id = s.id
		WHERE r.id = ?
		      AND desired_state.execution_state = ?
		`, replicaSetID, MongodExecutionStateRunning,
	).Rows()
	defer rows.Close()

	if err != nil {
		return []msp.ReplicaSetMember{}, fmt.Errorf("could not fetch replica set members for ReplicaSet.ID `%v`: %s", replicaSetID, err)
	}

	for rows.Next() {
		member := msp.ReplicaSetMember{}
		err = rows.Scan(member.HostPort.Hostname, member.HostPort.Port)
		if err != nil {
			return
		}
		replicaSetMembers = append(replicaSetMembers, member)
	}

	return

}
<commit_msg>FIX: deployer: wrong column name in query.<commit_after>package master

import (
	"fmt"
	. "github.com/KIT-MAMID/mamid/model"
	"github.com/KIT-MAMID/mamid/msp"
	"github.com/Sirupsen/logrus"
	"github.com/jinzhu/gorm"
)

var deployerLog = logrus.WithField("module", "deployer")

/*
  Listens on the bus for state mismatches and tries to solve them by pushing the desired state to the Mongod
*/
type Deployer struct {
	DB             *DB
	MSPClient      msp.MSPClient
	BusReadChannel <-chan interface{}
}

func (d *Deployer) Run() {

	for {
		msg := <-d.BusReadChannel
		switch msg.(type) {
		case MongodMatchStatus:
			go d.handleMatchStatus(msg.(MongodMatchStatus))
		case ReplicaSetInitiationStatus:
			go d.handleReplicaSetInitiationStatus(msg.(ReplicaSetInitiationStatus))
		}

	}
}

func (d *Deployer) handleMatchStatus(m MongodMatchStatus) {
	if !m.Mismatch {
		return
	}
	d.pushMongodState(m.Mongod)
}

func (d *Deployer) handleReplicaSetInitiationStatus(s ReplicaSetInitiationStatus) {

	if s.Initiated {
		return
	}

	var msg msp.RsInitiateMessage
	var mspErr *msp.Error

	tx := d.DB.Begin()

	slave, initiator, err := d.findInitiatorForReplicaSet(tx, s.ReplicaSet)
	if err != nil {
		deployerLog.WithError(err).Errorf("could not find initiator for replica set `%s`", s.ReplicaSet.Name)
		goto rollbackAndReturn
	}

	msg = msp.RsInitiateMessage{
		Port: msp.PortNumber(initiator.Port),
	}

	msg.ReplicaSetConfig, err = d.replicaSetConfig(tx, s.ReplicaSet)
	if err != nil {
		deployerLog.WithError(err).Errorf("could not generate replica set config `%s`", s.ReplicaSet.Name)
		goto rollbackAndReturn
	}

	deployerLog.Debugf("initializing Replica Set `%s` from `%s` using message: %#v", s.ReplicaSet.Name, slave.Hostname, msg)

	mspErr = d.MSPClient.InitiateReplicaSet(msp.HostPort{slave.Hostname, msp.PortNumber(slave.Port)}, msg)

	if mspErr != nil {
		deployerLog.Errorf("error initializing Replica Set `%s` from `%s`: %s", s.ReplicaSet.Name, slave.Hostname, mspErr)
	} else {

		if err = tx.Model(&s.ReplicaSet).Update("Initiated", true).Error; err != nil {
			deployerLog.Errorf("error initializing Replica Set `%s` from `%s`: %s", s.ReplicaSet.Name, slave.Hostname, mspErr)
			goto rollbackAndReturn
		}
		tx.Commit()
	}

	return

rollbackAndReturn:
	tx.Rollback()
	return

}

// Find a Mongod of ReplicaSet r for `initiiating` the ReplicaSet
func (d *Deployer) findInitiatorForReplicaSet(tx *gorm.DB, r ReplicaSet) (s Slave, m Mongod, err error) {

	err = tx.Raw(`
		SELECT m.*
		FROM mongods m
		JOIN replica_sets r ON m.replica_set_id = r.id
		WHERE
			r.initiated = false
			AND
			m.replica_set_id = ?
		LIMIT 1
			`, r.ID).Scan(&m).Error
	if err != nil {
		return
	}

	if err = tx.Model(&m).Related(&s, "ParentSlaveID").Error; err != nil {
		return
	}

	return

}

func (d *Deployer) pushMongodState(mongod Mongod) {

	deployerLog.Debugf("fetch Mongod state representation: `%d` on slave `%d`", mongod.ID, mongod.ParentSlaveID)
	// Readonly tx
	tx := d.DB.Begin()

	hostPort, mspMongod, err := d.mspMongodStateRepresentation(tx, mongod)
	if err != nil {
		deployerLog.Println(err)
	}
	// Readonly tx
	tx.Rollback()
	deployerLog.Debugf("finish fetching Mongod state representation: `%d` on slave `%d`", mongod.ID, mongod.ParentSlaveID)

	deployerLog.Debugf("establishing Mongod state on `%s`", hostPort)

	mspError := d.MSPClient.EstablishMongodState(hostPort, mspMongod)
	if mspError != nil {
		deployerLog.Errorf("MSP error establishing mongod state on `%s` for Mongod `(%v(id=%d),%d,)` in Replica Set `%s`: %s",
			hostPort, mongod.ParentSlave, mongod.ParentSlaveID, mongod.Port, mongod.ReplSetName, mspError)
	} else {
		deployerLog.Debugf("finished establishing Mongod state on %s", hostPort)
	}

}

// Generate an MSP-compatible representation of the deisred Mongod state
// uses tx readonly
// When err != nil is returned, the tx. should be rolled back and the error be reported
func (d *Deployer) mspMongodStateRepresentation(tx *gorm.DB, mongod Mongod) (hostPort msp.HostPort, mspMongod msp.Mongod, err error) {

	var slave Slave
	var desiredState MongodState
	var mspMongodState msp.MongodState
	var replicaSetMembers []msp.ReplicaSetMember

	// Fetch master representation
	if err = tx.Model(&mongod).Related(&slave, "ParentSlave").Error; err != nil {
		return
	}
	if err = tx.Model(&mongod).Related(&desiredState, "DesiredState").Error; err != nil {
		return
	}
	mspMongodState, err = mspMongodStateFromExecutionState(desiredState.ExecutionState)
	if err != nil {
		return
	}

	// TODO use DesiredState once this is set
	if !mongod.ReplicaSetID.Valid {
		replicaSetMembers = make([]msp.ReplicaSetMember, 0, 0)
	} else {
		if replicaSetMembers, err = mspDesiredReplicaSetMembersForReplicaSetID(tx, mongod.ReplicaSetID.Int64); err != nil {
			return
		}
	}

	// Construct msp representation
	hostPort = msp.HostPort{
		Hostname: slave.Hostname,
		Port:     msp.PortNumber(slave.Port),
	}
	mspMongod = msp.Mongod{
		Port: msp.PortNumber(mongod.Port),
		ReplicaSetConfig: msp.ReplicaSetConfig{
			ReplicaSetName:       mongod.ReplSetName,
			ReplicaSetMembers:    replicaSetMembers,
			ShardingConfigServer: desiredState.IsShardingConfigServer,
		},
		State: mspMongodState,
	}

	return

}

func mspMongodStateFromExecutionState(s MongodExecutionState) (msp.MongodState, error) {
	switch s {
	case MongodExecutionStateDestroyed:
		return msp.MongodStateDestroyed, nil
	case MongodExecutionStateNotRunning:
		return msp.MongodStateNotRunning, nil
	case MongodExecutionStateRecovering:
		return msp.MongodStateRecovering, nil
	case MongodExecutionStateRunning:
		return msp.MongodStateRunning, nil
	default:
		return "", fmt.Errorf("deployer: unable to map `%v` from model.ExecutionState to msp.MongodState", s)
	}
}

// Generate a ReplicaSetConfig used to describe the ReplicaSet r
func (d *Deployer) replicaSetConfig(tx *gorm.DB, r ReplicaSet) (config msp.ReplicaSetConfig, err error) {

	config = msp.ReplicaSetConfig{
		ReplicaSetName:       r.Name,
		ReplicaSetMembers:    make([]msp.ReplicaSetMember, 0, 0),
		ShardingConfigServer: r.ConfigureAsShardingConfigServer,
	}

	config.ReplicaSetMembers, err = mspDesiredReplicaSetMembersForReplicaSetID(tx, r.ID)

	return
}

// Return the list of msp.HostPort a Mongod should have as members
// Includes the mongod passed as parameter m
func mspDesiredReplicaSetMembersForReplicaSetID(tx *gorm.DB, replicaSetID int64) (replicaSetMembers []msp.ReplicaSetMember, err error) {

	rows, err := tx.Raw(`SELECT s.hostname, m.port
		FROM mongods m
		JOIN replica_sets r ON m.replica_set_id = r.id
		JOIN mongod_states desired_state ON m.desired_state_id = desired_state.id
		JOIN slaves s ON m.parent_slave_id = s.id
		WHERE r.id = ?
		      AND desired_state.execution_state = ?
		`, replicaSetID, MongodExecutionStateRunning,
	).Rows()
	defer rows.Close()

	if err != nil {
		return []msp.ReplicaSetMember{}, fmt.Errorf("could not fetch replica set members for ReplicaSet.ID `%v`: %s", replicaSetID, err)
	}

	for rows.Next() {
		member := msp.ReplicaSetMember{}
		err = rows.Scan(member.HostPort.Hostname, member.HostPort.Port)
		if err != nil {
			return
		}
		replicaSetMembers = append(replicaSetMembers, member)
	}

	return

}
<|endoftext|>


<commit_before>package handler

import (
	"fmt"
	"github.com/Comcast/webpa-common/logging"
	"net/http"
	"os"
)

func sampleContextHandler(requestContext context.Context, response http.ResponseWriter, request *http.Request) {
	response.WriteHeader(http.StatusContinue)
	response.Write([]byte("hello, world"))
}

type remoteSystem struct {
}

func (r remoteSystem) Connected() bool {
	return true
}

// ExampleBasicChain shows the typical usage pattern for chained handlers
func ExampleBasicChain() {
	logger := logging.DefaultLogger{os.Stdout}
	handler := Chain{
		Recovery(),
		RemoteGate(remoteSystem{}, http.StatusServiceUnavailable, "Service Unavailable"),
	}.DecorateContext(logger, ContextHandlerFunc(sampleContextHandler))

	fmt.Println(handler)
}
<commit_msg>Fixed the no context package issue<commit_after>package handler

import (
	"fmt"
	"github.com/Comcast/webpa-common/context"
	"github.com/Comcast/webpa-common/logging"
	"net/http"
	"os"
)

func sampleContextHandler(requestContext context.Context, response http.ResponseWriter, request *http.Request) {
	response.WriteHeader(http.StatusContinue)
	response.Write([]byte("hello, world"))
}

type remoteSystem struct {
}

func (r remoteSystem) Connected() bool {
	return true
}

// ExampleBasicChain shows the typical usage pattern for chained handlers
func ExampleBasicChain() {
	logger := logging.DefaultLogger{os.Stdout}
	handler := Chain{
		Recovery(),
		RemoteGate(remoteSystem{}, http.StatusServiceUnavailable, "Service Unavailable"),
	}.DecorateContext(logger, ContextHandlerFunc(sampleContextHandler))

	fmt.Println(handler)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"strconv"
	"testing"
	"time"

	"github.com/simulatedsimian/assert"
)

func TestFileIndex(t *testing.T) {
	fi := MakeFileIndex("data")

	assert.Equal(t, fi.makeFileName(0), "data/00000/000")
	assert.Equal(t, fi.makeFileName(999), "data/00000/999")
	assert.Equal(t, fi.makeFileName(1000), "data/00001/000")
	assert.Equal(t, fi.makeFileName(12345678), "data/12345/678")
}

func exist(fname string) bool {
	_, err := os.Stat(fname)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

func TestStore(t *testing.T) {

	assert := assert.Make(t)

	path := filepath.Join("/tmp", "testdata", strconv.FormatInt(time.Now().UnixNano(), 10))

	fi := MakeFileIndex(path)

	err := fi.MakeDummyFiles(3999)
	assert(err).IsNil()

	fi.RefeshFileCount()
	assert(fi.fileCount).Equal(uint64(3999))

	assert(exist(filepath.Join(path, "00003", "999"))).Equal(false)
	index := fi.ReserveFileIndex()
	assert(fi.StoreFile(index, "test file")).NoError()
	assert(exist(filepath.Join(path, "00003", "999"))).Equal(true)

	assert(exist(filepath.Join(path, "00004", "000"))).Equal(false)
	index = fi.ReserveFileIndex()
	assert(fi.StoreFile(index, "test file")).NoError()
	assert(exist(filepath.Join(path, "00004", "000"))).Equal(true)
}
<commit_msg>change to the new test helper code<commit_after>package main

import (
	"os"
	"path/filepath"
	"strconv"
	"testing"
	"time"

	"github.com/simulatedsimian/assert"
)

func TestFileIndex(t *testing.T) {
	assert := assert.Make(t)

	fi := MakeFileIndex("data")

	assert(fi.makeFileName(0)).Equal("data/00000/000")
	assert(fi.makeFileName(999)).Equal("data/00000/999")
	assert(fi.makeFileName(1000)).Equal("data/00001/000")
	assert(fi.makeFileName(12345678)).Equal("data/12345/678")
}

func exist(fname string) bool {
	_, err := os.Stat(fname)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

func TestStore(t *testing.T) {

	assert := assert.Make(t)

	path := filepath.Join("/tmp", "testdata", strconv.FormatInt(time.Now().UnixNano(), 10))

	fi := MakeFileIndex(path)

	err := fi.MakeDummyFiles(3999)
	assert(err).IsNil()

	fi.RefeshFileCount()
	assert(fi.fileCount).Equal(uint64(3999))

	assert(exist(filepath.Join(path, "00003", "999"))).Equal(false)
	index := fi.ReserveFileIndex()
	assert(fi.StoreFile(index, "test file")).NoError()
	assert(exist(filepath.Join(path, "00003", "999"))).Equal(true)

	assert(exist(filepath.Join(path, "00004", "000"))).Equal(false)
	index = fi.ReserveFileIndex()
	assert(fi.StoreFile(index, "test file")).NoError()
	assert(exist(filepath.Join(path, "00004", "000"))).Equal(true)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"net"
	"syscall"
)

type IP_Writer struct {
	fd          int
	sockAddr    syscall.Sockaddr
	version     uint8
	dst, src    string
	headerLen   uint16
	ttl         uint8
	protocol    uint8
	identifier  uint16
	maxFragSize uint16
}

func NewIP_Writer(dst string, protocol uint8) (*IP_Writer, error) {
	fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
	if err != nil {
		fmt.Println("Write's socket failed")
		return nil, err
	}

	dstIPAddr, err := net.ResolveIPAddr("ip", dst)
	if err != nil {
		//fmt.Println(err)
		return nil, err
	}
	fmt.Println("Full Address: ", dstIPAddr)

	addr := &syscall.SockaddrInet4{
		Port: 20000,
		Addr: [4]byte{
			dstIPAddr.IP[12],
			dstIPAddr.IP[13],
			dstIPAddr.IP[14],
			dstIPAddr.IP[15],
		},
	}

	err = syscall.Connect(fd, addr)
	if err != nil {
		return nil, errors.New("Failed to connect.")
	}

	return &IP_Writer{
		fd:          fd,
		sockAddr:    addr,
		version:     4,
		headerLen:   20,
		dst:         dst,
		src:         "127.0.0.1",
		ttl:         8,
		protocol:    17,
		identifier:  20000,
		maxFragSize: 1500,
	}, nil
}

func (ipw *IP_Writer) WriteTo(p []byte) error {
	header := make([]byte, ipw.headerLen)
	header[0] = (byte)((ipw.version << 4) + (uint8)(ipw.headerLen/4)) // Version, IHL
	header[1] = 0
	id := ipw.identifier
	header[4] = byte(id >> 8) // Identification
	header[5] = byte(id)
	ipw.identifier++
	header[6] = byte(1 << 5)         // Flags: May fragment, more fragments
	header[8] = (byte)(ipw.ttl)      // Time to Live
	header[9] = (byte)(ipw.protocol) // Protocol

	// Src and Dst IPs
	srcIP := net.ParseIP(ipw.src)
	fmt.Println(srcIP)
	//    fmt.Println(srcIP[12])
	//    fmt.Println(srcIP[13])
	//    fmt.Println(srcIP[14])
	//    fmt.Println(srcIP[15])
	dstIP := net.ParseIP(ipw.dst)
	fmt.Println(dstIP)
	header[12] = srcIP[12]
	header[13] = srcIP[13]
	header[14] = srcIP[14]
	header[15] = srcIP[15]
	header[16] = dstIP[12]
	header[17] = dstIP[13]
	header[18] = dstIP[14]
	header[19] = dstIP[15]

	maxFragSize := int(ipw.maxFragSize)
	maxPaySize := maxFragSize - int(ipw.headerLen)

	for i := 0; i < len(p)/maxPaySize+1; i += 1 {
		fmt.Println("Looping fragmenting")
		if len(p) <= maxPaySize*(i+1) {
			header[6] = byte(0)
		}
		fmt.Println("off", i*maxFragSize, byte((i*maxFragSize)>>8), byte(i*maxFragSize))

		offset := (i * maxFragSize) / 8
		header[6] += byte(offset >> 8)
		header[7] = byte(i * offset) // Fragment offset

		totalLen := uint16(0)

		// Payload
		newPacket := make([]byte, 1)
		if len(p) <= maxFragSize*(i+1) {
			totalLen = uint16(ipw.headerLen) + uint16(len(p[maxPaySize*i:]))
			fmt.Println("Full Pack")
			fmt.Println("len", len(p[maxPaySize*i:]))
			header[6] = byte(0)

			fmt.Println("Total Len: ", totalLen)
			header[2] = (byte)(totalLen >> 8) // Total Len
			header[3] = (byte)(totalLen)

			// IPv4 header test (before checksum)
			fmt.Println("Packet before checksum: ", header)
			// Checksum
			checksum := calcChecksum(header[:20], true)
			header[10] = byte(checksum >> 8)
			header[11] = byte(checksum)

			newPacket = append(header, p[maxPaySize*i:]...)
			fmt.Println("Full Packet:  ", newPacket)
			fmt.Println("CALCULATED LEN:", i*maxFragSize+len(p[maxPaySize*i:]))
		} else {
			totalLen = uint16(ipw.headerLen) + uint16(len(p[maxPaySize*i:maxPaySize*(i+1)]))
			fmt.Println("Partial packet")
			fmt.Println("len", len(p[maxPaySize*i:maxPaySize*(i+1)]))

			fmt.Println("Total Len: ", totalLen)
			header[2] = (byte)(totalLen >> 8) // Total Len
			header[3] = (byte)(totalLen)

			// IPv4 header test (before checksum)
			fmt.Println("Packet before checksum: ", header)
			// Checksum
			checksum := calcChecksum(header[:20], true)
			header[10] = byte(checksum >> 8)
			header[11] = byte(checksum)

			newPacket = append(header, p[maxPaySize*i:maxPaySize*(i+1)]...)
			fmt.Println("Full Packet:  ", newPacket)
		}

		err := syscall.Sendto(ipw.fd, newPacket, 0, ipw.sockAddr)
		if err != nil {
			return err
		}
	}

	// TODO: Allow IP fragmentation (use 1500 as MTU)
	return nil
}

func (ipw *IP_Writer) Close() error {
	return syscall.Close(ipw.fd)
}

/* h := &ipv4.Header{
	Version:  ipv4.Version,      // protocol version
	Len:      20,                // header length
	TOS:      0,                 // type-of-service (0 is everything normal)
	TotalLen: len(x) + 20,       // packet total length (octets)
	ID:       0,                 // identification
	Flags:    ipv4.DontFragment, // flags
	FragOff:  0,                 // fragment offset
	TTL:      8,                 // time-to-live (maximum lifespan in seconds)
	Protocol: 17,                // next protocol (17 is UDP)
	Checksum: 0,                 // checksum (apparently autocomputed)
	//Src:    net.IPv4(127, 0, 0, 1), // source address, apparently done automatically
	Dst: net.ParseIP(c.manager.ipAddress), // destination address
	//Options                         // options, extension headers
}
*/
<commit_msg>Bug fix<commit_after>package main

import (
	"errors"
	"fmt"
	"net"
	"syscall"
)

type IP_Writer struct {
	fd          int
	sockAddr    syscall.Sockaddr
	version     uint8
	dst, src    string
	headerLen   uint16
	ttl         uint8
	protocol    uint8
	identifier  uint16
	maxFragSize uint16
}

func NewIP_Writer(dst string, protocol uint8) (*IP_Writer, error) {
	fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
	if err != nil {
		fmt.Println("Write's socket failed")
		return nil, err
	}

	dstIPAddr, err := net.ResolveIPAddr("ip", dst)
	if err != nil {
		//fmt.Println(err)
		return nil, err
	}
	fmt.Println("Full Address: ", dstIPAddr)

	addr := &syscall.SockaddrInet4{
		Port: 20000,
		Addr: [4]byte{
			dstIPAddr.IP[12],
			dstIPAddr.IP[13],
			dstIPAddr.IP[14],
			dstIPAddr.IP[15],
		},
	}

	err = syscall.Connect(fd, addr)
	if err != nil {
		return nil, errors.New("Failed to connect.")
	}

	return &IP_Writer{
		fd:          fd,
		sockAddr:    addr,
		version:     4,
		headerLen:   20,
		dst:         dst,
		src:         "127.0.0.1",
		ttl:         8,
		protocol:    17,
		identifier:  20000,
		maxFragSize: 1500,
	}, nil
}

func (ipw *IP_Writer) WriteTo(p []byte) error {
	header := make([]byte, ipw.headerLen)
	header[0] = (byte)((ipw.version << 4) + (uint8)(ipw.headerLen/4)) // Version, IHL
	header[1] = 0
	id := ipw.identifier
	header[4] = byte(id >> 8) // Identification
	header[5] = byte(id)
	ipw.identifier++
	header[6] = byte(1 << 5)         // Flags: May fragment, more fragments
	header[8] = (byte)(ipw.ttl)      // Time to Live
	header[9] = (byte)(ipw.protocol) // Protocol

	// Src and Dst IPs
	srcIP := net.ParseIP(ipw.src)
	fmt.Println(srcIP)
	//    fmt.Println(srcIP[12])
	//    fmt.Println(srcIP[13])
	//    fmt.Println(srcIP[14])
	//    fmt.Println(srcIP[15])
	dstIP := net.ParseIP(ipw.dst)
	fmt.Println(dstIP)
	header[12] = srcIP[12]
	header[13] = srcIP[13]
	header[14] = srcIP[14]
	header[15] = srcIP[15]
	header[16] = dstIP[12]
	header[17] = dstIP[13]
	header[18] = dstIP[14]
	header[19] = dstIP[15]

	maxFragSize := int(ipw.maxFragSize)
	maxPaySize := maxFragSize - int(ipw.headerLen)

	for i := 0; i < len(p)/maxPaySize+1; i += 1 {
		fmt.Println("Looping fragmenting")
		if len(p) <= maxPaySize*(i+1) {
			header[6] = byte(0)
		}
		fmt.Println("off", i*maxFragSize, byte((i*maxFragSize)>>8), byte(i*maxFragSize))

		offset := (i * maxFragSize) / 8
		header[6] += byte(offset >> 8)
		header[7] = byte(offset) // Fragment offset

		totalLen := uint16(0)

		// Payload
		newPacket := make([]byte, 1)
		if len(p) <= maxFragSize*(i+1) {
			totalLen = uint16(ipw.headerLen) + uint16(len(p[maxPaySize*i:]))
			fmt.Println("Full Pack")
			fmt.Println("len", len(p[maxPaySize*i:]))
			header[6] = byte(0)

			fmt.Println("Total Len: ", totalLen)
			header[2] = (byte)(totalLen >> 8) // Total Len
			header[3] = (byte)(totalLen)

			// IPv4 header test (before checksum)
			fmt.Println("Packet before checksum: ", header)
			// Checksum
			checksum := calcChecksum(header[:20], true)
			header[10] = byte(checksum >> 8)
			header[11] = byte(checksum)

			newPacket = append(header, p[maxPaySize*i:]...)
			fmt.Println("Full Packet:  ", newPacket)
			fmt.Println("CALCULATED LEN:", i*maxFragSize+len(p[maxPaySize*i:]))
		} else {
			totalLen = uint16(ipw.headerLen) + uint16(len(p[maxPaySize*i:maxPaySize*(i+1)]))
			fmt.Println("Partial packet")
			fmt.Println("len", len(p[maxPaySize*i:maxPaySize*(i+1)]))

			fmt.Println("Total Len: ", totalLen)
			header[2] = (byte)(totalLen >> 8) // Total Len
			header[3] = (byte)(totalLen)

			// IPv4 header test (before checksum)
			fmt.Println("Packet before checksum: ", header)
			// Checksum
			checksum := calcChecksum(header[:20], true)
			header[10] = byte(checksum >> 8)
			header[11] = byte(checksum)

			newPacket = append(header, p[maxPaySize*i:maxPaySize*(i+1)]...)
			fmt.Println("Full Packet:  ", newPacket)
		}

		err := syscall.Sendto(ipw.fd, newPacket, 0, ipw.sockAddr)
		if err != nil {
			return err
		}
	}

	// TODO: Allow IP fragmentation (use 1500 as MTU)
	return nil
}

func (ipw *IP_Writer) Close() error {
	return syscall.Close(ipw.fd)
}

/* h := &ipv4.Header{
	Version:  ipv4.Version,      // protocol version
	Len:      20,                // header length
	TOS:      0,                 // type-of-service (0 is everything normal)
	TotalLen: len(x) + 20,       // packet total length (octets)
	ID:       0,                 // identification
	Flags:    ipv4.DontFragment, // flags
	FragOff:  0,                 // fragment offset
	TTL:      8,                 // time-to-live (maximum lifespan in seconds)
	Protocol: 17,                // next protocol (17 is UDP)
	Checksum: 0,                 // checksum (apparently autocomputed)
	//Src:    net.IPv4(127, 0, 0, 1), // source address, apparently done automatically
	Dst: net.ParseIP(c.manager.ipAddress), // destination address
	//Options                         // options, extension headers
}
*/
<|endoftext|>


<commit_before>package svfs

import (
	"os"
	"regexp"
	"strings"

	"github.com/ncw/swift"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

var (
	FolderRegex = regexp.MustCompile("^.+/$")
)

type Directory struct {
	name     string
	path     string
	s        *swift.Connection
	c        *swift.Container
	children []Node
}

func (d *Directory) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Mode = os.ModeDir | 0600
	a.Size = uint64(4096)
	return nil
}

func (d *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	// Create an empty object in swift
	path := d.path + req.Name
	w, err := d.s.ObjectCreate(d.c.Name, path, false, "", "application/octet-stream", nil)
	if err != nil {
		return nil, nil, fuse.EIO
	}
	if _, err := w.Write([]byte(nil)); err != nil {
		return nil, nil, fuse.EIO
	}
	w.Close()

	// Retrieve it
	obj, _, err := d.s.Object(d.c.Name, path)
	if err != nil {
		return nil, nil, fuse.EIO
	}

	// New node
	node := &Object{
		name: req.Name,
		path: path,
		s:    d.s,
		so:   &obj,
		c:    d.c,
	}

	// Get object handler handler
	h, err := node.open(fuse.OpenWriteOnly)
	if err != nil {
		return nil, nil, fuse.EIO
	}

	// Force cache eviction
	d.children = []Node{}

	return node, h, nil
}

func (d *Directory) Export() fuse.Dirent {
	return fuse.Dirent{
		Name: d.name,
		Type: fuse.DT_Dir,
	}
}

func (d *Directory) ReadDirAll(ctx context.Context) (entries []fuse.Dirent, err error) {
	// Cache hit
	if len(d.children) > 0 {
		for _, child := range d.children {
			entries = append(entries, child.Export())
		}
		return entries, nil
	}

	// Fetch objects
	objects, err := d.s.ObjectsAll(d.c.Name, &swift.ObjectsOpts{
		Delimiter: '/',
		Prefix:    d.path,
	})
	if err != nil {
		return nil, err
	}

	// Fill cache
	for _, object := range objects {
		var (
			child    Node
			o        = object
			fileName = strings.TrimPrefix(o.Name, d.path)
		)
		// This is a directory
		if FolderRegex.Match([]byte(o.Name)) && fileName != "" {
			child = &Directory{
				s:    d.s,
				c:    d.c,
				path: o.Name,
				name: fileName[:len(fileName)-1],
			}
		}
		// This is a swift object
		if !FolderRegex.Match([]byte(o.Name)) {
			child = &Object{
				path: o.Name,
				name: fileName,
				s:    d.s,
				c:    d.c,
				so:   &o,
				p:    d,
			}
		}

		if child != nil {
			d.children = append(d.children, child)
			entries = append(entries, child.Export())
		}
	}

	return entries, nil
}

func (d *Directory) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {
	for _, item := range d.children {
		if item.Name() == req.Name {
			if n, ok := item.(*Container); ok {
				return n, nil
			}
			if n, ok := item.(*Directory); ok {
				return n, nil
			}
			if n, ok := item.(*Object); ok {
				return n, nil
			}
		}
	}
	return nil, fuse.ENOENT
}

func (d *Directory) Name() string {
	return d.name
}

func (d *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	// Delete from swift
	err := d.s.ObjectDelete(d.c.Name, d.path+req.Name)
	if err != nil {
		return err
	}

	// Cache eviction
	d.children = []Node{}

	return nil
}

func (d *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
	// Not supported
	if _, ok := newDir.(*Root); ok {
		return fuse.ENOTSUP
	}
	// Swift move = copy + delete
	if t, ok := newDir.(*Container); ok {
		d.s.ObjectMove(d.c.Name, d.path+req.OldName, t.c.Name, t.path+req.NewName)
		t.children = []Node{}
		d.children = []Node{}
		return nil
	}
	if t, ok := newDir.(*Directory); ok {
		d.s.ObjectMove(d.c.Name, d.path+req.OldName, t.c.Name, t.path+req.NewName)
		t.children = []Node{}
		d.children = []Node{}
		return nil
	}
	return nil
}

var (
	_ Node           = (*Directory)(nil)
	_ fs.Node        = (*Directory)(nil)
	_ fs.NodeCreater = (*Directory)(nil)
	_ fs.NodeRemover = (*Directory)(nil)
	_ fs.NodeRenamer = (*Directory)(nil)
)
<commit_msg>Bugfix: removing pseudo directory cause I/O error<commit_after>package svfs

import (
	"os"
	"regexp"
	"strings"

	"github.com/ncw/swift"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

var (
	FolderRegex = regexp.MustCompile("^.+/$")
)

type Directory struct {
	name     string
	path     string
	s        *swift.Connection
	c        *swift.Container
	children []Node
}

func (d *Directory) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Mode = os.ModeDir | 0600
	a.Size = uint64(4096)
	return nil
}

func (d *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	// Create an empty object in swift
	path := d.path + req.Name
	w, err := d.s.ObjectCreate(d.c.Name, path, false, "", "application/octet-stream", nil)
	if err != nil {
		return nil, nil, fuse.EIO
	}
	if _, err := w.Write([]byte(nil)); err != nil {
		return nil, nil, fuse.EIO
	}
	w.Close()

	// Retrieve it
	obj, _, err := d.s.Object(d.c.Name, path)
	if err != nil {
		return nil, nil, fuse.EIO
	}

	// New node
	node := &Object{
		name: req.Name,
		path: path,
		s:    d.s,
		so:   &obj,
		c:    d.c,
	}

	// Get object handler handler
	h, err := node.open(fuse.OpenWriteOnly)
	if err != nil {
		return nil, nil, fuse.EIO
	}

	// Force cache eviction
	d.children = []Node{}

	return node, h, nil
}

func (d *Directory) Export() fuse.Dirent {
	return fuse.Dirent{
		Name: d.name,
		Type: fuse.DT_Dir,
	}
}

func (d *Directory) ReadDirAll(ctx context.Context) (entries []fuse.Dirent, err error) {
	// Cache hit
	if len(d.children) > 0 {
		for _, child := range d.children {
			entries = append(entries, child.Export())
		}
		return entries, nil
	}

	// Fetch objects
	objects, err := d.s.ObjectsAll(d.c.Name, &swift.ObjectsOpts{
		Delimiter: '/',
		Prefix:    d.path,
	})
	if err != nil {
		return nil, err
	}

	// Fill cache
	for _, object := range objects {
		var (
			child    Node
			o        = object
			fileName = strings.TrimPrefix(o.Name, d.path)
		)
		// This is a directory
		if FolderRegex.Match([]byte(o.Name)) && fileName != "" {
			child = &Directory{
				s:    d.s,
				c:    d.c,
				path: o.Name,
				name: fileName[:len(fileName)-1],
			}
		}
		// This is a swift object
		if !FolderRegex.Match([]byte(o.Name)) {
			child = &Object{
				path: o.Name,
				name: fileName,
				s:    d.s,
				c:    d.c,
				so:   &o,
				p:    d,
			}
		}

		if child != nil {
			d.children = append(d.children, child)
			entries = append(entries, child.Export())
		}
	}

	return entries, nil
}

func (d *Directory) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {
	for _, item := range d.children {
		if item.Name() == req.Name {
			if n, ok := item.(*Container); ok {
				return n, nil
			}
			if n, ok := item.(*Directory); ok {
				return n, nil
			}
			if n, ok := item.(*Object); ok {
				return n, nil
			}
		}
	}
	return nil, fuse.ENOENT
}

func (d *Directory) Name() string {
	return d.name
}

func (d *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	// Delete from swift
	err := d.s.ObjectDelete(d.c.Name, d.path+req.Name)
	if err != nil && err != swift.ObjectNotFound {
		return err
	}

	// Cache eviction
	d.children = []Node{}

	return nil
}

func (d *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
	// Not supported
	if _, ok := newDir.(*Root); ok {
		return fuse.ENOTSUP
	}
	// Swift move = copy + delete
	if t, ok := newDir.(*Container); ok {
		d.s.ObjectMove(d.c.Name, d.path+req.OldName, t.c.Name, t.path+req.NewName)
		t.children = []Node{}
		d.children = []Node{}
		return nil
	}
	if t, ok := newDir.(*Directory); ok {
		d.s.ObjectMove(d.c.Name, d.path+req.OldName, t.c.Name, t.path+req.NewName)
		t.children = []Node{}
		d.children = []Node{}
		return nil
	}
	return nil
}

var (
	_ Node           = (*Directory)(nil)
	_ fs.Node        = (*Directory)(nil)
	_ fs.NodeCreater = (*Directory)(nil)
	_ fs.NodeRemover = (*Directory)(nil)
	_ fs.NodeRenamer = (*Directory)(nil)
)
<|endoftext|>


<commit_before>// Package db contains all interfaces to the databases used by Ponzu, including
// exported functions to easily manage addons, users, indices, search, content,
// and configuration.
package db

import (
	"log"

	"github.com/ponzu-cms/ponzu/system/item"
	"github.com/ponzu-cms/ponzu/system/search"

	"github.com/boltdb/bolt"
	"github.com/nilslice/jwt"
)

var store *bolt.DB

// Close exports the abillity to close our db file. Should be called with defer
// after call to Init() from the same place.
func Close() {
	err := store.Close()
	if err != nil {
		log.Println(err)
	}
}

// Init creates a db connection, initializes db with required info, sets secrets
func Init() {
	if store != nil {
		return
	}

	var err error
	store, err = bolt.Open("system.db", 0666, nil)
	if err != nil {
		log.Fatalln(err)
	}

	err = store.Update(func(tx *bolt.Tx) error {
		// initialize db with all content type buckets & sorted bucket for type
		for t := range item.Types {
			_, err := tx.CreateBucketIfNotExists([]byte(t))
			if err != nil {
				return err
			}

			_, err = tx.CreateBucketIfNotExists([]byte(t + "__sorted"))
			if err != nil {
				return err
			}
		}

		// init db with other buckets as needed
		buckets := []string{
			"__config", "__users", "__contentIndex",
			"__addons", "__uploads",
		}
		for _, name := range buckets {
			_, err := tx.CreateBucketIfNotExists([]byte(name))
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		log.Fatalln("Coudn't initialize db with buckets.", err)
	}

	err = LoadCacheConfig()
	if err != nil {
		log.Fatalln("Failed to load config cache.", err)
	}

	clientSecret := ConfigCache("client_secret").(string)

	if clientSecret != "" {
		jwt.Secret([]byte(clientSecret))
	}

	// invalidate cache on system start
	err = InvalidateCache()
	if err != nil {
		log.Fatalln("Failed to invalidate cache.", err)
	}

	go func() {
		for t := range item.Types {
			err := search.MapIndex(t)
			if err != nil {
				log.Fatalln(err)
				return
			}

			SortContent(t)
		}
	}()
}

// InitSearchIndex initializes Search Index for search to be functional
// This was moved out of db.Init and put to main(), because addoon checker was initializing db together with
// search indexing initialisation in time when there were no item.Types defined so search index was always empty when using addons.
// We still have no guarentee whatsoever that item.Types is defined
// Should be called from a goroutine after SetContent is successful (SortContent requirement)
func InitSearchIndex() {
	for t := range item.Types {
		err := search.MapIndex(t)
		if err != nil {
			log.Fatalln(err)
			return
		}
		SortContent(t)
	}
}

// SystemInitComplete checks if there is at least 1 admin user in the db which
// would indicate that the system has been configured to the minimum required.
func SystemInitComplete() bool {
	complete := false

	err := store.View(func(tx *bolt.Tx) error {
		users := tx.Bucket([]byte("__users"))
		if users == nil {
			return bolt.ErrBucketNotFound
		}

		err := users.ForEach(func(k, v []byte) error {
			complete = true
			return nil
		})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		complete = false
		log.Fatalln(err)
	}

	return complete
}
<commit_msg>fix typo<commit_after>// Package db contains all interfaces to the databases used by Ponzu, including
// exported functions to easily manage addons, users, indices, search, content,
// and configuration.
package db

import (
	"log"

	"github.com/ponzu-cms/ponzu/system/item"
	"github.com/ponzu-cms/ponzu/system/search"

	"github.com/boltdb/bolt"
	"github.com/nilslice/jwt"
)

var store *bolt.DB

// Close exports the abillity to close our db file. Should be called with defer
// after call to Init() from the same place.
func Close() {
	err := store.Close()
	if err != nil {
		log.Println(err)
	}
}

// Init creates a db connection, initializes db with required info, sets secrets
func Init() {
	if store != nil {
		return
	}

	var err error
	store, err = bolt.Open("system.db", 0666, nil)
	if err != nil {
		log.Fatalln(err)
	}

	err = store.Update(func(tx *bolt.Tx) error {
		// initialize db with all content type buckets & sorted bucket for type
		for t := range item.Types {
			_, err := tx.CreateBucketIfNotExists([]byte(t))
			if err != nil {
				return err
			}

			_, err = tx.CreateBucketIfNotExists([]byte(t + "__sorted"))
			if err != nil {
				return err
			}
		}

		// init db with other buckets as needed
		buckets := []string{
			"__config", "__users", "__contentIndex",
			"__addons", "__uploads",
		}
		for _, name := range buckets {
			_, err := tx.CreateBucketIfNotExists([]byte(name))
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		log.Fatalln("Coudn't initialize db with buckets.", err)
	}

	err = LoadCacheConfig()
	if err != nil {
		log.Fatalln("Failed to load config cache.", err)
	}

	clientSecret := ConfigCache("client_secret").(string)

	if clientSecret != "" {
		jwt.Secret([]byte(clientSecret))
	}

	// invalidate cache on system start
	err = InvalidateCache()
	if err != nil {
		log.Fatalln("Failed to invalidate cache.", err)
	}

	go func() {
		for t := range item.Types {
			err := search.MapIndex(t)
			if err != nil {
				log.Fatalln(err)
				return
			}

			SortContent(t)
		}
	}()
}

// InitSearchIndex initializes Search Index for search to be functional
// This was moved out of db.Init and put to main(), because addon checker was initializing db together with
// search indexing initialisation in time when there were no item.Types defined so search index was always
// empty when using addons. We still have no guarentee whatsoever that item.Types is defined
// Should be called from a goroutine after SetContent is successful (SortContent requirement)
func InitSearchIndex() {
	for t := range item.Types {
		err := search.MapIndex(t)
		if err != nil {
			log.Fatalln(err)
			return
		}
		SortContent(t)
	}
}

// SystemInitComplete checks if there is at least 1 admin user in the db which
// would indicate that the system has been configured to the minimum required.
func SystemInitComplete() bool {
	complete := false

	err := store.View(func(tx *bolt.Tx) error {
		users := tx.Bucket([]byte("__users"))
		if users == nil {
			return bolt.ErrBucketNotFound
		}

		err := users.ForEach(func(k, v []byte) error {
			complete = true
			return nil
		})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		complete = false
		log.Fatalln(err)
	}

	return complete
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// Consumer struct
type Consumer struct {
	inputChan chan int
	jobsChan  chan int
}

func getRandomTime() int {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(10)
}

func withContextFunc(ctx context.Context, f func()) context.Context {
	ctx, cancel := context.WithCancel(ctx)
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		defer signal.Stop(c)

		select {
		case <-ctx.Done():
		case <-c:
			cancel()
			f()
		}
	}()

	return ctx
}

func (c *Consumer) queue(input int) bool {
	select {
	case c.inputChan <- input:
		log.Println("already send input value:", input)
		return true
	default:
		return false
	}
}

func (c Consumer) startConsumer(ctx context.Context) {
	for {
		select {
		case job := <-c.inputChan:
			if ctx.Err() != nil {
				close(c.jobsChan)
				return
			}
			c.jobsChan <- job
		case <-ctx.Done():
			close(c.jobsChan)
			return
		}
	}
}

func (c *Consumer) process(num, job int) {
	n := getRandomTime()
	log.Printf("Sleeping %d seconds...\n", n)
	time.Sleep(time.Duration(n) * time.Second)
	log.Println("worker:", num, " job value:", job)
}

func (c *Consumer) worker(ctx context.Context, num int) {
	log.Println("start the worker", num)
	for {
		select {
		case job := <-c.jobsChan:
			if ctx.Err() != nil {
				log.Println("get next job", job, "and close the worker", num)
				return
			}
			c.process(num, job)
		case <-ctx.Done():
			log.Println("close the worker", num)
			return
		}
	}
}

const poolSize = 2

func main() {
	finished := make(chan bool)
	// create the consumer
	consumer := Consumer{
		inputChan: make(chan int, 10),
		jobsChan:  make(chan int, poolSize),
	}

	ctx := withContextFunc(context.Background(), func() {
		log.Println("cancel from ctrl+c event")
		finished <- true
	})

	for i := 0; i < poolSize; i++ {
		go consumer.worker(ctx, i)
	}

	go consumer.startConsumer(ctx)

	go func() {
		consumer.queue(1)
		consumer.queue(2)
		consumer.queue(3)
		consumer.queue(4)
		consumer.queue(5)
	}()

	<-finished
}
<commit_msg>chore: finished graceful shutdown the worker<commit_after>package main

import (
	"context"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

// Consumer struct
type Consumer struct {
	inputChan chan int
	jobsChan  chan int
}

func getRandomTime() int {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(10)
}

func withContextFunc(ctx context.Context, f func()) context.Context {
	ctx, cancel := context.WithCancel(ctx)
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		defer signal.Stop(c)

		select {
		case <-ctx.Done():
		case <-c:
			cancel()
			f()
		}
	}()

	return ctx
}

func (c *Consumer) queue(input int) bool {
	select {
	case c.inputChan <- input:
		log.Println("already send input value:", input)
		return true
	default:
		return false
	}
}

func (c Consumer) startConsumer(ctx context.Context) {
	for {
		select {
		case job := <-c.inputChan:
			if ctx.Err() != nil {
				close(c.jobsChan)
				return
			}
			c.jobsChan <- job
		case <-ctx.Done():
			close(c.jobsChan)
			return
		}
	}
}

func (c *Consumer) process(num, job int) {
	n := getRandomTime()
	log.Printf("Sleeping %d seconds...\n", n)
	time.Sleep(time.Duration(n) * time.Second)
	log.Println("worker:", num, " job value:", job)
}

func (c *Consumer) worker(ctx context.Context, num int, wg *sync.WaitGroup) {
	defer wg.Done()
	log.Println("start the worker", num)
	for {
		select {
		case job := <-c.jobsChan:
			if ctx.Err() != nil {
				log.Println("get next job", job, "and close the worker", num)
				return
			}
			c.process(num, job)
		case <-ctx.Done():
			log.Println("close the worker", num)
			return
		}
	}
}

const poolSize = 2

func main() {
	finished := make(chan bool)
	wg := &sync.WaitGroup{}
	wg.Add(poolSize)
	// create the consumer
	consumer := Consumer{
		inputChan: make(chan int, 10),
		jobsChan:  make(chan int, poolSize),
	}

	ctx := withContextFunc(context.Background(), func() {
		log.Println("cancel from ctrl+c event")
		wg.Wait()
		close(finished)
	})

	for i := 0; i < poolSize; i++ {
		go consumer.worker(ctx, i, wg)
	}

	go consumer.startConsumer(ctx)

	go func() {
		consumer.queue(1)
		consumer.queue(2)
		consumer.queue(3)
		consumer.queue(4)
		consumer.queue(5)
	}()

	<-finished
	log.Println("Game over")
}
<|endoftext|>


<commit_before>package irmago

import (
	"fmt"
	"math/big"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestMain(m *testing.M) {
	if len(MetaStore.SchemeManagers) == 0 { // FIXME
		MetaStore.ParseFolder("testdata/irma_configuration")
	}
	Manager = newCredentialManager()
	err := os.RemoveAll("testdata/storage/test")
	if err != nil {
		fmt.Println("Could not delete test storage")
		os.Exit(1)
	}
	err = os.Mkdir("testdata/storage/test", 0755)
	if err != nil {
		fmt.Println("Could not create test storage")
		os.Exit(1)
	}

	retCode := m.Run()

	err = os.RemoveAll("testdata/storage/test")
	if err != nil {
		fmt.Println("Could not delete test storage")
		os.Exit(1)
	}

	os.Exit(retCode)
}

// A convenience function for initializing big integers from known correct (10
// base) strings. Use with care, errors are ignored.
func s2big(s string) (r *big.Int) {
	r, _ = new(big.Int).SetString(s, 10)
	return
}

func parseAndroidStorage(t *testing.T) {
	err := Manager.Init("testdata/storage/test")
	assert.NoError(t, err, "Manager.Init() failed")
	err = Manager.ParseAndroidStorage()
	assert.NoError(t, err, "ParseAndroidStorage failed")
}

func verifyStoreIsUnmarshaled(t *testing.T) {
	cred, err := Manager.Credential("irma-demo.RU.studentCard", 0)
	assert.NoError(t, err, "could not fetch credential")
	assert.NotNil(t, cred, "Credential should exist")
	assert.NotNil(t, cred.Attributes[0], "Metadata attribute of irma-demo.RU.studentCard should not be nil")

	assert.True(t,
		cred.Signature.Verify(cred.PublicKey(), cred.Attributes),
		"Credential should be valid",
	)
}

func TestAndroidParse(t *testing.T) {
	parseAndroidStorage(t)
	verifyStoreIsUnmarshaled(t)
}

func TestUnmarshaling(t *testing.T) {
	parseAndroidStorage(t)

	Manager = newCredentialManager()
	Manager.Init("testdata/storage/test")

	verifyStoreIsUnmarshaled(t)
}

func TestParseStore(t *testing.T) {
	err := MetaStore.ParseFolder("testdata/irma_configuration")
	if err != nil {
		t.Fatal(err)
	}

	assert.NotNil(t, MetaStore.Issuers["irma-demo.RU"].CurrentPublicKey().N, "irma-demo.RU public key has no modulus")
	assert.Equal(t,
		"Irma Demo",
		MetaStore.SchemeManagers["irma-demo"].HRName.Translation("en"),
		"irma-demo scheme manager has unexpected name")
	assert.Equal(t,
		"Radboud Universiteit Nijmegen",
		MetaStore.Issuers["irma-demo.RU"].HRName.Translation("en"),
		"irma-demo.RU issuer has unexpected name")
	assert.Equal(t,
		"Student Card",
		MetaStore.Credentials["irma-demo.RU.studentCard"].HRShortName.Translation("en"),
		"irma-demo.RU.studentCard has unexpected name")

	assert.Equal(t,
		"studentID",
		MetaStore.Credentials["irma-demo.RU.studentCard"].Attributes[2].ID,
		"irma-demo.RU.studentCard.studentID has unexpected name")

	// Hash algorithm pseudocode:
	// Base64(SHA256("irma-demo.RU.studentCard")[0:16])
	assert.Contains(t, MetaStore.reverseHashes, "1stqlPad5edpfS1Na1U+DA==",
		"irma-demo.RU.studentCard had improper hash")
	assert.Contains(t, MetaStore.reverseHashes, "CLjnADMBYlFcuGOT7Z0xRg==",
		"irma-demo.MijnOverheid.root had improper hash")
}

func TestMetadataAttribute(t *testing.T) {
	metadata := NewMetadataAttribute()
	if metadata.Version() != 0x02 {
		t.Errorf("Unexpected metadata version: %d", metadata.Version())
	}

	expiry := metadata.SigningDate().Unix() + int64(metadata.ValidityDuration()*ExpiryFactor)
	if !time.Unix(expiry, 0).Equal(metadata.Expiry()) {
		t.Errorf("Invalid signing date")
	}

	if metadata.KeyCounter() != 0 {
		t.Errorf("Unexpected key counter")
	}
}

func TestMetadataCompatibility(t *testing.T) {
	err := MetaStore.ParseFolder("testdata/irma_configuration")
	if err != nil {
		t.Fatal(err)
	}

	// An actual metadata attribute of an IRMA credential extracted from the IRMA app
	attr := MetadataFromInt(s2big("49043481832371145193140299771658227036446546573739245068"))
	assert.NotNil(t, attr.CredentialType(), "attr.CredentialType() should not be nil")

	assert.Equal(t,
		"irma-demo.RU.studentCard",
		attr.CredentialType().Identifier(),
		"Metadata credential type was not irma-demo.RU.studentCard",
	)
	assert.Equal(t, byte(0x02), attr.Version(), "Unexpected metadata version")
	assert.Equal(t, time.Unix(1499904000, 0), attr.SigningDate(), "Unexpected signing date")
	assert.Equal(t, time.Unix(1516233600, 0), attr.Expiry(), "Unexpected expiry date")
	assert.Equal(t, 2, attr.KeyCounter(), "Unexpected key counter")
}
<commit_msg>Make tests more independent<commit_after>package irmago

import (
	"fmt"
	"math/big"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestMain(m *testing.M) {
	retCode := m.Run()

	err := os.RemoveAll("testdata/storage/test")
	if err != nil {
		fmt.Println("Could not delete test storage")
		os.Exit(1)
	}

	os.Exit(retCode)
}

func parseMetaStore(t *testing.T) {
	require.NoError(t, MetaStore.ParseFolder("testdata/irma_configuration"), "MetaStore.ParseFolder() failed")
}

func parseStorage(t *testing.T) {
	exists, err := pathExists("testdata/storage/path")
	require.NoError(t, err, "pathexists() failed")
	if !exists {
		require.NoError(t, os.Mkdir("testdata/storage/test", 0755), "Could not create test storage")
	}
	require.NoError(t, Manager.Init("testdata/storage/test"), "Manager.Init() failed")

}

func teardown(t *testing.T) {
	MetaStore = newConfigurationStore()
	Manager = newCredentialManager()
	assert.NoError(t, os.RemoveAll("testdata/storage/test"))
}

// A convenience function for initializing big integers from known correct (10
// base) strings. Use with care, errors are ignored.
func s2big(s string) (r *big.Int) {
	r, _ = new(big.Int).SetString(s, 10)
	return
}

func parseAndroidStorage(t *testing.T) {
	assert.NoError(t, Manager.ParseAndroidStorage(), "ParseAndroidStorage() failed")
}

func verifyStoreIsUnmarshaled(t *testing.T) {
	cred, err := Manager.Credential("irma-demo.RU.studentCard", 0)
	assert.NoError(t, err, "could not fetch credential")
	assert.NotNil(t, cred, "Credential should exist")
	assert.NotNil(t, cred.Attributes[0], "Metadata attribute of irma-demo.RU.studentCard should not be nil")

	assert.True(t,
		cred.Signature.Verify(cred.PublicKey(), cred.Attributes),
		"Credential should be valid",
	)
}

func TestAndroidParse(t *testing.T) {
	parseMetaStore(t)
	parseStorage(t)
	parseAndroidStorage(t)
	verifyStoreIsUnmarshaled(t)

	teardown(t)
}

func TestUnmarshaling(t *testing.T) {
	parseMetaStore(t)
	parseStorage(t)
	parseAndroidStorage(t)

	Manager = newCredentialManager()
	Manager.Init("testdata/storage/test")

	verifyStoreIsUnmarshaled(t)

	teardown(t)
}

func TestParseStore(t *testing.T) {
	parseMetaStore(t)

	assert.NotNil(t, MetaStore.Issuers["irma-demo.RU"].CurrentPublicKey().N, "irma-demo.RU public key has no modulus")
	assert.Equal(t,
		"Irma Demo",
		MetaStore.SchemeManagers["irma-demo"].HRName.Translation("en"),
		"irma-demo scheme manager has unexpected name")
	assert.Equal(t,
		"Radboud Universiteit Nijmegen",
		MetaStore.Issuers["irma-demo.RU"].HRName.Translation("en"),
		"irma-demo.RU issuer has unexpected name")
	assert.Equal(t,
		"Student Card",
		MetaStore.Credentials["irma-demo.RU.studentCard"].HRShortName.Translation("en"),
		"irma-demo.RU.studentCard has unexpected name")

	assert.Equal(t,
		"studentID",
		MetaStore.Credentials["irma-demo.RU.studentCard"].Attributes[2].ID,
		"irma-demo.RU.studentCard.studentID has unexpected name")

	// Hash algorithm pseudocode:
	// Base64(SHA256("irma-demo.RU.studentCard")[0:16])
	assert.Contains(t, MetaStore.reverseHashes, "1stqlPad5edpfS1Na1U+DA==",
		"irma-demo.RU.studentCard had improper hash")
	assert.Contains(t, MetaStore.reverseHashes, "CLjnADMBYlFcuGOT7Z0xRg==",
		"irma-demo.MijnOverheid.root had improper hash")

	teardown(t)
}

func TestMetadataAttribute(t *testing.T) {
	metadata := NewMetadataAttribute()
	if metadata.Version() != 0x02 {
		t.Errorf("Unexpected metadata version: %d", metadata.Version())
	}

	expiry := metadata.SigningDate().Unix() + int64(metadata.ValidityDuration()*ExpiryFactor)
	if !time.Unix(expiry, 0).Equal(metadata.Expiry()) {
		t.Errorf("Invalid signing date")
	}

	if metadata.KeyCounter() != 0 {
		t.Errorf("Unexpected key counter")
	}
}

func TestMetadataCompatibility(t *testing.T) {
	parseMetaStore(t)

	// An actual metadata attribute of an IRMA credential extracted from the IRMA app
	attr := MetadataFromInt(s2big("49043481832371145193140299771658227036446546573739245068"))
	assert.NotNil(t, attr.CredentialType(), "attr.CredentialType() should not be nil")

	assert.Equal(t,
		"irma-demo.RU.studentCard",
		attr.CredentialType().Identifier(),
		"Metadata credential type was not irma-demo.RU.studentCard",
	)
	assert.Equal(t, byte(0x02), attr.Version(), "Unexpected metadata version")
	assert.Equal(t, time.Unix(1499904000, 0), attr.SigningDate(), "Unexpected signing date")
	assert.Equal(t, time.Unix(1516233600, 0), attr.Expiry(), "Unexpected expiry date")
	assert.Equal(t, 2, attr.KeyCounter(), "Unexpected key counter")

	teardown(t)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

// Package v1alpha1 contains definitions of Vertical Pod Autoscaler related objects.
package v1alpha1

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

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

// VerticalPodAutoscaler is the configuration for a vertical pod
// autoscaler, which automatically manages pod resources based on historical and
// real time resource utilization.
type VerticalPodAutoscaler struct {
	metav1.TypeMeta `json:",inline"`
	// Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Specification of the behavior of the autoscaler.
	// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status.
	// +optional
	Spec VerticalPodAutoscalerSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

	// Current information about the autoscaler.
	// +optional
	Status VerticalPodAutoscalerStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

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

// VerticalPodAutoscalerList is a list of VerticalPodAutoscaler objects.
type VerticalPodAutoscalerList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`
	Items           []VerticalPodAutoscaler `json:"items"`
}

// VerticalPodAutoscalerSpec is the specification of the behavior of the autoscaler.
type VerticalPodAutoscalerSpec struct {
	// A label query that determines the set of pods controlled by the Autoscaler.
	// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
	Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,1,opt,name=selector"`

	// Describes the rules on how changes are applied to the pods.
	// +optional
	UpdatePolicy PodUpdatePolicy `json:"updatePolicy,omitempty" protobuf:"bytes,2,opt,name=updatePolicy"`

	// Controls how the autoscaler computes recommended resources.
	// +optional
	ResourcePolicy PodResourcePolicy `json:"podResourcePolicy,omitempty" protobuf:"bytes,3,opt,name=podResourcePolicy"`
}

// VerticalPodAutoscalerStatus describes the runtime state of the autoscaler.
type VerticalPodAutoscalerStatus struct {
	// The time when the status was last refreshed.
	LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,1,opt,name=lastUpdateTime"`
	// The most recently computed amount of resources recommended by the
	// autoscaler for the controlled pods.
	// +optional
	Recommendation RecommendedPodResources `json:"recommendation,omitempty" protobuf:"bytes,2,opt,name=recommendation"`

	// Conditions is the set of conditions required for this autoscaler to scale its target,
	// and indicates whether or not those conditions are met.
	Conditions []VerticalPodAutoscalerCondition `json:"conditions" protobuf:"bytes,3,rep,name=conditions"`
}

// VerticalPodAutoscalerConditionType are the valid conditions of
// a VerticalPodAutoscaler.
type VerticalPodAutoscalerConditionType string

var (
	// RecommendationProvided indicates whether the VPA recommender was able to calculate a recommendation.
	RecommendationProvided VerticalPodAutoscalerConditionType = "RecommendationProvided"
)

// VerticalPodAutoscalerCondition describes the state of
// a VerticalPodAutoscaler at a certain point.
type VerticalPodAutoscalerCondition struct {
	// type describes the current condition
	Type VerticalPodAutoscalerConditionType `json:"type" protobuf:"bytes,1,name=type"`
	// status is the status of the condition (True, False, Unknown)
	Status apiv1.ConditionStatus `json:"status" protobuf:"bytes,2,name=status"`
	// lastTransitionTime is the last time the condition transitioned from
	// one status to another
	// +optional
	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,3,opt,name=lastTransitionTime"`
	// reason is the reason for the condition's last transition.
	// +optional
	Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
	// message is a human-readable explanation containing details about
	// the transition
	// +optional
	Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
}

// UpdateMode controls when autoscaler applies changes to the pod resoures.
type UpdateMode string

const (
	// UpdateModeOff means that autoscaler never changes Pod resources.
	// The recommender still sets the recommended resources in the
	// VerticalPodAutoscaler object. This can be used for a "dry run".
	UpdateModeOff UpdateMode = "Off"
	// UpdateModeInitial means that autoscaler only assigns resources on pod
	// creation and does not change them during the lifetime of the pod.
	UpdateModeInitial UpdateMode = "Initial"
	// UpdateModeAuto means that autoscaler assigns resources on pod creation
	// and additionally can update them during the lifetime of the pod,
	// including evicting / rescheduling the pod.
	UpdateModeAuto UpdateMode = "Auto"
)

// PodUpdatePolicy describes the rules on how changes are applied to the pods.
type PodUpdatePolicy struct {
	// Controls when autoscaler applies changes to the pod resoures.
	// +optional
	UpdateMode UpdateMode `json:"updateMode,omitempty" protobuf:"bytes,1,opt,name=updateMode"`
}

const (
	// DefaultContainerResourcePolicy can be passed as
	// ContainerResourcePolicy.Name to specify the default policy.
	DefaultContainerResourcePolicy = "*"
)

// ContainerResourcePolicy controls how autoscaler computes the recommended
// resources for a specific container.
type ContainerResourcePolicy struct {
	// Name of the container or DefaultContainerResourcePolicy, in which
	// case the policy is used by the containers that don't have their own
	// policy specified.
	Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
	// Whether autoscaler is enabled for the container. Defaults to "On".
	// +optional
	Mode ContainerScalingMode `json:"mode,omitempty" protobuf:"bytes,2,opt,name=mode"`
	// Specifies the minimal amount of resources that will be recommended
	// for the container.
	// +optional
	MinAllowed apiv1.ResourceList `json:"minAllowed,omitempty" protobuf:"bytes,3,rep,name=minAllowed,casttype=ResourceList,castkey=ResourceName"`
	// Specifies the maximum amount of resources that will be recommended
	// for the container.
	// +optional
	MaxAllowed apiv1.ResourceList `json:"maxAllowed,omitempty" protobuf:"bytes,4,rep,name=maxAllowed,casttype=ResourceList,castkey=ResourceName"`
}

// PodResourcePolicy controls how autoscaler computes the recommended resources
// for containers belonging to the pod.
type PodResourcePolicy struct {
	// Per-container resource policies.
	ContainerPolicies []ContainerResourcePolicy `json:"containerPolicies" protobuf:"bytes,1,rep,name=containerPolicies"`
}

// ContainerScalingMode controls whether autoscaler is enabled for a specific
// container.
type ContainerScalingMode string

const (
	// ContainerScalingModeOn means autoscaling is enabled for a container.
	ContainerScalingModeOn ContainerScalingMode = "On"
	// ContainerScalingModeOff means autoscaling is disabled for a container.
	ContainerScalingModeOff ContainerScalingMode = "Off"
)

// RecommendedPodResources is the recommendation of resources computed by
// autoscaler.
type RecommendedPodResources struct {
	// Resources recommended by the autoscaler for each container.
	ContainerRecommendations []RecommendedContainerResources `json:"containerRecommendations" protobuf:"bytes,1,rep,name=containerRecommendations"`
}

// RecommendedContainerResources is the recommendation of resources computed by
// autoscaler for a specific container. Respects the container resource policy
// if present in the spec.
type RecommendedContainerResources struct {
	// Name of the container.
	Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
	// Recommended amount of resources.
	Target apiv1.ResourceList `json:"target,omitempty" protobuf:"bytes,2,rep,name=target,casttype=ResourceList,castkey=ResourceName"`
	// Minimum recommended amount of resources.
	// Running the application with less resources is likely to have
	// significant impact on performance/availability.
	// +optional
	MinRecommended apiv1.ResourceList `json:"minRecommended,omitempty" protobuf:"bytes,3,rep,name=minRecommended,casttype=ResourceList,castkey=ResourceName"`
	// Maximum recommended amount of resources.
	// Any resources allocated beyond this value are likely wasted.
	// +optional
	MaxRecommended apiv1.ResourceList `json:"maxRecommended,omitempty" protobuf:"bytes,3,rep,name=maxRecommended,casttype=ResourceList,castkey=ResourceName"`
}
<commit_msg>Fix JSON annotation for ResourcePolicy.<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

// Package v1alpha1 contains definitions of Vertical Pod Autoscaler related objects.
package v1alpha1

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

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

// VerticalPodAutoscaler is the configuration for a vertical pod
// autoscaler, which automatically manages pod resources based on historical and
// real time resource utilization.
type VerticalPodAutoscaler struct {
	metav1.TypeMeta `json:",inline"`
	// Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// Specification of the behavior of the autoscaler.
	// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status.
	// +optional
	Spec VerticalPodAutoscalerSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

	// Current information about the autoscaler.
	// +optional
	Status VerticalPodAutoscalerStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

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

// VerticalPodAutoscalerList is a list of VerticalPodAutoscaler objects.
type VerticalPodAutoscalerList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`
	Items           []VerticalPodAutoscaler `json:"items"`
}

// VerticalPodAutoscalerSpec is the specification of the behavior of the autoscaler.
type VerticalPodAutoscalerSpec struct {
	// A label query that determines the set of pods controlled by the Autoscaler.
	// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
	Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,1,opt,name=selector"`

	// Describes the rules on how changes are applied to the pods.
	// +optional
	UpdatePolicy PodUpdatePolicy `json:"updatePolicy,omitempty" protobuf:"bytes,2,opt,name=updatePolicy"`

	// Controls how the autoscaler computes recommended resources.
	// +optional
	ResourcePolicy PodResourcePolicy `json:"resourcePolicy,omitempty" protobuf:"bytes,3,opt,name=resourcePolicy"`
}

// VerticalPodAutoscalerStatus describes the runtime state of the autoscaler.
type VerticalPodAutoscalerStatus struct {
	// The time when the status was last refreshed.
	LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,1,opt,name=lastUpdateTime"`
	// The most recently computed amount of resources recommended by the
	// autoscaler for the controlled pods.
	// +optional
	Recommendation RecommendedPodResources `json:"recommendation,omitempty" protobuf:"bytes,2,opt,name=recommendation"`

	// Conditions is the set of conditions required for this autoscaler to scale its target,
	// and indicates whether or not those conditions are met.
	Conditions []VerticalPodAutoscalerCondition `json:"conditions" protobuf:"bytes,3,rep,name=conditions"`
}

// VerticalPodAutoscalerConditionType are the valid conditions of
// a VerticalPodAutoscaler.
type VerticalPodAutoscalerConditionType string

var (
	// RecommendationProvided indicates whether the VPA recommender was able to calculate a recommendation.
	RecommendationProvided VerticalPodAutoscalerConditionType = "RecommendationProvided"
)

// VerticalPodAutoscalerCondition describes the state of
// a VerticalPodAutoscaler at a certain point.
type VerticalPodAutoscalerCondition struct {
	// type describes the current condition
	Type VerticalPodAutoscalerConditionType `json:"type" protobuf:"bytes,1,name=type"`
	// status is the status of the condition (True, False, Unknown)
	Status apiv1.ConditionStatus `json:"status" protobuf:"bytes,2,name=status"`
	// lastTransitionTime is the last time the condition transitioned from
	// one status to another
	// +optional
	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,3,opt,name=lastTransitionTime"`
	// reason is the reason for the condition's last transition.
	// +optional
	Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
	// message is a human-readable explanation containing details about
	// the transition
	// +optional
	Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
}

// UpdateMode controls when autoscaler applies changes to the pod resoures.
type UpdateMode string

const (
	// UpdateModeOff means that autoscaler never changes Pod resources.
	// The recommender still sets the recommended resources in the
	// VerticalPodAutoscaler object. This can be used for a "dry run".
	UpdateModeOff UpdateMode = "Off"
	// UpdateModeInitial means that autoscaler only assigns resources on pod
	// creation and does not change them during the lifetime of the pod.
	UpdateModeInitial UpdateMode = "Initial"
	// UpdateModeAuto means that autoscaler assigns resources on pod creation
	// and additionally can update them during the lifetime of the pod,
	// including evicting / rescheduling the pod.
	UpdateModeAuto UpdateMode = "Auto"
)

// PodUpdatePolicy describes the rules on how changes are applied to the pods.
type PodUpdatePolicy struct {
	// Controls when autoscaler applies changes to the pod resoures.
	// +optional
	UpdateMode UpdateMode `json:"updateMode,omitempty" protobuf:"bytes,1,opt,name=updateMode"`
}

const (
	// DefaultContainerResourcePolicy can be passed as
	// ContainerResourcePolicy.Name to specify the default policy.
	DefaultContainerResourcePolicy = "*"
)

// ContainerResourcePolicy controls how autoscaler computes the recommended
// resources for a specific container.
type ContainerResourcePolicy struct {
	// Name of the container or DefaultContainerResourcePolicy, in which
	// case the policy is used by the containers that don't have their own
	// policy specified.
	Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
	// Whether autoscaler is enabled for the container. Defaults to "On".
	// +optional
	Mode ContainerScalingMode `json:"mode,omitempty" protobuf:"bytes,2,opt,name=mode"`
	// Specifies the minimal amount of resources that will be recommended
	// for the container.
	// +optional
	MinAllowed apiv1.ResourceList `json:"minAllowed,omitempty" protobuf:"bytes,3,rep,name=minAllowed,casttype=ResourceList,castkey=ResourceName"`
	// Specifies the maximum amount of resources that will be recommended
	// for the container.
	// +optional
	MaxAllowed apiv1.ResourceList `json:"maxAllowed,omitempty" protobuf:"bytes,4,rep,name=maxAllowed,casttype=ResourceList,castkey=ResourceName"`
}

// PodResourcePolicy controls how autoscaler computes the recommended resources
// for containers belonging to the pod.
type PodResourcePolicy struct {
	// Per-container resource policies.
	ContainerPolicies []ContainerResourcePolicy `json:"containerPolicies" protobuf:"bytes,1,rep,name=containerPolicies"`
}

// ContainerScalingMode controls whether autoscaler is enabled for a specific
// container.
type ContainerScalingMode string

const (
	// ContainerScalingModeOn means autoscaling is enabled for a container.
	ContainerScalingModeOn ContainerScalingMode = "On"
	// ContainerScalingModeOff means autoscaling is disabled for a container.
	ContainerScalingModeOff ContainerScalingMode = "Off"
)

// RecommendedPodResources is the recommendation of resources computed by
// autoscaler.
type RecommendedPodResources struct {
	// Resources recommended by the autoscaler for each container.
	ContainerRecommendations []RecommendedContainerResources `json:"containerRecommendations" protobuf:"bytes,1,rep,name=containerRecommendations"`
}

// RecommendedContainerResources is the recommendation of resources computed by
// autoscaler for a specific container. Respects the container resource policy
// if present in the spec.
type RecommendedContainerResources struct {
	// Name of the container.
	Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
	// Recommended amount of resources.
	Target apiv1.ResourceList `json:"target,omitempty" protobuf:"bytes,2,rep,name=target,casttype=ResourceList,castkey=ResourceName"`
	// Minimum recommended amount of resources.
	// Running the application with less resources is likely to have
	// significant impact on performance/availability.
	// +optional
	MinRecommended apiv1.ResourceList `json:"minRecommended,omitempty" protobuf:"bytes,3,rep,name=minRecommended,casttype=ResourceList,castkey=ResourceName"`
	// Maximum recommended amount of resources.
	// Any resources allocated beyond this value are likely wasted.
	// +optional
	MaxRecommended apiv1.ResourceList `json:"maxRecommended,omitempty" protobuf:"bytes,3,rep,name=maxRecommended,casttype=ResourceList,castkey=ResourceName"`
}
<|endoftext|>


<commit_before>package metrics

import (
    "net/http"
    "expvar"
    "github.com/bwmarrin/discordgo"
    "time"
    "github.com/sn0w/Karen/logger"
)

var (
    MessagesReceived = expvar.NewInt("messages_received")
    UserCount = expvar.NewInt("user_count")
    ChannelCount = expvar.NewInt("channel_count")
    GuildCount = expvar.NewInt("guild_count")
    CommandsExecuted = expvar.NewInt("commands_executed")
    CleverbotRequests = expvar.NewInt("cleverbot_requests")
)

func Init() {
    logger.INF("[METRICS] Listening on http://[::1]:1337")
    go http.ListenAndServe(":1337", nil)
}

func OnReady(session *discordgo.Session, event *discordgo.Ready) {
    go CollectDiscordMetrics(session)
}

func OnMessageCreate(session *discordgo.Session, event *discordgo.MessageCreate) {
    MessagesReceived.Add(1)
}

func CollectDiscordMetrics(session *discordgo.Session) {
    for {
        time.Sleep(1 * time.Minute)

        users := make(map[string]string)
        channels := 0
        guilds := session.State.Guilds

        for _, guild := range guilds {
            channels += len(guild.Channels)

            for _, u := range guild.Members {
                users[u.User.ID] = u.User.Username
            }
        }

        UserCount.Set(int64(len(users)))
        ChannelCount.Set(int64(channels))
        GuildCount.Set(int64(len(guilds)))
    }
}
<commit_msg>Add goroutine metric<commit_after>package metrics

import (
    "net/http"
    "expvar"
    "github.com/bwmarrin/discordgo"
    "time"
    "github.com/sn0w/Karen/logger"
    "runtime"
)

var (
    MessagesReceived = expvar.NewInt("messages_received")
    UserCount = expvar.NewInt("user_count")
    ChannelCount = expvar.NewInt("channel_count")
    GuildCount = expvar.NewInt("guild_count")
    CommandsExecuted = expvar.NewInt("commands_executed")
    CleverbotRequests = expvar.NewInt("cleverbot_requests")
    GoroutineCount = expvar.NewInt("coroutine_count")
)

func Init() {
    logger.INF("[METRICS] Listening on http://[::1]:1337")
    go http.ListenAndServe(":1337", nil)
}

func OnReady(session *discordgo.Session, event *discordgo.Ready) {
    go CollectDiscordMetrics(session)
    go CollectRuntimeMetrics()
}

func OnMessageCreate(session *discordgo.Session, event *discordgo.MessageCreate) {
    MessagesReceived.Add(1)
}

func CollectDiscordMetrics(session *discordgo.Session) {
    for {
        time.Sleep(15 * time.Second)

        users := make(map[string]string)
        channels := 0
        guilds := session.State.Guilds

        for _, guild := range guilds {
            channels += len(guild.Channels)

            for _, u := range guild.Members {
                users[u.User.ID] = u.User.Username
            }
        }

        UserCount.Set(int64(len(users)))
        ChannelCount.Set(int64(channels))
        GuildCount.Set(int64(len(guilds)))
    }
}

func CollectRuntimeMetrics() {
    for {
        time.Sleep(15 * time.Second)
        GoroutineCount.Set(runtime.NumGoroutine())
    }
}
<|endoftext|>


<commit_before>package kapusta

import (
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"
)

type dummy struct{}

func (d dummy) Do(r *http.Request) (*http.Response, error) {
	return &http.Response{Request: r}, nil
}

type callOrder []string

func send(r *http.Request, middleware MiddlewareFunc) (*http.Response, error) {
	return Chain(&dummy{}, middleware).Do(r)
}

func createMiddleware(name string, order *callOrder) MiddlewareFunc {
	return func(c Client) Client {
		return ClientFunc(func(r *http.Request) (*http.Response, error) {
			*order = append(*order, name)
			return c.Do(r)
		})
	}
}

func TestChain(t *testing.T) {
	var order callOrder
	client := Chain(&dummy{}, createMiddleware("A", &order), createMiddleware("B", &order), createMiddleware("C", &order))

	client.Do(&http.Request{})

	assert.Equal(t, callOrder{"C", "B", "A"}, order)
}

func TestHeaderMiddleware(t *testing.T) {
	r, _ := http.NewRequest("GET", "/", nil)
	res, _ := send(r, HeaderMiddleware("X-Foo", "123"))

	assert.Equal(t, res.Request.Header.Get("X-Foo"), "123")
}

func TestHeadersMiddleware(t *testing.T) {
	r, _ := http.NewRequest("GET", "/", nil)
	res, _ := send(r, HeadersMiddleware(map[string]string{"X-Foo": "123", "X-Bar": "456"}))

	assert.Equal(t, res.Request.Header.Get("X-Foo"), "123")
	assert.Equal(t, res.Request.Header.Get("X-Bar"), "456")
}

func TestBaseURLMiddleware(t *testing.T) {
	r, _ := http.NewRequest("GET", "/", nil)
	res, _ := send(r, BaseURLMiddleware("http://example.com"))

	assert.Equal(t, res.Request.URL.String(), "http://example.com/")

}

func TestPanicMiddleware(t *testing.T) {
	panicTriggerDecorator := func(c Client) Client {
		return ClientFunc(func(r *http.Request) (res *http.Response, err error) {
			panic("oops")
		})
	}
	r, _ := http.NewRequest("GET", "/", nil)
	client := Chain(&dummy{}, panicTriggerDecorator, RecoverMiddleware())
	res, err := client.Do(r)

	assert.Nil(t, res)
	assert.Error(t, err, "oops")
}
<commit_msg>BaseURLMiddleware test<commit_after>package kapusta

import (
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"
)

type dummy struct{}

func (d dummy) Do(r *http.Request) (*http.Response, error) {
	return &http.Response{Request: r}, nil
}

type callOrder []string

func send(r *http.Request, middleware MiddlewareFunc) (*http.Response, error) {
	return Chain(&dummy{}, middleware).Do(r)
}

func createMiddleware(name string, order *callOrder) MiddlewareFunc {
	return func(c Client) Client {
		return ClientFunc(func(r *http.Request) (*http.Response, error) {
			*order = append(*order, name)
			return c.Do(r)
		})
	}
}

func TestChain(t *testing.T) {
	var order callOrder
	client := Chain(&dummy{}, createMiddleware("A", &order), createMiddleware("B", &order), createMiddleware("C", &order))

	client.Do(&http.Request{})

	assert.Equal(t, callOrder{"C", "B", "A"}, order)
}

func TestHeaderMiddleware(t *testing.T) {
	r, _ := http.NewRequest("GET", "/", nil)
	res, _ := send(r, HeaderMiddleware("X-Foo", "123"))

	assert.Equal(t, res.Request.Header.Get("X-Foo"), "123")
}

func TestHeadersMiddleware(t *testing.T) {
	r, _ := http.NewRequest("GET", "/", nil)
	res, _ := send(r, HeadersMiddleware(map[string]string{"X-Foo": "123", "X-Bar": "456"}))

	assert.Equal(t, res.Request.Header.Get("X-Foo"), "123")
	assert.Equal(t, res.Request.Header.Get("X-Bar"), "456")
}

func TestBaseURLMiddleware(t *testing.T) {
	r, _ := http.NewRequest("GET", "/", nil)
	res, _ := send(r, BaseURLMiddleware("http://example.com"))

	assert.Equal(t, res.Request.URL.String(), "http://example.com/")
}

func TestBaseURLMiddlewareFail(t *testing.T) {
	assert.Panics(t, func() {
		BaseURLMiddleware("://example.com")
	})
}

func TestPanicMiddleware(t *testing.T) {
	panicTriggerDecorator := func(c Client) Client {
		return ClientFunc(func(r *http.Request) (res *http.Response, err error) {
			panic("oops")
		})
	}
	r, _ := http.NewRequest("GET", "/", nil)
	client := Chain(&dummy{}, panicTriggerDecorator, RecoverMiddleware())
	res, err := client.Do(r)

	assert.Nil(t, res)
	assert.Error(t, err, "oops")
}
<|endoftext|>


<commit_before>package template

// Functions available to gondola templates

import (
	"bytes"
	"encoding/json"
	"fmt"
	"gnd.la/app/serialize"
	"gnd.la/html"
	"gnd.la/util/types"
	"html/template"
	"math"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func lt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() < v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() < v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() < v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func lte(arg1, arg2 interface{}) (bool, error) {
	lessThan, err := lt(arg1, arg2)
	if lessThan || err != nil {
		return lessThan, err
	}
	return eq(arg1, arg2), nil
}

func gt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() > v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() > v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() > v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func gte(arg1, arg2 interface{}) (bool, error) {
	greaterThan, err := gt(arg1, arg2)
	if greaterThan || err != nil {
		return greaterThan, err
	}
	return eq(arg1, arg2), nil
}

func jsons(arg interface{}) (string, error) {
	if jw, ok := arg.(serialize.JSONWriter); ok {
		var buf bytes.Buffer
		_, err := jw.WriteJSON(&buf)
		return buf.String(), err
	}
	b, err := json.Marshal(arg)
	return string(b), err
}

func _json(arg interface{}) (template.JS, error) {
	s, err := jsons(arg)
	return template.JS(s), err
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func lower(x string) string {
	return strings.ToLower(x)
}

func join(x []string, sep string) string {
	return strings.Join(x, sep)
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else if s, ok := v.(*string); ok {
				key = *s
			} else {
				return nil, fmt.Errorf("invalid argument to map at index %d, %s instead of string", ii, reflect.TypeOf(v))
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

// this returns *[]interface{} so append works on
// slices declared in templates
func _slice(args ...interface{}) *[]interface{} {
	return &args
}

func _append(items interface{}, args ...interface{}) (string, error) {
	val := reflect.ValueOf(items)
	if !val.IsValid() || val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Slice {
		return "", fmt.Errorf("first argument to append must be pointer to slice, it's %T", items)
	}
	sl := val.Elem()
	for _, v := range args {
		vval := reflect.ValueOf(v)
		if !vval.Type().AssignableTo(sl.Type().Elem()) {
			return "", fmt.Errorf("can't append %s to %s", vval.Type(), sl.Type())
		}
		sl = reflect.Append(sl, vval)
	}
	val.Elem().Set(sl)
	return "", nil
}

func deref(arg interface{}) (interface{}, error) {
	v := reflect.ValueOf(arg)
	if v.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("argument to deref must be pointer, not %T", arg)
	}
	return v.Elem().Interface(), nil
}

func mult(args ...interface{}) (float64, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	return val, nil
}

func imult(args ...interface{}) (int, error) {
	val, err := mult(args...)
	return int(val), err
}

func add(args ...interface{}) (interface{}, error) {
	val := 0.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val += float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val += float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val += value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("error parsing string passed to add() at index %d: %s", ii, err)
			}
			val += v
		default:
			return 0, fmt.Errorf("invalid argument of type %T passed to add() at index %d", v, ii)
		}
	}
	if math.Floor(val) == val {
		return int(val), nil
	}
	return val, nil

}

func concat(args ...interface{}) string {
	s := make([]string, len(args))
	for ii, v := range args {
		s[ii] = types.ToString(v)
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) interface{} {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if t {
			return v
		}
	}
	return nil
}

func not(arg interface{}) bool {
	t, _ := types.IsTrue(arg)
	return !t
}

func divisible(n interface{}, d interface{}) (bool, error) {
	ni, err := types.ToInt(n)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid number %v: %s", n, err)
	}
	di, err := types.ToInt(d)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid divisor %v: %s", d, err)
	}
	return ni%di == 0, nil
}

func even(arg interface{}) (bool, error) {
	return divisible(arg, 2)
}

func odd(arg interface{}) (bool, error) {
	res, err := divisible(arg, 2)
	if err != nil {
		return false, err
	}
	return !res, nil
}

func now() time.Time {
	return time.Now()
}

func toHtml(s string) template.HTML {
	return template.HTML(strings.Replace(html.Escape(s), "\n", "
", -1))
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":        eq,
	"neq":       neq,
	"lt":        lt,
	"lte":       lte,
	"gt":        gt,
	"gte":       gte,
	"json":      _json,
	"jsons":     jsons,
	"nz":        nz,
	"lower":     lower,
	"join":      join,
	"map":       _map,
	"slice":     _slice,
	"append":    _append,
	"deref":     deref,
	"mult":      mult,
	"imult":     imult,
	"divisible": divisible,
	"add":       add,
	"even":      even,
	"odd":       odd,
	"concat":    concat,
	"and":       and,
	"or":        or,
	"not":       not,
	"now":       now,
	"to_lower":  strings.ToLower,
	"to_title":  strings.ToTitle,
	"to_upper":  strings.ToUpper,
	"to_html":   toHtml,

	// Go builtins
	"call":     call,
	"html":     template.HTMLEscaper,
	"index":    index,
	"js":       template.JSEscaper,
	"len":      length,
	"print":    fmt.Sprint,
	"printf":   fmt.Sprintf,
	"println":  fmt.Sprintln,
	"urlquery": template.URLQueryEscaper,
}
<commit_msg>Remove duplicate func lower<commit_after>package template

// Functions available to gondola templates

import (
	"bytes"
	"encoding/json"
	"fmt"
	"gnd.la/app/serialize"
	"gnd.la/html"
	"gnd.la/util/types"
	"html/template"
	"math"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func lt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() < v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() < v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() < v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func lte(arg1, arg2 interface{}) (bool, error) {
	lessThan, err := lt(arg1, arg2)
	if lessThan || err != nil {
		return lessThan, err
	}
	return eq(arg1, arg2), nil
}

func gt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() > v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() > v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() > v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func gte(arg1, arg2 interface{}) (bool, error) {
	greaterThan, err := gt(arg1, arg2)
	if greaterThan || err != nil {
		return greaterThan, err
	}
	return eq(arg1, arg2), nil
}

func jsons(arg interface{}) (string, error) {
	if jw, ok := arg.(serialize.JSONWriter); ok {
		var buf bytes.Buffer
		_, err := jw.WriteJSON(&buf)
		return buf.String(), err
	}
	b, err := json.Marshal(arg)
	return string(b), err
}

func _json(arg interface{}) (template.JS, error) {
	s, err := jsons(arg)
	return template.JS(s), err
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func join(x []string, sep string) string {
	return strings.Join(x, sep)
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else if s, ok := v.(*string); ok {
				key = *s
			} else {
				return nil, fmt.Errorf("invalid argument to map at index %d, %s instead of string", ii, reflect.TypeOf(v))
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

// this returns *[]interface{} so append works on
// slices declared in templates
func _slice(args ...interface{}) *[]interface{} {
	return &args
}

func _append(items interface{}, args ...interface{}) (string, error) {
	val := reflect.ValueOf(items)
	if !val.IsValid() || val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Slice {
		return "", fmt.Errorf("first argument to append must be pointer to slice, it's %T", items)
	}
	sl := val.Elem()
	for _, v := range args {
		vval := reflect.ValueOf(v)
		if !vval.Type().AssignableTo(sl.Type().Elem()) {
			return "", fmt.Errorf("can't append %s to %s", vval.Type(), sl.Type())
		}
		sl = reflect.Append(sl, vval)
	}
	val.Elem().Set(sl)
	return "", nil
}

func deref(arg interface{}) (interface{}, error) {
	v := reflect.ValueOf(arg)
	if v.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("argument to deref must be pointer, not %T", arg)
	}
	return v.Elem().Interface(), nil
}

func mult(args ...interface{}) (float64, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	return val, nil
}

func imult(args ...interface{}) (int, error) {
	val, err := mult(args...)
	return int(val), err
}

func add(args ...interface{}) (interface{}, error) {
	val := 0.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val += float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val += float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val += value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("error parsing string passed to add() at index %d: %s", ii, err)
			}
			val += v
		default:
			return 0, fmt.Errorf("invalid argument of type %T passed to add() at index %d", v, ii)
		}
	}
	if math.Floor(val) == val {
		return int(val), nil
	}
	return val, nil

}

func concat(args ...interface{}) string {
	s := make([]string, len(args))
	for ii, v := range args {
		s[ii] = types.ToString(v)
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) interface{} {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if t {
			return v
		}
	}
	return nil
}

func not(arg interface{}) bool {
	t, _ := types.IsTrue(arg)
	return !t
}

func divisible(n interface{}, d interface{}) (bool, error) {
	ni, err := types.ToInt(n)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid number %v: %s", n, err)
	}
	di, err := types.ToInt(d)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid divisor %v: %s", d, err)
	}
	return ni%di == 0, nil
}

func even(arg interface{}) (bool, error) {
	return divisible(arg, 2)
}

func odd(arg interface{}) (bool, error) {
	res, err := divisible(arg, 2)
	if err != nil {
		return false, err
	}
	return !res, nil
}

func now() time.Time {
	return time.Now()
}

func toHtml(s string) template.HTML {
	return template.HTML(strings.Replace(html.Escape(s), "\n", "
", -1))
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":        eq,
	"neq":       neq,
	"lt":        lt,
	"lte":       lte,
	"gt":        gt,
	"gte":       gte,
	"json":      _json,
	"jsons":     jsons,
	"nz":        nz,
	"join":      join,
	"map":       _map,
	"slice":     _slice,
	"append":    _append,
	"deref":     deref,
	"mult":      mult,
	"imult":     imult,
	"divisible": divisible,
	"add":       add,
	"even":      even,
	"odd":       odd,
	"concat":    concat,
	"and":       and,
	"or":        or,
	"not":       not,
	"now":       now,
	"to_lower":  strings.ToLower,
	"to_title":  strings.ToTitle,
	"to_upper":  strings.ToUpper,
	"to_html":   toHtml,

	// Go builtins
	"call":     call,
	"html":     template.HTMLEscaper,
	"index":    index,
	"js":       template.JSEscaper,
	"len":      length,
	"print":    fmt.Sprint,
	"printf":   fmt.Sprintf,
	"println":  fmt.Sprintln,
	"urlquery": template.URLQueryEscaper,
}
<|endoftext|>