<commit_before>// Code generated by "tools/gen_mackerel_plugin.pl"; DO NOT EDIT
package main

import (
	"fmt"

	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-apache2/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-cloudfront/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-ec2-cpucredit/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-ec2-ebs/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-elasticache/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-elasticsearch/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-elb/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-kinesis-streams/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-lambda/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-rds/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-ses/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-conntrack/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-docker/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-elasticsearch/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-fluentd/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-gostats/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-graphite/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-haproxy/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-inode/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-jmx-jolokia/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-jvm/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-linux/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-mailq/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-memcached/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-mongodb/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-multicore/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-munin/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-mysql/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-nginx/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-php-apc/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-php-fpm/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-php-opcache/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-plack/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-postgres/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-proc-fd/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-rabbitmq/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-redis/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-snmp/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-solr/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-squid/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-td-table-count/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-trafficserver/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-twemproxy/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-unicorn/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-uptime/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-uwsgi-vassal/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-varnish/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-xentop/lib"
)

func runPlugin(plug string) error {
	switch plug {
	case "apache2":
		mpapache2.Do()
	case "aws-cloudfront":
		mpawscloudfront.Do()
	case "aws-ec2-cpucredit":
		mpawsec2cpucredit.Do()
	case "aws-ec2-ebs":
		mpawsec2ebs.Do()
	case "aws-elasticache":
		mpawselasticache.Do()
	case "aws-elasticsearch":
		mpawselasticsearch.Do()
	case "aws-elb":
		mpawselb.Do()
	case "aws-kinesis-streams":
		mpawskinesisstreams.Do()
	case "aws-lambda":
		mpawslambda.Do()
	case "aws-rds":
		mpawsrds.Do()
	case "aws-ses":
		mpawsses.Do()
	case "conntrack":
		mpconntrack.Do()
	case "docker":
		mpdocker.Do()
	case "elasticsearch":
		mpelasticsearch.Do()
	case "fluentd":
		mpfluentd.Do()
	case "gostats":
		mpgostats.Do()
	case "graphite":
		mpgraphite.Do()
	case "haproxy":
		mphaproxy.Do()
	case "inode":
		mpinode.Do()
	case "jmx-jolokia":
		mpjmxjolokia.Do()
	case "jvm":
		mpjvm.Do()
	case "linux":
		mplinux.Do()
	case "mailq":
		mpmailq.Do()
	case "memcached":
		mpmemcached.Do()
	case "mongodb":
		mpmongodb.Do()
	case "multicore":
		mpmulticore.Do()
	case "munin":
		mpmunin.Do()
	case "mysql":
		mpmysql.Do()
	case "nginx":
		mpnginx.Do()
	case "php-apc":
		mpphpapc.Do()
	case "php-fpm":
		mpphpfpm.Do()
	case "php-opcache":
		mpphpopcache.Do()
	case "plack":
		mpplack.Do()
	case "postgres":
		mppostgres.Do()
	case "proc-fd":
		mpprocfd.Do()
	case "rabbitmq":
		mprabbitmq.Do()
	case "redis":
		mpredis.Do()
	case "snmp":
		mpsnmp.Do()
	case "solr":
		mpsolr.Do()
	case "squid":
		mpsquid.Do()
	case "td-table-count":
		mptdtablecount.Do()
	case "trafficserver":
		mptrafficserver.Do()
	case "twemproxy":
		mptwemproxy.Do()
	case "unicorn":
		mpunicorn.Do()
	case "uptime":
		mpuptime.Do()
	case "uwsgi-vassal":
		mpuwsgivassal.Do()
	case "varnish":
		mpvarnish.Do()
	case "xentop":
		mpxentop.Do()
	default:
		return fmt.Errorf("unknown plugin: %q", plug)
	}
	return nil
}

var plugins = []string{
	"apache2",
	"aws-cloudfront",
	"aws-ec2-cpucredit",
	"aws-ec2-ebs",
	"aws-elasticache",
	"aws-elasticsearch",
	"aws-elb",
	"aws-kinesis-streams",
	"aws-lambda",
	"aws-rds",
	"aws-ses",
	"conntrack",
	"docker",
	"elasticsearch",
	"fluentd",
	"gostats",
	"graphite",
	"haproxy",
	"inode",
	"jmx-jolokia",
	"jvm",
	"linux",
	"mailq",
	"memcached",
	"mongodb",
	"multicore",
	"munin",
	"mysql",
	"nginx",
	"php-apc",
	"php-fpm",
	"php-opcache",
	"plack",
	"postgres",
	"proc-fd",
	"rabbitmq",
	"redis",
	"snmp",
	"solr",
	"squid",
	"td-table-count",
	"trafficserver",
	"twemproxy",
	"unicorn",
	"uptime",
	"uwsgi-vassal",
	"varnish",
	"xentop",
}
<commit_msg>go generate ./...<commit_after>// Code generated by "tools/gen_mackerel_plugin.pl"; DO NOT EDIT
package main

import (
	"fmt"

	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-apache2/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-cloudfront/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-dynamodb/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-ec2-cpucredit/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-ec2-ebs/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-elasticache/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-elasticsearch/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-elb/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-kinesis-streams/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-lambda/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-rds/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-aws-ses/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-conntrack/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-docker/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-elasticsearch/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-fluentd/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-gostats/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-graphite/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-haproxy/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-inode/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-jmx-jolokia/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-jvm/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-linux/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-mailq/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-memcached/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-mongodb/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-multicore/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-munin/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-mysql/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-nginx/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-php-apc/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-php-fpm/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-php-opcache/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-plack/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-postgres/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-proc-fd/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-rabbitmq/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-redis/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-snmp/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-solr/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-squid/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-td-table-count/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-trafficserver/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-twemproxy/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-unicorn/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-uptime/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-uwsgi-vassal/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-varnish/lib"
	"github.com/mackerelio/mackerel-agent-plugins/mackerel-plugin-xentop/lib"
)

func runPlugin(plug string) error {
	switch plug {
	case "apache2":
		mpapache2.Do()
	case "aws-cloudfront":
		mpawscloudfront.Do()
	case "aws-dynamodb":
		mpawsdynamodb.Do()
	case "aws-ec2-cpucredit":
		mpawsec2cpucredit.Do()
	case "aws-ec2-ebs":
		mpawsec2ebs.Do()
	case "aws-elasticache":
		mpawselasticache.Do()
	case "aws-elasticsearch":
		mpawselasticsearch.Do()
	case "aws-elb":
		mpawselb.Do()
	case "aws-kinesis-streams":
		mpawskinesisstreams.Do()
	case "aws-lambda":
		mpawslambda.Do()
	case "aws-rds":
		mpawsrds.Do()
	case "aws-ses":
		mpawsses.Do()
	case "conntrack":
		mpconntrack.Do()
	case "docker":
		mpdocker.Do()
	case "elasticsearch":
		mpelasticsearch.Do()
	case "fluentd":
		mpfluentd.Do()
	case "gostats":
		mpgostats.Do()
	case "graphite":
		mpgraphite.Do()
	case "haproxy":
		mphaproxy.Do()
	case "inode":
		mpinode.Do()
	case "jmx-jolokia":
		mpjmxjolokia.Do()
	case "jvm":
		mpjvm.Do()
	case "linux":
		mplinux.Do()
	case "mailq":
		mpmailq.Do()
	case "memcached":
		mpmemcached.Do()
	case "mongodb":
		mpmongodb.Do()
	case "multicore":
		mpmulticore.Do()
	case "munin":
		mpmunin.Do()
	case "mysql":
		mpmysql.Do()
	case "nginx":
		mpnginx.Do()
	case "php-apc":
		mpphpapc.Do()
	case "php-fpm":
		mpphpfpm.Do()
	case "php-opcache":
		mpphpopcache.Do()
	case "plack":
		mpplack.Do()
	case "postgres":
		mppostgres.Do()
	case "proc-fd":
		mpprocfd.Do()
	case "rabbitmq":
		mprabbitmq.Do()
	case "redis":
		mpredis.Do()
	case "snmp":
		mpsnmp.Do()
	case "solr":
		mpsolr.Do()
	case "squid":
		mpsquid.Do()
	case "td-table-count":
		mptdtablecount.Do()
	case "trafficserver":
		mptrafficserver.Do()
	case "twemproxy":
		mptwemproxy.Do()
	case "unicorn":
		mpunicorn.Do()
	case "uptime":
		mpuptime.Do()
	case "uwsgi-vassal":
		mpuwsgivassal.Do()
	case "varnish":
		mpvarnish.Do()
	case "xentop":
		mpxentop.Do()
	default:
		return fmt.Errorf("unknown plugin: %q", plug)
	}
	return nil
}

var plugins = []string{
	"apache2",
	"aws-cloudfront",
	"aws-dynamodb",
	"aws-ec2-cpucredit",
	"aws-ec2-ebs",
	"aws-elasticache",
	"aws-elasticsearch",
	"aws-elb",
	"aws-kinesis-streams",
	"aws-lambda",
	"aws-rds",
	"aws-ses",
	"conntrack",
	"docker",
	"elasticsearch",
	"fluentd",
	"gostats",
	"graphite",
	"haproxy",
	"inode",
	"jmx-jolokia",
	"jvm",
	"linux",
	"mailq",
	"memcached",
	"mongodb",
	"multicore",
	"munin",
	"mysql",
	"nginx",
	"php-apc",
	"php-fpm",
	"php-opcache",
	"plack",
	"postgres",
	"proc-fd",
	"rabbitmq",
	"redis",
	"snmp",
	"solr",
	"squid",
	"td-table-count",
	"trafficserver",
	"twemproxy",
	"unicorn",
	"uptime",
	"uwsgi-vassal",
	"varnish",
	"xentop",
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/SSSAAS/sssa-golang"

	"flag"
	"fmt"
	"strings"
)

func main() {
	create := flag.Bool("create", false, "create shares from a secret")
	minimum := flag.Int("minimum", 3, "minimum shares required to recreate secret")
	shares := flag.Int("shares", 4, "total shares to create (shares >= minimum)")
	secret := flag.String("secret", "Hello, World!", "secret to share")
	combine := flag.Bool("combine", false, "combines shares into a secret")
	raw := flag.String("secrets", "", "comma separated list of shared secrets")

	flag.Parse()

	if *create == *combine {
		flag.Usage()
	} else if *create {
		if *minimum > *shares {
			flag.Usage()
		} else {
			values := sssa.Create(*minimum, *shares, *secret)
			fmt.Println("=====Begin Shares=====")
			for i := range values {
				fmt.Println(values[i])
			}
			fmt.Println("=====End Shares=====")
		}
	} else {
		if *raw == "" {
			flag.Usage()
		} else {
			secrets := strings.Split(*raw, ",")
			value := sssa.Combine(secrets)
			fmt.Println("Secret: ", value)
		}
	}
}
<commit_msg>Fixed casing<commit_after>package main

import (
	"github.com/SSSaaS/sssa-golang"

	"flag"
	"fmt"
	"strings"
)

