<commit_before>package logtap

import (
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/pagodabox/golang-hatchet"
	"net/http"
	"strconv"
)

// HistoricalDrain matches the drain interface
type HistoricalDrain struct {
	port string
	max  int
	log  hatchet.Logger
	db   *bolt.DB
	deploy []string
}

// NewHistoricalDrain returns a new instance of a HistoricalDrain
func NewHistoricalDrain(port string, file string, max int) *HistoricalDrain {
	db, err := bolt.Open(file, 0644, nil)
	if err != nil {
		db, err = bolt.Open("./bolt.db", 0644, nil)
	}
	return &HistoricalDrain{
		port: port,
		max:  max,
		db:   db,
	}
}

// allow us to clear history of the deploy logs
func (h *HistoricalDrain) ClearDeploy() {
	h.deploy = []string{}
}

// Start starts the http listener.
// The listener on every request returns a json hash of logs of some arbitrary size
// default size is 100
func (h *HistoricalDrain) Start() {
	go func() {
		mux := http.NewServeMux()
		mux.HandleFunc("/logtap/system", h.handlerSystem)
		mux.HandleFunc("/logtap/deploy", h.handlerDeploy)
		err := http.ListenAndServe(":"+h.port, mux)
		if err != nil {
			h.log.Error("[LOGTAP]"+err.Error())
		}
	}()
}

// Handle deploys that come into this drain
// deploy logs should stay relatively short and should be cleared out easily
func (h *HistoricalDrain) handlerDeploy(w http.ResponseWriter, r *http.Request) {
	for _, msg := range h.deploy {
		fmt.Fprintf(w, "%s", msg)
	}
}

// handlerSystem handles any web request with any path and returns logs
// this makes it so a client that talks to pagodabox's logvac
// can communicate with this system
func (h *HistoricalDrain) handlerSystem(w http.ResponseWriter, r *http.Request) {
	var limit int64
	if i, err := strconv.ParseInt(r.FormValue("limit"), 10, 64); err == nil {
		limit = i
	} else {
		limit = 10000
	}
	h.log.Debug("[LOGTAP][handler] limit: %d", limit)
	h.db.View(func(tx *bolt.Tx) error {
		// Create a new bucket.
		b := tx.Bucket([]byte("log"))
		c := b.Cursor()

		// move the curser along so we can start dropping logs
		// in the right order at the right place
		if int64(b.Stats().KeyN) > limit {
			c.First()
			move_forward := int64(b.Stats().KeyN) - limit
			for i := int64(1); i < move_forward; i++ {
				c.Next()
			}
		} else {
			c.First()
		}

		for k, v := c.Next(); k != nil; k, v = c.Next() {
			fmt.Fprintf(w, "%s - %s", k, v)
		}

		return nil
	})

}

// SetLogger really allows the logtap main struct
// to assign its own logger to the historical drain
func (h *HistoricalDrain) SetLogger(l hatchet.Logger) {
	h.log = l
}

// Write is used to implement the interface and do
// type switching
func (h *HistoricalDrain) Write(msg Message) {
  switch msg.Type {
  case "deploy":
  	h.WriteDeploy(msg)
  default :
    h.WriteSystem(msg)
  }
}

// Write deploy logs to the deploy array.
// much quicker and better at handling deploy logs
func (h *HistoricalDrain) WriteDeploy(msg Message) {
	h.deploy = append(h.deploy, (msg.Time.String()+" - "+msg.Content))
}

// WriteSyslog drops data into a capped collection of logs
// if we hit the limit the last log item will be removed from the beginning
func (h *HistoricalDrain) WriteSystem(msg Message) {
	h.log.Debug("[LOGTAP][Historical][write] message: (%s)%s", msg.Time.String(), msg.Content)
	h.db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte("log"))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}
		err = bucket.Put([]byte(msg.Time.String()), []byte(msg.Content))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}

		if bucket.Stats().KeyN > h.max {
			delete_count := bucket.Stats().KeyN - h.max
			c := bucket.Cursor()
			for i := 0; i < delete_count; i++ {
				c.First()
				c.Delete()
			}
		}

		return nil
	})

}
<commit_msg>make new lines happen on deploy logs<commit_after>package logtap

import (
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/pagodabox/golang-hatchet"
	"net/http"
	"strconv"
)

// HistoricalDrain matches the drain interface
type HistoricalDrain struct {
	port string
	max  int
	log  hatchet.Logger
	db   *bolt.DB
	deploy []string
}

// NewHistoricalDrain returns a new instance of a HistoricalDrain
func NewHistoricalDrain(port string, file string, max int) *HistoricalDrain {
	db, err := bolt.Open(file, 0644, nil)
	if err != nil {
		db, err = bolt.Open("./bolt.db", 0644, nil)
	}
	return &HistoricalDrain{
		port: port,
		max:  max,
		db:   db,
	}
}

// allow us to clear history of the deploy logs
func (h *HistoricalDrain) ClearDeploy() {
	h.deploy = []string{}
}

// Start starts the http listener.
// The listener on every request returns a json hash of logs of some arbitrary size
// default size is 100
func (h *HistoricalDrain) Start() {
	go func() {
		mux := http.NewServeMux()
		mux.HandleFunc("/logtap/system", h.handlerSystem)
		mux.HandleFunc("/logtap/deploy", h.handlerDeploy)
		err := http.ListenAndServe(":"+h.port, mux)
		if err != nil {
			h.log.Error("[LOGTAP]"+err.Error())
		}
	}()
}

// Handle deploys that come into this drain
// deploy logs should stay relatively short and should be cleared out easily
func (h *HistoricalDrain) handlerDeploy(w http.ResponseWriter, r *http.Request) {
	for _, msg := range h.deploy {
		fmt.Fprintf(w, "%s\n", msg)
	}
}

// handlerSystem handles any web request with any path and returns logs
// this makes it so a client that talks to pagodabox's logvac
// can communicate with this system
func (h *HistoricalDrain) handlerSystem(w http.ResponseWriter, r *http.Request) {
	var limit int64
	if i, err := strconv.ParseInt(r.FormValue("limit"), 10, 64); err == nil {
		limit = i
	} else {
		limit = 10000
	}
	h.log.Debug("[LOGTAP][handler] limit: %d", limit)
	h.db.View(func(tx *bolt.Tx) error {
		// Create a new bucket.
		b := tx.Bucket([]byte("log"))
		c := b.Cursor()

		// move the curser along so we can start dropping logs
		// in the right order at the right place
		if int64(b.Stats().KeyN) > limit {
			c.First()
			move_forward := int64(b.Stats().KeyN) - limit
			for i := int64(1); i < move_forward; i++ {
				c.Next()
			}
		} else {
			c.First()
		}

		for k, v := c.Next(); k != nil; k, v = c.Next() {
			fmt.Fprintf(w, "%s - %s", k, v)
		}

		return nil
	})

}

// SetLogger really allows the logtap main struct
// to assign its own logger to the historical drain
func (h *HistoricalDrain) SetLogger(l hatchet.Logger) {
	h.log = l
}

// Write is used to implement the interface and do
// type switching
func (h *HistoricalDrain) Write(msg Message) {
  switch msg.Type {
  case "deploy":
  	h.WriteDeploy(msg)
  default :
    h.WriteSystem(msg)
  }
}

// Write deploy logs to the deploy array.
// much quicker and better at handling deploy logs
func (h *HistoricalDrain) WriteDeploy(msg Message) {
	h.deploy = append(h.deploy, (msg.Time.String()+" - "+msg.Content))
}

// WriteSyslog drops data into a capped collection of logs
// if we hit the limit the last log item will be removed from the beginning
func (h *HistoricalDrain) WriteSystem(msg Message) {
	h.log.Debug("[LOGTAP][Historical][write] message: (%s)%s", msg.Time.String(), msg.Content)
	h.db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte("log"))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}
		err = bucket.Put([]byte(msg.Time.String()), []byte(msg.Content))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}

		if bucket.Stats().KeyN > h.max {
			delete_count := bucket.Stats().KeyN - h.max
			c := bucket.Cursor()
			for i := 0; i < delete_count; i++ {
				c.First()
				c.Delete()
			}
		}

		return nil
	})

}
<|endoftext|>


<commit_before>package certinfo

import (
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"errors"
	"io/ioutil"
	"net"
	"strings"
	"time"

	"github.com/cloudflare/cfssl/helpers"
)

// Certificate represents a JSON description of an X.509 certificate.
type Certificate struct {
	Subject            Name      `json:"subject,omitempty"`
	SANs               []string  `json:"sans,omitempty"`
	NotBefore          time.Time `json:"not_before"`
	NotAfter           time.Time `json:"not_after"`
	SignatureAlgorithm string    `json:"sigalg"`
	RawPEM             string    `json:"pem"`
}

// Name represents a JSON description of a PKIX Name
type Name struct {
	CommonName         string        `json:"common_name,omitempty"`
	SerialNumber       string        `json:"serial_number,omitempty"`
	Country            string        `json:"country,omitempty"`
	Organization       string        `json:"organization,omitempty"`
	OrganizationalUnit string        `json:"organizational_unit,omitempty"`
	Locality           string        `json:"locality,omitempty"`
	Province           string        `json:"province,omitempty"`
	StreetAddress      string        `json:"street_address,omitempty"`
	PostalCode         string        `json:"postal_code,omitempty"`
	Names              []interface{} `json:"names,omitempty"`
	//ExtraNames         []interface{} `json:"extra_names,omitempty"`
}

// ParseName parses a new name from a *pkix.Name
func ParseName(name pkix.Name) Name {
	n := Name{
		CommonName:         name.CommonName,
		SerialNumber:       name.SerialNumber,
		Country:            strings.Join(name.Country, ","),
		Organization:       strings.Join(name.Organization, ","),
		OrganizationalUnit: strings.Join(name.OrganizationalUnit, ","),
		Locality:           strings.Join(name.Locality, ","),
		Province:           strings.Join(name.Province, ","),
		StreetAddress:      strings.Join(name.StreetAddress, ","),
		PostalCode:         strings.Join(name.PostalCode, ","),
	}

	for i := range name.Names {
		n.Names = append(n.Names, name.Names[i].Value)
	}

	// ExtraNames aren't supported in Go 1.4
	// for i := range name.ExtraNames {
	// 	n.ExtraNames = append(n.ExtraNames, name.ExtraNames[i].Value)
	// }

	return n
}

// ParseCertificate parses an x509 certificate.
func ParseCertificate(cert *x509.Certificate) *Certificate {
	c := &Certificate{
		RawPEM:             string(helpers.EncodeCertificatePEM(cert)),
		SignatureAlgorithm: helpers.SignatureString(cert.SignatureAlgorithm),
		NotBefore:          cert.NotBefore,
		NotAfter:           cert.NotAfter,
		Subject:            ParseName(cert.Subject),
		SANs:               cert.DNSNames,
	}
	for _, ip := range cert.IPAddresses {
		c.SANs = append(c.SANs, ip.String())
	}
	return c
}

// ParseCertificateFile parses x509 certificate file.
func ParseCertificateFile(certFile string) (*Certificate, error) {
	certPEM, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}

	return ParseCertificatePEM(certPEM)
}

// ParseCertificatePEM parses an x509 certificate PEM.
func ParseCertificatePEM(certPEM []byte) (*Certificate, error) {
	cert, err := helpers.ParseCertificatePEM(certPEM)
	if err != nil {
		return nil, err
	}

	return ParseCertificate(cert), nil
}

func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
	// block, _ := pem.Decode([]byte(csrPEM))
	// der := block.Bytes
	// csr_object, err := x509.ParseCertificateRequest(der)
	csr_object, err := helpers.ParseCSRPEM(csrPEM)
	if err != nil {
		return nil, err
	}

	return csr_object, nil
}

func ParseCSRFile(csrFile string) (*x509.CertificateRequest, error) {
	csrPEM, err := ioutil.ReadFile(csrFile)
	if err != nil {
		return nil, err
	}

	return ParseCSRPEM(csrPEM)
}

