<commit_before>package driver

import (
	"database/sql"
	"fmt"
	m "github.com/Boostport/migration"
	_ "github.com/lib/pq"
)

type Postgres struct {
	db *sql.DB
}

const postgresTableName = "schema_migration"

// NewPostgres creates a new Postgres driver.
// The DSN is documented here: https://godoc.org/github.com/lib/pq#hdr-Connection_String_Parameters
func NewPostgres(dsn string) (m.Driver, error) {

	db, err := sql.Open("postgres", dsn)

	if err != nil {
		return nil, err
	}

	if err := db.Ping(); err != nil {
		return nil, err
	}

	d := &Postgres{
		db: db,
	}

	if err := d.ensureVersionTableExists(); err != nil {
		return nil, err
	}

	return d, nil
}

// Close closes the connection to the Postgres server.
func (driver *Postgres) Close() error {

	if err := driver.db.Close(); err != nil {
		return err
	}

	return nil
}

func (driver *Postgres) ensureVersionTableExists() error {
	_, err := driver.db.Exec("CREATE TABLE IF NOT EXISTS " + postgresTableName + " (version varchar(255) not null primary key)")
	return err
}

// Migrate runs a migration.
func (driver *Postgres) Migrate(migration *m.PlannedMigration) error {

	// Note: MySQL does not support DDL statements in a transaction. If DDL statements are
	// executed in a transaction, it is an implicit commit.
	// See: http://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html
	var content string

	if migration.Direction == m.Up {

		content = migration.Up

	} else if migration.Direction == m.Down {

		content = migration.Down
	}

	tx, err := driver.db.Begin()

	if err != nil {
		return err
	}

	if _, err := tx.Exec(content); err != nil {

		if err := tx.Rollback(); err != nil {
			return err
		}

		return fmt.Errorf("Error executing statement: %s\n%s", err, content)
	}

	if migration.Direction == m.Up {
		if _, err := driver.db.Exec("INSERT INTO "+postgresTableName+" (version) VALUES ($1)", migration.ID); err != nil {

			if err := tx.Rollback(); err != nil {
				return err
			}

			return err
		}
	} else {
		if _, err := driver.db.Exec("DELETE FROM "+postgresTableName+" WHERE version=$1", migration.ID); err != nil {

			if err := tx.Rollback(); err != nil {
				return err
			}

			return err
		}
	}

	if err := tx.Commit(); err != nil {
		return err
	}

	return nil
}

// Versions lists all the applied versions.
func (driver *Postgres) Versions() ([]string, error) {
	versions := []string{}

	rows, err := driver.db.Query("SELECT version FROM " + postgresTableName + " ORDER BY version DESC")

	if err != nil {
		return versions, err
	}

	defer rows.Close()

	for rows.Next() {
		var version string

		err := rows.Scan(&version)

		if err != nil {
			return versions, err
		}

		versions = append(versions, version)
	}

	err = rows.Err()

	return versions, err
}
<commit_msg>Fix postgres issue where inserting versions were not in the same transaction as the migration statements.<commit_after>package driver

import (
	"database/sql"
	"fmt"
	m "github.com/Boostport/migration"
	_ "github.com/lib/pq"
)

type Postgres struct {
	db *sql.DB
}

const postgresTableName = "schema_migration"

// NewPostgres creates a new Postgres driver.
// The DSN is documented here: https://godoc.org/github.com/lib/pq#hdr-Connection_String_Parameters
func NewPostgres(dsn string) (m.Driver, error) {

	db, err := sql.Open("postgres", dsn)

	if err != nil {
		return nil, err
	}

	if err := db.Ping(); err != nil {
		return nil, err
	}

	d := &Postgres{
		db: db,
	}

	if err := d.ensureVersionTableExists(); err != nil {
		return nil, err
	}

	return d, nil
}

// Close closes the connection to the Postgres server.
func (driver *Postgres) Close() error {

	if err := driver.db.Close(); err != nil {
		return err
	}

	return nil
}

func (driver *Postgres) ensureVersionTableExists() error {
	_, err := driver.db.Exec("CREATE TABLE IF NOT EXISTS " + postgresTableName + " (version varchar(255) not null primary key)")
	return err
}

// Migrate runs a migration.
func (driver *Postgres) Migrate(migration *m.PlannedMigration) error {

	// Note: MySQL does not support DDL statements in a transaction. If DDL statements are
	// executed in a transaction, it is an implicit commit.
	// See: http://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html
	var content string

	if migration.Direction == m.Up {

		content = migration.Up

	} else if migration.Direction == m.Down {

		content = migration.Down
	}

	tx, err := driver.db.Begin()

	if err != nil {
		return err
	}

	if _, err := tx.Exec(content); err != nil {

		if err := tx.Rollback(); err != nil {
			return err
		}

		return fmt.Errorf("Error executing statement: %s\n%s", err, content)
	}

	if migration.Direction == m.Up {
		if _, err := tx.Exec("INSERT INTO "+postgresTableName+" (version) VALUES ($1)", migration.ID); err != nil {

			if err := tx.Rollback(); err != nil {
				return err
			}

			return err
		}
	} else {
		if _, err := tx.Exec("DELETE FROM "+postgresTableName+" WHERE version=$1", migration.ID); err != nil {

			if err := tx.Rollback(); err != nil {
				return err
			}

			return err
		}
	}

	if err := tx.Commit(); err != nil {
		return err
	}

	return nil
}

// Versions lists all the applied versions.
func (driver *Postgres) Versions() ([]string, error) {
	versions := []string{}

	rows, err := driver.db.Query("SELECT version FROM " + postgresTableName + " ORDER BY version DESC")

	if err != nil {
		return versions, err
	}

	defer rows.Close()

	for rows.Next() {
		var version string

		err := rows.Scan(&version)

		if err != nil {
			return versions, err
		}

		versions = append(versions, version)
	}

	err = rows.Err()

	return versions, err
}
<|endoftext|>


<commit_before>package main

import (
	"code.cloudfoundry.org/bytefmt"
	"fmt"
	"log"
	"net"
	"time"
)

// Telnet negoitation
const (
	// COMMANDS
	IAC  byte = 255
	DONT byte = 254
	DO   byte = 253
	WONT byte = 252
	WILL byte = 251
	SB   byte = 250
	GA   byte = 249
	EL   byte = 248
	EC   byte = 247
	AYT  byte = 246
	AO   byte = 245
	IP   byte = 244
	BRK  byte = 243
	DM   byte = 242
	NOP  byte = 241
	SE   byte = 240

	// OPTIONS
	ECHO     byte = 1
	SGA      byte = 3
	STATUS   byte = 5
	TIMINGMK byte = 6
	TERM     byte = 24
	WINSIZE  byte = 31
	TERMSPD  byte = 32
	REMFLOW  byte = 33
	LINEMODE byte = 34
	ENVVAR   byte = 36
)

var decodeMap map[byte]string = map[byte]string{
	IAC:      "IAC",
	DONT:     "DONT",
	DO:       "DO",
	WONT:     "WONT",
	WILL:     "WILL",
	SB:       "SB",
	GA:       "GA",
	EL:       "EL",
	EC:       "EC",
	AYT:      "AYT",
	AO:       "AO",
	IP:       "IP",
	BRK:      "BRK",
	DM:       "DM",
	NOP:      "NOP",
	SE:       "SE",
	ECHO:     "ECHO",
	SGA:      "SGA",
	STATUS:   "STATUS",
	TIMINGMK: "TIMINGMK",
	TERM:     "TERM",
	WINSIZE:  "WINSIZE",
	TERMSPD:  "TERMSPD",
	REMFLOW:  "REMFLOW",
	LINEMODE: "LINEMODE",
	ENVVAR:   "ENVVAR",
}

func decode(b byte) string {
	s, ok := decodeMap[b]
	if !ok {
		return fmt.Sprintf("!%d ", b)
	}
	return s + " "
}

// Implements connection for in- and out-bound telnet
type telnetReadWriteCloser struct {
	direction int
	mode      bool
	c         net.Conn
	sent      uint64
	recv      uint64
}

func (m *telnetReadWriteCloser) String() string {
	var s, p, host string
	if m.direction == INBOUND {
		s = "Inbound"
		p = "from"
	} else {
		s = "Outbound"
		p = "to"
	}
	ip, _, err := net.SplitHostPort(m.c.RemoteAddr().String())
	if err != nil {
		logger.Printf("SplitHostPort(): %s", err)
	}
	names, err := net.LookupAddr(ip)
	if err != nil {
		host = "(nil)"
		logger.Printf("LookupAddr(): %s", err)
	} else {
		host = names[0]
	}
	sent, recv := m.Stats()

	s = fmt.Sprintf("%s %s %s (%s), sent %s, received %s",
		s, p, host, m.c.RemoteAddr(),
		bytefmt.ByteSize(sent), bytefmt.ByteSize(recv))

	return s
}

func (m *telnetReadWriteCloser) command(p []byte) (i int, err error) {
	if p[0] != IAC {
		return 0, nil
	}

	var s string
	i, err = m.c.Read(p)
	s += decode(p[0])

	switch p[0] {
	case SB:
		// Comsume options until we read a final SE
		for p[0] != SE {
			i, err = m.c.Read(p)
			s += decode(p[0])
		}
		i, err = m.c.Read(p) // read one beyond the SE

	case WILL:
		m.c.Read(p)
		s += decode(p[0])
		if p[0] != LINEMODE && p[0] != ECHO {
			m.c.Write([]byte{IAC, DONT, p[0]})
			logger.Printf("Sending: IAC WONT %s", decode(p[0]))
		}
		i, err = m.c.Read(p) // read next char

	case DO:
		m.c.Read(p)
		s += decode(p[0])
		if p[0] != LINEMODE && p[0] != ECHO {
			m.c.Write([]byte{IAC, WONT, p[0]})
			logger.Printf("Sending: IAC WONT %s", decode(p[0]))
		}
		i, err = m.c.Read(p) // read next char

	case DONT:
		m.c.Read(p)
		s += decode(p[0])
		m.c.Write([]byte{IAC, WONT, p[0]})
		i, err = m.c.Read(p) // read next char

	case WONT:
		m.c.Read(p)
		s += decode(p[0])
		m.c.Write([]byte{IAC, DONT, p[0]})
		i, err = m.c.Read(p) // read next char

	case NOP, DM, BRK, IP, AO, AYT, EC, EL, GA, SE:
		m.c.Read(p)

	case IAC: // Two in a row, it's just ASCII 255

	}

	return i, err
}

func (m *telnetReadWriteCloser) Read(p []byte) (int, error) {
	i, err := m.c.Read(p)

	// If it's a telnet command, process it
	for p[0] == IAC {
		i, err = m.command(p)
	}
	m.recv += uint64(i)
	return i, err
}

func (m *telnetReadWriteCloser) Write(p []byte) (int, error) {
	i, err := m.c.Write(p)
	if err != nil {
		logger.Print(err)
	}
	m.sent += uint64(i)
	return i, err
}

func (m *telnetReadWriteCloser) Close() error {
	logger.Printf("Closing telnet connection to %s", m.RemoteAddr())
	return m.c.Close()
}

func (m *telnetReadWriteCloser) Mode() bool {
	return m.mode
}

func (m *telnetReadWriteCloser) Direction() int {
	return m.direction
}

func (m *telnetReadWriteCloser) RemoteAddr() net.Addr {
	return m.c.RemoteAddr()
}