func main() {
	create := flag.Bool("create", false, "create shares from a secret")
	minimum := flag.Int("minimum", 3, "minimum shares required to recreate secret")
	shares := flag.Int("shares", 4, "total shares to create (shares >= minimum)")
	secret := flag.String("secret", "Hello, World!", "secret to share")
	combine := flag.Bool("combine", false, "combines shares into a secret")
	raw := flag.String("secrets", "", "comma separated list of shared secrets")

	flag.Parse()

	if *create == *combine {
		flag.Usage()
	} else if *create {
		if *minimum > *shares {
			flag.Usage()
		} else {
			values := sssa.Create(*minimum, *shares, *secret)
			fmt.Println("=====Begin Shares=====")
			for i := range values {
				fmt.Println(values[i])
			}
			fmt.Println("=====End Shares=====")
		}
	} else {
		if *raw == "" {
			flag.Usage()
		} else {
			secrets := strings.Split(*raw, ",")
			value := sssa.Combine(secrets)
			fmt.Println("Secret: ", value)
		}
	}
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package bees is Beehive's central module system.
package bees

import (
	"fmt"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	uuid "github.com/nu7hatch/gouuid"
)

// BeeInterface is an interface all bees implement.
type BeeInterface interface {
	// Name of the bee
	Name() string
	// Namespace of the bee
	Namespace() string

	// Description of the bee
	Description() string
	// SetDescription sets a description
	SetDescription(s string)

	// Config returns this bees config
	Config() BeeConfig
	// Options of the bee
	Options() BeeOptions
	// SetOptions to configure the bee
	SetOptions(options BeeOptions)

	// ReloadOptions gets called after a bee's options get updated
	ReloadOptions(options BeeOptions)

	// Activates the bee
	Run(eventChannel chan Event)
	// Running returns the current state of the bee
	IsRunning() bool
	// Start the bee
	Start()
	// Stop the bee
	Stop()

	LastEvent() time.Time
	LogEvent()
	LastAction() time.Time
	LogAction()

	Logln(args ...interface{})
	Logf(format string, args ...interface{})
	LogErrorf(format string, args ...interface{})
	LogFatal(args ...interface{})

	SetSigChan(c chan bool)
	WaitGroup() *sync.WaitGroup

	// Handles an action
	Action(action Action) []Placeholder
}

// Bee is the base-struct to be embedded by bee implementations.
type Bee struct {
	config BeeConfig

	lastEvent  time.Time
	lastAction time.Time

	Running   bool
	SigChan   chan bool
	waitGroup *sync.WaitGroup
}

var (
	bees      = make(map[string]*BeeInterface)
	factories = make(map[string]*BeeFactoryInterface)
)

// RegisterBee gets called by Bees to register themselves.
func RegisterBee(bee BeeInterface) {
	log.Println("Worker bee ready:", bee.Name(), "-", bee.Description())

	bees[bee.Name()] = &bee
}

// GetBee returns a bee with a specific name.
func GetBee(identifier string) *BeeInterface {
	bee, ok := bees[identifier]
	if ok {
		return bee
	}

	return nil
}

// GetBees returns all known bees.
func GetBees() []*BeeInterface {
	r := []*BeeInterface{}
	for _, bee := range bees {
		r = append(r, bee)
	}

	return r
}

// startBee starts a bee and recovers from panics.
func startBee(bee *BeeInterface, fatals int) {
	if fatals >= 3 {
		log.Println("Terminating evil bee", (*bee).Name(), "after", fatals, "failed tries!")
		return
	}

	(*bee).WaitGroup().Add(1)
	defer (*bee).WaitGroup().Done()

	defer func(bee *BeeInterface) {
		if e := recover(); e != nil {
			log.Println("Fatal bee event:", e, fatals)
			startBee(bee, fatals+1)
		}
	}(bee)

	(*bee).Run(eventsIn)
}

// NewBeeInstance sets up a new Bee with supplied config.
func NewBeeInstance(bee BeeConfig) *BeeInterface {
	factory := GetFactory(bee.Class)
	if factory == nil {
		panic("Unknown bee-class in config file: " + bee.Class)
	}
	mod := (*factory).New(bee.Name, bee.Description, bee.Options)
	RegisterBee(mod)

	return &mod
}

// DeleteBee removes a Bee instance.
func DeleteBee(bee *BeeInterface) {
	(*bee).Stop()

	delete(bees, (*bee).Name())
}

// StartBee starts a bee.
func StartBee(bee BeeConfig) *BeeInterface {
	b := NewBeeInstance(bee)

	(*b).Start()
	go func(mod *BeeInterface) {
		startBee(mod, 0)
	}(b)

	return b
}

// StartBees starts all registered bees.
func StartBees(beeList []BeeConfig) {
	eventsIn = make(chan Event)
	go handleEvents()

	for _, bee := range beeList {
		StartBee(bee)
	}
}

// StopBees stops all bees gracefully.
func StopBees() {
	for _, bee := range bees {
		log.Println("Stopping bee:", (*bee).Name())
		(*bee).Stop()
	}

	close(eventsIn)
	bees = make(map[string]*BeeInterface)
}

// RestartBee restarts a Bee.
func RestartBee(bee *BeeInterface) {
	(*bee).Stop()

	(*bee).SetSigChan(make(chan bool))
	(*bee).Start()
	go func(mod *BeeInterface) {
		startBee(mod, 0)
	}(bee)
}

// RestartBees stops all running bees and restarts a new set of bees.
func RestartBees(bees []BeeConfig) {
	StopBees()
	StartBees(bees)
}

// NewBee returns a new bee and sets up sig-channel & waitGroup.
func NewBee(name, factoryName, description string, options []BeeOption) Bee {
	c := BeeConfig{
		Name:        name,
		Class:       factoryName,
		Description: description,
		Options:     options,
	}
	b := Bee{
		config:    c,
		SigChan:   make(chan bool),
		waitGroup: &sync.WaitGroup{},
	}

	return b
}

// Name returns the configured name for a bee.
func (bee *Bee) Name() string {
	return bee.config.Name
}

// Namespace returns the namespace for a bee.
func (bee *Bee) Namespace() string {
	return bee.config.Class
}

// Description returns the description for a bee.
func (bee *Bee) Description() string {
	return bee.config.Description
}

// SetDescription sets the description for a bee.
func (bee *Bee) SetDescription(s string) {
	bee.config.Description = s
}

// Config returns the config for a bee.
func (bee *Bee) Config() BeeConfig {
	return bee.config
}

// Options returns the options for a bee.
func (bee *Bee) Options() BeeOptions {
	return bee.config.Options
}

// SetOptions sets the options for a bee.
func (bee *Bee) SetOptions(options BeeOptions) {
	bee.config.Options = options
}

// SetSigChan sets the signaling channel for a bee.
func (bee *Bee) SetSigChan(c chan bool) {
	bee.SigChan = c
}

// WaitGroup returns the WaitGroup for a bee.
func (bee *Bee) WaitGroup() *sync.WaitGroup {
	return bee.waitGroup
}

// Run is the default, empty implementation of a Bee's Run method.
func (bee *Bee) Run(chan Event) {
}

// Action is the default, empty implementation of a Bee's Action method.
func (bee *Bee) Action(action Action) []Placeholder {
	return []Placeholder{}
}

// IsRunning returns whether a Bee is currently running.
func (bee *Bee) IsRunning() bool {
	return bee.Running
}

// Start gets called when a Bee gets started.
func (bee *Bee) Start() {
	bee.Running = true
}

// Stop gracefully stops a Bee.
func (bee *Bee) Stop() {
	if !bee.IsRunning() {
		return
	}

	close(bee.SigChan)
	bee.waitGroup.Wait()
	bee.Running = false
	log.Println(bee.Name(), "stopped gracefully!")
}

// LastEvent returns the timestamp of the last triggered event.
func (bee *Bee) LastEvent() time.Time {
	return bee.lastEvent
}

// LastAction returns the timestamp of the last triggered action.
func (bee *Bee) LastAction() time.Time {
	return bee.lastAction
}

// LogEvent logs the last triggered event.
func (bee *Bee) LogEvent() {
	bee.lastEvent = time.Now()
}

// LogAction logs the last triggered action.
func (bee *Bee) LogAction() {
	bee.lastAction = time.Now()
}

// Logln logs args
func (bee *Bee) Logln(args ...interface{}) {
	a := []interface{}{"[" + bee.Name() + "]:"}
	for _, v := range args {
		a = append(a, v)
	}

	log.Println(a...)
}

// Logf logs a formatted string
func (bee *Bee) Logf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	log.Printf("[%s]: %s", bee.Name(), s)
}

// LogErrorf logs a formatted error string
func (bee *Bee) LogErrorf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	log.Errorf("[%s]: %s", bee.Name(), s)
}

// LogFatal logs a fatal error
func (bee *Bee) LogFatal(args ...interface{}) {
	a := []interface{}{"[" + bee.Name() + "]:"}
	for _, v := range args {
		a = append(a, v)
	}
	log.Fatal(a...)
}

// UUID generates a new unique ID.
func UUID() string {
	u, _ := uuid.NewV4()
	return u.String()
}
<commit_msg>Block and wait for SigChan in Bee's default Run() implementation<commit_after>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package bees is Beehive's central module system.
package bees

import (
	"fmt"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	uuid "github.com/nu7hatch/gouuid"
)

// BeeInterface is an interface all bees implement.
type BeeInterface interface {
	// Name of the bee
	Name() string
	// Namespace of the bee
	Namespace() string

	// Description of the bee
	Description() string
	// SetDescription sets a description
	SetDescription(s string)

	// Config returns this bees config
	Config() BeeConfig
	// Options of the bee
	Options() BeeOptions
	// SetOptions to configure the bee
	SetOptions(options BeeOptions)

	// ReloadOptions gets called after a bee's options get updated
	ReloadOptions(options BeeOptions)

	// Activates the bee
	Run(eventChannel chan Event)
	// Running returns the current state of the bee
	IsRunning() bool
	// Start the bee
	Start()
	// Stop the bee
	Stop()

	LastEvent() time.Time
	LogEvent()
	LastAction() time.Time
	LogAction()

	Logln(args ...interface{})
	Logf(format string, args ...interface{})
	LogErrorf(format string, args ...interface{})
	LogFatal(args ...interface{})

	SetSigChan(c chan bool)
	WaitGroup() *sync.WaitGroup

	// Handles an action
	Action(action Action) []Placeholder
}

// Bee is the base-struct to be embedded by bee implementations.
type Bee struct {
	config BeeConfig

	lastEvent  time.Time
	lastAction time.Time

	Running   bool
	SigChan   chan bool
	waitGroup *sync.WaitGroup
}

var (
	bees      = make(map[string]*BeeInterface)
	factories = make(map[string]*BeeFactoryInterface)
)

// RegisterBee gets called by Bees to register themselves.
func RegisterBee(bee BeeInterface) {
	log.Println("Worker bee ready:", bee.Name(), "-", bee.Description())

	bees[bee.Name()] = &bee
}

// GetBee returns a bee with a specific name.
func GetBee(identifier string) *BeeInterface {
	bee, ok := bees[identifier]
	if ok {
		return bee
	}

	return nil
}

// GetBees returns all known bees.
func GetBees() []*BeeInterface {
	r := []*BeeInterface{}
	for _, bee := range bees {
		r = append(r, bee)
	}

	return r
}

// startBee starts a bee and recovers from panics.
func startBee(bee *BeeInterface, fatals int) {
	if fatals >= 3 {
		log.Println("Terminating evil bee", (*bee).Name(), "after", fatals, "failed tries!")
		return
	}

	(*bee).WaitGroup().Add(1)
	defer (*bee).WaitGroup().Done()

	defer func(bee *BeeInterface) {
		if e := recover(); e != nil {
			log.Println("Fatal bee event:", e, fatals)
			startBee(bee, fatals+1)
		}
	}(bee)

	(*bee).Run(eventsIn)
}