// ParseCertificateDomain parses the certificate served by the given domain.
func ParseCertificateDomain(domain string) (cert *Certificate, err error) {
	var host, port string
	if host, port, err = net.SplitHostPort(domain); err != nil {
		host = domain
		port = "443"
	}

	var conn *tls.Conn
	conn, err = tls.DialWithDialer(&net.Dialer{Timeout: 10 * time.Second}, "tcp", net.JoinHostPort(host, port), &tls.Config{InsecureSkipVerify: true})
	if err != nil {
		return
	}
	defer conn.Close()

	if len(conn.ConnectionState().PeerCertificates) == 0 {
		return nil, errors.New("received no server certificates")
	}

	cert = ParseCertificate(conn.ConnectionState().PeerCertificates[0])
	return
}
<commit_msg>Removing shrapnel comments.<commit_after>package certinfo

import (
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"errors"
	"io/ioutil"
	"net"
	"strings"
	"time"

	"github.com/cloudflare/cfssl/helpers"
)

// Certificate represents a JSON description of an X.509 certificate.
type Certificate struct {
	Subject            Name      `json:"subject,omitempty"`
	SANs               []string  `json:"sans,omitempty"`
	NotBefore          time.Time `json:"not_before"`
	NotAfter           time.Time `json:"not_after"`
	SignatureAlgorithm string    `json:"sigalg"`
	RawPEM             string    `json:"pem"`
}

// Name represents a JSON description of a PKIX Name
type Name struct {
	CommonName         string        `json:"common_name,omitempty"`
	SerialNumber       string        `json:"serial_number,omitempty"`
	Country            string        `json:"country,omitempty"`
	Organization       string        `json:"organization,omitempty"`
	OrganizationalUnit string        `json:"organizational_unit,omitempty"`
	Locality           string        `json:"locality,omitempty"`
	Province           string        `json:"province,omitempty"`
	StreetAddress      string        `json:"street_address,omitempty"`
	PostalCode         string        `json:"postal_code,omitempty"`
	Names              []interface{} `json:"names,omitempty"`
	//ExtraNames         []interface{} `json:"extra_names,omitempty"`
}

// ParseName parses a new name from a *pkix.Name
func ParseName(name pkix.Name) Name {
	n := Name{
		CommonName:         name.CommonName,
		SerialNumber:       name.SerialNumber,
		Country:            strings.Join(name.Country, ","),
		Organization:       strings.Join(name.Organization, ","),
		OrganizationalUnit: strings.Join(name.OrganizationalUnit, ","),
		Locality:           strings.Join(name.Locality, ","),
		Province:           strings.Join(name.Province, ","),
		StreetAddress:      strings.Join(name.StreetAddress, ","),
		PostalCode:         strings.Join(name.PostalCode, ","),
	}

	for i := range name.Names {
		n.Names = append(n.Names, name.Names[i].Value)
	}

	// ExtraNames aren't supported in Go 1.4
	// for i := range name.ExtraNames {
	// 	n.ExtraNames = append(n.ExtraNames, name.ExtraNames[i].Value)
	// }

	return n
}

// ParseCertificate parses an x509 certificate.
func ParseCertificate(cert *x509.Certificate) *Certificate {
	c := &Certificate{
		RawPEM:             string(helpers.EncodeCertificatePEM(cert)),
		SignatureAlgorithm: helpers.SignatureString(cert.SignatureAlgorithm),
		NotBefore:          cert.NotBefore,
		NotAfter:           cert.NotAfter,
		Subject:            ParseName(cert.Subject),
		SANs:               cert.DNSNames,
	}
	for _, ip := range cert.IPAddresses {
		c.SANs = append(c.SANs, ip.String())
	}
	return c
}

// ParseCertificateFile parses x509 certificate file.
func ParseCertificateFile(certFile string) (*Certificate, error) {
	certPEM, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}

	return ParseCertificatePEM(certPEM)
}

// ParseCertificatePEM parses an x509 certificate PEM.
func ParseCertificatePEM(certPEM []byte) (*Certificate, error) {
	cert, err := helpers.ParseCertificatePEM(certPEM)
	if err != nil {
		return nil, err
	}

	return ParseCertificate(cert), nil
}

func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
	csr_object, err := helpers.ParseCSRPEM(csrPEM)
	if err != nil {
		return nil, err
	}

	return csr_object, nil
}

func ParseCSRFile(csrFile string) (*x509.CertificateRequest, error) {
	csrPEM, err := ioutil.ReadFile(csrFile)
	if err != nil {
		return nil, err
	}

	return ParseCSRPEM(csrPEM)
}

// ParseCertificateDomain parses the certificate served by the given domain.
func ParseCertificateDomain(domain string) (cert *Certificate, err error) {
	var host, port string
	if host, port, err = net.SplitHostPort(domain); err != nil {
		host = domain
		port = "443"
	}

	var conn *tls.Conn
	conn, err = tls.DialWithDialer(&net.Dialer{Timeout: 10 * time.Second}, "tcp", net.JoinHostPort(host, port), &tls.Config{InsecureSkipVerify: true})
	if err != nil {
		return
	}
	defer conn.Close()

	if len(conn.ConnectionState().PeerCertificates) == 0 {
		return nil, errors.New("received no server certificates")
	}

	cert = ParseCertificate(conn.ConnectionState().PeerCertificates[0])
	return
}
<|endoftext|>


<commit_before>package backends

import (
	"errors"
	"time"

	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/log"
	"github.com/RichardKnop/machinery/v1/tasks"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
)

type DynamoDBBackend struct {
	cnf     *config.Config
	client  dynamodbiface.DynamoDBAPI
	session *session.Session
}

// NewDynamoDBBackend creates a DynamoDBBackend instance
func NewDynamoDBBackend(cnf *config.Config) Interface {
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))
	dy := dynamodb.New(sess)
	return &DynamoDBBackend{cnf: cnf, client: dy, session: sess}
}

func (b *DynamoDBBackend) InitGroup(groupUUID string, taskUUIDs []string) error {
	meta := tasks.GroupMeta{
		GroupUUID: groupUUID,
		TaskUUIDs: taskUUIDs,
		CreatedAt: time.Now().UTC(),
	}
	av, err := dynamodbattribute.MarshalMap(meta)
	if err != nil {
		log.ERROR.Printf("Error when marshaling Dynamodb attributes. Err: %v", err)
		return err
	}
	input := &dynamodb.PutItemInput{
		Item:      av,
		TableName: aws.String(b.cnf.DynamoDB.GroupMetasTable),
	}
	_, err = b.client.PutItem(input)

	if err != nil {
		log.ERROR.Printf("Got error when calling PutItem: %v; Error: %v", input, err)
		return err
	}
	return nil
}

func (b *DynamoDBBackend) GroupCompleted(groupUUID string, groupTaskCount int) (bool, error) {
	groupMeta, err := b.getGroupMeta(groupUUID)
	if err != nil {
		return false, err
	}
	taskStates, err := b.getStates(groupMeta.TaskUUIDs...)
	if err != nil {
		return false, err
	}
	var countSuccessTasks = 0
	for _, taskState := range taskStates {
		if taskState.IsCompleted() {
			countSuccessTasks++
		}
	}

	return countSuccessTasks == groupTaskCount, nil
}

func (b *DynamoDBBackend) GroupTaskStates(groupUUID string, groupTaskCount int) ([]*tasks.TaskState, error) {
	groupMeta, err := b.getGroupMeta(groupUUID)
	if err != nil {
		return nil, err
	}

	return b.getStates(groupMeta.TaskUUIDs...)
}

func (b *DynamoDBBackend) TriggerChord(groupUUID string) (bool, error) {
	// Get the group meta data
	groupMeta, err := b.getGroupMeta(groupUUID)

	if err != nil {
		return false, err
	}

	// Chord has already been triggered, return false (should not trigger again)
	if groupMeta.ChordTriggered {
		return false, nil
	}

	// If group meta is locked, wait until it's unlocked
	for groupMeta.Lock {
		groupMeta, _ = b.getGroupMeta(groupUUID)
		log.WARNING.Print("Group meta locked, waiting")
		<-time.After(time.Millisecond * 5)
	}

	// Acquire lock
	if err = b.lockGroupMeta(groupUUID); err != nil {
		return false, err
	}
	defer b.unlockGroupMeta(groupUUID)

	// update group meta data
	err = b.chordTriggered(groupUUID)
	if err != nil {
		return false, err
	}
	return true, err
}