func (m *telnetReadWriteCloser) SetMode(mode bool) {
	m.mode = mode
}

func (m *telnetReadWriteCloser) Stats() (uint64, uint64) {
	return m.sent, m.recv
}

func (m *telnetReadWriteCloser) SetDeadline(t time.Time) error {
	return m.c.SetDeadline(t)
}

func acceptTelnet(channel chan connection, busy busyFunc, log *log.Logger,
	ok chan error) {

	port := fmt.Sprintf(":%d", flags.telnetPort)
	l, err := net.Listen("tcp", port)
	if err != nil {
		log.Print("Fatal Error: ", err)
		ok <- err
		return
	}
	defer l.Close()
	log.Printf("Listening: telnet tcp/%s", port)
	ok <- nil

	for {
		conn, err := l.Accept()
		if err != nil {
			log.Printf("l.Accept(): %s\n", err)
			continue
		}

		if busy() {
			conn.Write([]byte("Busy...\n\r"))
			conn.Close()
			continue
		}

		// This is a telnet session, negotiate char-at-a-time
		// and turn off local echo
		conn.Write([]byte{IAC, DO, LINEMODE}) // You go into linemode
		conn.Write([]byte{IAC, WILL, ECHO})   // I'll echo to you

		channel <- &telnetReadWriteCloser{INBOUND, DATAMODE, conn, 0, 0}
	}
}

func dialTelnet(remote string, log *log.Logger) (connection, error) {

	if _, _, err := net.SplitHostPort(remote); err != nil {
		remote += ":23"
	}
	log.Printf("Connecting to: %s", remote)
	conn, err := net.DialTimeout("tcp", remote, __CONNECT_TIMEOUT)
	if err != nil {
		if err, ok := err.(net.Error); ok && err.Timeout() {
			log.Print("net.DialTimeout: Timed out")
		}
		log.Printf("Error: %s", err)
		return nil, err
	}

	log.Printf("Connected to %s", conn.RemoteAddr())
	return &telnetReadWriteCloser{OUTBOUND, DATAMODE, conn, 0, 0}, nil
}
<commit_msg>Cleanup log messages<commit_after>package main

import (
	"code.cloudfoundry.org/bytefmt"
	"fmt"
	"log"
	"net"
	"time"
)

// Telnet negoitation
const (
	// COMMANDS
	IAC  byte = 255
	DONT byte = 254
	DO   byte = 253
	WONT byte = 252
	WILL byte = 251
	SB   byte = 250
	GA   byte = 249
	EL   byte = 248
	EC   byte = 247
	AYT  byte = 246
	AO   byte = 245
	IP   byte = 244
	BRK  byte = 243
	DM   byte = 242
	NOP  byte = 241
	SE   byte = 240

	// OPTIONS
	ECHO     byte = 1
	SGA      byte = 3
	STATUS   byte = 5
	TIMINGMK byte = 6
	TERM     byte = 24
	WINSIZE  byte = 31
	TERMSPD  byte = 32
	REMFLOW  byte = 33
	LINEMODE byte = 34
	ENVVAR   byte = 36
)

var decodeMap map[byte]string = map[byte]string{
	IAC:      "IAC",
	DONT:     "DONT",
	DO:       "DO",
	WONT:     "WONT",
	WILL:     "WILL",
	SB:       "SB",
	GA:       "GA",
	EL:       "EL",
	EC:       "EC",
	AYT:      "AYT",
	AO:       "AO",
	IP:       "IP",
	BRK:      "BRK",
	DM:       "DM",
	NOP:      "NOP",
	SE:       "SE",
	ECHO:     "ECHO",
	SGA:      "SGA",
	STATUS:   "STATUS",
	TIMINGMK: "TIMINGMK",
	TERM:     "TERM",
	WINSIZE:  "WINSIZE",
	TERMSPD:  "TERMSPD",
	REMFLOW:  "REMFLOW",
	LINEMODE: "LINEMODE",
	ENVVAR:   "ENVVAR",
}

func decode(b byte) string {
	s, ok := decodeMap[b]
	if !ok {
		return fmt.Sprintf("!%d ", b)
	}
	return s + " "
}

// Implements connection for in- and out-bound telnet
type telnetReadWriteCloser struct {
	direction int
	mode      bool
	c         net.Conn
	sent      uint64
	recv      uint64
}

func (m *telnetReadWriteCloser) String() string {
	var s, p, host string
	if m.direction == INBOUND {
		s = "Inbound"
		p = "from"
	} else {
		s = "Outbound"
		p = "to"
	}
	ip, _, err := net.SplitHostPort(m.c.RemoteAddr().String())
	if err != nil {
		logger.Printf("SplitHostPort(): %s", err)
	}
	names, err := net.LookupAddr(ip)
	if err != nil {
		host = "(nil)"
		logger.Printf("LookupAddr(): %s", err)
	} else {
		host = names[0]
	}
	sent, recv := m.Stats()

	s = fmt.Sprintf("%s %s %s (%s), sent %s, received %s",
		s, p, host, m.c.RemoteAddr(),
		bytefmt.ByteSize(sent), bytefmt.ByteSize(recv))

	return s
}

func (m *telnetReadWriteCloser) command(p []byte) (i int, err error) {
	if p[0] != IAC {
		return 0, nil
	}

	var s string
	i, err = m.c.Read(p)
	s += decode(p[0])

	switch p[0] {
	case SB:
		// Comsume options until we read a final SE
		for p[0] != SE {
			i, err = m.c.Read(p)
			s += decode(p[0])
		}
		i, err = m.c.Read(p) // read one beyond the SE

	case WILL:
		m.c.Read(p)
		s += decode(p[0])
		if p[0] != LINEMODE && p[0] != ECHO {
			m.c.Write([]byte{IAC, DONT, p[0]})
		}
		i, err = m.c.Read(p) // read next char

	case DO:
		m.c.Read(p)
		s += decode(p[0])
		if p[0] != LINEMODE && p[0] != ECHO {
			m.c.Write([]byte{IAC, WONT, p[0]})
		}
		i, err = m.c.Read(p) // read next char

	case DONT:
		m.c.Read(p)
		s += decode(p[0])
		m.c.Write([]byte{IAC, WONT, p[0]})
		i, err = m.c.Read(p) // read next char

	case WONT:
		m.c.Read(p)
		s += decode(p[0])
		m.c.Write([]byte{IAC, DONT, p[0]})
		i, err = m.c.Read(p) // read next char

	case NOP, DM, BRK, IP, AO, AYT, EC, EL, GA, SE:
		m.c.Read(p)

	case IAC: // Two in a row, it's just ASCII 255

	}

	return i, err
}

func (m *telnetReadWriteCloser) Read(p []byte) (int, error) {
	i, err := m.c.Read(p)

	// If it's a telnet command, process it
	for p[0] == IAC {
		i, err = m.command(p)
	}
	m.recv += uint64(i)
	return i, err
}

func (m *telnetReadWriteCloser) Write(p []byte) (int, error) {
	i, err := m.c.Write(p)
	if err != nil {
		logger.Print(err)
	}
	m.sent += uint64(i)
	return i, err
}

func (m *telnetReadWriteCloser) Close() error {
	logger.Printf("Closing telnet connection to %s", m.RemoteAddr())
	return m.c.Close()
}

func (m *telnetReadWriteCloser) Mode() bool {
	return m.mode
}

func (m *telnetReadWriteCloser) Direction() int {
	return m.direction
}

func (m *telnetReadWriteCloser) RemoteAddr() net.Addr {
	return m.c.RemoteAddr()
}

func (m *telnetReadWriteCloser) SetMode(mode bool) {
	m.mode = mode
}

func (m *telnetReadWriteCloser) Stats() (uint64, uint64) {
	return m.sent, m.recv
}

func (m *telnetReadWriteCloser) SetDeadline(t time.Time) error {
	return m.c.SetDeadline(t)
}

func acceptTelnet(channel chan connection, busy busyFunc, log *log.Logger,
	ok chan error) {

	port := fmt.Sprintf(":%d", flags.telnetPort)
	l, err := net.Listen("tcp", port)
	if err != nil {
		log.Print("Fatal Error: ", err)
		ok <- err
		return
	}
	defer l.Close()
	log.Printf("Listening: telnet tcp/%s", port)
	ok <- nil

	for {
		conn, err := l.Accept()
		if err != nil {
			log.Printf("l.Accept(): %s\n", err)
			continue
		}

		if busy() {
			conn.Write([]byte("Busy...\n\r"))
			conn.Close()
			continue
		}

		// This is a telnet session, negotiate char-at-a-time
		// and turn off local echo
		conn.Write([]byte{IAC, DO, LINEMODE}) // You go into linemode
		conn.Write([]byte{IAC, WILL, ECHO})   // I'll echo to you

		channel <- &telnetReadWriteCloser{INBOUND, DATAMODE, conn, 0, 0}
	}
}