// NewBeeInstance sets up a new Bee with supplied config.
func NewBeeInstance(bee BeeConfig) *BeeInterface {
	factory := GetFactory(bee.Class)
	if factory == nil {
		panic("Unknown bee-class in config file: " + bee.Class)
	}
	mod := (*factory).New(bee.Name, bee.Description, bee.Options)
	RegisterBee(mod)

	return &mod
}

// DeleteBee removes a Bee instance.
func DeleteBee(bee *BeeInterface) {
	(*bee).Stop()

	delete(bees, (*bee).Name())
}

// StartBee starts a bee.
func StartBee(bee BeeConfig) *BeeInterface {
	b := NewBeeInstance(bee)

	(*b).Start()
	go func(mod *BeeInterface) {
		startBee(mod, 0)
	}(b)

	return b
}

// StartBees starts all registered bees.
func StartBees(beeList []BeeConfig) {
	eventsIn = make(chan Event)
	go handleEvents()

	for _, bee := range beeList {
		StartBee(bee)
	}
}

// StopBees stops all bees gracefully.
func StopBees() {
	for _, bee := range bees {
		log.Println("Stopping bee:", (*bee).Name())
		(*bee).Stop()
	}

	close(eventsIn)
	bees = make(map[string]*BeeInterface)
}

// RestartBee restarts a Bee.
func RestartBee(bee *BeeInterface) {
	(*bee).Stop()

	(*bee).SetSigChan(make(chan bool))
	(*bee).Start()
	go func(mod *BeeInterface) {
		startBee(mod, 0)
	}(bee)
}

// RestartBees stops all running bees and restarts a new set of bees.
func RestartBees(bees []BeeConfig) {
	StopBees()
	StartBees(bees)
}

// NewBee returns a new bee and sets up sig-channel & waitGroup.
func NewBee(name, factoryName, description string, options []BeeOption) Bee {
	c := BeeConfig{
		Name:        name,
		Class:       factoryName,
		Description: description,
		Options:     options,
	}
	b := Bee{
		config:    c,
		SigChan:   make(chan bool),
		waitGroup: &sync.WaitGroup{},
	}

	return b
}

// Name returns the configured name for a bee.
func (bee *Bee) Name() string {
	return bee.config.Name
}

// Namespace returns the namespace for a bee.
func (bee *Bee) Namespace() string {
	return bee.config.Class
}

// Description returns the description for a bee.
func (bee *Bee) Description() string {
	return bee.config.Description
}

// SetDescription sets the description for a bee.
func (bee *Bee) SetDescription(s string) {
	bee.config.Description = s
}

// Config returns the config for a bee.
func (bee *Bee) Config() BeeConfig {
	return bee.config
}

// Options returns the options for a bee.
func (bee *Bee) Options() BeeOptions {
	return bee.config.Options
}

// SetOptions sets the options for a bee.
func (bee *Bee) SetOptions(options BeeOptions) {
	bee.config.Options = options
}

// SetSigChan sets the signaling channel for a bee.
func (bee *Bee) SetSigChan(c chan bool) {
	bee.SigChan = c
}

// WaitGroup returns the WaitGroup for a bee.
func (bee *Bee) WaitGroup() *sync.WaitGroup {
	return bee.waitGroup
}

// Run is the default, empty implementation of a Bee's Run method.
func (bee *Bee) Run(chan Event) {
	select {
	case <-bee.SigChan:
		return
	}
}

// Action is the default, empty implementation of a Bee's Action method.
func (bee *Bee) Action(action Action) []Placeholder {
	return []Placeholder{}
}

// IsRunning returns whether a Bee is currently running.
func (bee *Bee) IsRunning() bool {
	return bee.Running
}

// Start gets called when a Bee gets started.
func (bee *Bee) Start() {
	bee.Running = true
}

// Stop gracefully stops a Bee.
func (bee *Bee) Stop() {
	if !bee.IsRunning() {
		return
	}

	close(bee.SigChan)
	bee.waitGroup.Wait()
	bee.Running = false
	log.Println(bee.Name(), "stopped gracefully!")
}

// LastEvent returns the timestamp of the last triggered event.
func (bee *Bee) LastEvent() time.Time {
	return bee.lastEvent
}

// LastAction returns the timestamp of the last triggered action.
func (bee *Bee) LastAction() time.Time {
	return bee.lastAction
}

// LogEvent logs the last triggered event.
func (bee *Bee) LogEvent() {
	bee.lastEvent = time.Now()
}

// LogAction logs the last triggered action.
func (bee *Bee) LogAction() {
	bee.lastAction = time.Now()
}

// Logln logs args
func (bee *Bee) Logln(args ...interface{}) {
	a := []interface{}{"[" + bee.Name() + "]:"}
	for _, v := range args {
		a = append(a, v)
	}

	log.Println(a...)
}

// Logf logs a formatted string
func (bee *Bee) Logf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	log.Printf("[%s]: %s", bee.Name(), s)
}

// LogErrorf logs a formatted error string
func (bee *Bee) LogErrorf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	log.Errorf("[%s]: %s", bee.Name(), s)
}

// LogFatal logs a fatal error
func (bee *Bee) LogFatal(args ...interface{}) {
	a := []interface{}{"[" + bee.Name() + "]:"}
	for _, v := range args {
		a = append(a, v)
	}
	log.Fatal(a...)
}

// UUID generates a new unique ID.
func UUID() string {
	u, _ := uuid.NewV4()
	return u.String()
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"io"
	"strings"

	"github.com/juju/cmd"
	"github.com/juju/errors"

	"github.com/juju/juju/cmd/envcmd"
)

// UploadClient has the API client methods needed by UploadCommand.
type UploadClient interface {
	Upload(service, name string, resource io.Reader) error
	Close() error
}

// UploadDeps is a type that contains external functions that Upload depends on
// to function.
type UploadDeps struct {
	// NewClient returns the value that wraps the API for uploading to the server.
	NewClient func(*UploadCommand) (UploadClient, error)
	// OpenResource handles creating a reader from the resource path.
	OpenResource func(path string) (io.ReadCloser, error)
}

// UploadCommand implements the upload command.
type UploadCommand struct {
	deps UploadDeps
	envcmd.EnvCommandBase
	service       string
	resourceFiles []resourceFile
	resources     map[string]struct{}
}

// NewUploadCommand returns a new command that lists resources defined
// by a charm.
func NewUploadCommand(deps UploadDeps) *UploadCommand {
	return &UploadCommand{deps: deps}
}

// Info implements cmd.Command.Info
func (c *UploadCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "upload",
		Args:    "service name=file [name2=file2 ...]",
		Purpose: "upload a file as a resource for a service",
		Doc: `
This command uploads a file from your local disk to the juju controller to be
used as a resource for a service.
`,
	}
}