func (b *DynamoDBBackend) SetStatePending(signature *tasks.Signature) error {
	taskState := tasks.NewPendingTaskState(signature)
	// taskUUID is the primary key of the table, so a new task need to be created first, instead of using dynamodb.UpdateItemInput directly
	return b.initTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateReceived(signature *tasks.Signature) error {
	taskState := tasks.NewReceivedTaskState(signature)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateStarted(signature *tasks.Signature) error {
	taskState := tasks.NewStartedTaskState(signature)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateRetry(signature *tasks.Signature) error {
	taskState := tasks.NewRetryTaskState(signature)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateSuccess(signature *tasks.Signature, results []*tasks.TaskResult) error {
	taskState := tasks.NewSuccessTaskState(signature, results)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateFailure(signature *tasks.Signature, err string) error {
	taskState := tasks.NewFailureTaskState(signature, err)
	return b.updateToFailureStateWithError(taskState)
}

func (b *DynamoDBBackend) GetState(taskUUID string) (*tasks.TaskState, error) {
	result, err := b.client.GetItem(&dynamodb.GetItemInput{
		TableName: aws.String(b.cnf.DynamoDB.TaskStatesTable),
		Key: map[string]*dynamodb.AttributeValue{
			"TaskUUID": {
				S: aws.String(taskUUID),
			},
		},
	})
	if err != nil {
		return nil, err
	}
	return b.unmarshalTaskStateGetItemResult(result)
}

func (b *DynamoDBBackend) PurgeState(taskUUID string) error {
	input := &dynamodb.DeleteItemInput{
		Key: map[string]*dynamodb.AttributeValue{
			"TaskUUID": {
				N: aws.String(taskUUID),
			},
		},
		TableName: aws.String(b.cnf.DynamoDB.TaskStatesTable),
	}
	_, err := b.client.DeleteItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) PurgeGroupMeta(groupUUID string) error {
	input := &dynamodb.DeleteItemInput{
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				N: aws.String(groupUUID),
			},
		},
		TableName: aws.String(b.cnf.DynamoDB.GroupMetasTable),
	}
	_, err := b.client.DeleteItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) getGroupMeta(groupUUID string) (*tasks.GroupMeta, error) {
	result, err := b.client.GetItem(&dynamodb.GetItemInput{
		TableName: aws.String(b.cnf.DynamoDB.GroupMetasTable),
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				S: aws.String(groupUUID),
			},
		},
	})
	if err != nil {
		log.ERROR.Printf("Error when getting group meta. Error: %v", err)
		return nil, err
	}
	item, err := b.unmarshalGroupMetaGetItemResult(result)
	if err != nil {
		log.INFO.Println("!!!", result)
		log.ERROR.Printf("Failed to unmarshal item, %v", err)
		return nil, err
	}
	return item, nil
}

func (b *DynamoDBBackend) getStates(taskUUIDs ...string) ([]*tasks.TaskState, error) {
	states := make([]*tasks.TaskState, 0)
	stateChan := make(chan *tasks.TaskState, len(taskUUIDs))
	errChan := make(chan error)
	// There is no method like querying items by `in` a list of primary keys.
	// So a for loop with go routine is used to get multiple items
	for _, id := range taskUUIDs {
		go func(id string) {
			state, err := b.GetState(id)
			if err != nil {
				errChan <- err
			}
			stateChan <- state
		}(id)
	}

	for s := range stateChan {
		states = append(states, s)
		if len(states) == len(taskUUIDs) {
			close(stateChan)
		}
	}
	return states, nil
}

func (b *DynamoDBBackend) lockGroupMeta(groupUUID string) error {
	err := b.updateGroupMetaLock(groupUUID, true)
	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) unlockGroupMeta(groupUUID string) error {
	err := b.updateGroupMetaLock(groupUUID, false)
	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) updateGroupMetaLock(groupUUID string, status bool) error {
	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames: map[string]*string{
			"#L": aws.String("Lock"),
		},
		ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
			":l": {
				BOOL: aws.Bool(status),
			},
		},
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				S: aws.String(groupUUID),
			},
		},
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.GroupMetasTable),
		UpdateExpression: aws.String("SET #L = :l"),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) chordTriggered(groupUUID string) error {
	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames: map[string]*string{
			"#CT": aws.String("ChordTriggered"),
		},
		ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
			":ct": {
				BOOL: aws.Bool(true),
			},
		},
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				S: aws.String(groupUUID),
			},
		},
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.GroupMetasTable),
		UpdateExpression: aws.String("SET #CT = :ct"),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) setTaskState(taskState *tasks.TaskState) error {
	expAttributeNames := map[string]*string{
		"#S": aws.String("State"),
	}
	expAttributeValues := map[string]*dynamodb.AttributeValue{
		":s": {
			S: aws.String(taskState.State),
		},
	}
	keyAttributeValues := map[string]*dynamodb.AttributeValue{
		"TaskUUID": {
			S: aws.String(taskState.TaskUUID),
		},
	}
	exp := "SET #S = :s"
	if !taskState.CreatedAt.IsZero() {
		expAttributeNames["#C"] = aws.String("CreatedAt")
		expAttributeValues[":c"] = &dynamodb.AttributeValue{
			S: aws.String(taskState.CreatedAt.String()),
		}
		exp += ", #C = :c"
	}
	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames:  expAttributeNames,
		ExpressionAttributeValues: expAttributeValues,
		Key:              keyAttributeValues,
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.TaskStatesTable),
		UpdateExpression: aws.String(exp),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) initTaskState(taskState *tasks.TaskState) error {
	av, err := dynamodbattribute.MarshalMap(taskState)
	input := &dynamodb.PutItemInput{
		Item:      av,
		TableName: aws.String(b.cnf.DynamoDB.TaskStatesTable),
	}
	_, err = b.client.PutItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) updateToFailureStateWithError(taskState *tasks.TaskState) error {

	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames: map[string]*string{
			"#S": aws.String("State"),
			"#E": aws.String("Error"),
		},
		ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
			":s": {
				S: aws.String(taskState.State),
			},
			":e": {
				S: aws.String(taskState.Error),
			},
		},
		Key: map[string]*dynamodb.AttributeValue{
			"TaskUUID": {
				S: aws.String(taskState.TaskUUID),
			},
		},
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.TaskStatesTable),
		UpdateExpression: aws.String("SET #S = :s, #E = :e"),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) unmarshalGroupMetaGetItemResult(result *dynamodb.GetItemOutput) (*tasks.GroupMeta, error) {
	if result == nil {
		err := errors.New("task state is nil")
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	item := tasks.GroupMeta{}
	err := dynamodbattribute.UnmarshalMap(result.Item, &item)
	if err != nil {
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	return &item, err
}

func (b *DynamoDBBackend) unmarshalTaskStateGetItemResult(result *dynamodb.GetItemOutput) (*tasks.TaskState, error) {
	if result == nil {
		err := errors.New("task state is nil")
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	state := tasks.TaskState{}
	err := dynamodbattribute.UnmarshalMap(result.Item, &state)
	if err != nil {
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	return &state, nil
}
<commit_msg>add result saving<commit_after>package backends

import (
	"errors"
	"fmt"
	"time"

	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/log"
	"github.com/RichardKnop/machinery/v1/tasks"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
)

type DynamoDBBackend struct {
	cnf     *config.Config
	client  dynamodbiface.DynamoDBAPI
	session *session.Session
}

// NewDynamoDBBackend creates a DynamoDBBackend instance
func NewDynamoDBBackend(cnf *config.Config) Interface {
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))
	dy := dynamodb.New(sess)
	return &DynamoDBBackend{cnf: cnf, client: dy, session: sess}
}

func (b *DynamoDBBackend) InitGroup(groupUUID string, taskUUIDs []string) error {
	meta := tasks.GroupMeta{
		GroupUUID: groupUUID,
		TaskUUIDs: taskUUIDs,
		CreatedAt: time.Now().UTC(),
	}
	av, err := dynamodbattribute.MarshalMap(meta)
	if err != nil {
		log.ERROR.Printf("Error when marshaling Dynamodb attributes. Err: %v", err)
		return err
	}
	input := &dynamodb.PutItemInput{
		Item:      av,
		TableName: aws.String(b.cnf.DynamoDB.GroupMetasTable),
	}
	_, err = b.client.PutItem(input)

	if err != nil {
		log.ERROR.Printf("Got error when calling PutItem: %v; Error: %v", input, err)
		return err
	}
	return nil
}

func (b *DynamoDBBackend) GroupCompleted(groupUUID string, groupTaskCount int) (bool, error) {
	groupMeta, err := b.getGroupMeta(groupUUID)
	if err != nil {
		return false, err
	}
	taskStates, err := b.getStates(groupMeta.TaskUUIDs...)
	if err != nil {
		return false, err
	}
	var countSuccessTasks = 0
	for _, taskState := range taskStates {
		if taskState.IsCompleted() {
			countSuccessTasks++
		}
	}

	return countSuccessTasks == groupTaskCount, nil
}

func (b *DynamoDBBackend) GroupTaskStates(groupUUID string, groupTaskCount int) ([]*tasks.TaskState, error) {
	groupMeta, err := b.getGroupMeta(groupUUID)
	if err != nil {
		return nil, err
	}

	return b.getStates(groupMeta.TaskUUIDs...)
}

func (b *DynamoDBBackend) TriggerChord(groupUUID string) (bool, error) {
	// Get the group meta data
	groupMeta, err := b.getGroupMeta(groupUUID)

	if err != nil {
		return false, err
	}

	// Chord has already been triggered, return false (should not trigger again)
	if groupMeta.ChordTriggered {
		return false, nil
	}

	// If group meta is locked, wait until it's unlocked
	for groupMeta.Lock {
		groupMeta, _ = b.getGroupMeta(groupUUID)
		log.WARNING.Print("Group meta locked, waiting")
		<-time.After(time.Millisecond * 5)
	}

	// Acquire lock
	if err = b.lockGroupMeta(groupUUID); err != nil {
		return false, err
	}
	defer b.unlockGroupMeta(groupUUID)

	// update group meta data
	err = b.chordTriggered(groupUUID)
	if err != nil {
		return false, err
	}
	return true, err
}

func (b *DynamoDBBackend) SetStatePending(signature *tasks.Signature) error {
	taskState := tasks.NewPendingTaskState(signature)
	// taskUUID is the primary key of the table, so a new task need to be created first, instead of using dynamodb.UpdateItemInput directly
	return b.initTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateReceived(signature *tasks.Signature) error {
	taskState := tasks.NewReceivedTaskState(signature)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateStarted(signature *tasks.Signature) error {
	taskState := tasks.NewStartedTaskState(signature)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateRetry(signature *tasks.Signature) error {
	taskState := tasks.NewRetryTaskState(signature)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateSuccess(signature *tasks.Signature, results []*tasks.TaskResult) error {
	taskState := tasks.NewSuccessTaskState(signature, results)
	return b.setTaskState(taskState)
}

func (b *DynamoDBBackend) SetStateFailure(signature *tasks.Signature, err string) error {
	taskState := tasks.NewFailureTaskState(signature, err)
	return b.updateToFailureStateWithError(taskState)
}

func (b *DynamoDBBackend) GetState(taskUUID string) (*tasks.TaskState, error) {
	result, err := b.client.GetItem(&dynamodb.GetItemInput{
		TableName: aws.String(b.cnf.DynamoDB.TaskStatesTable),
		Key: map[string]*dynamodb.AttributeValue{
			"TaskUUID": {
				S: aws.String(taskUUID),
			},
		},
	})
	if err != nil {
		return nil, err
	}
	return b.unmarshalTaskStateGetItemResult(result)
}

func (b *DynamoDBBackend) PurgeState(taskUUID string) error {
	input := &dynamodb.DeleteItemInput{
		Key: map[string]*dynamodb.AttributeValue{
			"TaskUUID": {
				N: aws.String(taskUUID),
			},
		},
		TableName: aws.String(b.cnf.DynamoDB.TaskStatesTable),
	}
	_, err := b.client.DeleteItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) PurgeGroupMeta(groupUUID string) error {
	input := &dynamodb.DeleteItemInput{
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				N: aws.String(groupUUID),
			},
		},
		TableName: aws.String(b.cnf.DynamoDB.GroupMetasTable),
	}
	_, err := b.client.DeleteItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) getGroupMeta(groupUUID string) (*tasks.GroupMeta, error) {
	result, err := b.client.GetItem(&dynamodb.GetItemInput{
		TableName: aws.String(b.cnf.DynamoDB.GroupMetasTable),
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				S: aws.String(groupUUID),
			},
		},
	})
	if err != nil {
		log.ERROR.Printf("Error when getting group meta. Error: %v", err)
		return nil, err
	}
	item, err := b.unmarshalGroupMetaGetItemResult(result)
	if err != nil {
		log.INFO.Println("!!!", result)
		log.ERROR.Printf("Failed to unmarshal item, %v", err)
		return nil, err
	}
	return item, nil
}

func (b *DynamoDBBackend) getStates(taskUUIDs ...string) ([]*tasks.TaskState, error) {
	states := make([]*tasks.TaskState, 0)
	stateChan := make(chan *tasks.TaskState, len(taskUUIDs))
	errChan := make(chan error)
	// There is no method like querying items by `in` a list of primary keys.
	// So a for loop with go routine is used to get multiple items
	for _, id := range taskUUIDs {
		go func(id string) {
			state, err := b.GetState(id)
			if err != nil {
				errChan <- err
			}
			stateChan <- state
		}(id)
	}

	for s := range stateChan {
		states = append(states, s)
		if len(states) == len(taskUUIDs) {
			close(stateChan)
		}
	}
	return states, nil
}

func (b *DynamoDBBackend) lockGroupMeta(groupUUID string) error {
	err := b.updateGroupMetaLock(groupUUID, true)
	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) unlockGroupMeta(groupUUID string) error {
	err := b.updateGroupMetaLock(groupUUID, false)
	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) updateGroupMetaLock(groupUUID string, status bool) error {
	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames: map[string]*string{
			"#L": aws.String("Lock"),
		},
		ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
			":l": {
				BOOL: aws.Bool(status),
			},
		},
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				S: aws.String(groupUUID),
			},
		},
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.GroupMetasTable),
		UpdateExpression: aws.String("SET #L = :l"),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) chordTriggered(groupUUID string) error {
	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames: map[string]*string{
			"#CT": aws.String("ChordTriggered"),
		},
		ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
			":ct": {
				BOOL: aws.Bool(true),
			},
		},
		Key: map[string]*dynamodb.AttributeValue{
			"GroupUUID": {
				S: aws.String(groupUUID),
			},
		},
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.GroupMetasTable),
		UpdateExpression: aws.String("SET #CT = :ct"),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) setTaskState(taskState *tasks.TaskState) error {
	expAttributeNames := map[string]*string{
		"#S": aws.String("State"),
	}
	expAttributeValues := map[string]*dynamodb.AttributeValue{
		":s": {
			S: aws.String(taskState.State),
		},
	}
	keyAttributeValues := map[string]*dynamodb.AttributeValue{
		"TaskUUID": {
			S: aws.String(taskState.TaskUUID),
		},
	}
	exp := "SET #S = :s"
	if !taskState.CreatedAt.IsZero() {
		expAttributeNames["#C"] = aws.String("CreatedAt")
		expAttributeValues[":c"] = &dynamodb.AttributeValue{
			S: aws.String(taskState.CreatedAt.String()),
		}
		exp += ", #C = :c"
	}
	if taskState.Results != nil {
		expAttributeNames["#R"] = aws.String("Results")
		var results []*dynamodb.AttributeValue
		for _, r := range taskState.Results {
			avMap := map[string]*dynamodb.AttributeValue{
				"Type": {
					S: aws.String(r.Type),
				},
				"Value": {
					S: aws.String(fmt.Sprintf("%v", r.Value)),
				},
			}
			rs := &dynamodb.AttributeValue{
				M: avMap,
			}
			results = append(results, rs)
		}
		expAttributeValues[":r"] = &dynamodb.AttributeValue{
			L: results,
		}
		exp += ", #R = :r"
	}
	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames:  expAttributeNames,
		ExpressionAttributeValues: expAttributeValues,
		Key:              keyAttributeValues,
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.TaskStatesTable),
		UpdateExpression: aws.String(exp),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) initTaskState(taskState *tasks.TaskState) error {
	av, err := dynamodbattribute.MarshalMap(taskState)
	input := &dynamodb.PutItemInput{
		Item:      av,
		TableName: aws.String(b.cnf.DynamoDB.TaskStatesTable),
	}
	_, err = b.client.PutItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) updateToFailureStateWithError(taskState *tasks.TaskState) error {

	input := &dynamodb.UpdateItemInput{
		ExpressionAttributeNames: map[string]*string{
			"#S": aws.String("State"),
			"#E": aws.String("Error"),
		},
		ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
			":s": {
				S: aws.String(taskState.State),
			},
			":e": {
				S: aws.String(taskState.Error),
			},
		},
		Key: map[string]*dynamodb.AttributeValue{
			"TaskUUID": {
				S: aws.String(taskState.TaskUUID),
			},
		},
		ReturnValues:     aws.String("UPDATED_NEW"),
		TableName:        aws.String(b.cnf.DynamoDB.TaskStatesTable),
		UpdateExpression: aws.String("SET #S = :s, #E = :e"),
	}

	_, err := b.client.UpdateItem(input)

	if err != nil {
		return err
	}
	return nil
}