func dialTelnet(remote string, log *log.Logger) (connection, error) {

	if _, _, err := net.SplitHostPort(remote); err != nil {
		remote += ":23"
	}
	log.Printf("Connecting to: %s", remote)
	conn, err := net.DialTimeout("tcp", remote, __CONNECT_TIMEOUT)
	if err != nil {
		if err, ok := err.(net.Error); ok && err.Timeout() {
			log.Print("net.DialTimeout: Timed out")
		}
		log.Printf("Error: %s", err)
		return nil, err
	}

	log.Printf("Connected to %s", conn.RemoteAddr())
	return &telnetReadWriteCloser{OUTBOUND, DATAMODE, conn, 0, 0}, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 health

import (
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/control-center/serviced/dao"
	"github.com/control-center/serviced/datastore"
	"github.com/control-center/serviced/facade"
	"github.com/control-center/serviced/node"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
)

type healthStatus struct {
	Status    string
	Timestamp int64
	Interval  float64
	StartedAt int64
}

type messagePacket struct {
	Timestamp int64
	Statuses  map[string]map[string]map[string]*healthStatus
}

// Map of ServiceID -> InstanceID -> HealthCheckName -> healthStatus
var healthStatuses = make(map[string]map[string]map[string]*healthStatus)

var cpDao dao.ControlPlane
var runningServices []dao.RunningService
var exitChannel = make(chan bool)
var lock = &sync.Mutex{}

func init() {
	foreverHealthy := &healthStatus{
		Status:    "passed",
		Timestamp: time.Now().UTC().Unix(),
		Interval:  3.156e9, // One century in seconds.
	}
	healthStatuses["isvc-internalservices"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-elasticsearch-logstash"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-elasticsearch-serviced"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-zookeeper"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-opentsdb"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-logstash"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-celery"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-dockerRegistry"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}

}

func getService(serviceID, instanceID string) *dao.RunningService {
	for _, svc := range runningServices {
		if svc.ServiceID == serviceID && strconv.Itoa(svc.InstanceID) == instanceID {
			return &svc
		}
	}
	return nil
}

func isService(serviceID string) bool {
	for _, svc := range runningServices {
		if svc.ServiceID == serviceID {
			return true
		}
	}
	return false
}

// Removes no longer running services and updates service start time.
func Cleanup(shutdown <-chan interface{}) {
	var empty interface{}
	for {
		select {
		case <-shutdown:
			return
		case <-time.After(time.Second * 5):
			if cpDao == nil {
				break
			}
			err := cpDao.GetRunningServices(&empty, &runningServices)
			if err != nil {
				glog.Warningf("Error acquiring running services: %v", err)
				continue
			}
			lock.Lock()
			for serviceID, instances := range healthStatuses {
				if strings.HasPrefix(serviceID, "isvc-") {
					continue
				}
				if !isService(serviceID) {
					delete(healthStatuses, serviceID)
					continue
				}
				for instanceID, healthChecks := range instances {
					svc := getService(serviceID, instanceID)
					if svc == nil {
						delete(instances, instanceID)
						continue
					}
					for _, check := range healthChecks {
						if check.StartedAt == 0 {
							check.StartedAt = svc.StartedAt.Unix()
						}
					}
				}
			}
			lock.Unlock()
		}
	}
}

// Stores the dao.ControlPlane object created in daemon.go for use in this module.
func SetDao(d dao.ControlPlane) {
	cpDao = d
}

// RestGetHealthStatus writes a JSON response with the health status of all services that have health checks.
func RestGetHealthStatus(w *rest.ResponseWriter, r *rest.Request, client *node.ControlClient) {
	packet := messagePacket{time.Now().UTC().Unix(), healthStatuses}
	w.WriteJson(&packet)
}

// RegisterHealthCheck updates the healthStatus and healthTime structures with a health check result.
func RegisterHealthCheck(serviceID string, instanceID string, name string, passed string, f *facade.Facade) {
	lock.Lock()
	defer lock.Unlock()
	serviceStatus, ok := healthStatuses[serviceID]
	if !ok {
		serviceStatus = make(map[string]map[string]*healthStatus)
		healthStatuses[serviceID] = serviceStatus
	}
	instanceStatus, ok := serviceStatus[instanceID]
	if !ok {
		instanceStatus = make(map[string]*healthStatus)
		serviceStatus[instanceID] = instanceStatus
	}
	if name == "__instance_shutdown" {
		delete(serviceStatus, instanceID)
		return
	}
	thisStatus, ok := instanceStatus[name]
	if !ok {
		healthChecks, err := f.GetHealthChecksForService(datastore.Get(), serviceID)
		if err != nil {
			glog.Errorf("Unable to acquire health checks: %+v", err)
			return
		}
		for iname, icheck := range healthChecks {
			_, ok = instanceStatus[iname]
			if !ok {
				instanceStatus[name] = &healthStatus{"unknown", 0, icheck.Interval.Seconds(), time.Now().Unix()}
			}
		}
	}
	thisStatus, ok = instanceStatus[name]
	if !ok {
		glog.Warningf("ignoring %s health status %s, not found in service %s", passed, name, serviceID)
		return
	}
	thisStatus.Status = passed
	thisStatus.Timestamp = time.Now().UTC().Unix()
}
<commit_msg>fixes ZEN-16209: initialize health statuses correctly for interval<commit_after>// Copyright 2014 The Serviced 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 health

import (
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/control-center/serviced/dao"
	"github.com/control-center/serviced/datastore"
	"github.com/control-center/serviced/facade"
	"github.com/control-center/serviced/node"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
)

type healthStatus struct {
	Status    string
	Timestamp int64
	Interval  float64
	StartedAt int64
}

type messagePacket struct {
	Timestamp int64
	Statuses  map[string]map[string]map[string]*healthStatus
}

// Map of ServiceID -> InstanceID -> HealthCheckName -> healthStatus
var healthStatuses = make(map[string]map[string]map[string]*healthStatus)

var cpDao dao.ControlPlane
var runningServices []dao.RunningService
var exitChannel = make(chan bool)
var lock = &sync.Mutex{}

func init() {
	foreverHealthy := &healthStatus{
		Status:    "passed",
		Timestamp: time.Now().UTC().Unix(),
		Interval:  3.156e9, // One century in seconds.
	}
	healthStatuses["isvc-internalservices"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-elasticsearch-logstash"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-elasticsearch-serviced"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-zookeeper"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-opentsdb"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-logstash"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-celery"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}
	healthStatuses["isvc-dockerRegistry"] = map[string]map[string]*healthStatus{"0": {"alive": foreverHealthy}}

}

func getService(serviceID, instanceID string) *dao.RunningService {
	for _, svc := range runningServices {
		if svc.ServiceID == serviceID && strconv.Itoa(svc.InstanceID) == instanceID {
			return &svc
		}
	}
	return nil
}

func isService(serviceID string) bool {
	for _, svc := range runningServices {
		if svc.ServiceID == serviceID {
			return true
		}
	}
	return false
}

// Removes no longer running services and updates service start time.
func Cleanup(shutdown <-chan interface{}) {
	var empty interface{}
	for {
		select {
		case <-shutdown:
			return
		case <-time.After(time.Second * 5):
			if cpDao == nil {
				break
			}
			err := cpDao.GetRunningServices(&empty, &runningServices)
			if err != nil {
				glog.Warningf("Error acquiring running services: %v", err)
				continue
			}
			lock.Lock()
			for serviceID, instances := range healthStatuses {
				if strings.HasPrefix(serviceID, "isvc-") {
					continue
				}
				if !isService(serviceID) {
					delete(healthStatuses, serviceID)
					continue
				}
				for instanceID, healthChecks := range instances {
					svc := getService(serviceID, instanceID)
					if svc == nil {
						delete(instances, instanceID)
						continue
					}
					for _, check := range healthChecks {
						if check.StartedAt == 0 {
							check.StartedAt = svc.StartedAt.Unix()
						}
					}
				}
			}
			lock.Unlock()
		}
	}
}

// Stores the dao.ControlPlane object created in daemon.go for use in this module.
func SetDao(d dao.ControlPlane) {
	cpDao = d
}

// RestGetHealthStatus writes a JSON response with the health status of all services that have health checks.
func RestGetHealthStatus(w *rest.ResponseWriter, r *rest.Request, client *node.ControlClient) {
	packet := messagePacket{time.Now().UTC().Unix(), healthStatuses}
	w.WriteJson(&packet)
}

// RegisterHealthCheck updates the healthStatus and healthTime structures with a health check result.
func RegisterHealthCheck(serviceID string, instanceID string, name string, passed string, f *facade.Facade) {
	lock.Lock()
	defer lock.Unlock()
	serviceStatus, ok := healthStatuses[serviceID]
	if !ok {
		serviceStatus = make(map[string]map[string]*healthStatus)
		healthStatuses[serviceID] = serviceStatus
	}
	instanceStatus, ok := serviceStatus[instanceID]
	if !ok {
		instanceStatus = make(map[string]*healthStatus)
		serviceStatus[instanceID] = instanceStatus
	}
	if name == "__instance_shutdown" {
		delete(serviceStatus, instanceID)
		return
	}
	thisStatus, ok := instanceStatus[name]
	if !ok {
		healthChecks, err := f.GetHealthChecksForService(datastore.Get(), serviceID)
		if err != nil {
			glog.Errorf("Unable to acquire health checks: %+v", err)
			return
		}
		for iname, icheck := range healthChecks {
			_, ok = instanceStatus[iname]
			if !ok {
				instanceStatus[iname] = &healthStatus{"unknown", 0, icheck.Interval.Seconds(), time.Now().Unix()}
			}
		}
	}
	thisStatus, ok = instanceStatus[name]
	if !ok {
		glog.Warningf("ignoring %s health status %s, not found in service %s", passed, name, serviceID)
		return
	}
	thisStatus.Status = passed
	thisStatus.Timestamp = time.Now().UTC().Unix()
}
<|endoftext|>


<commit_before>package kafka

import (
	"encoding/binary"
	"sarama/mock"
	"testing"
)

func TestSimpleClient(t *testing.T) {
	responses := make(chan []byte, 1)
	mockBroker := mock.NewBroker(t, responses)
	defer mockBroker.Close()

	// Only one response needed, an empty metadata response
	responses <- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}

	client, err := NewClient("clientID", "localhost", mockBroker.Port())
	if err != nil {
		t.Fatal(err)
	}
	client.Close()
}

func TestClientExtraBrokers(t *testing.T) {
	responses := make(chan []byte, 1)
	mockBroker := mock.NewBroker(t, responses)
	mockExtra := mock.NewBroker(t, make(chan []byte))
	defer mockBroker.Close()
	defer mockExtra.Close()

	// return the extra mock as another available broker
	response := []byte{
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x09, 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't',
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00}
	binary.BigEndian.PutUint32(response[19:], uint32(mockExtra.Port()))
	responses <- response

	client, err := NewClient("clientID", "localhost", mockBroker.Port())
	if err != nil {
		t.Fatal(err)
	}
	client.Close()
}

func TestClientMetadata(t *testing.T) {
	responses := make(chan []byte, 1)
	mockBroker := mock.NewBroker(t, responses)
	mockExtra := mock.NewBroker(t, make(chan []byte))
	defer mockBroker.Close()
	defer mockExtra.Close()

	// return the extra mock as another available broker
	response := []byte{
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x05,
		0x00, 0x09, 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't',
		0x00, 0x00, 0x00, 0x00,

		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00,
		0x00, 0x07, 'm', 'y', 'T', 'o', 'p', 'i', 'c',
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x05,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00}
	binary.BigEndian.PutUint32(response[19:], uint32(mockExtra.Port()))
	responses <- response

	client, err := NewClient("clientID", "localhost", mockBroker.Port())
	if err != nil {
		t.Fatal(err)
	}

	parts, err := client.partitions("myTopic")
	if err != nil {
		t.Error(err)
	} else if len(parts) != 1 || parts[0] != 0 {
		t.Error("Client returned incorrect partitions for myTopic:", parts)
	}

	tst, err := client.leader("myTopic", 0)
	if err != nil {
		t.Error(err)
	} else if tst.ID() != 5 {
		t.Error("Leader for myTopic had incorrect ID.")
	}

	client.Close()
}
<commit_msg>Another client test<commit_after>package kafka

import (
	"encoding/binary"
	"sarama/mock"
	"testing"
)

func TestSimpleClient(t *testing.T) {
	responses := make(chan []byte, 1)
	mockBroker := mock.NewBroker(t, responses)
	defer mockBroker.Close()

	// Only one response needed, an empty metadata response
	responses <- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}

	client, err := NewClient("clientID", "localhost", mockBroker.Port())
	if err != nil {
		t.Fatal(err)
	}
	client.Close()
}

func TestClientExtraBrokers(t *testing.T) {
	responses := make(chan []byte, 1)
	mockBroker := mock.NewBroker(t, responses)
	mockExtra := mock.NewBroker(t, make(chan []byte))
	defer mockBroker.Close()
	defer mockExtra.Close()

	// return the extra mock as another available broker
	response := []byte{
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x09, 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't',
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00}
	binary.BigEndian.PutUint32(response[19:], uint32(mockExtra.Port()))
	responses <- response

	client, err := NewClient("clientID", "localhost", mockBroker.Port())
	if err != nil {
		t.Fatal(err)
	}
	client.Close()
}