// Init implements cmd.Command.Init. It will return an error satisfying
// errors.BadRequest if you give it an incorrect number of arguments.
func (c *UploadCommand) Init(args []string) error {
	switch len(args) {
	case 0:
		return errors.BadRequestf("missing service name")
	case 1:
		return errors.BadRequestf("no resource specified")
	}

	service := args[0]
	if service == "" { // TODO(ericsnow) names.IsValidService
		return errors.NewNotValid(nil, "missing service name")
	}
	c.service = service

	c.resources = make(map[string]struct{})

	for _, arg := range args[1:] {
		if err := c.addResourceFile(arg); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

// addResourceFile parses the given arg into a name and a resource file,
// and saves it in c.resourceFiles.
func (c *UploadCommand) addResourceFile(arg string) error {
	name, filename, err := parseResourceFileArg(arg)
	if err != nil {
		return errors.Annotatef(err, "bad resource arg %q", arg)
	}
	rf := resourceFile{
		service:  c.service,
		name:     name,
		filename: filename,
	}

	if _, ok := c.resources[rf.name]; ok {
		msg := fmt.Sprintf("duplicate resource %q", rf.name)
		return errors.NewAlreadyExists(nil, msg)
	}
	c.resourceFiles = append(c.resourceFiles, rf)
	c.resources[rf.name] = struct{}{}
	return nil
}

// Run implements cmd.Command.Run.
func (c *UploadCommand) Run(*cmd.Context) error {
	apiclient, err := c.deps.NewClient(c)
	if err != nil {
		return errors.Annotatef(err, "can't connect to %s", c.ConnectionName())
	}
	defer apiclient.Close()

	errs := []error{}

	for _, rf := range c.resourceFiles {
		// don't want to do a bulk upload since we're doing potentially large
		// file uploads.
		if err := c.upload(rf, apiclient); err != nil {
			name := rf.service + "/" + rf.name
			errs = append(errs, errors.Annotatef(err, "failed to upload resource %q", name))
		}
	}
	switch len(errs) {
	case 0:
		return nil
	case 1:
		return errs[0]
	default:
		msgs := make([]string, len(errs))
		for i := range errs {
			msgs[i] = errs[i].Error()
		}
		return errors.Errorf(strings.Join(msgs, "\n"))
	}
}

// upload opens the given file and calls the apiclient to upload it to the given
// service with the given name.
func (c *UploadCommand) upload(rf resourceFile, client UploadClient) error {
	f, err := c.deps.OpenResource(rf.filename)
	if err != nil {
		return errors.Trace(err)
	}
	defer f.Close()
	err = client.Upload(rf.service, rf.name, f)
	return errors.Trace(err)
}
<commit_msg>Do not include the service in an error message.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package cmd

import (
	"fmt"
	"io"
	"strings"

	"github.com/juju/cmd"
	"github.com/juju/errors"

	"github.com/juju/juju/cmd/envcmd"
)

// UploadClient has the API client methods needed by UploadCommand.
type UploadClient interface {
	Upload(service, name string, resource io.Reader) error
	Close() error
}

// UploadDeps is a type that contains external functions that Upload depends on
// to function.
type UploadDeps struct {
	// NewClient returns the value that wraps the API for uploading to the server.
	NewClient func(*UploadCommand) (UploadClient, error)
	// OpenResource handles creating a reader from the resource path.
	OpenResource func(path string) (io.ReadCloser, error)
}

// UploadCommand implements the upload command.
type UploadCommand struct {
	deps UploadDeps
	envcmd.EnvCommandBase
	service       string
	resourceFiles []resourceFile
	resources     map[string]struct{}
}

// NewUploadCommand returns a new command that lists resources defined
// by a charm.
func NewUploadCommand(deps UploadDeps) *UploadCommand {
	return &UploadCommand{deps: deps}
}

// Info implements cmd.Command.Info
func (c *UploadCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "upload",
		Args:    "service name=file [name2=file2 ...]",
		Purpose: "upload a file as a resource for a service",
		Doc: `
This command uploads a file from your local disk to the juju controller to be
used as a resource for a service.
`,
	}
}

// Init implements cmd.Command.Init. It will return an error satisfying
// errors.BadRequest if you give it an incorrect number of arguments.
func (c *UploadCommand) Init(args []string) error {
	switch len(args) {
	case 0:
		return errors.BadRequestf("missing service name")
	case 1:
		return errors.BadRequestf("no resource specified")
	}

	service := args[0]
	if service == "" { // TODO(ericsnow) names.IsValidService
		return errors.NewNotValid(nil, "missing service name")
	}
	c.service = service

	c.resources = make(map[string]struct{})

	for _, arg := range args[1:] {
		if err := c.addResourceFile(arg); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

// addResourceFile parses the given arg into a name and a resource file,
// and saves it in c.resourceFiles.
func (c *UploadCommand) addResourceFile(arg string) error {
	name, filename, err := parseResourceFileArg(arg)
	if err != nil {
		return errors.Annotatef(err, "bad resource arg %q", arg)
	}
	rf := resourceFile{
		service:  c.service,
		name:     name,
		filename: filename,
	}

	if _, ok := c.resources[rf.name]; ok {
		msg := fmt.Sprintf("duplicate resource %q", rf.name)
		return errors.NewAlreadyExists(nil, msg)
	}
	c.resourceFiles = append(c.resourceFiles, rf)
	c.resources[rf.name] = struct{}{}
	return nil
}

// Run implements cmd.Command.Run.
func (c *UploadCommand) Run(*cmd.Context) error {
	apiclient, err := c.deps.NewClient(c)
	if err != nil {
		return errors.Annotatef(err, "can't connect to %s", c.ConnectionName())
	}
	defer apiclient.Close()

	errs := []error{}

	for _, rf := range c.resourceFiles {
		// don't want to do a bulk upload since we're doing potentially large
		// file uploads.
		if err := c.upload(rf, apiclient); err != nil {
			errs = append(errs, errors.Annotatef(err, "failed to upload resource %q", rf.name))
		}
	}
	switch len(errs) {
	case 0:
		return nil
	case 1:
		return errs[0]
	default:
		msgs := make([]string, len(errs))
		for i := range errs {
			msgs[i] = errs[i].Error()
		}
		return errors.Errorf(strings.Join(msgs, "\n"))
	}
}

// upload opens the given file and calls the apiclient to upload it to the given
// service with the given name.
func (c *UploadCommand) upload(rf resourceFile, client UploadClient) error {
	f, err := c.deps.OpenResource(rf.filename)
	if err != nil {
		return errors.Trace(err)
	}
	defer f.Close()
	err = client.Upload(rf.service, rf.name, f)
	return errors.Trace(err)
}
<|endoftext|>


<commit_before>// Package singlefile implements a host wide locking mechanism.
//
// Singlefile can be used to ensure that two scheduled processes
// on a host do not run at the same time.
package singlefile

import "errors"

// Lock takes a host wide lock on the specified key.
// Lock returns an unlock function, and an error indicating the
// success or failure of the lock operation.
// key must not be an empty string and implementations may require
// that they key is of sufficient length to ensure uniqueness.
func Lock(key string) (unlock func() error, err error) {
	if key == "" {
		return nil, errors.New("key must not be empty")
	}
	return lock(key)
}
<commit_msg>Added larger description to Lock<commit_after>// Package singlefile implements a host wide locking mechanism.
//
// Singlefile can be used to ensure that two scheduled processes
// on a host do not run at the same time.
package singlefile

import "errors"

// Lock takes a host wide lock on the specified key.
// Lock is guarenteed to release the lock when the process exits,
// even if that is uncontrolled (runtime panic, OOM killer, etc).
// Lock returns an unlock function, and an error indicating the
// success or failure of the lock operation. The unlock function
// may be used to release the lock before the end of the program execution.
// key must not be an empty string and implementations may require
// that they key is of sufficient length to ensure uniqueness.
func Lock(key string) (unlock func() error, err error) {
	if key == "" {
		return nil, errors.New("key must not be empty")
	}
	return lock(key)
}
<|endoftext|>


<commit_before>package state

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/txn"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state/presence"
	"launchpad.net/juju-core/state/watcher"
)

// Info encapsulates information about cluster of
// servers holding juju state and can be used to make a
// connection to that cluster.
type Info struct {
	// Addrs gives the addresses of the MongoDB servers for the state.
	// Each address should be in the form address:port.
	Addrs []string

	// UseSSH specifies whether MongoDB should be contacted through an
	// SSH tunnel.
	// TODO(rog) remove
	UseSSH bool

	// CACert holds the CA certificate that will be used
	// to validate the state server's certificate.
	CACertPEM []byte

	// EntityName holds the name of the entity that is connecting.
	// It should be empty when connecting as an administrator.
	EntityName string

	// Password holds the password for the administrator or connecting entity.
	Password string
}

// Open connects to the server described by the given
// info, waits for it to be initialized, and returns a new State
// representing the environment connected to.
// It returns ErrUnauthorized if access is unauthorized.
func Open(info *Info) (*State, error) {
	log.Printf("state: opening state; mongo addresses: %q", info.Addrs)
	if len(info.Addrs) == 0 {
		return nil, errors.New("no mongo addresses")
	}
	var (
		session *mgo.Session
		fwd     *sshForwarder
		err     error
	)
	// TODO(rog) require CA cert
	if info.UseSSH {
		// TODO implement authorization on SSL connection; drop sshDial.
		if len(info.Addrs) > 1 {
			return nil, errors.New("ssh connect does not support multiple addresses")
		}
		fwd, session, err = sshDial(info.Addrs[0], "")
	} else {
		session, err = mgo.DialWithTimeout(strings.Join(info.Addrs, ","), 10*time.Minute)
	}
	if err != nil {
		return nil, err
	}
	st, err := newState(session, fwd, info.EntityName, info.Password)
	if err != nil {
		session.Close()
		return nil, err
	}
	return st, nil
}

// Initialize sets up an initial empty state and returns it.
// This needs to be performed only once for a given environment.
// It returns ErrUnauthorized if access is unauthorized.
func Initialize(info *Info, cfg *config.Config) (*State, error) {
	st, err := Open(info)
	if err != nil {
		return nil, err
	}
	// A valid environment config is used as a signal that the
	// state has already been initalized. If this is the case
	// do nothing.
	if _, err = st.EnvironConfig(); !IsNotFound(err) {
		return st, nil
	}
	log.Printf("state: storing no-secrets environment configuration")
	if _, err = createSettings(st, "e", nil); err != nil {
		st.Close()
		return nil, err
	}
	if err = st.SetEnvironConfig(cfg); err != nil {
		st.Close()
		return nil, err
	}
	return st, nil
}

var indexes = []struct {
	collection string
	key        []string
}{
	// After the first public release, do not remove entries from here
	// without adding them to a list of indexes to drop, to ensure
	// old databases are modified to have the correct indexes.
	{"relations", []string{"endpoints.relationname"}},
	{"relations", []string{"endpoints.servicename"}},
	{"units", []string{"service"}},
	{"units", []string{"principal"}},
	{"units", []string{"machineid"}},
}

// The capped collection used for transaction logs defaults to 10MB.
// It's tweaked in export_test.go to 1MB to avoid the overhead of
// creating and deleting the large file repeatedly in tests.
var (
	logSize      = 10000000
	logSizeTests = 1000000
)

var ErrUnauthorized = errors.New("unauthorized access")

func maybeUnauthorized(err error, msg string) error {
	if err == nil {
		return nil
	}
	// Unauthorized access errors have no error code,
	// just a simple error string.
	if err.Error() == "auth fails" {
		return ErrUnauthorized
	}
	if err, ok := err.(*mgo.QueryError); ok && err.Code == 10057 {
		return ErrUnauthorized
	}
	return fmt.Errorf("%s: %v", msg, err)
}

func newState(session *mgo.Session, fwd *sshForwarder, entity, password string) (*State, error) {
	db := session.DB("juju")
	pdb := session.DB("presence")
	if entity != "" {
		if err := db.Login(entity, password); err != nil {
			return nil, maybeUnauthorized(err, "cannot log in to juju database")
		}
		if err := pdb.Login(entity, password); err != nil {
			return nil, maybeUnauthorized(err, "cannot log in to presence database")
		}
	} else if password != "" {
		admin := session.DB("admin")
		if err := admin.Login("admin", password); err != nil {
			return nil, maybeUnauthorized(err, "cannot log in to admin database")
		}
	}
	st := &State{
		db:             db,
		charms:         db.C("charms"),
		machines:       db.C("machines"),
		relations:      db.C("relations"),
		relationScopes: db.C("relationscopes"),
		services:       db.C("services"),
		settings:       db.C("settings"),
		units:          db.C("units"),
		presence:       pdb.C("presence"),
		cleanups:       db.C("cleanups"),
		fwd:            fwd,
	}
	log := db.C("txns.log")
	info := mgo.CollectionInfo{Capped: true, MaxBytes: logSize}
	// The lack of error code for this error was reported upstream:
	//     https://jira.mongodb.org/browse/SERVER-6992
	err := log.Create(&info)
	if err != nil && err.Error() != "collection already exists" {
		return nil, maybeUnauthorized(err, "cannot create log collection")
	}
	st.runner = txn.NewRunner(db.C("txns"))
	st.runner.ChangeLog(db.C("txns.log"))
	st.watcher = watcher.New(db.C("txns.log"))
	st.pwatcher = presence.NewWatcher(pdb.C("presence"))
	for _, item := range indexes {
		index := mgo.Index{Key: item.key}
		if err := db.C(item.collection).EnsureIndex(index); err != nil {
			return nil, fmt.Errorf("cannot create database index: %v", err)
		}
	}
	return st, nil
}

func (st *State) Close() error {
	err1 := st.watcher.Stop()
	err2 := st.pwatcher.Stop()
	st.db.Session.Close()
	for _, err := range []error{err1, err2} {
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>state: make state.Info mandatory<commit_after>package state

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/txn"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state/presence"
	"launchpad.net/juju-core/state/watcher"
)

// Info encapsulates information about cluster of
// servers holding juju state and can be used to make a
// connection to that cluster.
type Info struct {
	// Addrs gives the addresses of the MongoDB servers for the state.
	// Each address should be in the form address:port.
	Addrs []string

	// UseSSH specifies whether MongoDB should be contacted through an
	// SSH tunnel.
	// TODO(rog) remove
	UseSSH bool

	// CACert holds the CA certificate that will be used
	// to validate the state server's certificate.
	CACertPEM []byte

	// EntityName holds the name of the entity that is connecting.
	// It should be empty when connecting as an administrator.
	EntityName string

	// Password holds the password for the administrator or connecting entity.
	Password string
}

// Open connects to the server described by the given
// info, waits for it to be initialized, and returns a new State
// representing the environment connected to.
// It returns ErrUnauthorized if access is unauthorized.
func Open(info *Info) (*State, error) {
	log.Printf("state: opening state; mongo addresses: %q", info.Addrs)
	if len(info.Addrs) == 0 {
		return nil, errors.New("no mongo addresses")
	}
	if len(info.CACertPEM) == 0 {
		return nil, errors.New("no CA certificate")
	}
	var (
		session *mgo.Session
		fwd     *sshForwarder
		err     error
	)
	// TODO(rog) require CA cert
	if info.UseSSH {
		// TODO implement authorization on SSL connection; drop sshDial.
		if len(info.Addrs) > 1 {
			return nil, errors.New("ssh connect does not support multiple addresses")
		}
		fwd, session, err = sshDial(info.Addrs[0], "")
	} else {
		session, err = mgo.DialWithTimeout(strings.Join(info.Addrs, ","), 10*time.Minute)
	}
	if err != nil {
		return nil, err
	}
	st, err := newState(session, fwd, info.EntityName, info.Password)
	if err != nil {
		session.Close()
		return nil, err
	}
	return st, nil
}

// Initialize sets up an initial empty state and returns it.
// This needs to be performed only once for a given environment.
// It returns ErrUnauthorized if access is unauthorized.
func Initialize(info *Info, cfg *config.Config) (*State, error) {
	st, err := Open(info)
	if err != nil {
		return nil, err
	}
	// A valid environment config is used as a signal that the
	// state has already been initalized. If this is the case
	// do nothing.
	if _, err = st.EnvironConfig(); !IsNotFound(err) {
		return st, nil
	}
	log.Printf("state: storing no-secrets environment configuration")
	if _, err = createSettings(st, "e", nil); err != nil {
		st.Close()
		return nil, err
	}
	if err = st.SetEnvironConfig(cfg); err != nil {
		st.Close()
		return nil, err
	}
	return st, nil
}

var indexes = []struct {
	collection string
	key        []string
}{
	// After the first public release, do not remove entries from here
	// without adding them to a list of indexes to drop, to ensure
	// old databases are modified to have the correct indexes.
	{"relations", []string{"endpoints.relationname"}},
	{"relations", []string{"endpoints.servicename"}},
	{"units", []string{"service"}},
	{"units", []string{"principal"}},
	{"units", []string{"machineid"}},
}

// The capped collection used for transaction logs defaults to 10MB.
// It's tweaked in export_test.go to 1MB to avoid the overhead of
// creating and deleting the large file repeatedly in tests.
var (
	logSize      = 10000000
	logSizeTests = 1000000
)

var ErrUnauthorized = errors.New("unauthorized access")

func maybeUnauthorized(err error, msg string) error {
	if err == nil {
		return nil
	}
	// Unauthorized access errors have no error code,
	// just a simple error string.
	if err.Error() == "auth fails" {
		return ErrUnauthorized
	}
	if err, ok := err.(*mgo.QueryError); ok && err.Code == 10057 {
		return ErrUnauthorized
	}
	return fmt.Errorf("%s: %v", msg, err)
}

func newState(session *mgo.Session, fwd *sshForwarder, entity, password string) (*State, error) {
	db := session.DB("juju")
	pdb := session.DB("presence")
	if entity != "" {
		if err := db.Login(entity, password); err != nil {
			return nil, maybeUnauthorized(err, "cannot log in to juju database")
		}
		if err := pdb.Login(entity, password); err != nil {
			return nil, maybeUnauthorized(err, "cannot log in to presence database")
		}
	} else if password != "" {
		admin := session.DB("admin")
		if err := admin.Login("admin", password); err != nil {
			return nil, maybeUnauthorized(err, "cannot log in to admin database")
		}
	}
	st := &State{
		db:             db,
		charms:         db.C("charms"),
		machines:       db.C("machines"),
		relations:      db.C("relations"),
		relationScopes: db.C("relationscopes"),
		services:       db.C("services"),
		settings:       db.C("settings"),
		units:          db.C("units"),
		presence:       pdb.C("presence"),
		cleanups:       db.C("cleanups"),
		fwd:            fwd,
	}
	log := db.C("txns.log")
	info := mgo.CollectionInfo{Capped: true, MaxBytes: logSize}
	// The lack of error code for this error was reported upstream:
	//     https://jira.mongodb.org/browse/SERVER-6992
	err := log.Create(&info)
	if err != nil && err.Error() != "collection already exists" {
		return nil, maybeUnauthorized(err, "cannot create log collection")
	}
	st.runner = txn.NewRunner(db.C("txns"))
	st.runner.ChangeLog(db.C("txns.log"))
	st.watcher = watcher.New(db.C("txns.log"))
	st.pwatcher = presence.NewWatcher(pdb.C("presence"))
	for _, item := range indexes {
		index := mgo.Index{Key: item.key}
		if err := db.C(item.collection).EnsureIndex(index); err != nil {
			return nil, fmt.Errorf("cannot create database index: %v", err)
		}
	}
	return st, nil
}

func (st *State) Close() error {
	err1 := st.watcher.Stop()
	err2 := st.pwatcher.Stop()
	st.db.Session.Close()
	for _, err := range []error{err1, err2} {
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package memberlist

import (
	"testing"
	"time"
)

func TestMemberList_NextSeq(t *testing.T) {
	m := &Memberlist{}
	if m.nextSeqNo() != 1 {
		t.Fatalf("bad sequence no")
	}
	if m.nextSeqNo() != 2 {
		t.Fatalf("bad sequence no")
	}
}

func TestMemberList_SetAckHandler(t *testing.T) {
	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}

	f := func() {}
	m.setAckHandler(0, f, 10*time.Millisecond)

	if _, ok := m.ackHandlers[0]; !ok {
		t.Fatalf("missing handler")
	}
	time.Sleep(11 * time.Millisecond)

	if _, ok := m.ackHandlers[0]; ok {
		t.Fatalf("non-reaped handler")
	}
}

func TestMemberList_InvokeAckHandler(t *testing.T) {
	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}

	// Does nothing
	m.invokeAckHandler(0)

	var b bool
	f := func() { b = true }
	m.setAckHandler(0, f, 10*time.Millisecond)

	// Should set b
	m.invokeAckHandler(0)
	if !b {
		t.Fatalf("b not set")
	}

	if _, ok := m.ackHandlers[0]; ok {
		t.Fatalf("non-reaped handler")
	}
}
<commit_msg>Test aliveNode handling<commit_after>package memberlist

import (
	"testing"
	"time"
)

func TestMemberList_NextSeq(t *testing.T) {
	m := &Memberlist{}
	if m.nextSeqNo() != 1 {
		t.Fatalf("bad sequence no")
	}
	if m.nextSeqNo() != 2 {
		t.Fatalf("bad sequence no")
	}
}

func TestMemberList_SetAckHandler(t *testing.T) {
	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}

	f := func() {}
	m.setAckHandler(0, f, 10*time.Millisecond)

	if _, ok := m.ackHandlers[0]; !ok {
		t.Fatalf("missing handler")
	}
	time.Sleep(11 * time.Millisecond)

	if _, ok := m.ackHandlers[0]; ok {
		t.Fatalf("non-reaped handler")
	}
}

func TestMemberList_InvokeAckHandler(t *testing.T) {
	m := &Memberlist{ackHandlers: make(map[uint32]*ackHandler)}

	// Does nothing
	m.invokeAckHandler(0)

	var b bool
	f := func() { b = true }
	m.setAckHandler(0, f, 10*time.Millisecond)

	// Should set b
	m.invokeAckHandler(0)
	if !b {
		t.Fatalf("b not set")
	}

	if _, ok := m.ackHandlers[0]; ok {
		t.Fatalf("non-reaped handler")
	}
}

func TestMemberList_AliveNode_NewNode(t *testing.T) {
	ch := make(chan *Node, 1)
	m := GetMemberlist(t)
	m.NotifyJoin(ch)

	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
	m.aliveNode(&a)

	if len(m.nodes) != 1 {
		t.Fatalf("should add node")
	}

	state, ok := m.nodeMap["test"]
	if !ok {
		t.Fatalf("should map node")
	}

	if state.Incarnation != 1 {
		t.Fatalf("bad incarnation")
	}
	if state.State != StateAlive {
		t.Fatalf("bad state")
	}
	if time.Now().Sub(state.StateChange) > time.Second {
		t.Fatalf("bad change delta")
	}

	// Check for a join message
	select {
	case join := <-ch:
		if join.Name != "test" {
			t.Fatalf("bad node name")
		}
	default:
		t.Fatalf("no join message")
	}
}

func TestMemberList_AliveNode_SuspectNode(t *testing.T) {
	ch := make(chan *Node, 1)
	m := GetMemberlist(t)

	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
	m.aliveNode(&a)

	// Listen only after first join
	m.NotifyJoin(ch)

	// Make suspect
	state := m.nodeMap["test"]
	state.State = StateSuspect
	state.StateChange = state.StateChange.Add(-time.Hour)

	// Old incarnation number, should not change
	m.aliveNode(&a)
	if state.State != StateSuspect {
		t.Fatalf("update with old incarnation!")
	}

	// Should reset to alive now
	a.Incarnation = 2
	m.aliveNode(&a)
	if state.State != StateAlive {
		t.Fatalf("no update with new incarnation!")
	}

	if time.Now().Sub(state.StateChange) > time.Second {
		t.Fatalf("bad change delta")
	}

	// Check for a no join message
	select {
	case <-ch:
		t.Fatalf("got bad join message")
	default:
	}
}

func TestMemberList_AliveNode_Idempotent(t *testing.T) {
	ch := make(chan *Node, 1)
	m := GetMemberlist(t)

	a := alive{Node: "test", Addr: []byte{127, 0, 0, 1}, Incarnation: 1}
	m.aliveNode(&a)

	// Listen only after first join
	m.NotifyJoin(ch)

	// Make suspect
	state := m.nodeMap["test"]
	stateTime := state.StateChange

	// Should reset to alive now
	a.Incarnation = 2
	m.aliveNode(&a)
	if state.State != StateAlive {
		t.Fatalf("non idempotent")
	}

	if stateTime != state.StateChange {
		t.Fatalf("should not change state")
	}

	// Check for a no join message
	select {
	case <-ch:
		t.Fatalf("got bad join message")
	default:
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"log"
	"math/rand"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	MAX_REPLY_DELAY_MS = 300000 // 5 minutes
)

type TwitterConnector struct {
	api *anaconda.TwitterApi
}

func NewTwitterConnector() (error, *TwitterConnector) {
	var (
		consumerSecret    string
		consumerKey       string
		accessToken       string
		accessTokenSecret string
	)
	// Get the environment variables for twitter api access
	consumerSecret = os.Getenv("TWITTER_CONSUMER_SECRET")
	consumerKey = os.Getenv("TWITTER_CONSUMER_KEY")
	accessTokenSecret = os.Getenv("TWITTER_ACCESS_TOKEN_SECRET")
	accessToken = os.Getenv("TWITTER_ACCESS_TOKEN")
	// If the environment variables are missing, we need to furnish them
	if consumerSecret == "" {
		return errors.New("TWITTER_CONSUMER_SECRET environment variable was missing"), nil
	}
	if consumerKey == "" {
		return errors.New("TWITTER_CONSUMER_KEY environment variable was missing"), nil
	}
	if accessToken == "" {
		return errors.New("TWITTER_ACCESS_TOKEN_SECRET environment variable was missing"), nil
	}
	if accessTokenSecret == "" {
		return errors.New("TWITTER_ACCESS_TOKEN environment variable was missing"), nil
	}
	// Create a client
	anaconda.SetConsumerKey(consumerKey)
	anaconda.SetConsumerSecret(consumerSecret)
	tc := TwitterConnector{
		api: anaconda.NewTwitterApi(accessToken, accessTokenSecret),
	}
	// Return the connector
	return nil, &tc
}

func (tc *TwitterConnector) listenForTweets() error {
	// Create parameters for the request
	params := url.Values{}
	params.Set("track", "#owlhacks,#owlhacks2015,hackathons,#hackru,#HackCWRU")
	// Get dat stream
	stream, err := tc.api.PublicStreamFilter(params)
	if err != nil {
		return err
	} else {
		for {
			select {
			case incomingStreamItem, ok := <-stream.C:
				if ok {
					// TODO make goroutines work
					tc.handleIncomingTweet(incomingStreamItem)
				} else {
					log.Fatalln("The stream closed suddenly :(")
				}
			}
		}
	}
}

func (tc *TwitterConnector) handleIncomingTweet(potentialTweet interface{}) {
	tweet, ok := potentialTweet.(anaconda.Tweet)
	if ok {
		fromHandle := tweet.User.ScreenName
		isNotRetweet := (tweet.RetweetedStatus == nil)
		if fromHandle != "owlhacks" && isNotRetweet {
			tweetId := tweet.Id
			tweetText := tweet.Text
			responseTweet, isPunified := punify(tweetText)
			// Prepare a random wait time, to create some drama
			waitTime := rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(MAX_REPLY_DELAY_MS)
			time.Sleep(time.Duration(waitTime) * time.Millisecond)
			// Favorite the tweet if its about Owlhacks
			if strings.Contains(tweetText, "owlhacks") || strings.Contains(tweetText, "Owlhacks") {
				tc.api.Favorite(tweetId)
				log.Println("Favorited tweet from @" + fromHandle)
			}
			// Only if we could figure out a punified version of the tweet, continue
			if isPunified {
				tweetId := tweet.Id
				fromName := tweet.User.Name
				// Send the response
				params := url.Values{}
				params.Set("in_reply_to_status_id", strconv.FormatInt(tweetId, 10))
				_, err := tc.api.PostTweet("@"+fromHandle+" \""+responseTweet+"\" #owled", params)
				if err != nil {
					log.Println("Could not post a reply:", err)
				} else {
					log.Println("New tweet from " + fromName + ":\n-> \"" + tweetText + "\"\n<- \"" + responseTweet + "\"\n")
				}
			}
		}
	} else {
		log.Println("Could not read the tweet")
	}
}
<commit_msg>fixed the conflict<commit_after>package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"log"
	"math/rand"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	MAX_REPLY_DELAY_MS = 300000 // 5 minutes
)

type TwitterConnector struct {
	api *anaconda.TwitterApi
}

func NewTwitterConnector() (error, *TwitterConnector) {
	var (
		consumerSecret    string
		consumerKey       string
		accessToken       string
		accessTokenSecret string
	)
	// Get the environment variables for twitter api access
	consumerSecret = os.Getenv("TWITTER_CONSUMER_SECRET")
	consumerKey = os.Getenv("TWITTER_CONSUMER_KEY")
	accessTokenSecret = os.Getenv("TWITTER_ACCESS_TOKEN_SECRET")
	accessToken = os.Getenv("TWITTER_ACCESS_TOKEN")
	// If the environment variables are missing, we need to furnish them
	if consumerSecret == "" {
		return errors.New("TWITTER_CONSUMER_SECRET environment variable was missing"), nil
	}
	if consumerKey == "" {
		return errors.New("TWITTER_CONSUMER_KEY environment variable was missing"), nil
	}
	if accessToken == "" {
		return errors.New("TWITTER_ACCESS_TOKEN_SECRET environment variable was missing"), nil
	}
	if accessTokenSecret == "" {
		return errors.New("TWITTER_ACCESS_TOKEN environment variable was missing"), nil
	}
	// Create a client
	anaconda.SetConsumerKey(consumerKey)
	anaconda.SetConsumerSecret(consumerSecret)
	tc := TwitterConnector{
		api: anaconda.NewTwitterApi(accessToken, accessTokenSecret),
	}
	// Return the connector
	return nil, &tc
}

func (tc *TwitterConnector) listenForTweets() error {
	// Create parameters for the request
	params := url.Values{}
	params.Set("track", "#owlhacks,#owlhacks2015,hackathon,hackathons,#hackru,#hackcwru")
	// Get dat stream
	stream, err := tc.api.PublicStreamFilter(params)
	if err != nil {
		return err
	} else {
		for {
			select {
			case incomingStreamItem, ok := <-stream.C:
				if ok {
					// TODO make goroutines work
					tc.handleIncomingTweet(incomingStreamItem)
				} else {
					log.Fatalln("The stream closed suddenly :(")
				}
			}
		}
	}
}

func (tc *TwitterConnector) handleIncomingTweet(potentialTweet interface{}) {
	tweet, ok := potentialTweet.(anaconda.Tweet)
	if ok {
		fromHandle := tweet.User.ScreenName
		isNotRetweet := (tweet.RetweetedStatus == nil)
		if fromHandle != "owlhacks" && isNotRetweet {
			tweetId := tweet.Id
			tweetText := tweet.Text
			responseTweet, isPunified := punify(tweetText)
			// Prepare a random wait time, to create some drama
			waitTime := rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(MAX_REPLY_DELAY_MS)
			time.Sleep(time.Duration(waitTime) * time.Millisecond)
			// Favorite the tweet if its about Owlhacks
			if strings.Contains(tweetText, "owlhacks") || strings.Contains(tweetText, "Owlhacks") {
				tc.api.Favorite(tweetId)
				log.Println("Favorited tweet from @" + fromHandle)
			}
			// Only if we could figure out a punified version of the tweet, continue
			if isPunified {
				tweetId := tweet.Id
				fromName := tweet.User.Name
				// Send the response
				params := url.Values{}
				params.Set("in_reply_to_status_id", strconv.FormatInt(tweetId, 10))
				_, err := tc.api.PostTweet("@"+fromHandle+" \""+responseTweet+"\" #owled", params)
				if err != nil {
					log.Println("Could not post a reply:", err)
				} else {
					log.Println("New tweet from " + fromName + ":\n-> \"" + tweetText + "\"\n<- \"" + responseTweet + "\"\n")
				}
			}
		}
	} else {
		log.Println("Could not read the tweet")
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"expvar"
	"fmt"
	"net/http"
	"net/http/pprof"

	"github.com/pressly/chi"
)

// Profiler is a convenient subrouter used for mounting net/http/pprof. ie.
//
//  func MyService() http.Handler {
//    r := chi.NewRouter()
//    // ..middlewares
//    r.Mount("/debug", profiler.Router())
//    // ..routes
//    return r
//  }
func Profiler() http.Handler {
	r := chi.NewRouter()
	r.Use(NoCache)

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, r.RequestURI+"/pprof/", 301)
	})
	r.HandleFunc("/pprof", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, r.RequestURI+"/", 301)
	})

	r.HandleFunc("/pprof/", pprof.Index)
	r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
	r.HandleFunc("/pprof/profile", pprof.Profile)
	r.HandleFunc("/pprof/symbol", pprof.Symbol)
	r.Handle("/pprof/block", pprof.Handler("block"))
	r.Handle("/pprof/heap", pprof.Handler("heap"))
	r.Handle("/pprof/goroutine", pprof.Handler("goroutine"))
	r.Handle("/pprof/threadcreate", pprof.Handler("threadcreate"))
	r.HandleFunc("/vars", expVars)

	return r
}