func (b *DynamoDBBackend) unmarshalGroupMetaGetItemResult(result *dynamodb.GetItemOutput) (*tasks.GroupMeta, error) {
	if result == nil {
		err := errors.New("task state is nil")
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	item := tasks.GroupMeta{}
	err := dynamodbattribute.UnmarshalMap(result.Item, &item)
	if err != nil {
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	return &item, err
}

func (b *DynamoDBBackend) unmarshalTaskStateGetItemResult(result *dynamodb.GetItemOutput) (*tasks.TaskState, error) {
	if result == nil {
		err := errors.New("task state is nil")
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	state := tasks.TaskState{}
	err := dynamodbattribute.UnmarshalMap(result.Item, &state)
	if err != nil {
		log.ERROR.Printf("Got error when unmarshal map. Error: %v", err)
		return nil, err
	}
	return &state, nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

const (
	stateStarted = "started"
	stateStopped = "stopped"
)

var currentState string
var config Config
var isStopping bool

type Config struct {
	Check struct {
		Command  string `json:"command"`
		Contains string `json:"contains"`
	} `json:"check"`
	MasterAddress      string `json:"master_address"`
	CommunicationsPort string `json:"communications_port"`
	EncryptionKey      string `json:"encryption_key"`
	StartCommand       string `json:"start_command"`
	StopCommand        string `json:"stop_command"`
	WorkingDirectory   string `json:"working_directory"`
	EncryptionKeyBytes []byte `json:"-"`
}

func main() {
	config = loadConfig()
	if checkState() == stateStopped {
		startServer()
	}

	go respondState()

	for {
		newState := checkState()
		if newState != currentState {
			currentState = newState
			sendState()
		}
		time.Sleep(time.Second * 2)
	}
}

func loadConfig() Config {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}

	data, err := ioutil.ReadFile(dir + "/config.json")
	if err != nil {
		log.Fatal(err)
	}

	var loadedConfig Config
	err = json.Unmarshal(data, &loadedConfig)
	if err != nil {
		log.Fatal(err)
	}

	loadedConfig.EncryptionKeyBytes, err =
		hex.DecodeString(loadedConfig.EncryptionKey)
	if err != nil {
		log.Fatal(err)
	}

	return loadedConfig
}

func checkState() string {
	checkCommand := strings.Fields(config.Check.Command)

	cmd := exec.Command(checkCommand[0], checkCommand[1:]...)
	cmd.Dir = config.WorkingDirectory
	response, _ := cmd.Output()
	if strings.Contains(string(response), config.Check.Contains) {
		return stateStarted
	}

	return stateStopped
}

func startServer() {
	runCommand := strings.Fields(config.StartCommand)

	cmd := exec.Command(runCommand[0], runCommand[1:]...)
	cmd.Dir = config.WorkingDirectory
	_ = cmd.Start()
}

func stopServer() {
	stopCommand := strings.Fields(config.StopCommand)

	cmd := exec.Command(stopCommand[0], stopCommand[1:]...)
	cmd.Dir = config.WorkingDirectory
	_ = cmd.Start()
}

func sendState() {
	for i := 0; i < 3; i++ {
		conn, err := net.Dial("tcp", config.MasterAddress+":"+
			config.CommunicationsPort)
		if err != nil {
			log.Println("Could not connect to master:", err)
			time.Sleep(time.Second)
			continue
		}

		data, err := encrypt(config.EncryptionKeyBytes, []byte(currentState))
		if err != nil {
			log.Println("Could not encrypt message:", err)
			return
		}

		_, err = conn.Write(data)
		if err != nil {
			log.Println("Could not send message to master:", err)
			conn.Close()
			time.Sleep(time.Second)
			continue
		}

		conn.Close()
		return
	}
}

func respondState() {
	listener, err := net.Listen("tcp", ":"+config.CommunicationsPort)
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}

		go func(conn net.Conn) {
			defer conn.Close()

			data, err := encrypt(config.EncryptionKeyBytes,
				[]byte(currentState))
			if err != nil {
				log.Println("Could not encrypt message:", err)
				return
			}

			_, err = conn.Write(data)
			if err != nil {
				log.Println("Failed to write response:", err)
				return
			}

			conn.Write([]byte{'\n'})

			conn.SetReadDeadline(time.Now().Add(time.Second * 5))
			command, err := ioutil.ReadAll(conn)
			if len(command) == 0 {
				return
			}

			decrypted, err := decrypt(config.EncryptionKeyBytes, command)
			if err != nil {
				log.Println("Failed to decrypt message from master:", err)
				return
			}

			if string(decrypted) == "stop" {
				log.Println("Received request to stop.")
				stopServer()
			} else {
				log.Println("Received unknown command:", decrypted)
			}
		}(conn)
	}
}

// Encrypt and decrypt functions from
// http://stackoverflow.com/questions/18817336/golang-encrypting-a-string-with-aes-and-base64
func encrypt(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	b := base64.StdEncoding.EncodeToString(text)
	ciphertext := make([]byte, aes.BlockSize+len(b))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
	return ciphertext, nil
}

func decrypt(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	if len(text) < aes.BlockSize {
		return nil, errors.New("ciphertext too short")
	}
	iv := text[:aes.BlockSize]
	text = text[aes.BlockSize:]
	cfb := cipher.NewCFBDecrypter(block, iv)
	cfb.XORKeyStream(text, text)
	data, err := base64.StdEncoding.DecodeString(string(text))
	if err != nil {
		return nil, err
	}
	return data, nil
}
<commit_msg>Attempted fixes at invalid protocol data<commit_after>package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

const (
	stateStarted = "started"
	stateStopped = "stopped"
)

var currentState string
var config Config
var isStopping bool

type Config struct {
	Check struct {
		Command  string `json:"command"`
		Contains string `json:"contains"`
	} `json:"check"`
	MasterAddress      string `json:"master_address"`
	CommunicationsPort string `json:"communications_port"`
	EncryptionKey      string `json:"encryption_key"`
	StartCommand       string `json:"start_command"`
	StopCommand        string `json:"stop_command"`
	WorkingDirectory   string `json:"working_directory"`
	EncryptionKeyBytes []byte `json:"-"`
}

func main() {
	config = loadConfig()
	if checkState() == stateStopped {
		startServer()
	}

	go respondState()

	for {
		newState := checkState()
		if newState != currentState {
			currentState = newState
			sendState()
		}
		time.Sleep(time.Second * 2)
	}
}

func loadConfig() Config {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}

	data, err := ioutil.ReadFile(dir + "/config.json")
	if err != nil {
		log.Fatal(err)
	}

	var loadedConfig Config
	err = json.Unmarshal(data, &loadedConfig)
	if err != nil {
		log.Fatal(err)
	}

	loadedConfig.EncryptionKeyBytes, err =
		hex.DecodeString(loadedConfig.EncryptionKey)
	if err != nil {
		log.Fatal(err)
	}

	return loadedConfig
}

func checkState() string {
	checkCommand := strings.Fields(config.Check.Command)

	cmd := exec.Command(checkCommand[0], checkCommand[1:]...)
	cmd.Dir = config.WorkingDirectory
	response, _ := cmd.Output()
	if strings.Contains(string(response), config.Check.Contains) {
		return stateStarted
	}

	return stateStopped
}

func startServer() {
	runCommand := strings.Fields(config.StartCommand)

	cmd := exec.Command(runCommand[0], runCommand[1:]...)
	cmd.Dir = config.WorkingDirectory
	_ = cmd.Start()
}

func stopServer() {
	stopCommand := strings.Fields(config.StopCommand)

	cmd := exec.Command(stopCommand[0], stopCommand[1:]...)
	cmd.Dir = config.WorkingDirectory
	_ = cmd.Start()
}

func sendState() {
	for i := 0; i < 3; i++ {
		conn, err := net.Dial("tcp", config.MasterAddress+":"+
			config.CommunicationsPort)
		if err != nil {
			log.Println("Could not connect to master:", err)
			time.Sleep(time.Second)
			continue
		}

		data, err := encrypt(config.EncryptionKeyBytes, []byte(currentState))
		if err != nil {
			log.Println("Could not encrypt message:", err)
			return
		}

		_, err = conn.Write(data)
		if err != nil {
			log.Println("Could not send message to master:", err)
			conn.Close()
			time.Sleep(time.Second)
			continue
		}

		conn.Close()
		return
	}
}

func respondState() {
	listener, err := net.Listen("tcp", ":"+config.CommunicationsPort)
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}

		go func(conn net.Conn) {
			defer conn.Close()

			data, err := encrypt(config.EncryptionKeyBytes,
				[]byte(currentState))
			if err != nil {
				log.Println("Could not encrypt message:", err)
				return
			}

			_, err = conn.Write(append(data, '\n'))
			if err != nil {
				log.Println("Failed to write response:", err)
				return
			}

			conn.SetReadDeadline(time.Now().Add(time.Second * 5))
			command, err := ioutil.ReadAll(conn)
			if len(command) == 0 {
				return
			}

			decrypted, err := decrypt(config.EncryptionKeyBytes, command)
			if err != nil {
				log.Println("Failed to decrypt message from master:", err)
				return
			}

			if string(decrypted) == "stop" {
				log.Println("Received request to stop.")
				stopServer()
			} else {
				log.Println("Received unknown command:", decrypted)
			}
		}(conn)
	}
}

// Encrypt and decrypt functions from
// http://stackoverflow.com/questions/18817336/golang-encrypting-a-string-with-aes-and-base64
func encrypt(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	b := base64.StdEncoding.EncodeToString(text)
	ciphertext := make([]byte, aes.BlockSize+len(b))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
	return ciphertext, nil
}

func decrypt(key, text []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	if len(text) < aes.BlockSize {
		return nil, errors.New("ciphertext too short")
	}
	iv := text[:aes.BlockSize]
	text = text[aes.BlockSize:]
	cfb := cipher.NewCFBDecrypter(block, iv)
	cfb.XORKeyStream(text, text)
	data, err := base64.StdEncoding.DecodeString(string(text))
	if err != nil {
		return nil, err
	}
	return data, nil
}
<|endoftext|>


<commit_before>// Package checkmgr provides a check management interace to circonus-gometrics
package checkmgr

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path"
	"strconv"
	"sync"
	"time"

	"github.com/circonus-labs/circonus-gometrics/api"
)

// Check management offers:
//
// Create a check if one cannot be found matching specific criteria
// Manage metrics in the supplied check (enabling new metrics as they are submitted)
//
// To disable check management, leave Config.Api.Token.Key blank
//
// use cases:
// configure without api token - check management disabled
//  - configuration parameters other than Check.SubmissionUrl, Debug and Log are ignored
//  - note: SubmissionUrl is **required** in this case as there is no way to derive w/o api
// configure with api token - check management enabled
//  - all otehr configuration parameters affect how the trap url is obtained
//    1. provided (Check.SubmissionUrl)
//    2. via check lookup (CheckConfig.Id)
//    3. via a search using CheckConfig.InstanceId + CheckConfig.SearchTag
//    4. a new check is created

const (
	defaultCheckType             = "httptrap"
	defaultTrapMaxURLAge         = "60s"   // 60 seconds
	defaultBrokerMaxResponseTime = "500ms" // 500 milliseconds
	defaultForceMetricActivation = "false"
	statusActive                 = "active"
)