func TestClientMetadata(t *testing.T) {
	responses := make(chan []byte, 1)
	mockBroker := mock.NewBroker(t, responses)
	mockExtra := mock.NewBroker(t, make(chan []byte))
	defer mockBroker.Close()
	defer mockExtra.Close()

	// return the extra mock as another available broker
	response := []byte{
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x05,
		0x00, 0x09, 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't',
		0x00, 0x00, 0x00, 0x00,

		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00,
		0x00, 0x07, 'm', 'y', 'T', 'o', 'p', 'i', 'c',
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x05,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00}
	binary.BigEndian.PutUint32(response[19:], uint32(mockExtra.Port()))
	responses <- response

	client, err := NewClient("clientID", "localhost", mockBroker.Port())
	if err != nil {
		t.Fatal(err)
	}

	parts, err := client.partitions("myTopic")
	if err != nil {
		t.Error(err)
	} else if len(parts) != 1 || parts[0] != 0 {
		t.Error("Client returned incorrect partitions for myTopic:", parts)
	}

	tst, err := client.leader("myTopic", 0)
	if err != nil {
		t.Error(err)
	} else if tst.ID() != 5 {
		t.Error("Leader for myTopic had incorrect ID.")
	}

	client.Close()
}

func TestClientRefreshBehaviour(t *testing.T) {
	responses := make(chan []byte, 3)
	mockBroker := mock.NewBroker(t, responses)
	mockExtra := mock.NewBroker(t, make(chan []byte))
	defer mockBroker.Close()
	defer mockExtra.Close()

	// return the extra mock as another available broker
	response := []byte{
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0xaa,
		0x00, 0x09, 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't',
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00}
	binary.BigEndian.PutUint32(response[19:], uint32(mockExtra.Port()))
	responses <- response
	responses <- []byte{
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00,
		0x00, 0x07, 'm', 'y', 'T', 'o', 'p', 'i', 'c',
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x05,
		0x00, 0x00, 0x00, 0x0e,
		0xFF, 0xFF, 0xFF, 0xFF,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00}
	responses <- []byte{
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00,
		0x00, 0x07, 'm', 'y', 'T', 'o', 'p', 'i', 'c',
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00,
		0x00, 0x00, 0x00, 0x0b,
		0x00, 0x00, 0x00, 0xaa,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00}

	client, err := NewClient("clientID", "localhost", mockBroker.Port())
	if err != nil {
		t.Fatal(err)
	}

	parts, err := client.partitions("myTopic")
	if err != nil {
		t.Error(err)
	} else if len(parts) != 1 || parts[0] != 0xb {
		t.Error("Client returned incorrect partitions for myTopic:", parts)
	}

	tst, err := client.leader("myTopic", 0xb)
	if err != nil {
		t.Error(err)
	} else if tst.ID() != 0xaa {
		t.Error("Leader for myTopic had incorrect ID.")
	}

	client.disconnectBroker(tst)

	client.Close()
}
<|endoftext|>


<commit_before>package bosh

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"

	"github.com/EngineerBetter/concourse-up/db"
)

const concourseManifestFilename = "concourse.yml"
const credsFilename = "concourse-creds.yml"
const concourseDeploymentName = "concourse"
const concourseVersionsFilename = "versions.json"
const concourseGrafanaFilename = "grafana_dashboard.yml"
const concourseCompatibilityFilename = "cup_compatibility.yml"

func (client *Client) uploadConcourseStemcell() error {
	var ops []struct {
		Path  string
		Value json.RawMessage
	}
	err := json.Unmarshal(awsConcourseVersions, &ops)
	if err != nil {
		return err
	}
	var version string
	for _, op := range ops {
		if op.Path != "/stemcells/alias=xenial/version" {
			continue
		}
		err := json.Unmarshal(op.Value, &version)
		if err != nil {
			return err
		}
	}
	if version == "" {
		return errors.New("did not find stemcell version in versions.json")
	}
	return client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		false,
		"upload-stemcell",
		fmt.Sprintf("https://s3.amazonaws.com/bosh-aws-light-stemcells/light-bosh-stemcell-%s-aws-xen-hvm-ubuntu-xenial-go_agent.tgz", version),
	)
}

func (client *Client) deployConcourse(creds []byte, detach bool) (newCreds []byte, err error) {

	concourseManifestPath, err := client.director.SaveFileToWorkingDir(concourseManifestFilename, awsConcourseManifest)
	if err != nil {
		return
	}

	concourseVersionsPath, err := client.director.SaveFileToWorkingDir(concourseVersionsFilename, awsConcourseVersions)
	if err != nil {
		return
	}

	concourseCompatibilityPath, err := client.director.SaveFileToWorkingDir(concourseCompatibilityFilename, awsConcourseCompatibility)
	if err != nil {
		return
	}

	concourseGrafanaPath, err := client.director.SaveFileToWorkingDir(concourseGrafanaFilename, awsConcourseGrafana)
	if err != nil {
		return
	}

	credsPath, err := client.director.SaveFileToWorkingDir(credsFilename, creds)
	if err != nil {
		return
	}

	vmap := map[string]interface{}{
		"deployment_name":          concourseDeploymentName,
		"domain":                   client.config.Domain,
		"project":                  client.config.Project,
		"web_network_name":         "public",
		"worker_network_name":      "private",
		"postgres_host":            client.metadata.BoshDBAddress.Value,
		"postgres_port":            client.metadata.BoshDBPort.Value,
		"postgres_role":            client.config.RDSUsername,
		"postgres_password":        client.config.RDSPassword,
		"postgres_ca_cert":         db.RDSRootCert,
		"web_vm_type":              "concourse-web-" + client.config.ConcourseWebSize,
		"worker_vm_type":           "concourse-" + client.config.ConcourseWorkerSize,
		"worker_count":             client.config.ConcourseWorkerCount,
		"atc_eip":                  client.metadata.ATCPublicIP.Value,
		"external_tls.certificate": client.config.ConcourseCert,
		"external_tls.private_key": client.config.ConcourseKey,
		"atc_encryption_key":       client.config.EncryptionKey,
	}

	if client.config.ConcoursePassword != "" {
		vmap["atc_password"] = client.config.ConcoursePassword
	}

	vs := vars(vmap)

	err = client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		detach,
		append([]string{
			"--deployment",
			concourseDeploymentName,
			"deploy",
			concourseManifestPath,
			"--vars-store",
			credsPath,
			"--ops-file",
			concourseVersionsPath,
			"--ops-file",
			concourseCompatibilityPath,
			"--vars-file",
			concourseGrafanaPath,
		},
			vs...)...,
	)
	newCreds, err1 := ioutil.ReadFile(credsPath)
	if err == nil {
		err = err1
	}
	return
}

func vars(vars map[string]interface{}) []string {
	var x []string
	for k, v := range vars {
		switch v.(type) {
		case string:
			x = append(x, "--var", fmt.Sprintf("%s=%q", k, v))
		case int:
			x = append(x, "--var", fmt.Sprintf("%s=%d", k, v))
		default:
			panic("unsupported type")
		}
	}
	return x
}

//go:generate go-bindata -pkg $GOPACKAGE  assets/... ../resources/...
var awsConcourseGrafana = MustAsset("assets/grafana_dashboard.yml")
var awsConcourseCompatibility = MustAsset("assets/ops/cup_compatibility.yml")
var awsConcourseManifest = MustAsset("../resources/manifest.yml")
var awsConcourseVersions = MustAsset("../resources/versions.json")
<commit_msg>deploy using both ops files<commit_after>package bosh

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"

	"github.com/EngineerBetter/concourse-up/db"
)

const concourseManifestFilename = "concourse.yml"
const credsFilename = "concourse-creds.yml"
const concourseDeploymentName = "concourse"
const concourseVersionsFilename = "versions.json"
const concourseSHAsFilename = "shas.json"
const concourseGrafanaFilename = "grafana_dashboard.yml"
const concourseCompatibilityFilename = "cup_compatibility.yml"

func (client *Client) uploadConcourseStemcell() error {
	var ops []struct {
		Path  string
		Value json.RawMessage
	}
	err := json.Unmarshal(awsConcourseVersions, &ops)
	if err != nil {
		return err
	}
	var version string
	for _, op := range ops {
		if op.Path != "/stemcells/alias=xenial/version" {
			continue
		}
		err := json.Unmarshal(op.Value, &version)
		if err != nil {
			return err
		}
	}
	if version == "" {
		return errors.New("did not find stemcell version in versions.json")
	}
	return client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		false,
		"upload-stemcell",
		fmt.Sprintf("https://s3.amazonaws.com/bosh-aws-light-stemcells/light-bosh-stemcell-%s-aws-xen-hvm-ubuntu-xenial-go_agent.tgz", version),
	)
}

func (client *Client) deployConcourse(creds []byte, detach bool) (newCreds []byte, err error) {

	concourseManifestPath, err := client.director.SaveFileToWorkingDir(concourseManifestFilename, awsConcourseManifest)
	if err != nil {
		return
	}

	concourseVersionsPath, err := client.director.SaveFileToWorkingDir(concourseVersionsFilename, awsConcourseVersions)
	if err != nil {
		return
	}

	concourseSHAsPath, err := client.director.SaveFileToWorkingDir(concourseSHAsFilename, awsConcourseSHAs)
	if err != nil {
		return
	}

	concourseCompatibilityPath, err := client.director.SaveFileToWorkingDir(concourseCompatibilityFilename, awsConcourseCompatibility)
	if err != nil {
		return
	}

	concourseGrafanaPath, err := client.director.SaveFileToWorkingDir(concourseGrafanaFilename, awsConcourseGrafana)
	if err != nil {
		return
	}

	credsPath, err := client.director.SaveFileToWorkingDir(credsFilename, creds)
	if err != nil {
		return
	}

	vmap := map[string]interface{}{
		"deployment_name":          concourseDeploymentName,
		"domain":                   client.config.Domain,
		"project":                  client.config.Project,
		"web_network_name":         "public",
		"worker_network_name":      "private",
		"postgres_host":            client.metadata.BoshDBAddress.Value,
		"postgres_port":            client.metadata.BoshDBPort.Value,
		"postgres_role":            client.config.RDSUsername,
		"postgres_password":        client.config.RDSPassword,
		"postgres_ca_cert":         db.RDSRootCert,
		"web_vm_type":              "concourse-web-" + client.config.ConcourseWebSize,
		"worker_vm_type":           "concourse-" + client.config.ConcourseWorkerSize,
		"worker_count":             client.config.ConcourseWorkerCount,
		"atc_eip":                  client.metadata.ATCPublicIP.Value,
		"external_tls.certificate": client.config.ConcourseCert,
		"external_tls.private_key": client.config.ConcourseKey,
		"atc_encryption_key":       client.config.EncryptionKey,
	}

	if client.config.ConcoursePassword != "" {
		vmap["atc_password"] = client.config.ConcoursePassword
	}

	vs := vars(vmap)

	err = client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		detach,
		append([]string{
			"--deployment",
			concourseDeploymentName,
			"deploy",
			concourseManifestPath,
			"--vars-store",
			credsPath,
			"--ops-file",
			concourseVersionsPath,
			"--ops-file",
			concourseSHAsPath,
			"--ops-file",
			concourseCompatibilityPath,
			"--vars-file",
			concourseGrafanaPath,
		},
			vs...)...,
	)
	newCreds, err1 := ioutil.ReadFile(credsPath)
	if err == nil {
		err = err1
	}
	return
}

func vars(vars map[string]interface{}) []string {
	var x []string
	for k, v := range vars {
		switch v.(type) {
		case string:
			x = append(x, "--var", fmt.Sprintf("%s=%q", k, v))
		case int:
			x = append(x, "--var", fmt.Sprintf("%s=%d", k, v))
		default:
			panic("unsupported type")
		}
	}
	return x
}