// Replicated from expvar.go as not public.
func expVars(w http.ResponseWriter, r *http.Request) {
	first := true
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	fmt.Fprintf(w, "{\n")
	expvar.Do(func(kv expvar.KeyValue) {
		if !first {
			fmt.Fprintf(w, ",\n")
		}
		first = false
		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
	})
	fmt.Fprintf(w, "\n}\n")
}
<commit_msg>Fix example in middleware.Profiler godoc<commit_after>package middleware

import (
	"expvar"
	"fmt"
	"net/http"
	"net/http/pprof"

	"github.com/pressly/chi"
)

// Profiler is a convenient subrouter used for mounting net/http/pprof. ie.
//
//  func MyService() http.Handler {
//    r := chi.NewRouter()
//    // ..middlewares
//    r.Mount("/debug", middleware.Profiler())
//    // ..routes
//    return r
//  }
func Profiler() http.Handler {
	r := chi.NewRouter()
	r.Use(NoCache)

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, r.RequestURI+"/pprof/", 301)
	})
	r.HandleFunc("/pprof", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, r.RequestURI+"/", 301)
	})

	r.HandleFunc("/pprof/", pprof.Index)
	r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
	r.HandleFunc("/pprof/profile", pprof.Profile)
	r.HandleFunc("/pprof/symbol", pprof.Symbol)
	r.Handle("/pprof/block", pprof.Handler("block"))
	r.Handle("/pprof/heap", pprof.Handler("heap"))
	r.Handle("/pprof/goroutine", pprof.Handler("goroutine"))
	r.Handle("/pprof/threadcreate", pprof.Handler("threadcreate"))
	r.HandleFunc("/vars", expVars)

	return r
}