// CheckConfig options for check
type CheckConfig struct {
	// a specific submission url
	SubmissionURL string
	// a specific check id (not check bundle id)
	ID string
	// unique instance id string
	// used to search for a check to use
	// used as check.target when creating a check
	InstanceID string
	// unique check searching tag
	// used to search for a check to use (combined with instanceid)
	// used as a regular tag when creating a check
	SearchTag string
	// a custom display name for the check (as viewed in UI Checks)
	DisplayName string
	// httptrap check secret (for creating a check)
	Secret string
	// additional tags to add to a check (when creating a check)
	// these tags will not be added to an existing check
	Tags []string
	// max amount of time to to hold on to a submission url
	// when a given submission fails (due to retries) if the
	// time the url was last updated is > than this, the trap
	// url will be refreshed (e.g. if the broker is changed
	// in the UI) **only relevant when check management is enabled**
	// e.g. 5m, 30m, 1h, etc.
	MaxURLAge string
	// force metric activation - if a metric has been disabled via the UI
	// the default behavior is to *not* re-activate the metric; this setting
	// overrides the behavior and will re-activate the metric when it is
	// encountered. "(true|false)", default "false"
	ForceMetricActivation string
}

// BrokerConfig options for broker
type BrokerConfig struct {
	// a specific broker id (numeric portion of cid)
	ID string
	// a tag that can be used to select 1-n brokers from which to select
	// when creating a new check (e.g. datacenter:abc)
	SelectTag string
	// for a broker to be considered viable it must respond to a
	// connection attempt within this amount of time e.g. 200ms, 2s, 1m
	MaxResponseTime string
}

// Config options
type Config struct {
	Log   *log.Logger
	Debug bool

	// Circonus API config
	API api.Config
	// Check specific configuration options
	Check CheckConfig
	// Broker specific configuration options
	Broker BrokerConfig
}

// CheckTypeType check type
type CheckTypeType string

// CheckInstanceIDType check instance id
type CheckInstanceIDType string

// CheckSecretType check secret
type CheckSecretType string

// CheckTagsType check tags
type CheckTagsType []string

// CheckDisplayNameType check display name
type CheckDisplayNameType string

// BrokerCNType broker common name
type BrokerCNType string

// CheckManager settings
type CheckManager struct {
	enabled bool
	Log     *log.Logger
	Debug   bool
	apih    *api.API

	// check
	checkType             CheckTypeType
	checkID               api.IDType
	checkInstanceID       CheckInstanceIDType
	checkSearchTag        api.SearchTagType
	checkSecret           CheckSecretType
	checkTags             CheckTagsType
	checkSubmissionURL    api.URLType
	checkDisplayName      CheckDisplayNameType
	forceMetricActivation bool

	// broker
	brokerID              api.IDType
	brokerSelectTag       api.SearchTagType
	brokerMaxResponseTime time.Duration

	// state
	checkBundle      *api.CheckBundle
	availableMetrics map[string]bool
	trapURL          api.URLType
	trapCN           BrokerCNType
	trapLastUpdate   time.Time
	trapMaxURLAge    time.Duration
	trapmu           sync.Mutex
	certPool         *x509.CertPool
}

// Trap config
type Trap struct {
	URL *url.URL
	TLS *tls.Config
}

// NewCheckManager returns a new check manager
func NewCheckManager(cfg *Config) (*CheckManager, error) {

	if cfg == nil {
		return nil, errors.New("Invalid Check Manager configuration (nil).")
	}

	cm := &CheckManager{
		enabled: false,
	}

	cm.Debug = cfg.Debug
	cm.Log = cfg.Log
	if cm.Log == nil {
		if cm.Debug {
			cm.Log = log.New(os.Stderr, "", log.LstdFlags)
		} else {
			cm.Log = log.New(ioutil.Discard, "", log.LstdFlags)
		}
	}

	if cfg.Check.SubmissionURL != "" {
		cm.checkSubmissionURL = api.URLType(cfg.Check.SubmissionURL)
	}

	if cfg.API.TokenKey == "" {
		if cm.checkSubmissionURL == "" {
			return nil, errors.New("Invalid check manager configuration (no API token AND no submission url).")
		}
		cm.trapURL = cm.checkSubmissionURL
		return cm, nil
	}

	// enable check manager (a blank api.Token.Key *disables* check management)

	cm.enabled = true

	// initialize api handle

	cfg.API.Debug = cm.Debug
	cfg.API.Log = cm.Log

	apih, err := api.NewAPI(&cfg.API)
	if err != nil {
		return nil, err
	}
	cm.apih = apih

	// initialize check related data

	cm.checkType = defaultCheckType
	cm.checkID = 0
	if cfg.Check.ID != "" {
		id, errSC := strconv.Atoi(cfg.Check.ID)
		if errSC != nil {
			return nil, errSC
		}
		cm.checkID = api.IDType(id)
	}
	cm.checkInstanceID = CheckInstanceIDType(cfg.Check.InstanceID)
	cm.checkDisplayName = CheckDisplayNameType(cfg.Check.DisplayName)
	cm.checkSearchTag = api.SearchTagType(cfg.Check.SearchTag)
	cm.checkSecret = CheckSecretType(cfg.Check.Secret)
	cm.checkTags = cfg.Check.Tags
	fma := defaultForceMetricActivation
	if cfg.Check.ForceMetricActivation != "" {
		fma = cfg.Check.ForceMetricActivation
	}
	fm, err := strconv.ParseBool(fma)
	if err != nil {
		return nil, err
	}
	cm.forceMetricActivation = fm

	_, an := path.Split(os.Args[0])

	if cm.checkInstanceID == "" {
		hn, errHN := os.Hostname()
		if errHN != nil {
			hn = "unknown"
		}
		cm.checkInstanceID = CheckInstanceIDType(fmt.Sprintf("%s:%s", hn, an))
	}

	if cm.checkSearchTag == "" {
		cm.checkSearchTag = api.SearchTagType(fmt.Sprintf("service:%s", an))
	}

	if cm.checkDisplayName == "" {
		cm.checkDisplayName = CheckDisplayNameType(fmt.Sprintf("%s /cgm", string(cm.checkInstanceID)))
	}

	dur := cfg.Check.MaxURLAge
	if dur == "" {
		dur = defaultTrapMaxURLAge
	}
	maxDur, err := time.ParseDuration(dur)
	if err != nil {
		return nil, err
	}
	cm.trapMaxURLAge = maxDur

	// setup broker

	cm.brokerID = 0
	if cfg.Broker.ID != "" {
		id, errSC := strconv.Atoi(cfg.Broker.ID)
		if errSC != nil {
			return nil, errSC
		}
		cm.brokerID = api.IDType(id)
	}
	cm.brokerSelectTag = api.SearchTagType(cfg.Broker.SelectTag)
	dur = cfg.Broker.MaxResponseTime
	if dur == "" {
		dur = defaultBrokerMaxResponseTime
	}
	maxDur, err = time.ParseDuration(dur)
	if err != nil {
		return nil, err
	}
	cm.brokerMaxResponseTime = maxDur

	// metrics
	cm.availableMetrics = make(map[string]bool)

	if err := cm.initializeTrapURL(); err != nil {
		return nil, err
	}

	return cm, nil
}

// GetTrap return the trap url
func (cm *CheckManager) GetTrap() (*Trap, error) {
	if cm.trapURL == "" {
		if err := cm.initializeTrapURL(); err != nil {
			return nil, err
		}
	}

	trap := &Trap{}

	u, err := url.Parse(string(cm.trapURL))
	if err != nil {
		return nil, err
	}

	trap.URL = u

	if u.Scheme == "https" {
		if cm.certPool == nil {
			cm.loadCACert()
		}
		t := &tls.Config{
			RootCAs: cm.certPool,
		}
		if cm.trapCN != "" {
			t.ServerName = string(cm.trapCN)
		}
		trap.TLS = t
	}

	return trap, nil
}

// ResetTrap URL, force request to the API for the submission URL and broker ca cert
func (cm *CheckManager) ResetTrap() error {
	if cm.trapURL == "" {
		return nil
	}

	cm.trapURL = ""
	cm.certPool = nil
	err := cm.initializeTrapURL()
	return err
}

// RefreshTrap check when the last time the URL was reset, reset if needed
func (cm *CheckManager) RefreshTrap() {
	if cm.trapURL == "" {
		return
	}

	if time.Since(cm.trapLastUpdate) >= cm.trapMaxURLAge {
		cm.ResetTrap()
	}
}
<commit_msg>initialize trap correctly when short-circuiting due to no token. normalize type conversions<commit_after>// Package checkmgr provides a check management interace to circonus-gometrics
package checkmgr

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path"
	"strconv"
	"sync"
	"time"

	"github.com/circonus-labs/circonus-gometrics/api"
)

// Check management offers:
//
// Create a check if one cannot be found matching specific criteria
// Manage metrics in the supplied check (enabling new metrics as they are submitted)
//
// To disable check management, leave Config.Api.Token.Key blank
//
// use cases:
// configure without api token - check management disabled
//  - configuration parameters other than Check.SubmissionUrl, Debug and Log are ignored
//  - note: SubmissionUrl is **required** in this case as there is no way to derive w/o api
// configure with api token - check management enabled
//  - all otehr configuration parameters affect how the trap url is obtained
//    1. provided (Check.SubmissionUrl)
//    2. via check lookup (CheckConfig.Id)
//    3. via a search using CheckConfig.InstanceId + CheckConfig.SearchTag
//    4. a new check is created

const (
	defaultCheckType             = "httptrap"
	defaultTrapMaxURLAge         = "60s"   // 60 seconds
	defaultBrokerMaxResponseTime = "500ms" // 500 milliseconds
	defaultForceMetricActivation = "false"
	statusActive                 = "active"
)

// CheckConfig options for check
type CheckConfig struct {
	// a specific submission url
	SubmissionURL string
	// a specific check id (not check bundle id)
	ID string
	// unique instance id string
	// used to search for a check to use
	// used as check.target when creating a check
	InstanceID string
	// unique check searching tag
	// used to search for a check to use (combined with instanceid)
	// used as a regular tag when creating a check
	SearchTag string
	// a custom display name for the check (as viewed in UI Checks)
	DisplayName string
	// httptrap check secret (for creating a check)
	Secret string
	// additional tags to add to a check (when creating a check)
	// these tags will not be added to an existing check
	Tags []string
	// max amount of time to to hold on to a submission url
	// when a given submission fails (due to retries) if the
	// time the url was last updated is > than this, the trap
	// url will be refreshed (e.g. if the broker is changed
	// in the UI) **only relevant when check management is enabled**
	// e.g. 5m, 30m, 1h, etc.
	MaxURLAge string
	// force metric activation - if a metric has been disabled via the UI
	// the default behavior is to *not* re-activate the metric; this setting
	// overrides the behavior and will re-activate the metric when it is
	// encountered. "(true|false)", default "false"
	ForceMetricActivation string
}

// BrokerConfig options for broker
type BrokerConfig struct {
	// a specific broker id (numeric portion of cid)
	ID string
	// a tag that can be used to select 1-n brokers from which to select
	// when creating a new check (e.g. datacenter:abc)
	SelectTag string
	// for a broker to be considered viable it must respond to a
	// connection attempt within this amount of time e.g. 200ms, 2s, 1m
	MaxResponseTime string
}

// Config options
type Config struct {
	Log   *log.Logger
	Debug bool

	// Circonus API config
	API api.Config
	// Check specific configuration options
	Check CheckConfig
	// Broker specific configuration options
	Broker BrokerConfig
}

// CheckTypeType check type
type CheckTypeType string

// CheckInstanceIDType check instance id
type CheckInstanceIDType string

// CheckSecretType check secret
type CheckSecretType string

// CheckTagsType check tags
type CheckTagsType []string

// CheckDisplayNameType check display name
type CheckDisplayNameType string

// BrokerCNType broker common name
type BrokerCNType string

// CheckManager settings
type CheckManager struct {
	enabled bool
	Log     *log.Logger
	Debug   bool
	apih    *api.API

	// check
	checkType             CheckTypeType
	checkID               api.IDType
	checkInstanceID       CheckInstanceIDType
	checkSearchTag        api.SearchTagType
	checkSecret           CheckSecretType
	checkTags             CheckTagsType
	checkSubmissionURL    api.URLType
	checkDisplayName      CheckDisplayNameType
	forceMetricActivation bool

	// broker
	brokerID              api.IDType
	brokerSelectTag       api.SearchTagType
	brokerMaxResponseTime time.Duration

	// state
	checkBundle      *api.CheckBundle
	availableMetrics map[string]bool
	trapURL          api.URLType
	trapCN           BrokerCNType
	trapLastUpdate   time.Time
	trapMaxURLAge    time.Duration
	trapmu           sync.Mutex
	certPool         *x509.CertPool
}