//go:generate go-bindata -pkg $GOPACKAGE  assets/... ../resources/...
var awsConcourseGrafana = MustAsset("assets/grafana_dashboard.yml")
var awsConcourseCompatibility = MustAsset("assets/ops/cup_compatibility.yml")
var awsConcourseManifest = MustAsset("../resources/manifest.yml")
var awsConcourseVersions = MustAsset("../resources/versions.json")
var awsConcourseSHAs = MustAsset("../resources/shas.json")
<|endoftext|>


<commit_before><commit_msg>Add the skeleton of a CBF indexer<commit_after><|endoftext|>


<commit_before>package pelicantun

import (
	"testing"
	"time"

	cv "github.com/glycerine/goconvey/convey"
)

// 008 acts as verification that the test in 010 works without intermediate proxies.
func TestBcastCliSrvWorkStandAlone008(t *testing.T) {

	srv := NewBcastServer(Addr{})
	srv.Start()
	defer srv.Stop()

	if !PortIsBound(srv.Listen.IpPort) {
		panic("srv not up")
	}

	cli := NewBcastClient(Addr{Port: srv.Listen.Port})
	cli.Start()
	defer cli.Stop()
	<-srv.SecondClient

	msg := "BREAKING NEWS"
	srv.Bcast(msg)

	cv.Convey("Given a BcastClient and BcastServer without any intervening communication proxies, they communicate just fine.\n", t, func() {
		cv.Convey("when the server broadcasts a message to all waiting clients, the client should receive that message.\n", func() {

			// wait for message to get from server to client.
			select {
			case <-cli.MsgRecvd:
				// excllent
				po("excellent, cli got a message!\n")
				po("client saw: '%s'", cli.LastMsgReceived())
			case <-time.After(time.Second * 2):
				po("\n\nWe waited 2 seconds, bailing.\n")
				srv.Stop()
				// should have gotten a message from the server at the client by now.

				panic("should have gotten a message from the server at the client by now!")
				cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
			}

			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		})
	})
}

// The actual point of longpoll_test.go is to run this 010 round-trip test for low-latency.
func TestLongPollToGetLowLatency010(t *testing.T) {

	cli, srv, rev, fwd, err := StartTestSystemWithBcast()
	panicOn(err)
	defer srv.Stop()
	defer rev.Stop()
	defer fwd.Stop()

	<-srv.FirstClient
	po("got past <-srv.FirstClient\n")

	cli.Start()
	defer cli.Stop()

	<-srv.SecondClient
	po("got past <-srv.SecondClient\n")

	msg := "BREAKING NEWS"
	srv.Bcast(msg)

	cv.Convey("Given a ForwardProxy and a ReverseProxy communicating over http, in order to acheive low-latency sends from server to client, long-polling with two sockets (one send and one receive) should be used. So a server that has something to send (e.g. broadcast here) should be able to send back to the client immediately.\n", t, func() {

		// wait for message to get from server to client.
		select {
		case <-cli.MsgRecvd:
			// excllent
			po("excellent, cli got a message!\n")
			po("client saw: '%s'", cli.LastMsgReceived())
		case <-time.After(time.Second * 2):
			po("\n\nWe waited 2 seconds, bailing.\n")
			srv.Stop()
			// should have gotten a message from the server at the client by now.

			panic("should have gotten a message from the server at the client by now!")
			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		}

		cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
	})
}

func TestLongPollToGetLowLatency01a(t *testing.T) {

	// no port is bound checks! works!
	cli, srv, rev, fwd, err := StartTestSystemWithBcastNoPortIsBoundChecks()
	panicOn(err)
	defer srv.Stop()
	defer rev.Stop()
	defer fwd.Stop()

	<-srv.FirstClient
	po("got past <-srv.FirstClient\n")

	cli.Start()
	defer cli.Stop()

	<-srv.SecondClient
	po("got past <-srv.SecondClient\n")

	msg := "BREAKING NEWS"
	srv.Bcast(msg)

	cv.Convey("Given a ForwardProxy and a ReverseProxy communicating over http, in order to acheive low-latency sends from server to client, long-polling with two sockets (one send and one receive) should be used. So a server that has something to send (e.g. broadcast here) should be able to send back to the client immediately.\n", t, func() {

		// wait for message to get from server to client.
		select {
		case <-cli.MsgRecvd:
			// excllent
			po("excellent, cli got a message!\n")
			po("client saw: '%s'", cli.LastMsgReceived())
		case <-time.After(time.Second * 2):
			po("\n\nWe waited 2 seconds, bailing.\n")
			srv.Stop()
			// should have gotten a message from the server at the client by now.

			panic("should have gotten a message from the server at the client by now!")
			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		}

		cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
	})
}

/*
func TestLongPollKeepsFifoOrdering016(t *testing.T) {

	cli, srv, rev, fwd, err := StartTestSystemWithBcast()
	panicOn(err)
	defer srv.Stop()
	defer rev.Stop()
	defer fwd.Stop()

	cv.Convey("Test ordering discipline for long-polling: Given a ForwardProxy and a ReverseProxy communicating over http, in order to acheive low-latency sends from server to client, long-polling with two sockets (one send and one receive) should be used. The two long polling sockets should still observe a first-to-send is first-to-get-a-reply order discipline.\n", t, func() {
		cli.Start()
		defer cli.Stop()
		<-srv.FirstClient

		po("got past <-srv.FirstClient\n")

		defer func() { po("deferred frunction running...!\n") }()

		msg := "BREAKING NEWS"
		srv.Bcast(msg)

		// wait for message to get from server to client.
		select {
		case <-cli.MsgRecvd:
			// excllent
			po("excellent, cli got a message!\n")
			po("client saw: '%s'", cli.LastMsgReceived())
		case <-time.After(time.Second * 2):
			po("\n\nWe waited 2 seconds, bailing.\n")
			srv.Stop()
			// should have gotten a message from the server at the client by now.

			panic("should have gotten a message from the server at the client by now!")
			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		}

		cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)

	})

	//	fmt.Printf("Given a Forward and Reverse proxy, in order to avoid creating new sockets too often (expensive), we should re-use the existing sockets for up to 5 round trips in 30 seconds.")
}

*/
<commit_msg>ft. 1a:isolated to just web server hanging for 60sec<commit_after>package pelicantun

import (
	"testing"
	"time"

	cv "github.com/glycerine/goconvey/convey"
)

// 008 acts as verification that the test in 010 works without intermediate proxies.
func TestBcastCliSrvWorkStandAlone008(t *testing.T) {

	srv := NewBcastServer(Addr{})
	srv.Start()
	defer srv.Stop()

	if !PortIsBound(srv.Listen.IpPort) {
		panic("srv not up")
	}

	cli := NewBcastClient(Addr{Port: srv.Listen.Port})
	cli.Start()
	defer cli.Stop()
	<-srv.SecondClient

	msg := "BREAKING NEWS"
	srv.Bcast(msg)

	cv.Convey("Given a BcastClient and BcastServer without any intervening communication proxies, they communicate just fine.\n", t, func() {
		cv.Convey("when the server broadcasts a message to all waiting clients, the client should receive that message.\n", func() {

			// wait for message to get from server to client.
			select {
			case <-cli.MsgRecvd:
				// excllent
				po("excellent, cli got a message!\n")
				po("client saw: '%s'", cli.LastMsgReceived())
			case <-time.After(time.Second * 2):
				po("\n\nWe waited 2 seconds, bailing.\n")
				srv.Stop()
				// should have gotten a message from the server at the client by now.

				panic("should have gotten a message from the server at the client by now!")
				cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
			}

			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		})
	})
}

// The actual point of longpoll_test.go is to run this 010 round-trip test for low-latency.
func TestLongPollToGetLowLatency010(t *testing.T) {

	cli, srv, rev, fwd, err := StartTestSystemWithBcast()
	panicOn(err)
	defer srv.Stop()
	defer rev.Stop()
	defer fwd.Stop()

	<-srv.FirstClient
	po("got past <-srv.FirstClient\n")

	cli.Start()
	defer cli.Stop()

	<-srv.SecondClient
	po("got past <-srv.SecondClient\n")

	msg := "BREAKING NEWS"
	srv.Bcast(msg)

	cv.Convey("Given a ForwardProxy and a ReverseProxy communicating over http, in order to acheive low-latency sends from server to client, long-polling with two sockets (one send and one receive) should be used. So a server that has something to send (e.g. broadcast here) should be able to send back to the client immediately.\n", t, func() {

		// wait for message to get from server to client.
		select {
		case <-cli.MsgRecvd:
			// excllent
			po("excellent, cli got a message!\n")
			po("client saw: '%s'", cli.LastMsgReceived())
		case <-time.After(time.Second * 2):
			po("\n\nWe waited 2 seconds, bailing.\n")
			srv.Stop()
			// should have gotten a message from the server at the client by now.

			panic("should have gotten a message from the server at the client by now!")
			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		}

		cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
	})
}

func TestLongPollToGetLowLatency01a(t *testing.T) {

	// no port is bound checks! works!
	cli, srv, rev, fwd, err := StartTestSystemWithBcastNoPortIsBoundChecks()
	panicOn(err)

	defer rev.Stop()

	// a little out of order shutdown, for cleaner hang diagnostics.
	defer srv.Stop()

	defer fwd.Stop()

	<-srv.FirstClient
	po("got past <-srv.FirstClient\n")

	cli.Start()
	defer cli.Stop()

	<-srv.SecondClient
	po("got past <-srv.SecondClient\n")

	msg := "BREAKING NEWS"
	srv.Bcast(msg)

	cv.Convey("Given a ForwardProxy and a ReverseProxy communicating over http, in order to acheive low-latency sends from server to client, long-polling with two sockets (one send and one receive) should be used. So a server that has something to send (e.g. broadcast here) should be able to send back to the client immediately.\n", t, func() {

		// wait for message to get from server to client.
		select {
		case <-cli.MsgRecvd:
			// excllent
			po("excellent, cli got a message!\n")
			po("client saw: '%s'", cli.LastMsgReceived())
		case <-time.After(time.Second * 2):
			po("\n\nWe waited 2 seconds, bailing.\n")
			srv.Stop()
			// should have gotten a message from the server at the client by now.

			panic("should have gotten a message from the server at the client by now!")
			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		}

		cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
	})
}

/*
func TestLongPollKeepsFifoOrdering016(t *testing.T) {

	cli, srv, rev, fwd, err := StartTestSystemWithBcast()
	panicOn(err)
	defer srv.Stop()
	defer rev.Stop()
	defer fwd.Stop()

	cv.Convey("Test ordering discipline for long-polling: Given a ForwardProxy and a ReverseProxy communicating over http, in order to acheive low-latency sends from server to client, long-polling with two sockets (one send and one receive) should be used. The two long polling sockets should still observe a first-to-send is first-to-get-a-reply order discipline.\n", t, func() {
		cli.Start()
		defer cli.Stop()
		<-srv.FirstClient

		po("got past <-srv.FirstClient\n")

		defer func() { po("deferred frunction running...!\n") }()

		msg := "BREAKING NEWS"
		srv.Bcast(msg)

		// wait for message to get from server to client.
		select {
		case <-cli.MsgRecvd:
			// excllent
			po("excellent, cli got a message!\n")
			po("client saw: '%s'", cli.LastMsgReceived())
		case <-time.After(time.Second * 2):
			po("\n\nWe waited 2 seconds, bailing.\n")
			srv.Stop()
			// should have gotten a message from the server at the client by now.

			panic("should have gotten a message from the server at the client by now!")
			cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)
		}

		cv.So(cli.LastMsgReceived(), cv.ShouldEqual, msg)

	})

	//	fmt.Printf("Given a Forward and Reverse proxy, in order to avoid creating new sockets too often (expensive), we should re-use the existing sockets for up to 5 round trips in 30 seconds.")
}

*/
<|endoftext|>