// Replicated from expvar.go as not public.
func expVars(w http.ResponseWriter, r *http.Request) {
	first := true
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	fmt.Fprintf(w, "{\n")
	expvar.Do(func(kv expvar.KeyValue) {
		if !first {
			fmt.Fprintf(w, ",\n")
		}
		first = false
		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
	})
	fmt.Fprintf(w, "\n}\n")
}
<|endoftext|>


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

package migration

import (
	"io"
	"io/ioutil"
	"os"

	"github.com/juju/errors"
	"github.com/juju/juju/version"
	"github.com/juju/loggo"
	"github.com/juju/utils/set"
	"gopkg.in/juju/charm.v6-unstable"
	"gopkg.in/mgo.v2"

	"github.com/juju/juju/api"
	"github.com/juju/juju/core/description"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/storage"
	"github.com/juju/juju/state/toolstorage"
	"github.com/juju/juju/tools"
)

var logger = loggo.GetLogger("juju.migration")

// ExportModel creates a description.Model representation of the active model
// for the state instance, and returns the serialized version. Primarily here
// as a symetric method for ImportModel.
func ExportModel(st *state.State) ([]byte, error) {
	model, err := st.Export()
	if err != nil {
		return nil, errors.Trace(err)
	}
	bytes, err := description.Serialize(model)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return bytes, nil
}

// ImportModel deserializes a model description from the bytes, transforms
// the model config based on information from the controller model, and then
// imports that as a new database model.
func ImportModel(st *state.State, bytes []byte) (*state.Model, *state.State, error) {
	model, err := description.Deserialize(bytes)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerModel, err := st.ControllerModel()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerConfig, err := controllerModel.Config()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	model.UpdateConfig(controllerValues(controllerConfig))

	if err := updateConfigFromProvider(model, controllerConfig); err != nil {
		return nil, nil, errors.Trace(err)
	}

	dbModel, dbState, err := st.Import(model)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	return dbModel, dbState, nil
}

func controllerValues(config *config.Config) map[string]interface{} {
	result := make(map[string]interface{})

	result["state-port"] = config.StatePort()
	result["api-port"] = config.APIPort()
	// We ignore the second bool param from the CACert check as if there
	// wasn't a CACert, there is no way we'd be importing a new model
	// into the controller
	result["ca-cert"], _ = config.CACert()

	return result
}

func updateConfigFromProvider(model description.Model, controllerConfig *config.Config) error {
	newConfig, err := config.New(config.NoDefaults, model.Config())
	if err != nil {
		return errors.Trace(err)
	}

	provider, err := environs.New(newConfig)
	if err != nil {
		return errors.Trace(err)
	}

	updater, ok := provider.(environs.MigrationConfigUpdater)
	if !ok {
		return nil
	}

	model.UpdateConfig(updater.MigrationConfigUpdate(controllerConfig))
	return nil
}

// UploadBackend define the methods on *state.State that are needed for
// uploading the tools and charms from the current controller to a different
// controller.
type UploadBackend interface {
	Charm(*charm.URL) (*state.Charm, error)
	ModelUUID() string
	MongoSession() *mgo.Session
	ToolsStorage() (toolstorage.StorageCloser, error)
}

// CharmUploader defines a simple single method interface that is used to
// upload a charm to the target controller
type CharmUploader interface {
	UploadCharm(*charm.URL, io.ReadSeeker) (*charm.URL, error)
}

// ToolsUploader defines a simple single method interface that is used to
// upload tools to the target controller
type ToolsUploader interface {
	UploadTools(io.ReadSeeker, version.Binary, ...string) (*tools.Tools, error)
}

// UploadBinariesConfig provides all the configuration that the UploadBinaries
// function needs to operate. The functions are configurable for testing
// purposes. To construct the config with the default functions, use
// `NewUploadBinariesConfig`.
type UploadBinariesConfig struct {
	State  UploadBackend
	Model  description.Model
	Target api.Connection

	GetCharmUploader func(api.Connection) CharmUploader
	GetToolsUploader func(api.Connection) ToolsUploader

	GetStateStorage     func(UploadBackend) storage.Storage
	GetCharmStoragePath func(UploadBackend, *charm.URL) (string, error)
}