// Trap config
type Trap struct {
	URL *url.URL
	TLS *tls.Config
}

// NewCheckManager returns a new check manager
func NewCheckManager(cfg *Config) (*CheckManager, error) {

	if cfg == nil {
		return nil, errors.New("Invalid Check Manager configuration (nil).")
	}

	cm := &CheckManager{
		enabled: false,
	}

	cm.Debug = cfg.Debug

	cm.Log = cfg.Log
	if cm.Log == nil {
		if cm.Debug {
			cm.Log = log.New(os.Stderr, "", log.LstdFlags)
		} else {
			cm.Log = log.New(ioutil.Discard, "", log.LstdFlags)
		}
	}

	if cfg.Check.SubmissionURL != "" {
		cm.checkSubmissionURL = api.URLType(cfg.Check.SubmissionURL)
	}
	// Blank API Token *disables* check management
	if cfg.API.TokenKey == "" {
		if cm.checkSubmissionURL == "" {
			return nil, errors.New("Invalid check manager configuration (no API token AND no submission url).")
		}
		if err := cm.initializeTrapURL(); err != nil {
			return nil, err
		}
		return cm, nil
	}

	// enable check manager

	cm.enabled = true

	// initialize api handle

	cfg.API.Debug = cm.Debug
	cfg.API.Log = cm.Log

	apih, err := api.NewAPI(&cfg.API)
	if err != nil {
		return nil, err
	}
	cm.apih = apih

	// initialize check related data

	cm.checkType = defaultCheckType

	idSetting := "0"
	if cfg.Check.ID != "" {
		idSetting = cfg.Check.ID
	}
	id, err := strconv.Atoi(idSetting)
	if err != nil {
		return nil, err
	}
	cm.checkID = api.IDType(id)

	cm.checkInstanceID = CheckInstanceIDType(cfg.Check.InstanceID)
	cm.checkDisplayName = CheckDisplayNameType(cfg.Check.DisplayName)
	cm.checkSearchTag = api.SearchTagType(cfg.Check.SearchTag)
	cm.checkSecret = CheckSecretType(cfg.Check.Secret)
	cm.checkTags = cfg.Check.Tags

	fma := defaultForceMetricActivation
	if cfg.Check.ForceMetricActivation != "" {
		fma = cfg.Check.ForceMetricActivation
	}
	fm, err := strconv.ParseBool(fma)
	if err != nil {
		return nil, err
	}
	cm.forceMetricActivation = fm

	_, an := path.Split(os.Args[0])
	hn, err := os.Hostname()
	if err != nil {
		hn = "unknown"
	}
	if cm.checkInstanceID == "" {
		cm.checkInstanceID = CheckInstanceIDType(fmt.Sprintf("%s:%s", hn, an))
	}

	if cm.checkSearchTag == "" {
		cm.checkSearchTag = api.SearchTagType(fmt.Sprintf("service:%s", an))
	}

	if cm.checkDisplayName == "" {
		cm.checkDisplayName = CheckDisplayNameType(fmt.Sprintf("%s /cgm", string(cm.checkInstanceID)))
	}

	dur := cfg.Check.MaxURLAge
	if dur == "" {
		dur = defaultTrapMaxURLAge
	}
	maxDur, err := time.ParseDuration(dur)
	if err != nil {
		return nil, err
	}
	cm.trapMaxURLAge = maxDur

	// setup broker

	idSetting = "0"
	if cfg.Broker.ID != "" {
		idSetting = cfg.Broker.ID
	}
	id, err = strconv.Atoi(idSetting)
	if err != nil {
		return nil, err
	}
	cm.brokerID = api.IDType(id)

	cm.brokerSelectTag = api.SearchTagType(cfg.Broker.SelectTag)

	dur = cfg.Broker.MaxResponseTime
	if dur == "" {
		dur = defaultBrokerMaxResponseTime
	}
	maxDur, err = time.ParseDuration(dur)
	if err != nil {
		return nil, err
	}
	cm.brokerMaxResponseTime = maxDur

	// metrics
	cm.availableMetrics = make(map[string]bool)

	if err := cm.initializeTrapURL(); err != nil {
		return nil, err
	}

	return cm, nil
}

// GetTrap return the trap url
func (cm *CheckManager) GetTrap() (*Trap, error) {
	if cm.trapURL == "" {
		if err := cm.initializeTrapURL(); err != nil {
			return nil, err
		}
	}

	trap := &Trap{}

	u, err := url.Parse(string(cm.trapURL))
	if err != nil {
		return nil, err
	}

	trap.URL = u

	if u.Scheme == "https" {
		if cm.certPool == nil {
			cm.loadCACert()
		}
		t := &tls.Config{
			RootCAs: cm.certPool,
		}
		if cm.trapCN != "" {
			t.ServerName = string(cm.trapCN)
		}
		trap.TLS = t
	}

	return trap, nil
}

// ResetTrap URL, force request to the API for the submission URL and broker ca cert
func (cm *CheckManager) ResetTrap() error {
	if cm.trapURL == "" {
		return nil
	}

	cm.trapURL = ""
	cm.certPool = nil
	err := cm.initializeTrapURL()
	return err
}

// RefreshTrap check when the last time the URL was reset, reset if needed
func (cm *CheckManager) RefreshTrap() {
	if cm.trapURL == "" {
		return
	}

	if time.Since(cm.trapLastUpdate) >= cm.trapMaxURLAge {
		cm.ResetTrap()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/mitchellh/packer/packer"
	"testing"
)

func TestArtifact_ImplementsArtifact(t *testing.T) {
	var raw interface{}
	raw = &Artifact{}
	if _, ok := raw.(packer.Artifact); !ok {
		t.Errorf("Artifact should be a Artifact")
	}
}

func TestArtifact_URL(t *testing.T) {
	artifact := &Artifact{"https://www.packer.io/"}
	if artifact.String() != "vagrant metadata url: https://www.packer.io/" {
		t.Errorf("should return metadata info")
	}
}
<commit_msg>refactor<commit_after>package main

import (
	"github.com/mitchellh/packer/packer"
	"strings"
	"testing"
)

func TestArtifact_ImplementsArtifact(t *testing.T) {
	var raw interface{}
	raw = &Artifact{}
	if _, ok := raw.(packer.Artifact); !ok {
		t.Errorf("Artifact should be a Artifact")
	}
}

func TestArtifact_URL(t *testing.T) {
	artifact := &Artifact{"https://www.packer.io/"}
	if !strings.Contains(artifact.String(), "vagrant metadata url: https://www.packer.io/") {
		t.Errorf("should return metadata info")
	}
}
<|endoftext|>


<commit_before>package check

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"syscall"
)

var skipDirs = []string{"Godeps", "vendor", "third_party"}

// GoFiles returns a slice of Go filenames
// in a given directory.
func GoFiles(dir string) ([]string, error) {
	var filenames []string
	visit := func(fp string, fi os.FileInfo, err error) error {
		for _, skip := range skipDirs {
			if strings.Contains(fp, skip) {
				return nil
			}
		}
		if err != nil {
			fmt.Println(err) // can't walk here,
			return nil       // but continue walking elsewhere
		}
		if fi.IsDir() {
			return nil // not a file.  ignore.
		}
		ext := filepath.Ext(fi.Name())
		if ext == ".go" {
			filenames = append(filenames, fp)
		}
		return nil
	}

	err := filepath.Walk(dir, visit)

	return filenames, err
}

// lineCount returns the number of lines in a given file
func lineCount(filepath string) (int, error) {
	out, err := exec.Command("wc", "-l", filepath).Output()
	if err != nil {
		return 0, err
	}
	// wc output is like: 999 filename.go
	count, err := strconv.Atoi(strings.Split(strings.TrimSpace(string(out)), " ")[0])
	if err != nil {
		return 0, err
	}

	return count, nil
}

// Error contains the line number and the reason for
// an error output from a command
type Error struct {
	LineNumber  int    `json:"line_number"`
	ErrorString string `json:"error_string"`
}

// FileSummary contains the filename, location of the file
// on GitHub, and all of the errors related to the file
type FileSummary struct {
	Filename string  `json:"filename"`
	FileURL  string  `json:"file_url"`
	Errors   []Error `json:"errors"`
}

// ByFilename implements sort.Interface for []Person based on
// the Age field.
type ByFilename []FileSummary

func (a ByFilename) Len() int           { return len(a) }
func (a ByFilename) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByFilename) Less(i, j int) bool { return a[i].Filename < a[j].Filename }

func getFileSummary(filename, dir, cmd, out string) (FileSummary, error) {
	filename = strings.TrimPrefix(filename, "repos/src")
	githubLink := strings.TrimPrefix(dir, "repos/src")
	fileURL := "https://" + strings.TrimPrefix(dir, "repos/src/") + "/blob/master" + strings.TrimPrefix(filename, githubLink)
	fs := FileSummary{
		Filename: filename,
		FileURL:  fileURL,
	}
	split := strings.Split(string(out), "\n")
	for _, sp := range split[0 : len(split)-1] {
		parts := strings.Split(sp, ":")
		msg := sp
		if cmd != "gocyclo" {
			msg = parts[len(parts)-1]
		}
		e := Error{ErrorString: msg}
		switch cmd {
		case "golint", "gocyclo", "vet":
			if len(strings.Split(sp, ":")) >= 2 {
				ln, err := strconv.Atoi(strings.Split(sp, ":")[1])
				if err != nil {
					return fs, err
				}
				e.LineNumber = ln
			}
		}

		fs.Errors = append(fs.Errors, e)
	}

	return fs, nil
}

// GoTool runs a given go command (for example gofmt, go tool vet)
// on a directory
func GoTool(dir string, filenames, command []string) (float64, []FileSummary, error) {
	var failed = []FileSummary{}
	for _, fi := range filenames {
		params := command[1:]
		params = append(params, fi)

		cmd := exec.Command(command[0], params...)
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			return 0, []FileSummary{}, nil
		}

		stderr, err := cmd.StderrPipe()
		if err != nil {
			return 0, []FileSummary{}, nil
		}

		err = cmd.Start()
		if err != nil {
			return 0, []FileSummary{}, nil
		}

		out, err := ioutil.ReadAll(stdout)
		if err != nil {
			return 0, []FileSummary{}, nil
		}

		errout, err := ioutil.ReadAll(stderr)
		if err != nil {
			return 0, []FileSummary{}, nil
		}

		if string(out) != "" {
			fs, err := getFileSummary(fi, dir, command[0], string(out))
			if err != nil {
				return 0, []FileSummary{}, nil
			}
			failed = append(failed, fs)
		}

		// go vet logs to stderr
		if string(errout) != "" {
			cmd := command[0]
			if reflect.DeepEqual(command, []string{"go", "tool", "vet"}) {
				cmd = "vet"
			}
			fs, err := getFileSummary(fi, dir, cmd, string(errout))
			if err != nil {
				return 0, []FileSummary{}, nil
			}
			failed = append(failed, fs)
		}

		err = cmd.Wait()
		if exitErr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0

			if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
				// some commands exit 1 when files fail to pass (for example go vet)
				if status.ExitStatus() != 1 {
					return 0, failed, err
					// return 0, Error{}, err
				}
			}
		}

	}

	if len(filenames) == 1 {
		lc, err := lineCount(filenames[0])
		if err != nil {
			return 0, failed, err
		}

		var errors int
		if len(failed) != 0 {
			errors = len(failed[0].Errors)
		}

		return float64(lc-errors) / float64(lc), failed, nil
	}

	return float64(len(filenames)-len(failed)) / float64(len(filenames)), failed, nil
}
<commit_msg>properly return error in GoTool<commit_after>package check

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"syscall"
)

var skipDirs = []string{"Godeps", "vendor", "third_party"}