<commit_before>package sluice

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func Test(t *testing.T) {
	Convey("Sluice can...", t, func() {
		gondola := New()

		Convey("pump values", func() {
			gondola.Push("x")
			gondola.Push("y")
			gondola.Push("z")
			So(<-gondola.Next(), ShouldEqual, "x")
			So(<-gondola.Next(), ShouldEqual, "y")
			So(<-gondola.Next(), ShouldEqual, "z")
		})

		Convey("block when empty", func() {
			var answered bool
			select {
			case <-gondola.Next():
				answered = true
			default:
				answered = false
			}
			So(answered, ShouldEqual, false)

			Convey("answers even dropped channels", func() {
				secondReq := gondola.Next()
				gondola.Push("1")
				// we still don't expect an answer,
				//  because the "1" routed to the channel in the prev test.
				select {
				case <-secondReq:
					answered = true
				default:
					answered = false
				}
				So(answered, ShouldEqual, false)

				Convey("definitely answers eventually", func() {
					gondola.Push("2")
					So(<-secondReq, ShouldEqual, "2")
				})
			})
		})
	})
}
<commit_msg>Fix a sluice test with probablistic failure.<commit_after>package sluice

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func Test(t *testing.T) {
	Convey("Sluice can...", t, func() {
		gondola := New()

		Convey("pump values", func() {
			gondola.Push("x")
			gondola.Push("y")
			gondola.Push("z")
			So(<-gondola.Next(), ShouldEqual, "x")
			So(<-gondola.Next(), ShouldEqual, "y")
			So(<-gondola.Next(), ShouldEqual, "z")
		})

		Convey("block when empty", func() {
			var answered bool
			select {
			case <-gondola.Next():
				answered = true
			default:
				answered = false
			}
			So(answered, ShouldEqual, false)

			Convey("answers even dropped channels", func() {
				gondola.Push("1")
				// we still don't expect an answer,
				//  because the "1" routed to the channel in the prev test.
				secondReq := gondola.Next()
				select {
				case <-secondReq:
					answered = true
				default:
					answered = false
				}
				So(answered, ShouldEqual, false)

				Convey("definitely answers eventually", func() {
					gondola.Push("2")
					So(<-secondReq, ShouldEqual, "2")
				})
			})
		})
	})
}
<|endoftext|>


<commit_before>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

   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.

   @author: Juliano Martinez
*/

package main