// NewUploadBinariesConfig constructs a `UploadBinariesConfig` with the default
// functions to get the uploaders for the target api connection, and functions
// used to get the charm data out of the database.
func NewUploadBinariesConfig(backend UploadBackend, model description.Model, target api.Connection) UploadBinariesConfig {
	return UploadBinariesConfig{
		State:  backend,
		Model:  model,
		Target: target,

		GetCharmUploader:    getCharmUploader,
		GetStateStorage:     getStateStorage,
		GetToolsUploader:    getToolsUploader,
		GetCharmStoragePath: getCharmStoragePath,
	}
}

// Validate makes sure that all the config values are non-nil.
func (c *UploadBinariesConfig) Validate() error {
	if c.State == nil {
		return errors.NotValidf("missing UploadBackend")
	}
	if c.Model == nil {
		return errors.NotValidf("missing Model")
	}
	if c.Target == nil {
		return errors.NotValidf("missing Target")
	}
	if c.GetCharmUploader == nil {
		return errors.NotValidf("missing GetCharmUploader")
	}
	if c.GetStateStorage == nil {
		return errors.NotValidf("missing GetStateStorage")
	}
	if c.GetToolsUploader == nil {
		return errors.NotValidf("missing GetToolsUploader")
	}
	if c.GetCharmStoragePath == nil {
		return errors.NotValidf("missing GetCharmStoragePath")
	}
	return nil
}