// GoFiles returns a slice of Go filenames
// in a given directory.
func GoFiles(dir string) ([]string, error) {
	var filenames []string
	visit := func(fp string, fi os.FileInfo, err error) error {
		for _, skip := range skipDirs {
			if strings.Contains(fp, skip) {
				return nil
			}
		}
		if err != nil {
			fmt.Println(err) // can't walk here,
			return nil       // but continue walking elsewhere
		}
		if fi.IsDir() {
			return nil // not a file.  ignore.
		}
		ext := filepath.Ext(fi.Name())
		if ext == ".go" {
			filenames = append(filenames, fp)
		}
		return nil
	}

	err := filepath.Walk(dir, visit)

	return filenames, err
}

// lineCount returns the number of lines in a given file
func lineCount(filepath string) (int, error) {
	out, err := exec.Command("wc", "-l", filepath).Output()
	if err != nil {
		return 0, err
	}
	// wc output is like: 999 filename.go
	count, err := strconv.Atoi(strings.Split(strings.TrimSpace(string(out)), " ")[0])
	if err != nil {
		return 0, err
	}

	return count, nil
}

// Error contains the line number and the reason for
// an error output from a command
type Error struct {
	LineNumber  int    `json:"line_number"`
	ErrorString string `json:"error_string"`
}

// FileSummary contains the filename, location of the file
// on GitHub, and all of the errors related to the file
type FileSummary struct {
	Filename string  `json:"filename"`
	FileURL  string  `json:"file_url"`
	Errors   []Error `json:"errors"`
}

// ByFilename implements sort.Interface for []Person based on
// the Age field.
type ByFilename []FileSummary

func (a ByFilename) Len() int           { return len(a) }
func (a ByFilename) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByFilename) Less(i, j int) bool { return a[i].Filename < a[j].Filename }

func getFileSummary(filename, dir, cmd, out string) (FileSummary, error) {
	filename = strings.TrimPrefix(filename, "repos/src")
	githubLink := strings.TrimPrefix(dir, "repos/src")
	fileURL := "https://" + strings.TrimPrefix(dir, "repos/src/") + "/blob/master" + strings.TrimPrefix(filename, githubLink)
	fs := FileSummary{
		Filename: filename,
		FileURL:  fileURL,
	}
	split := strings.Split(string(out), "\n")
	for _, sp := range split[0 : len(split)-1] {
		parts := strings.Split(sp, ":")
		msg := sp
		if cmd != "gocyclo" {
			msg = parts[len(parts)-1]
		}
		e := Error{ErrorString: msg}
		switch cmd {
		case "golint", "gocyclo", "vet":
			if len(strings.Split(sp, ":")) >= 2 {
				ln, err := strconv.Atoi(strings.Split(sp, ":")[1])
				if err != nil {
					return fs, err
				}
				e.LineNumber = ln
			}
		}

		fs.Errors = append(fs.Errors, e)
	}

	return fs, nil
}

// GoTool runs a given go command (for example gofmt, go tool vet)
// on a directory
func GoTool(dir string, filenames, command []string) (float64, []FileSummary, error) {
	var failed = []FileSummary{}
	for _, fi := range filenames {
		params := command[1:]
		params = append(params, fi)

		cmd := exec.Command(command[0], params...)
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			return 0, []FileSummary{}, err
		}

		stderr, err := cmd.StderrPipe()
		if err != nil {
			return 0, []FileSummary{}, err
		}

		err = cmd.Start()
		if err != nil {
			return 0, []FileSummary{}, err
		}

		out, err := ioutil.ReadAll(stdout)
		if err != nil {
			return 0, []FileSummary{}, err
		}

		errout, err := ioutil.ReadAll(stderr)
		if err != nil {
			return 0, []FileSummary{}, err
		}

		if string(out) != "" {
			fs, err := getFileSummary(fi, dir, command[0], string(out))
			if err != nil {
				return 0, []FileSummary{}, err
			}
			failed = append(failed, fs)
		}

		// go vet logs to stderr
		if string(errout) != "" {
			cmd := command[0]
			if reflect.DeepEqual(command, []string{"go", "tool", "vet"}) {
				cmd = "vet"
			}
			fs, err := getFileSummary(fi, dir, cmd, string(errout))
			if err != nil {
				return 0, []FileSummary{}, err
			}
			failed = append(failed, fs)
		}

		err = cmd.Wait()
		if exitErr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0

			if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
				// some commands exit 1 when files fail to pass (for example go vet)
				if status.ExitStatus() != 1 {
					return 0, failed, err
					// return 0, Error{}, err
				}
			}
		}

	}

	if len(filenames) == 1 {
		lc, err := lineCount(filenames[0])
		if err != nil {
			return 0, failed, err
		}

		var errors int
		if len(failed) != 0 {
			errors = len(failed[0].Errors)
		}

		return float64(lc-errors) / float64(lc), failed, nil
	}

	return float64(len(filenames)-len(failed)) / float64(len(filenames)), failed, nil
}
<|endoftext|>


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

// +build go1.3

package lxdclient

import (
	"fmt"

	"github.com/juju/errors"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"

	"github.com/juju/juju/network"
)

type rawNetworkClient interface {
	NetworkCreate(name string, config map[string]string) error
	NetworkGet(name string) (shared.NetworkConfig, error)
}

type networkClient struct {
	raw       rawNetworkClient
	supported bool
}

// NetworkCreate creates the specified network.
func (c *networkClient) NetworkCreate(name string, config map[string]string) error {
	if !c.supported {
		return errors.NotSupportedf("network API not supported on this remote")
	}

	return c.raw.NetworkCreate(name, config)
}

// NetworkGet returns the specified network's configuration.
func (c *networkClient) NetworkGet(name string) (shared.NetworkConfig, error) {
	if !c.supported {
		return shared.NetworkConfig{}, errors.NotSupportedf("network API not supported on this remote")
	}

	return c.raw.NetworkGet(name)
}

type creator interface {
	rawNetworkClient
	ProfileDeviceAdd(profile, devname, devtype string, props []string) (*lxd.Response, error)
	ProfileConfig(profile string) (*shared.ProfileConfig, error)
}

func checkBridgeConfig(client rawNetworkClient, bridge string) error {
	n, err := client.NetworkGet(bridge)
	if err != nil {
		return err
	}

	if n.Config["ipv6.address"] != "none" {
		return errors.Errorf(`juju doesn't support ipv6. Please disable LXD's IPV6:

	$ lxc network set %s ipv6.address none

and rebootstrap`, bridge)
	}

	return nil
}