import (
	"fmt"
	docopt "github.com/docopt/docopt.go"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"strconv"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func main() {
	usage := `Hot Potato Router Control.

Usage:
  hprctl add <vhost> <backend_ip:port> [--weight=<n>]
  hprctl del <vhost> <backend_ip:port> [--weight=<n>]
  hprctl show <vhost>
  hprctl list

Args:
  add           add a new vhost and backend
  dell          del a vhost and a backend
  show          show all backends from a given vhost
  list          list all vhosts

Options:
  -h --help     Show this screen.
  --version     Show version.
  --weight=<n>  Weight in wrr [default: 1].
`

	arguments, _ := docopt.Parse(usage, nil, true, "Hot Potato Router 0.3.0", false)
	if arguments["add"] == true {
		_, err := rc.ZAdd(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	}

	/* if arguments["del"] == true {
		_, err := rc.ZRem(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	} */

	if arguments["show"] == true {
		bes, err := rc.ZRange(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), 0, -1, true)
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		var url string
		for _, be := range bes {
			count, err := strconv.Atoi(be)
			if err != nil {
				url = be
				continue
			}
			fmt.Printf("backend %s weight %s", url, count)
		}
		return
	}

	if arguments["list"] == true {
		keys, err := rc.Keys("hpr-backends::*")
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		for _, k := range keys {
			fmt.Printf("vhost %s", k)
		}
		return
	}
}
<commit_msg>working<commit_after>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

   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.

   @author: Juliano Martinez
*/

package main

import (
	"fmt"
	docopt "github.com/docopt/docopt.go"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"strconv"
	"strings"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func main() {
	usage := `Hot Potato Router Control.

Usage:
  hprctl add <vhost> <backend_ip:port> [--weight=<n>]
  hprctl del <vhost> <backend_ip:port> [--weight=<n>]
  hprctl show <vhost>
  hprctl list

Args:
  add           add a new vhost and backend
  dell          del a vhost and a backend
  show          show all backends from a given vhost
  list          list all vhosts

Options:
  -h --help     Show this screen.
  --version     Show version.
  --weight=<n>  Weight in wrr [default: 1].
`

	arguments, _ := docopt.Parse(usage, nil, true, "Hot Potato Router 0.3.0", false)
	if arguments["add"] == true {
		_, err := rc.ZAdd(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	}

	/* if arguments["del"] == true {
		_, err := rc.ZRem(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), arguments["--weight"], arguments["<backend_ip:port>"])
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		return
	} */

	if arguments["show"] == true {
		bes, err := rc.ZRange(fmt.Sprintf("hpr-backends::%s", arguments["<vhost>"]), 0, -1, true)
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		fmt.Printf(":: vhost [ %s ]\n", arguments["<vhost>"])
		var url string
		for _, be := range bes {
			count, err := strconv.Atoi(be)
			if err != nil {
				url = be
				continue
			}
			fmt.Printf("-- backend %s weight=%d\n", url, count)
		}
		return
	}

	if arguments["list"] == true {
		keys, err := rc.Keys("hpr-backends::*")
		hpr_utils.CheckPanic(err, "Unable to write on hpr database")
		for _, k := range keys {
			fmt.Printf(":: vhost [ %s ]\n", strings.TrimLeft(k, "hpr-backends::"))
		}
		return
	}
}
<|endoftext|>


<commit_before>package dbase

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

const (
	Key = "_db"
)

type Config struct {
	Username    string
	Password    string
	Hostname    string
	Port        string
	Database    string
	TxIsolation string
}

func ConnectString(cfg Config) string {
	isolation := cfg.TxIsolation
	if isolation == "" {
		isolation = "READ-COMMITTED"
	}

	return fmt.Sprintf(`%v:%v@tcp(%v:%v)/%v?charset=utf8&parseTime=True&loc=Local&tx_isolation="%v"`,
		cfg.Username,
		cfg.Password,
		cfg.Hostname,
		cfg.Port,
		cfg.Database,
		isolation,
	)
}

func Open(connectString string) (*gorm.DB, error) {
	return gorm.Open("mysql", connectString)
}

func OpenNative(connectString string) (*sql.DB, error) {
	return sql.Open("mysql", connectString)
}

type Accessor interface {
	Open() (*gorm.DB, error)
	Close(*gorm.DB) error
	Begin(*gorm.DB) *gorm.DB
	Commit(*gorm.DB) *gorm.DB
	Rollback(*gorm.DB) *gorm.DB
	Tx(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error
}

type OpenFunc func() (*gorm.DB, error)

func (fn OpenFunc) Open() (*gorm.DB, error) {
	return fn()
}

func (fn OpenFunc) Close(db *gorm.DB) error {
	return db.Close()
}

func (fn OpenFunc) Begin(db *gorm.DB) *gorm.DB {
	return db.Begin()
}

func (fn OpenFunc) Commit(db *gorm.DB) *gorm.DB {
	return db.Commit()
}

func (fn OpenFunc) Rollback(db *gorm.DB) *gorm.DB {
	return db.Rollback()
}

func (fn OpenFunc) Tx(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error {
	db, err := fn.Open()
	if err != nil {
		return err
	}

	db = db.Begin()
	ctx = context.WithValue(ctx, Key, db)

	err = callback(ctx, db)
	if err != nil {
		db.Rollback()
		return err
	}

	db.Commit()
	return nil
}

// FromContext retrieves a db instance from a context
func FromContext(ctx context.Context) (*gorm.DB, bool) {
	v := ctx.Value(Key)
	if v == nil {
		return nil, false
	}

	db, ok := v.(*gorm.DB)
	return db, ok
}

func NewOpenFunc(connectString string) OpenFunc {
	return func() (*gorm.DB, error) {
		return Open(connectString)
	}
}

type Mock struct {
	DB            *gorm.DB
	OpenCount     int
	CloseCount    int
	BeginCount    int
	CommitCount   int
	RollbackCount int
	TxCount       int
}

func (m *Mock) Open() (*gorm.DB, error) {
	m.OpenCount++
	return m.DB, nil
}

func (m *Mock) Close(db *gorm.DB) error {
	m.CloseCount++
	return nil
}

func (m *Mock) Begin(db *gorm.DB) *gorm.DB {
	m.BeginCount++
	return m.DB
}

func (m *Mock) Commit(db *gorm.DB) *gorm.DB {
	m.CommitCount++
	return m.DB
}

func (m *Mock) Rollback(db *gorm.DB) *gorm.DB {
	m.RollbackCount++
	return m.DB
}

func (m *Mock) Tx(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error {
	m.TxCount++
	return callback(ctx, m.DB)
}
<commit_msg>- added ReadOnly support to db accessor<commit_after>package dbase

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

const (
	Key = "_db"
)

type Config struct {
	Username    string
	Password    string
	Hostname    string
	Port        string
	Database    string
	TxIsolation string
}

func ConnectString(cfg Config) string {
	isolation := cfg.TxIsolation
	if isolation == "" {
		isolation = "READ-COMMITTED"
	}

	return fmt.Sprintf(`%v:%v@tcp(%v:%v)/%v?charset=utf8&parseTime=True&loc=Local&tx_isolation="%v"`,
		cfg.Username,
		cfg.Password,
		cfg.Hostname,
		cfg.Port,
		cfg.Database,
		isolation,
	)
}

func Open(connectString string) (*gorm.DB, error) {
	return gorm.Open("mysql", connectString)
}

func OpenNative(connectString string) (*sql.DB, error) {
	return sql.Open("mysql", connectString)
}

type Accessor interface {
	Open() (*gorm.DB, error)
	Close(*gorm.DB) error
	Begin(*gorm.DB) *gorm.DB
	Commit(*gorm.DB) *gorm.DB
	Rollback(*gorm.DB) *gorm.DB
	Tx(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error
	ReadOnly(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error
}

type OpenFunc func() (*gorm.DB, error)

func (fn OpenFunc) Open() (*gorm.DB, error) {
	return fn()
}

func (fn OpenFunc) Close(db *gorm.DB) error {
	return db.Close()
}

func (fn OpenFunc) Begin(db *gorm.DB) *gorm.DB {
	return db.Begin()
}

func (fn OpenFunc) Commit(db *gorm.DB) *gorm.DB {
	return db.Commit()
}

func (fn OpenFunc) Rollback(db *gorm.DB) *gorm.DB {
	return db.Rollback()
}

func (fn OpenFunc) Tx(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error {
	db, err := fn.Open()
	if err != nil {
		return err
	}

	db = db.Begin()
	ctx = context.WithValue(ctx, Key, db)

	err = callback(ctx, db)
	if err != nil {
		db.Rollback()
		return err
	}

	db.Commit()
	return nil
}

func (fn OpenFunc) ReadOnly(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error {
	db, err := fn.Open()
	if err != nil {
		return err
	}
	db = db.Begin()
	defer db.Rollback()

	ctx = context.WithValue(ctx, Key, db)
	return callback(ctx, db)
}

// FromContext retrieves a db instance from a context
func FromContext(ctx context.Context) (*gorm.DB, bool) {
	v := ctx.Value(Key)
	if v == nil {
		return nil, false
	}

	db, ok := v.(*gorm.DB)
	return db, ok
}

func NewOpenFunc(connectString string) OpenFunc {
	return func() (*gorm.DB, error) {
		return Open(connectString)
	}
}

type Mock struct {
	DB            *gorm.DB
	OpenCount     int
	CloseCount    int
	BeginCount    int
	CommitCount   int
	RollbackCount int
	TxCount       int
	ReadOnlyCount int
}

func (m *Mock) Open() (*gorm.DB, error) {
	m.OpenCount++
	return m.DB, nil
}

func (m *Mock) Close(db *gorm.DB) error {
	m.CloseCount++
	return nil
}

func (m *Mock) Begin(db *gorm.DB) *gorm.DB {
	m.BeginCount++
	return m.DB
}

func (m *Mock) Commit(db *gorm.DB) *gorm.DB {
	m.CommitCount++
	return m.DB
}

func (m *Mock) Rollback(db *gorm.DB) *gorm.DB {
	m.RollbackCount++
	return m.DB
}

func (m *Mock) Tx(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error {
	m.TxCount++
	return callback(ctx, m.DB)
}

func (m *Mock) ReadOnly(ctx context.Context, callback func(ctx context.Context, db *gorm.DB) error) error {
	m.ReadOnlyCount++
	return callback(ctx, m.DB)
}
<|endoftext|>


<commit_before>package sudoku

type swordfishTechnique struct {
	*basicSolveTechnique
}

func (self *swordfishTechnique) humanLikelihood(step *SolveStep) float64 {
	//TODO: reason more carefully about how hard this technique is.
	return self.difficultyHelper(70.0)
}

func (self *swordfishTechnique) Description(step *SolveStep) string {
	//TODO: Implement this
	return "TODO: IMPLEMENT ME"
}

func (self *swordfishTechnique) Find(grid *Grid, results chan *SolveStep, done chan bool) {

	getter := self.getter(grid)

	//For this technique, the primary access is the first type of group we look at to find
	//cells with only 2 spots for a given number.

	//TODO: Implement the "relaxed" version of this technique, too.

	//TODO: walk through this in random order
	for i := 0; i < DIM; i++ {
		//The candidate we're considering

		//Consider each of the major-axis groups to see if more than three have
		//only two candidates for

		var majorAxisGroupsWithTwoOptionsForCandidate []CellSlice

		for c := 0; c < DIM; c++ {
			majorAxisGroup := getter(c)

			cellsWithCandidatePossibility := majorAxisGroup.FilterByPossible(i)

			if len(cellsWithCandidatePossibility) == 2 {
				//TODO: shouldn't we keep track of the rows where the possibilities were, too?
				majorAxisGroupsWithTwoOptionsForCandidate = append(majorAxisGroupsWithTwoOptionsForCandidate, cellsWithCandidatePossibility)
			}

		}

		//Do we have more than three major axis groups identified?
		if len(majorAxisGroupsWithTwoOptionsForCandidate) < 3 {
			continue
		}

		//Consider every subset of size three
		for _, indexes := range subsetIndexes(len(majorAxisGroupsWithTwoOptionsForCandidate), 3) {
			majorAxisGroups := make([]CellSlice, 3)
			for i, index := range indexes {
				majorAxisGroups[i] = majorAxisGroupsWithTwoOptionsForCandidate[index]
			}

			//OK, now majorAxisGroups has the set of three we're operating on.
			//Do their minorAxis groups line up to a set of three as well?

			var minorGroupIndexSet intSet

			for _, group := range majorAxisGroups {
				if self.groupType == _GROUP_COL {
					minorGroupIndexSet = minorGroupIndexSet.union(group.AllRows().toIntSet())
				} else {
					minorGroupIndexSet = minorGroupIndexSet.union(group.AllCols().toIntSet())
				}
			}

			if len(minorGroupIndexSet) != 3 {
				//Nah, didn't have three rows.
				continue
			}

			//Woot, looks like we found a valid set.

			//Generate the list of cells that will be affected
			var affectedCells CellSlice

			for minorGroupIndex, _ := range minorGroupIndexSet {
				if self.groupType == _GROUP_COL {
					affectedCells = append(affectedCells, grid.Row(minorGroupIndex)...)
				} else {
					affectedCells = append(affectedCells, grid.Col(minorGroupIndex)...)
				}
			}

			//Get rid of cells that are already filled, or where removing 'i'
			//would be a no-op anyway since it's not already a possible there.
			affectedCells = affectedCells.FilterByPossible(i)

			//Gather the list of all cells that are "pointing" to this

			var pointerCells CellSlice

			for _, group := range majorAxisGroups {
				pointerCells = append(pointerCells, group...)
			}

			//Get rid of all pointer cells from the rows of cells that will be
			//affected.
			affectedCells = affectedCells.RemoveCells(pointerCells)

			//Okay, now the set is solid.

			//Okay, we have a candidate step (unchunked). Is it useful?
			step := &SolveStep{self,
				affectedCells,
				IntSlice{i},
				pointerCells,
				nil,
				nil,
			}

			if step.IsUseful(grid) {
				select {
				case results <- step:
				case <-done:
					return
				}
			}

		}

	}

}
<commit_msg>TESTS FAIL. But fixed an off-by-one error for Swordfish techniques where we wouldn't have found swordfishes for '9'<commit_after>package sudoku

type swordfishTechnique struct {
	*basicSolveTechnique
}

func (self *swordfishTechnique) humanLikelihood(step *SolveStep) float64 {
	//TODO: reason more carefully about how hard this technique is.
	return self.difficultyHelper(70.0)
}

func (self *swordfishTechnique) Description(step *SolveStep) string {
	//TODO: Implement this
	return "TODO: IMPLEMENT ME"
}

func (self *swordfishTechnique) Find(grid *Grid, results chan *SolveStep, done chan bool) {

	getter := self.getter(grid)

	//For this technique, the primary access is the first type of group we look at to find
	//cells with only 2 spots for a given number.

	//TODO: Implement the "relaxed" version of this technique, too.

	//TODO: walk through this in random order
	for i := 1; i < DIM+1; i++ {
		//The candidate we're considering

		//Consider each of the major-axis groups to see if more than three have
		//only two candidates for

		var majorAxisGroupsWithTwoOptionsForCandidate []CellSlice

		for c := 0; c < DIM; c++ {
			majorAxisGroup := getter(c)

			cellsWithCandidatePossibility := majorAxisGroup.FilterByPossible(i)

			if len(cellsWithCandidatePossibility) == 2 {
				//TODO: shouldn't we keep track of the rows where the possibilities were, too?
				majorAxisGroupsWithTwoOptionsForCandidate = append(majorAxisGroupsWithTwoOptionsForCandidate, cellsWithCandidatePossibility)
			}

		}

		//Do we have more than three major axis groups identified?
		if len(majorAxisGroupsWithTwoOptionsForCandidate) < 3 {
			continue
		}

		//Consider every subset of size three
		for _, indexes := range subsetIndexes(len(majorAxisGroupsWithTwoOptionsForCandidate), 3) {
			majorAxisGroups := make([]CellSlice, 3)
			for i, index := range indexes {
				majorAxisGroups[i] = majorAxisGroupsWithTwoOptionsForCandidate[index]
			}

			//OK, now majorAxisGroups has the set of three we're operating on.
			//Do their minorAxis groups line up to a set of three as well?

			var minorGroupIndexSet intSet

			for _, group := range majorAxisGroups {
				if self.groupType == _GROUP_COL {
					minorGroupIndexSet = minorGroupIndexSet.union(group.AllRows().toIntSet())
				} else {
					minorGroupIndexSet = minorGroupIndexSet.union(group.AllCols().toIntSet())
				}
			}

			if len(minorGroupIndexSet) != 3 {
				//Nah, didn't have three rows.
				continue
			}

			//Woot, looks like we found a valid set.

			//Generate the list of cells that will be affected
			var affectedCells CellSlice

			for minorGroupIndex, _ := range minorGroupIndexSet {
				if self.groupType == _GROUP_COL {
					affectedCells = append(affectedCells, grid.Row(minorGroupIndex)...)
				} else {
					affectedCells = append(affectedCells, grid.Col(minorGroupIndex)...)
				}
			}

			//Get rid of cells that are already filled, or where removing 'i'
			//would be a no-op anyway since it's not already a possible there.
			affectedCells = affectedCells.FilterByPossible(i)

			//Gather the list of all cells that are "pointing" to this

			var pointerCells CellSlice

			for _, group := range majorAxisGroups {
				pointerCells = append(pointerCells, group...)
			}

			//Get rid of all pointer cells from the rows of cells that will be
			//affected.
			affectedCells = affectedCells.RemoveCells(pointerCells)

			//Okay, now the set is solid.

			//Okay, we have a candidate step (unchunked). Is it useful?
			step := &SolveStep{self,
				affectedCells,
				IntSlice{i},
				pointerCells,
				nil,
				nil,
			}

			if step.IsUseful(grid) {
				select {
				case results <- step:
				case <-done:
					return
				}
			}

		}

	}

}
<|endoftext|>


<commit_before>package http

import (
	"encoding/json"
	"github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/swipely/iam-docker/src/docker"
	"github.com/swipely/iam-docker/src/iam"
	"github.com/valyala/fasthttp"
	adaptor "github.com/valyala/fasthttp/fasthttpadaptor"
	"net/http"
	"regexp"
	"strings"
	"time"
)

const (
	iamMethod      = "GET"
	credentialType = "AWS-HMAC"
	credentialCode = "Success"
)

var (
	iamRegex  = regexp.MustCompile("^/[^/]+/meta-data/iam/security-credentials/[^/]+$")
	listRegex = regexp.MustCompile("^/[^/]+/meta-data/iam/security-credentials/?$")
	log       = logrus.WithField("prefix", "http")
)

// NewIAMHandler creates a http.Handler which responds to metadata API requests.
// When the request is for the IAM path, it looks up the IAM role in the
// container store and fetches those credentials. Otherwise, it acts as a
// reverse proxy for the real API.
func NewIAMHandler(upstream http.Handler, containerStore docker.ContainerStore, credentialStore iam.CredentialStore) fasthttp.RequestHandler {
	handler := &httpHandler{
		upstreamHandler: adaptor.NewFastHTTPHandler(upstream),
		containerStore:  containerStore,
		credentialStore: credentialStore,
	}

	return handler.serveFastHTTP
}

func (handler *httpHandler) serveFastHTTP(ctx *fasthttp.RequestCtx) {
	path := string(ctx.Path())
	method := string(ctx.Method())
	addr := ctx.RemoteAddr().String()

	logger := log.WithFields(logrus.Fields{
		"path":       path,
		"method":     method,
		"remoteAddr": addr,
	})

	if (method == iamMethod) && iamRegex.MatchString(path) {
		logger.Info("Serving IAM credentials request")
		handler.serveIAMRequest(ctx, addr, path, logger)
	} else if (method == iamMethod) && listRegex.MatchString(path) {
		logger.Debug("Serving list IAM credentials request")
		handler.serveListCredentialsRequest(ctx, addr, logger)
	} else {
		logger.Debug("Delegating request upstream")
		handler.upstreamHandler(ctx)
	}
}

func (handler *httpHandler) serveIAMRequest(ctx *fasthttp.RequestCtx, addr string, path string, logger *logrus.Entry) {
	role, creds, err := handler.credentialsForAddress(addr)
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to find credentials")
		ctx.SetStatusCode(http.StatusNotFound)
		return
	}
	idx := strings.LastIndex(path, "/")
	requestedRole := path[idx+1:]
	if !strings.HasSuffix(*role, requestedRole) {
		logger.WithFields(logrus.Fields{
			"actual-role":    *role,
			"requested-role": requestedRole,
		}).Warn("Role mismatch")
		ctx.SetStatusCode(http.StatusUnauthorized)
		return
	}
	response, err := json.Marshal(&CredentialResponse{
		AccessKeyID:     *creds.AccessKeyId,
		Code:            credentialCode,
		Expiration:      *creds.Expiration,
		LastUpdated:     creds.Expiration.Add(-1 * time.Hour),
		SecretAccessKey: *creds.SecretAccessKey,
		Token:           *creds.SessionToken,
		Type:            credentialType,
	})
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to serialize JSON")
		ctx.SetStatusCode(http.StatusInternalServerError)
		return
	}
	ctx.SetBody(response)
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to write response")
		return
	}
	logger.Debug("Successfully responded")
}

func (handler *httpHandler) serveListCredentialsRequest(ctx *fasthttp.RequestCtx, addr string, logger *logrus.Entry) {
	role, _, err := handler.credentialsForAddress(addr)
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to find credentials")
		ctx.SetStatusCode(http.StatusNotFound)
		return
	}
	idx := strings.LastIndex(*role, "/")
	ctx.SetBodyString((*role)[idx+1:])
	logger.Debug("Successfully responded")
}

func (handler *httpHandler) credentialsForAddress(address string) (*string, *sts.Credentials, error) {
	ip := strings.Split(address, ":")[0]
	role, err := handler.containerStore.IAMRoleForIP(ip)
	if err != nil {
		return nil, nil, err
	}
	creds, err := handler.credentialStore.CredentialsForRole(role)
	if err != nil {
		return nil, nil, err
	}
	return &role, creds, nil
}

type httpHandler struct {
	upstreamHandler fasthttp.RequestHandler
	containerStore  docker.ContainerStore
	credentialStore iam.CredentialStore
}
<commit_msg>Regex free and loving it<commit_after>package http

import (
	"encoding/json"
	"github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/swipely/iam-docker/src/docker"
	"github.com/swipely/iam-docker/src/iam"
	"github.com/valyala/fasthttp"
	adaptor "github.com/valyala/fasthttp/fasthttpadaptor"
	"net/http"
	"strings"
	"time"
)

const (
	iamMethod      = "GET"
	credentialType = "AWS-HMAC"
	credentialCode = "Success"
	iamPath        = "/meta-data/iam/security-credentials/"
)

var (
	log = logrus.WithField("prefix", "http")
)

// NewIAMHandler creates a http.Handler which responds to metadata API requests.
// When the request is for the IAM path, it looks up the IAM role in the
// container store and fetches those credentials. Otherwise, it acts as a
// reverse proxy for the real API.
func NewIAMHandler(upstream http.Handler, containerStore docker.ContainerStore, credentialStore iam.CredentialStore) fasthttp.RequestHandler {
	handler := &httpHandler{
		upstreamHandler: adaptor.NewFastHTTPHandler(upstream),
		containerStore:  containerStore,
		credentialStore: credentialStore,
	}

	return handler.serveFastHTTP
}

func (handler *httpHandler) serveFastHTTP(ctx *fasthttp.RequestCtx) {
	path := string(ctx.Path())
	method := string(ctx.Method())
	addr := ctx.RemoteAddr().String()

	logger := log.WithFields(logrus.Fields{
		"path":       path,
		"method":     method,
		"remoteAddr": addr,
	})

	if method == iamMethod {
		idx := strings.LastIndex(path, iamPath)
		if idx == (len(path) - len(iamPath)) {
			logger.Debug("Serving list IAM credentials request")
			handler.serveListCredentialsRequest(ctx, addr, logger)
			return
		} else if idx >= 0 {
			logger.Info("Serving IAM credentials request")
			handler.serveIAMRequest(ctx, addr, path, logger)
			return
		}
	}

	logger.Debug("Delegating request upstream")
	handler.upstreamHandler(ctx)
}

func (handler *httpHandler) serveIAMRequest(ctx *fasthttp.RequestCtx, addr string, path string, logger *logrus.Entry) {
	role, creds, err := handler.credentialsForAddress(addr)
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to find credentials")
		ctx.SetStatusCode(http.StatusNotFound)
		return
	}
	idx := strings.LastIndex(path, "/")
	requestedRole := path[idx+1:]
	if !strings.HasSuffix(*role, requestedRole) {
		logger.WithFields(logrus.Fields{
			"actual-role":    *role,
			"requested-role": requestedRole,
		}).Warn("Role mismatch")
		ctx.SetStatusCode(http.StatusUnauthorized)
		return
	}
	response, err := json.Marshal(&CredentialResponse{
		AccessKeyID:     *creds.AccessKeyId,
		Code:            credentialCode,
		Expiration:      *creds.Expiration,
		LastUpdated:     creds.Expiration.Add(-1 * time.Hour),
		SecretAccessKey: *creds.SecretAccessKey,
		Token:           *creds.SessionToken,
		Type:            credentialType,
	})
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to serialize JSON")
		ctx.SetStatusCode(http.StatusInternalServerError)
		return
	}
	ctx.SetBody(response)
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to write response")
		return
	}
	logger.Debug("Successfully responded")
}

func (handler *httpHandler) serveListCredentialsRequest(ctx *fasthttp.RequestCtx, addr string, logger *logrus.Entry) {
	role, _, err := handler.credentialsForAddress(addr)
	if err != nil {
		logger.WithField("error", err.Error()).Warn("Unable to find credentials")
		ctx.SetStatusCode(http.StatusNotFound)
		return
	}
	idx := strings.LastIndex(*role, "/")
	ctx.SetBodyString((*role)[idx+1:])
	logger.Debug("Successfully responded")
}

func (handler *httpHandler) credentialsForAddress(address string) (*string, *sts.Credentials, error) {
	ip := strings.Split(address, ":")[0]
	role, err := handler.containerStore.IAMRoleForIP(ip)
	if err != nil {
		return nil, nil, err
	}
	creds, err := handler.credentialStore.CredentialsForRole(role)
	if err != nil {
		return nil, nil, err
	}
	return &role, creds, nil
}

type httpHandler struct {
	upstreamHandler fasthttp.RequestHandler
	containerStore  docker.ContainerStore
	credentialStore iam.CredentialStore
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

const (
	// MaxDataCarrierSize is the maximum number of bytes allowed in pushed
	// data to be considered a nulldata transaction.
	MaxDataCarrierSize = 256
)

// ScriptClass is an enumeration for the list of standard types of script.
type ScriptClass byte

// Classes of script payment known about in the blockchain.
const (
	NonStandardTy     ScriptClass = iota // None of the recognized forms.
	PubKeyTy                             // Pay pubkey.
	PubKeyHashTy                         // Pay pubkey hash.
	ScriptHashTy                         // Pay to script hash.
	MultiSigTy                           // Multi signature.
	NullDataTy                           // Empty data-only (provably prunable).
	StakeSubmissionTy                    // Stake submission.
	StakeGenTy                           // Stake generation
	StakeRevocationTy                    // Stake revocation.
	StakeSubChangeTy                     // Change for stake submission tx.
	PubkeyAltTy                          // Alternative signature pubkey.
	PubkeyHashAltTy                      // Alternative signature pubkey hash.
	TreasuryAddTy                        // Add value to treasury
	TreasuryGenTy                        // Generate utxos from treasury account
)

// scriptClassToName houses the human-readable strings which describe each
// script class.
var scriptClassToName = []string{
	NonStandardTy:     "nonstandard",
	PubKeyTy:          "pubkey",
	PubkeyAltTy:       "pubkeyalt",
	PubKeyHashTy:      "pubkeyhash",
	PubkeyHashAltTy:   "pubkeyhashalt",
	ScriptHashTy:      "scripthash",
	MultiSigTy:        "multisig",
	NullDataTy:        "nulldata",
	StakeSubmissionTy: "stakesubmission",
	StakeGenTy:        "stakegen",
	StakeRevocationTy: "stakerevoke",
	StakeSubChangeTy:  "sstxchange",
	TreasuryAddTy:     "treasuryadd",
	TreasuryGenTy:     "treasurygen",
}

// String implements the Stringer interface by returning the name of
// the enum script class. If the enum is invalid then "Invalid" will be
// returned.
func (t ScriptClass) String() string {
	if int(t) > len(scriptClassToName) || int(t) < 0 {
		return "Invalid"
	}
	return scriptClassToName[t]
}
<commit_msg>txscript: Remove unused MaxDataCarrierSize.<commit_after>// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

// ScriptClass is an enumeration for the list of standard types of script.
type ScriptClass byte

// Classes of script payment known about in the blockchain.
const (
	NonStandardTy     ScriptClass = iota // None of the recognized forms.
	PubKeyTy                             // Pay pubkey.
	PubKeyHashTy                         // Pay pubkey hash.
	ScriptHashTy                         // Pay to script hash.
	MultiSigTy                           // Multi signature.
	NullDataTy                           // Empty data-only (provably prunable).
	StakeSubmissionTy                    // Stake submission.
	StakeGenTy                           // Stake generation
	StakeRevocationTy                    // Stake revocation.
	StakeSubChangeTy                     // Change for stake submission tx.
	PubkeyAltTy                          // Alternative signature pubkey.
	PubkeyHashAltTy                      // Alternative signature pubkey hash.
	TreasuryAddTy                        // Add value to treasury
	TreasuryGenTy                        // Generate utxos from treasury account
)

// scriptClassToName houses the human-readable strings which describe each
// script class.
var scriptClassToName = []string{
	NonStandardTy:     "nonstandard",
	PubKeyTy:          "pubkey",
	PubkeyAltTy:       "pubkeyalt",
	PubKeyHashTy:      "pubkeyhash",
	PubkeyHashAltTy:   "pubkeyhashalt",
	ScriptHashTy:      "scripthash",
	MultiSigTy:        "multisig",
	NullDataTy:        "nulldata",
	StakeSubmissionTy: "stakesubmission",
	StakeGenTy:        "stakegen",
	StakeRevocationTy: "stakerevoke",
	StakeSubChangeTy:  "sstxchange",
	TreasuryAddTy:     "treasuryadd",
	TreasuryGenTy:     "treasurygen",
}

// String implements the Stringer interface by returning the name of
// the enum script class. If the enum is invalid then "Invalid" will be
// returned.
func (t ScriptClass) String() string {
	if int(t) > len(scriptClassToName) || int(t) < 0 {
		return "Invalid"
	}
	return scriptClassToName[t]
}
<|endoftext|>