// UploadBinaries will send binaries stored in the source blobstore to
// the target controller.
func UploadBinaries(config UploadBinariesConfig) error {
	if err := config.Validate(); err != nil {
		return errors.Trace(err)
	}
	if err := uploadTools(config); err != nil {
		return errors.Trace(err)
	}

	if err := uploadCharms(config); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func getStateStorage(backend UploadBackend) storage.Storage {
	return storage.NewStorage(backend.ModelUUID(), backend.MongoSession())
}

func getToolsUploader(target api.Connection) ToolsUploader {
	return target.Client()
}

func getCharmUploader(target api.Connection) CharmUploader {
	return target.Client()
}

func uploadTools(config UploadBinariesConfig) error {
	storage, err := config.State.ToolsStorage()
	if err != nil {
		return errors.Trace(err)
	}
	defer storage.Close()

	usedVersions := getUsedToolsVersions(config.Model)
	toolsUploader := config.GetToolsUploader(config.Target)

	for toolsVersion := range usedVersions {
		logger.Debugf("send tools version %s to target", toolsVersion)
		_, reader, err := storage.Tools(toolsVersion)
		if err != nil {
			return errors.Trace(err)
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		// UploadTools encapsulates the HTTP POST necessary to send the tools
		// to the target API server.
		if _, err := toolsUploader.UploadTools(content, toolsVersion); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

func streamThroughTempFile(r io.Reader) (_ io.ReadSeeker, cleanup func(), err error) {
	tempFile, err := ioutil.TempFile("", "juju-tools")
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	defer func() {
		if err != nil {
			os.Remove(tempFile.Name())
		}
	}()
	_, err = io.Copy(tempFile, r)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	tempFile.Seek(0, 0)
	rmTempFile := func() {
		filename := tempFile.Name()
		tempFile.Close()
		os.Remove(filename)
	}

	return tempFile, rmTempFile, nil
}

func getUsedToolsVersions(model description.Model) map[version.Binary]bool {
	// Iterate through the model for all tools, and make a map of them.
	usedVersions := make(map[version.Binary]bool)
	// It is most likely that the preconditions will limit the number of
	// tools versions in use, but that is not depended on here.
	for _, machine := range model.Machines() {
		addToolsVersionForMachine(machine, usedVersions)
	}

	for _, service := range model.Services() {
		for _, unit := range service.Units() {
			tools := unit.Tools()
			usedVersions[tools.Version()] = true
		}
	}
	return usedVersions
}

func addToolsVersionForMachine(machine description.Machine, usedVersions map[version.Binary]bool) {
	tools := machine.Tools()
	usedVersions[tools.Version()] = true
	for _, container := range machine.Containers() {
		addToolsVersionForMachine(container, usedVersions)
	}
}

func uploadCharms(config UploadBinariesConfig) error {
	storage := config.GetStateStorage(config.State)
	usedCharms := getUsedCharms(config.Model)
	charmUploader := config.GetCharmUploader(config.Target)

	for _, charmUrl := range usedCharms.Values() {
		logger.Debugf("send charm %s to target", charmUrl)

		curl, err := charm.ParseURL(charmUrl)
		if err != nil {
			return errors.Annotate(err, "bad charm URL")
		}

		path, err := config.GetCharmStoragePath(config.State, curl)
		if err != nil {
			return errors.Trace(err)
		}

		reader, _, err := storage.Get(path)
		if err != nil {
			return errors.Annotate(err, "cannot get charm from storage")
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		if _, err := charmUploader.UploadCharm(curl, content); err != nil {
			return errors.Annotate(err, "cannot upload charm")
		}
	}
	return nil
}

func getUsedCharms(model description.Model) set.Strings {
	result := set.NewStrings()
	for _, service := range model.Services() {
		result.Add(service.CharmURL())
	}
	return result
}

func getCharmStoragePath(st UploadBackend, curl *charm.URL) (string, error) {
	ch, err := st.Charm(curl)
	if err != nil {
		return "", errors.Annotate(err, "cannot get charm from state")
	}

	return ch.StoragePath(), nil
}

// PrecheckBackend is implemented by *state.State but defined as an interface
// for easier testing.
type PrecheckBackend interface {
	NeedsCleanup() (bool, error)
}

// Precheck checks the database state to make sure that the preconditions
// for model migration are met.
func Precheck(backend PrecheckBackend) error {
	cleanupNeeded, err := backend.NeedsCleanup()
	if err != nil {
		return errors.Annotate(err, "precheck cleanups")
	}
	if cleanupNeeded {
		return errors.New("precheck failed: cleanup needed")
	}
	return nil
}
<commit_msg>migration: Have ExportModel take an interface instead of State<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package migration

import (
	"io"
	"io/ioutil"
	"os"

	"github.com/juju/errors"
	"github.com/juju/juju/version"
	"github.com/juju/loggo"
	"github.com/juju/utils/set"
	"gopkg.in/juju/charm.v6-unstable"
	"gopkg.in/mgo.v2"

	"github.com/juju/juju/api"
	"github.com/juju/juju/core/description"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/storage"
	"github.com/juju/juju/state/toolstorage"
	"github.com/juju/juju/tools"
)

var logger = loggo.GetLogger("juju.migration")

// StateExporter describes interface on state required to export a
// model.
type StateExporter interface {
	// Export generates an abstract representation of a model.
	Export() (description.Model, error)
}

// ExportModel creates a description.Model representation of the
// active model for StateExporter (typically a *state.State), and
// returns the serialized version. It provides the symmetric
// functionality to ImportModel.
func ExportModel(st StateExporter) ([]byte, error) {
	model, err := st.Export()
	if err != nil {
		return nil, errors.Trace(err)
	}
	bytes, err := description.Serialize(model)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return bytes, nil
}

// ImportModel deserializes a model description from the bytes, transforms
// the model config based on information from the controller model, and then
// imports that as a new database model.
func ImportModel(st *state.State, bytes []byte) (*state.Model, *state.State, error) {
	model, err := description.Deserialize(bytes)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerModel, err := st.ControllerModel()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	controllerConfig, err := controllerModel.Config()
	if err != nil {
		return nil, nil, errors.Trace(err)
	}

	model.UpdateConfig(controllerValues(controllerConfig))

	if err := updateConfigFromProvider(model, controllerConfig); err != nil {
		return nil, nil, errors.Trace(err)
	}

	dbModel, dbState, err := st.Import(model)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	return dbModel, dbState, nil
}

func controllerValues(config *config.Config) map[string]interface{} {
	result := make(map[string]interface{})

	result["state-port"] = config.StatePort()
	result["api-port"] = config.APIPort()
	// We ignore the second bool param from the CACert check as if there
	// wasn't a CACert, there is no way we'd be importing a new model
	// into the controller
	result["ca-cert"], _ = config.CACert()

	return result
}

func updateConfigFromProvider(model description.Model, controllerConfig *config.Config) error {
	newConfig, err := config.New(config.NoDefaults, model.Config())
	if err != nil {
		return errors.Trace(err)
	}

	provider, err := environs.New(newConfig)
	if err != nil {
		return errors.Trace(err)
	}

	updater, ok := provider.(environs.MigrationConfigUpdater)
	if !ok {
		return nil
	}

	model.UpdateConfig(updater.MigrationConfigUpdate(controllerConfig))
	return nil
}

// UploadBackend define the methods on *state.State that are needed for
// uploading the tools and charms from the current controller to a different
// controller.
type UploadBackend interface {
	Charm(*charm.URL) (*state.Charm, error)
	ModelUUID() string
	MongoSession() *mgo.Session
	ToolsStorage() (toolstorage.StorageCloser, error)
}

// CharmUploader defines a simple single method interface that is used to
// upload a charm to the target controller
type CharmUploader interface {
	UploadCharm(*charm.URL, io.ReadSeeker) (*charm.URL, error)
}

// ToolsUploader defines a simple single method interface that is used to
// upload tools to the target controller
type ToolsUploader interface {
	UploadTools(io.ReadSeeker, version.Binary, ...string) (*tools.Tools, error)
}

// UploadBinariesConfig provides all the configuration that the UploadBinaries
// function needs to operate. The functions are configurable for testing
// purposes. To construct the config with the default functions, use
// `NewUploadBinariesConfig`.
type UploadBinariesConfig struct {
	State  UploadBackend
	Model  description.Model
	Target api.Connection

	GetCharmUploader func(api.Connection) CharmUploader
	GetToolsUploader func(api.Connection) ToolsUploader

	GetStateStorage     func(UploadBackend) storage.Storage
	GetCharmStoragePath func(UploadBackend, *charm.URL) (string, error)
}

// NewUploadBinariesConfig constructs a `UploadBinariesConfig` with the default
// functions to get the uploaders for the target api connection, and functions
// used to get the charm data out of the database.
func NewUploadBinariesConfig(backend UploadBackend, model description.Model, target api.Connection) UploadBinariesConfig {
	return UploadBinariesConfig{
		State:  backend,
		Model:  model,
		Target: target,

		GetCharmUploader:    getCharmUploader,
		GetStateStorage:     getStateStorage,
		GetToolsUploader:    getToolsUploader,
		GetCharmStoragePath: getCharmStoragePath,
	}
}

// Validate makes sure that all the config values are non-nil.
func (c *UploadBinariesConfig) Validate() error {
	if c.State == nil {
		return errors.NotValidf("missing UploadBackend")
	}
	if c.Model == nil {
		return errors.NotValidf("missing Model")
	}
	if c.Target == nil {
		return errors.NotValidf("missing Target")
	}
	if c.GetCharmUploader == nil {
		return errors.NotValidf("missing GetCharmUploader")
	}
	if c.GetStateStorage == nil {
		return errors.NotValidf("missing GetStateStorage")
	}
	if c.GetToolsUploader == nil {
		return errors.NotValidf("missing GetToolsUploader")
	}
	if c.GetCharmStoragePath == nil {
		return errors.NotValidf("missing GetCharmStoragePath")
	}
	return nil
}

// UploadBinaries will send binaries stored in the source blobstore to
// the target controller.
func UploadBinaries(config UploadBinariesConfig) error {
	if err := config.Validate(); err != nil {
		return errors.Trace(err)
	}
	if err := uploadTools(config); err != nil {
		return errors.Trace(err)
	}

	if err := uploadCharms(config); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func getStateStorage(backend UploadBackend) storage.Storage {
	return storage.NewStorage(backend.ModelUUID(), backend.MongoSession())
}

func getToolsUploader(target api.Connection) ToolsUploader {
	return target.Client()
}

func getCharmUploader(target api.Connection) CharmUploader {
	return target.Client()
}

func uploadTools(config UploadBinariesConfig) error {
	storage, err := config.State.ToolsStorage()
	if err != nil {
		return errors.Trace(err)
	}
	defer storage.Close()

	usedVersions := getUsedToolsVersions(config.Model)
	toolsUploader := config.GetToolsUploader(config.Target)

	for toolsVersion := range usedVersions {
		logger.Debugf("send tools version %s to target", toolsVersion)
		_, reader, err := storage.Tools(toolsVersion)
		if err != nil {
			return errors.Trace(err)
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		// UploadTools encapsulates the HTTP POST necessary to send the tools
		// to the target API server.
		if _, err := toolsUploader.UploadTools(content, toolsVersion); err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}

func streamThroughTempFile(r io.Reader) (_ io.ReadSeeker, cleanup func(), err error) {
	tempFile, err := ioutil.TempFile("", "juju-tools")
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	defer func() {
		if err != nil {
			os.Remove(tempFile.Name())
		}
	}()
	_, err = io.Copy(tempFile, r)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	tempFile.Seek(0, 0)
	rmTempFile := func() {
		filename := tempFile.Name()
		tempFile.Close()
		os.Remove(filename)
	}

	return tempFile, rmTempFile, nil
}

func getUsedToolsVersions(model description.Model) map[version.Binary]bool {
	// Iterate through the model for all tools, and make a map of them.
	usedVersions := make(map[version.Binary]bool)
	// It is most likely that the preconditions will limit the number of
	// tools versions in use, but that is not depended on here.
	for _, machine := range model.Machines() {
		addToolsVersionForMachine(machine, usedVersions)
	}

	for _, service := range model.Services() {
		for _, unit := range service.Units() {
			tools := unit.Tools()
			usedVersions[tools.Version()] = true
		}
	}
	return usedVersions
}

func addToolsVersionForMachine(machine description.Machine, usedVersions map[version.Binary]bool) {
	tools := machine.Tools()
	usedVersions[tools.Version()] = true
	for _, container := range machine.Containers() {
		addToolsVersionForMachine(container, usedVersions)
	}
}

func uploadCharms(config UploadBinariesConfig) error {
	storage := config.GetStateStorage(config.State)
	usedCharms := getUsedCharms(config.Model)
	charmUploader := config.GetCharmUploader(config.Target)

	for _, charmUrl := range usedCharms.Values() {
		logger.Debugf("send charm %s to target", charmUrl)

		curl, err := charm.ParseURL(charmUrl)
		if err != nil {
			return errors.Annotate(err, "bad charm URL")
		}

		path, err := config.GetCharmStoragePath(config.State, curl)
		if err != nil {
			return errors.Trace(err)
		}

		reader, _, err := storage.Get(path)
		if err != nil {
			return errors.Annotate(err, "cannot get charm from storage")
		}
		defer reader.Close()

		content, cleanup, err := streamThroughTempFile(reader)
		if err != nil {
			return errors.Trace(err)
		}
		defer cleanup()

		if _, err := charmUploader.UploadCharm(curl, content); err != nil {
			return errors.Annotate(err, "cannot upload charm")
		}
	}
	return nil
}

func getUsedCharms(model description.Model) set.Strings {
	result := set.NewStrings()
	for _, service := range model.Services() {
		result.Add(service.CharmURL())
	}
	return result
}

func getCharmStoragePath(st UploadBackend, curl *charm.URL) (string, error) {
	ch, err := st.Charm(curl)
	if err != nil {
		return "", errors.Annotate(err, "cannot get charm from state")
	}

	return ch.StoragePath(), nil
}

// PrecheckBackend is implemented by *state.State but defined as an interface
// for easier testing.
type PrecheckBackend interface {
	NeedsCleanup() (bool, error)
}

// Precheck checks the database state to make sure that the preconditions
// for model migration are met.
func Precheck(backend PrecheckBackend) error {
	cleanupNeeded, err := backend.NeedsCleanup()
	if err != nil {
		return errors.Annotate(err, "precheck cleanups")
	}
	if cleanupNeeded {
		return errors.New("precheck failed: cleanup needed")
	}
	return nil
}
<|endoftext|>


<commit_before>package plainoperator

//
// import (
// 	"connectordb/streamdb/datastream"
// 	"connectordb/streamdb/operator/messenger"
// 	"connectordb/streamdb/users"
// 	"connectordb/streamdb/util"
// 	"strings"
//
// 	"github.com/nats-io/nats"
// 	"github.com/nu7hatch/gouuid"
// )
//
// //SetAdmin does exactly what it claims. It works on both users and devices
// func (o *PlainOperator) SetAdmin(path string, isadmin bool) error {
// 	switch strings.Count(path, "/") {
// 	default:
// 		return util.ErrBadPath
// 	case 0:
// 		u, err := o.ReadUser(path)
// 		if err != nil {
// 			return err
// 		}
// 		u.Admin = isadmin
// 		return o.UpdateUser(u)
// 	case 1:
// 		dev, err := o.ReadDevice(path)
// 		if err != nil {
// 			return err
// 		}
// 		dev.IsAdmin = isadmin
// 		return o.UpdateDevice(dev)
// 	}
// }
//
// //Subscribe given a path, attempts to subscribe to it and its childrens
// func (o *PlainOperator) Subscribe(path string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	switch strings.Count(path, "/") {
// 	default:
// 		return o.SubscribeStream(path, chn)
// 	case 0:
// 		return o.SubscribeUser(path, chn)
// 	case 1:
// 		return o.SubscribeDevice(path, chn)
// 	}
// }
//
// //ChangeUserPassword changes the password for the given user
// func (o *PlainOperator) ChangeUserPassword(username, newpass string) error {
// 	u, err := o.ReadUser(username)
// 	if err != nil {
// 		return err
// 	}
// 	u.SetNewPassword(newpass)
// 	return o.UpdateUser(u)
// }
//
// //DeleteUser deletes a user given the user's name
// func (o *PlainOperator) DeleteUser(username string) error {
// 	u, err := o.ReadUser(username)
// 	if err != nil {
// 		return err
// 	}
// 	return o.DeleteUserByID(u.UserId)
// }
//
// //ReadAllDevices for the given user
// func (o *PlainOperator) ReadAllDevices(username string) ([]users.Device, error) {
// 	u, err := o.ReadUser(username)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.ReadAllDevicesByUserID(u.UserId)
// }
//
// // ReadDevice reads the given device
// func (o *PlainOperator) ReadDevice(devicepath string) (*users.Device, error) {
// 	//Apparently not. Get the device from userdb
// 	usrname, devname, err := util.SplitDevicePath(devicepath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	u, err := o.ReadUser(usrname)
// 	if err != nil {
// 		return nil, err
// 	}
// 	dev, err := o.ReadDeviceByUserID(u.UserId, devname)
// 	return dev, err
// }
//
/**
//ReadStream reads the given stream
func (o *PlainOperator) ReadStream(streampath string) (*users.Stream, error) {
	//Make sure that substreams are stripped from read
	_, devicepath, streampath, streamname, _, err := util.SplitStreamPath(streampath)
	if err != nil {
		return nil, err
	}

	dev, err := o.ReadDevice(devicepath)
	if err != nil {
		return nil, err
	}
	return o.Userdb.ReadStreamByDeviceIdAndName(dev.DeviceId, streamname)
}**/

//
// //CreateDevice creates a new device at the given path
// func (o *PlainOperator) CreateDevice(devicepath string) error {
// 	userName, deviceName, err := util.SplitDevicePath(devicepath)
// 	if err != nil {
// 		return err
// 	}
// 	u, err := o.ReadUser(userName)
// 	if err != nil {
// 		return err
// 	}
//
// 	return o.CreateDeviceByUserID(u.UserId, deviceName)
// }
//
// //ChangeDeviceAPIKey generates a new api key for the given device, and returns the key
// func (o *PlainOperator) ChangeDeviceAPIKey(devicepath string) (apikey string, err error) {
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return "", err
// 	}
// 	newkey, err := uuid.NewV4()
// 	if err != nil {
// 		return "", err
// 	}
// 	dev.ApiKey = newkey.String()
// 	return dev.ApiKey, o.UpdateDevice(dev)
// }
//
// //DeleteDevice deletes an existing device
// func (o *PlainOperator) DeleteDevice(devicepath string) error {
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return err //Workaround for #81
// 	}
// 	return o.DeleteDeviceByID(dev.DeviceId)
// }
//
// //ReadAllStreams reads all the streams for the given device
// func (o *PlainOperator) ReadAllStreams(devicepath string) ([]users.Stream, error) {
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.ReadAllStreamsByDeviceID(dev.DeviceId)
// }
//
// //CreateStream makes a new stream
// func (o *PlainOperator) CreateStream(streampath, jsonschema string) error {
// 	_, devicepath, _, streamname, _, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return err
// 	}
// 	return o.CreateStreamByDeviceID(dev.DeviceId, streamname, jsonschema)
// }
//
// //DeleteStream deletes the given stream given its path
// func (o *PlainOperator) DeleteStream(streampath string) error {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	s, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	return o.DeleteStreamByID(s.StreamId, substream)
// }
//
// //LengthStream returns the total number of datapoints in the given stream
// func (o *PlainOperator) LengthStream(streampath string) (int64, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	return o.LengthStreamByID(strm.StreamId, substream)
// }
//
// //TimeToIndexStream returns the index closest to the given timestamp
// func (o *PlainOperator) TimeToIndexStream(streampath string, time float64) (int64, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	return o.TimeToIndexStreamByID(strm.StreamId, substream, time)
// }
//
// //InsertStream inserts the given array of datapoints into the given stream.
// func (o *PlainOperator) InsertStream(streampath string, data datastream.DatapointArray, restamp bool) error {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	return o.InsertStreamByID(strm.StreamId, substream, data, restamp)
// }
//
// //GetStreamTimeRange Reads the given stream by time range
// func (o *PlainOperator) GetStreamTimeRange(streampath string, t1 float64, t2 float64, limit int64) (datastream.DataRange, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.GetStreamTimeRangeByID(strm.StreamId, substream, t1, t2, limit)
// }
//
// //GetStreamIndexRange Reads the given stream by index range
// func (o *PlainOperator) GetStreamIndexRange(streampath string, i1 int64, i2 int64) (datastream.DataRange, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.GetStreamIndexRangeByID(strm.StreamId, substream, i1, i2)
// }
//
// //SubscribeUser subscribes to everything the user does
// func (o *PlainOperator) SubscribeUser(username string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	usr, err := o.ReadUser(username)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.SubscribeUserByID(usr.UserId, chn)
// }
//
// //SubscribeDevice subscribes to everythnig the device does
// func (o *PlainOperator) SubscribeDevice(devpath string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	dev, err := o.ReadDevice(devpath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.SubscribeDeviceByID(dev.DeviceId, chn)
// }
//
// //SubscribeStream subscribes to the given stream
// func (o *PlainOperator) SubscribeStream(streampath string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.SubscribeStreamByID(strm.StreamId, substream, chn)
// }
<commit_msg>Removed more commented out code<commit_after><|endoftext|>