// CreateDefaultBridgeInDefaultProfile creates a default bridge if it doesn't
// exist and (if necessary) inserts it into the default profile.
func CreateDefaultBridgeInDefaultProfile(client creator) error {
	/* create the default bridge if it doesn't exist */
	n, err := client.NetworkGet(network.DefaultLXDBridge)
	if err != nil {
		err := client.NetworkCreate(network.DefaultLXDBridge, map[string]string{
			"ipv6.address": "none",
			"ipv6.nat":     "false",
		})
		if err != nil {
			return err
		}

		n, err = client.NetworkGet(network.DefaultLXDBridge)
		if err != nil {
			return err
		}
	} else {
		if err := checkBridgeConfig(client, network.DefaultLXDBridge); err != nil {
			return err
		}
	}

	nicType := "macvlan"
	if n.Type == "bridge" {
		nicType = "bridged"
	}

	props := []string{fmt.Sprintf("nictype=%s", nicType), fmt.Sprintf("parent=%s", network.DefaultLXDBridge)}

	config, err := client.ProfileConfig("default")
	if err != nil {
		return err
	}

	_, ok := config.Devices["eth0"]
	if ok {
		/* don't configure an eth0 if it already exists */
		return nil
	}

	_, err = client.ProfileDeviceAdd("default", "eth0", "nic", props)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Ask to disable ipv6 on lxd network when lxd manages it.<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// +build go1.3

package lxdclient

import (
	"fmt"

	"github.com/juju/errors"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"

	"github.com/juju/juju/network"
)

type rawNetworkClient interface {
	NetworkCreate(name string, config map[string]string) error
	NetworkGet(name string) (shared.NetworkConfig, error)
}

type networkClient struct {
	raw       rawNetworkClient
	supported bool
}

// NetworkCreate creates the specified network.
func (c *networkClient) NetworkCreate(name string, config map[string]string) error {
	if !c.supported {
		return errors.NotSupportedf("network API not supported on this remote")
	}

	return c.raw.NetworkCreate(name, config)
}

// NetworkGet returns the specified network's configuration.
func (c *networkClient) NetworkGet(name string) (shared.NetworkConfig, error) {
	if !c.supported {
		return shared.NetworkConfig{}, errors.NotSupportedf("network API not supported on this remote")
	}

	return c.raw.NetworkGet(name)
}

type creator interface {
	rawNetworkClient
	ProfileDeviceAdd(profile, devname, devtype string, props []string) (*lxd.Response, error)
	ProfileConfig(profile string) (*shared.ProfileConfig, error)
}

func checkBridgeConfig(client rawNetworkClient, bridge string) error {
	n, err := client.NetworkGet(bridge)
	if err != nil {
		return err
	}

	if n.Managed && n.Config["ipv6.address"] != "none" {
		return errors.Errorf(`juju doesn't support ipv6. Please disable LXD's IPV6:

	$ lxc network set %s ipv6.address none

and rebootstrap`, bridge)
	}

	return nil
}

// CreateDefaultBridgeInDefaultProfile creates a default bridge if it doesn't
// exist and (if necessary) inserts it into the default profile.
func CreateDefaultBridgeInDefaultProfile(client creator) error {
	/* create the default bridge if it doesn't exist */
	n, err := client.NetworkGet(network.DefaultLXDBridge)
	if err != nil {
		err := client.NetworkCreate(network.DefaultLXDBridge, map[string]string{
			"ipv6.address": "none",
			"ipv6.nat":     "false",
		})
		if err != nil {
			return err
		}

		n, err = client.NetworkGet(network.DefaultLXDBridge)
		if err != nil {
			return err
		}
	} else {
		if err := checkBridgeConfig(client, network.DefaultLXDBridge); err != nil {
			return err
		}
	}

	nicType := "macvlan"
	if n.Type == "bridge" {
		nicType = "bridged"
	}

	props := []string{fmt.Sprintf("nictype=%s", nicType), fmt.Sprintf("parent=%s", network.DefaultLXDBridge)}

	config, err := client.ProfileConfig("default")
	if err != nil {
		return err
	}

	_, ok := config.Devices["eth0"]
	if ok {
		/* don't configure an eth0 if it already exists */
		return nil
	}

	_, err = client.ProfileDeviceAdd("default", "eth0", "nic", props)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// datastore.go

package naprrql

import (
	"fmt"
	"log"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/util"
)

var db *leveldb.DB
var dbOpen bool = false

var ge = GobEncoder{}

func GetDB() *leveldb.DB {
	if !dbOpen {
		log.Println("DB not initialised. Opening...")
		openDB()
	}
	return db
}

//
// open the kv store, this must be called before any access is attempted
//
func openDB() {

	workingDir := "kvs"

	var dbErr error
	db, dbErr = leveldb.OpenFile(workingDir, nil)
	if dbErr != nil {
		log.Fatalln("DB Create error: ", dbErr)
	}
	dbOpen = true
}

//
// Given a key or key-prefix, returns the reference ids that
// can be used in a Get operation to retreive the
// desired object
//
func getIdentifiers(keyPrefix string) []string {

	db = GetDB()
	objIDs := make([]string, 0)

	searchKey := []byte(keyPrefix + ":")
	// log.Printf("search_key: %s\n\n", searchKey)
	iter := db.NewIterator(util.BytesPrefix(searchKey), nil)
	for iter.Next() {
		id := fmt.Sprintf("%s", iter.Value())
		objIDs = append(objIDs, id)
		// break
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		log.Println("Iterator error: ", err)
	}

	return objIDs
}

//
// get objects stored against the list of keys
//
func getObjects(objIDs []string) ([]interface{}, error) {

	db = GetDB()
	objects := []interface{}{}

	for _, objID := range objIDs {
		var object interface{}
		data, err := db.Get([]byte(objID), nil)
		if err != nil {
			log.Println("Cannot find object with key: ", string(objID))
			return objects, err
		}
		err = ge.Decode(data, &object)
		if err != nil {
			log.Println("Cannot decode object with key: ", objID, err)
			return objects, err
		}
		objects = append(objects, object)
	}

	return objects, nil

}

//
//
//
<commit_msg>added datastore config params<commit_after>// datastore.go

package naprrql

import (
	"fmt"
	"log"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/filter"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"github.com/syndtr/goleveldb/leveldb/util"
)

var db *leveldb.DB
var dbOpen bool = false

var ge = GobEncoder{}

func GetDB() *leveldb.DB {
	if !dbOpen {
		log.Println("DB not initialised. Opening...")
		openDB()
	}
	return db
}

//
// open the kv store, this must be called before any access is attempted
//
func openDB() {

	workingDir := "kvs"

	o := &opt.Options{
		Filter: filter.NewBloomFilter(10),
		// BlockCacheCapacity: 128 * 1024 * 1024,
		// NoSync: true,
	}
	var dbErr error
	db, dbErr = leveldb.OpenFile(workingDir, o)
	if dbErr != nil {
		log.Fatalln("DB Create error: ", dbErr)
	}
	dbOpen = true
}

//
// Given a key or key-prefix, returns the reference ids that
// can be used in a Get operation to retreive the
// desired object
//
func getIdentifiers(keyPrefix string) []string {

	db = GetDB()
	objIDs := make([]string, 0)

	searchKey := []byte(keyPrefix + ":")
	// log.Printf("search_key: %s\n\n", searchKey)
	iter := db.NewIterator(util.BytesPrefix(searchKey), nil)
	for iter.Next() {
		id := fmt.Sprintf("%s", iter.Value())
		objIDs = append(objIDs, id)
		// break
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		log.Println("Iterator error: ", err)
	}

	return objIDs
}

//
// get objects stored against the list of keys
//
func getObjects(objIDs []string) ([]interface{}, error) {

	db = GetDB()
	objects := []interface{}{}

	for _, objID := range objIDs {
		var object interface{}
		data, err := db.Get([]byte(objID), nil)
		if err != nil {
			log.Println("Cannot find object with key: ", string(objID))
			return objects, err
		}
		err = ge.Decode(data, &object)
		if err != nil {
			log.Println("Cannot decode object with key: ", objID, err)
			return objects, err
		}
		objects = append(objects, object)
	}

	return objects, nil

}

//
//
//
<|endoftext|>


<commit_before>//+build gtk_3_6 gtk_3_8 gtk_3_10 gtk_3_12 gtk_3_14

package gtk

// #cgo pkg-config: gtk+-3.0
// #include <gtk/gtk.h>
// #include <stdlib.h>
import "C"

import (
	"github.com/gotk3/gotk3/gdk"
	"unsafe"
)

// OverrideColor is a wrapper around gtk_widget_override_color().
func (v *Widget) OverrideColor(state StateFlags, color *gdk.RGBA) {
	var cColor *C.GdkRGBA
	if color != nil {
		cColor = (*C.GdkRGBA)(unsafe.Pointer((&color.RGBA)))
	}
	C.gtk_widget_override_color(v.native(), C.GtkStateFlags(state), cColor)
}

// OverrideFont is a wrapper around gtk_widget_override_font().
func (v *Widget) OverrideFont(description string) {
	cstr := C.CString(description)
	defer C.free(unsafe.Pointer(cstr))
	c := C.pango_font_description_from_string(cstr)
	C.gtk_widget_override_font(v.native(), c)
}
<commit_msg>Fix issue introduced when changing name of internal member for RGBA type<commit_after>//+build gtk_3_6 gtk_3_8 gtk_3_10 gtk_3_12 gtk_3_14

package gtk

// #cgo pkg-config: gtk+-3.0
// #include <gtk/gtk.h>
// #include <stdlib.h>
import "C"

import (
	"unsafe"

	"github.com/gotk3/gotk3/gdk"
)

// OverrideColor is a wrapper around gtk_widget_override_color().
func (v *Widget) OverrideColor(state StateFlags, color *gdk.RGBA) {
	var cColor *C.GdkRGBA
	if color != nil {
		cColor = (*C.GdkRGBA)(unsafe.Pointer((&color.rgba)))
	}
	C.gtk_widget_override_color(v.native(), C.GtkStateFlags(state), cColor)
}

// OverrideFont is a wrapper around gtk_widget_override_font().
func (v *Widget) OverrideFont(description string) {
	cstr := C.CString(description)
	defer C.free(unsafe.Pointer(cstr))
	c := C.pango_font_description_from_string(cstr)
	C.gtk_widget_override_font(v.native(), c)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/dchest/uniuri"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Backend", func() {

	var backend *MongoBackend
	var err error
	It("should create a backend", func() {
		backend, err = NewMongoBackend("bubble", "test-fe", "files")
		Ω(err).To(BeNil())
		Ω(backend).ToNot(BeNil())
	})

	It("should create and id", func() {
		Ω(backend.NewId()).ToNot(BeNil())
		Ω(len(backend.NewId())).ToNot(Equal(0))
	})

	It("should set something and get it", func() {
		id := backend.NewId()
		Ω(id).ToNot(BeNil())

		data := map[string]interface{}{
			"test": uniuri.New(),
		}

		Ω(backend.Set(id, data)).To(BeNil())

		from := make(map[string]interface{})
		from, err := backend.Get(id)
		Ω(err).To(BeNil())
		Ω(from).ToNot(BeNil())
		Ω(from["test"]).ToNot(BeNil())
		Ω(from["test"]).To(Equal(data["test"]))

		Ω(backend.Delete(id)).To(BeNil())
		Ω(backend.Delete(id)).To(Equal(ErrNotFound))

		from = make(map[string]interface{})
		from, err = backend.Get(id)
		Ω(err).To(Equal(ErrNotFound))
	})

})
<commit_msg>use localhost as mongoserver in tests<commit_after>package main

import (
	"github.com/dchest/uniuri"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Backend", func() {

	var backend *MongoBackend
	It("should create a backend", func() {
		backend = &MongoBackend{
			Collection: "files",
			Database:   "test-fe",
			Host:       "localhost",
		}
		Ω(backend.Init()).To(BeNil())
	})

	It("should create and id", func() {
		Ω(backend.NewId()).ToNot(BeNil())
		Ω(len(backend.NewId())).ToNot(Equal(0))
	})

	It("should set something and get it", func() {
		id := backend.NewId()
		Ω(id).ToNot(BeNil())

		data := map[string]interface{}{
			"test": uniuri.New(),
		}

		Ω(backend.Set(id, data)).To(BeNil())

		from := make(map[string]interface{})
		from, err := backend.Get(id)
		Ω(err).To(BeNil())
		Ω(from).ToNot(BeNil())
		Ω(from["test"]).ToNot(BeNil())
		Ω(from["test"]).To(Equal(data["test"]))

		Ω(backend.Delete(id)).To(BeNil())
		Ω(backend.Delete(id)).To(Equal(ErrNotFound))

		from = make(map[string]interface{})
		from, err = backend.Get(id)
		Ω(err).To(Equal(ErrNotFound))
	})
})
<|endoftext|>


<commit_before>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package gtrace provides convenience wrapping functionality for tracing feature using OpenTelemetry.
package gtrace

import (
	"context"
	"github.com/gogf/gf/container/gvar"
	"github.com/gogf/gf/net/gipv4"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/baggage"
	"go.opentelemetry.io/otel/label"
	"go.opentelemetry.io/otel/trace"
	"os"
)

var (
	intranetIps, _ = gipv4.GetIntranetIpArray()
	hostname, _    = os.Hostname()
)

// IsActivated checks and returns if tracing feature is activated.
func IsActivated(ctx context.Context) bool {
	return GetTraceId(ctx) != ""
}

// CommonLabels returns common used attribute labels:
// ip.intranet, hostname.
func CommonLabels() []label.KeyValue {
	return []label.KeyValue{
		label.Array(`ip.intranet`, intranetIps),
		label.String(`hostname`, hostname),
	}
}

// Tracer is a short function for retrieve Tracer.
func Tracer(name ...string) trace.Tracer {
	tracerName := ""
	if len(name) > 0 {
		tracerName = name[0]
	}
	return otel.Tracer(tracerName)
}

// GetTraceId retrieves and returns TraceId from context.
// It returns an empty string is tracing feature is not activated.
func GetTraceId(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	traceId := trace.SpanContextFromContext(ctx).TraceID
	if traceId.IsValid() {
		return traceId.String()
	}
	return ""
}

// GetSpanId retrieves and returns SpanId from context.
// It returns an empty string is tracing feature is not activated.
func GetSpanId(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	spanId := trace.SpanContextFromContext(ctx).SpanID
	if spanId.IsValid() {
		return spanId.String()
	}
	return ""
}

// SetBaggageValue is a convenient function for adding one key-value pair to baggage.
// Note that it uses label.Any to set the key-value pair.
func SetBaggageValue(ctx context.Context, key string, value interface{}) context.Context {
	if ctx == nil {
		ctx = context.Background()
	}
	return baggage.ContextWithValues(ctx, label.Any(key, value))
}

// SetBaggageMap is a convenient function for adding map key-value pairs to baggage.
// Note that it uses label.Any to set the key-value pair.
func SetBaggageMap(ctx context.Context, data map[string]interface{}) context.Context {
	if ctx == nil {
		ctx = context.Background()
	}
	pairs := make([]label.KeyValue, 0)
	for k, v := range data {
		pairs = append(pairs, label.Any(k, v))
	}
	return baggage.ContextWithValues(ctx, pairs...)
}

// GetBaggageVar retrieves value and returns a *gvar.Var for specified key from baggage.
func GetBaggageVar(ctx context.Context, key string) *gvar.Var {
	if ctx == nil {
		return gvar.New(nil)
	}
	value := baggage.Value(ctx, label.Key(key))
	return gvar.New(value.AsInterface())
}
<commit_msg>add common tracing labels<commit_after>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package gtrace provides convenience wrapping functionality for tracing feature using OpenTelemetry.
package gtrace

import (
	"context"
	"github.com/gogf/gf/container/gvar"
	"github.com/gogf/gf/net/gipv4"
	"github.com/gogf/gf/text/gstr"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/baggage"
	"go.opentelemetry.io/otel/label"
	"go.opentelemetry.io/otel/trace"
	"os"
)

var (
	intranetIps, _ = gipv4.GetIntranetIpArray()
	hostname, _    = os.Hostname()
)

// IsActivated checks and returns if tracing feature is activated.
func IsActivated(ctx context.Context) bool {
	return GetTraceId(ctx) != ""
}

// CommonLabels returns common used attribute labels:
// ip.intranet, hostname.
func CommonLabels() []label.KeyValue {
	return []label.KeyValue{
		label.String(`ip.intranet`, gstr.Join(intranetIps, ",")),
		label.String(`hostname`, hostname),
	}
}

// Tracer is a short function for retrieve Tracer.
func Tracer(name ...string) trace.Tracer {
	tracerName := ""
	if len(name) > 0 {
		tracerName = name[0]
	}
	return otel.Tracer(tracerName)
}

// GetTraceId retrieves and returns TraceId from context.
// It returns an empty string is tracing feature is not activated.
func GetTraceId(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	traceId := trace.SpanContextFromContext(ctx).TraceID
	if traceId.IsValid() {
		return traceId.String()
	}
	return ""
}

// GetSpanId retrieves and returns SpanId from context.
// It returns an empty string is tracing feature is not activated.
func GetSpanId(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	spanId := trace.SpanContextFromContext(ctx).SpanID
	if spanId.IsValid() {
		return spanId.String()
	}
	return ""
}

// SetBaggageValue is a convenient function for adding one key-value pair to baggage.
// Note that it uses label.Any to set the key-value pair.
func SetBaggageValue(ctx context.Context, key string, value interface{}) context.Context {
	if ctx == nil {
		ctx = context.Background()
	}
	return baggage.ContextWithValues(ctx, label.Any(key, value))
}

// SetBaggageMap is a convenient function for adding map key-value pairs to baggage.
// Note that it uses label.Any to set the key-value pair.
func SetBaggageMap(ctx context.Context, data map[string]interface{}) context.Context {
	if ctx == nil {
		ctx = context.Background()
	}
	pairs := make([]label.KeyValue, 0)
	for k, v := range data {
		pairs = append(pairs, label.Any(k, v))
	}
	return baggage.ContextWithValues(ctx, pairs...)
}

// GetBaggageVar retrieves value and returns a *gvar.Var for specified key from baggage.
func GetBaggageVar(ctx context.Context, key string) *gvar.Var {
	if ctx == nil {
		return gvar.New(nil)
	}
	value := baggage.Value(ctx, label.Key(key))
	return gvar.New(value.AsInterface())
}
<|endoftext|>