<commit_before>package minion

import (
	"os"
	"os/signal"
	"log"
	"time"
	"strings"
	"strconv"
	"path/filepath"
	"encoding/json"

	"code.google.com/p/go-uuid/uuid"
	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/client"
)

// Root keyspace in etcd
const etcdKeySpace = "/gru"

// Etcd Minion
type EtcdMinion struct {
	// Name of this minion
	Name string

	// Minion root node in etcd
	MinionRootDir string

	// Minion queue node in etcd
	QueueDir string

	// Root node for results in etcd
	//ResultRootDir string

	// Root node for classifiers in etcd
	ClassifierDir string

	// Minion unique identifier
	UUID uuid.UUID

	// KeysAPI client to etcd
	KAPI client.KeysAPI
}

// Etcd minion task
type EtcdTask struct {
	// Command to be executed by the minion
	Command string

	// Time when the command was sent for processing
	Timestamp int64

	// ID of task
	// Task Node == task ID ?
}

func NewEtcdTask(command string, timestamp int64) MinionTask {
	t := &EtcdTask{
		Command: command,
		Timestamp: timestamp,
	}

	return t
}

// Gets the task command to be executed
func (t *EtcdTask) GetCommand() (string, error) {
	return t.Command, nil
}

// Returns the time a task has been received for processing
func (t *EtcdTask) GetTimestamp() (int64, error) {
	return t.Timestamp, nil
}

// Processes a task
func (t *EtcdTask) Process() error {
	command := t.GetCommand()
	log.Printf("Processing task: %s\n", command)

	err := t.Process()

	return nil
}

// Create a new minion
func NewEtcdMinion(name string, kapi client.KeysAPI) Minion {
	minionUUID := uuid.NewSHA1(uuid.NameSpace_DNS, []byte(name))
	minionRootDir := filepath.Join(etcdKeySpace, "minion", minionUUID.String())
	queueDir := filepath.Join(minionRootDir, "queue")
//	resultDir := filepath.Join(...)
	classifierDir := filepath.Join(minionRootDir, "classifier")

	log.Printf("Created minion with uuid %s\n", minionUUID)

	m := &EtcdMinion{
		Name: name,
		MinionRootDir: minionRootDir,
		QueueDir: queueDir,
//		ResultRootDir: resultRootDir,
		ClassifierDir: classifierDir,
		UUID: minionUUID,
		KAPI: kapi,
	}

	return m
}

// Get the minion UUID
func (m *EtcdMinion) GetUUID() uuid.UUID {
	return m.UUID
}

// Get the human-readable name of the minion
func (m *EtcdMinion) GetName() (string, error) {
	return m.Name, nil
}

// Set the human-readable name of the minion
func (m *EtcdMinion) SetName(name string) error {
	key := filepath.Join(m.MinionRootDir, "name")
	opts := &client.SetOptions{
		PrevExist: client.PrevIgnore,
	}

	_, err := m.KAPI.Set(context.Background(), key, m.Name, opts)

	return err
}

// Set the time the minion was last seen in seconds since the Epoch
func (m *EtcdMinion) SetLastseen(s int64) error {
	key := filepath.Join(m.MinionRootDir, "lastseen")
	lastseen := strconv.FormatInt(s, 10)
	opts := &client.SetOptions{
		PrevExist: client.PrevIgnore,
	}

	_, err := m.KAPI.Set(context.Background(), key, lastseen, opts)

	return err
}

// Get classifier for a minion
func (m *EtcdMinion) GetClassifier(key string) (MinionClassifier, error) {
	valueKey := filepath.Join(m.ClassifierDir, key, "value")
	descriptionKey := filepath.Join(m.ClassifierDir, key, "description")

	// Get value
	resp, err := m.KAPI.Get(context.Background(), valueKey, nil)
	if err != nil {
		return &SimpleClassifier{}, err
	}
	value := resp.Node.Value

	// Get description
	resp, err = m.KAPI.Get(context.Background(), descriptionKey, nil)
	if err != nil {
		return &SimpleClassifier{}, nil
	}
	description := resp.Node.Value

	c := NewSimpleClassifier(key, description, value)

	return c, nil
}

// Classify a minion with a given key and value
func (m *EtcdMinion) SetClassifier(c MinionClassifier) error {
	opts := &client.SetOptions{
		PrevExist: client.PrevIgnore,
		TTL: MinionClassifierTTL,
	}

	// Get classifier values
	key, err := c.GetKey()
	description, err := c.GetDescription()
	value, err := c.GetValue(m)

	if err != nil {
		log.Printf("Failed to classify %s\n", key)
		return err
	}

	// TODO: Use JSON object for the classifier value/description/etc

	// Set classifier value
	valueKey := filepath.Join(m.ClassifierDir, key, "value")
	_, err = m.KAPI.Set(context.Background(), valueKey, value, opts)

	if err != nil {
		return err
	}

	// Set classifier description
	descriptionKey := filepath.Join(m.ClassifierDir, key, "description")
	_, err = m.KAPI.Set(context.Background(), descriptionKey, description, opts)

	if err != nil {
		return err
	}

	return nil
}

// Runs periodic jobs such as refreshing classifiers and updating lastseen
func (m *EtcdMinion) Refresh(ticker *time.Ticker) error {
	for {
		// Update classifiers
		for _, classifier := range ClassifierRegistry {
			m.SetClassifier(classifier)
		}

		// Update lastseen time
		now := time.Now().Unix()
		err := m.SetLastseen(now)
		if err != nil {
			log.Printf("Failed to update lastseen time: %s\n", err)
		}

		<- ticker.C
	}

	return nil
}

// Unmarshals task from etcd and removes it from the queue
func UnmarshalEtcdTask(node *client.Node) (*EtcdTask, error) {
	var task *EtcdTask = new(EtcdTask)
	err := json.Unmarshal([]byte(node.Value), &task)

	if err != nil {
		log.Printf("Invalid task: key: %s\n", node.Key)
		log.Printf("Invalid task: value: %s\n", node.Value)
		log.Printf("Invalid task: error: %s\n", err)
	}

	return task, err
}

// Monitors etcd for new tasks for processing
func (m *EtcdMinion) TaskListener(c chan<- MinionTask) error {
	log.Printf("Starting task listener")

	watcherOpts := &client.WatcherOptions{
		Recursive: true,
	}
	watcher := m.KAPI.Watcher(m.QueueDir, watcherOpts)

	for {
		resp, err := watcher.Next(context.Background())
		if err != nil {
			log.Printf("Failed to read task: %s\n", err)
			continue
		}

		// Ignore "delete" events when removing a task from the queue
		action := strings.ToLower(resp.Action)
		if strings.EqualFold(action, "delete") {
			continue
		}

		task, err := UnmarshalEtcdTask(resp.Node)
		m.KAPI.Delete(context.Background(), resp.Node.Key, nil)

		if err != nil {
			continue
		}

		c <- task
	}

	return nil
}

// Processes new tasks
func (m *EtcdMinion) TaskRunner(c <-chan MinionTask) error {
	for {
		task := <-c:
		task.Process()
	}
}

// Checks for any tasks in backlog
func (m *EtcdMinion) CheckForBacklog(c chan<- MinionTask) error {
	opts := &client.GetOptions{
		Recursive: true,
		Sort: true,
	}

	// Get backlog tasks if any
	resp, err := m.KAPI.Get(context.Background(), m.QueueDir, opts)
	if err != nil {
		return nil
	}

	backlog := resp.Node.Nodes

	if len(backlog) == 0 {
		// No backlog tasks found
		return nil
	}

	log.Printf("Found %d tasks in backlog", len(backlog))
	for _, node := range backlog {
		task, err := UnmarshalEtcdTask(node)
		m.KAPI.Delete(context.Background(), node.Key, nil)

		if err != nil {
			continue
		}

		c <- task
	}

	return nil
}

// Main entry point of the minion
func (m *EtcdMinion) Serve() error {
	// Channel on which we send the quit signal
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt)

	// Start the periodic runner
	ticker := time.NewTicker(time.Minute * 1)
	go m.Refresh(ticker)

	// Check for backlog tasks and start task listener and runner
	tasks := make(chan MinionTask)
	go m.TaskListener(tasks)
	go m.CheckForBacklog(tasks)
	go m.TaskRunner(tasks)

	// Block until a signal is received
	s := <-quit
	log.Printf("Received %s signal, shutting down", s)
	close(quit)
	close(tasks)

	return nil
}

<commit_msg>Typo fixes<commit_after>package minion

import (
	"os"
	"os/signal"
	"log"
	"time"
	"strings"
	"strconv"
	"path/filepath"
	"encoding/json"

	"code.google.com/p/go-uuid/uuid"
	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/client"
)

// Root keyspace in etcd
const etcdKeySpace = "/gru"

// Etcd Minion
type EtcdMinion struct {
	// Name of this minion
	Name string

	// Minion root node in etcd
	MinionRootDir string

	// Minion queue node in etcd
	QueueDir string

	// Root node for results in etcd
	//ResultRootDir string

	// Root node for classifiers in etcd
	ClassifierDir string

	// Minion unique identifier
	UUID uuid.UUID

	// KeysAPI client to etcd
	KAPI client.KeysAPI
}

// Etcd minion task
type EtcdTask struct {
	// Command to be executed by the minion
	Command string

	// Time when the command was sent for processing
	Timestamp int64

	// ID of task
	// Task Node == task ID ?
}

func NewEtcdTask(command string, timestamp int64) MinionTask {
	t := &EtcdTask{
		Command: command,
		Timestamp: timestamp,
	}

	return t
}

// Gets the task command to be executed
func (t *EtcdTask) GetCommand() (string, error) {
	return t.Command, nil
}

// Returns the time a task has been received for processing
func (t *EtcdTask) GetTimestamp() (int64, error) {
	return t.Timestamp, nil
}

// Processes a task
func (t *EtcdTask) Process() error {
	command, _ := t.GetCommand()
	log.Printf("Processing task: %s\n", command)

	err := t.Process()

	return err
}

// Create a new minion
func NewEtcdMinion(name string, kapi client.KeysAPI) Minion {
	minionUUID := uuid.NewSHA1(uuid.NameSpace_DNS, []byte(name))
	minionRootDir := filepath.Join(etcdKeySpace, "minion", minionUUID.String())
	queueDir := filepath.Join(minionRootDir, "queue")
//	resultDir := filepath.Join(...)
	classifierDir := filepath.Join(minionRootDir, "classifier")

	log.Printf("Created minion with uuid %s\n", minionUUID)

	m := &EtcdMinion{
		Name: name,
		MinionRootDir: minionRootDir,
		QueueDir: queueDir,
//		ResultRootDir: resultRootDir,
		ClassifierDir: classifierDir,
		UUID: minionUUID,
		KAPI: kapi,
	}

	return m
}

// Get the minion UUID
func (m *EtcdMinion) GetUUID() uuid.UUID {
	return m.UUID
}

// Get the human-readable name of the minion
func (m *EtcdMinion) GetName() (string, error) {
	return m.Name, nil
}

// Set the human-readable name of the minion
func (m *EtcdMinion) SetName(name string) error {
	key := filepath.Join(m.MinionRootDir, "name")
	opts := &client.SetOptions{
		PrevExist: client.PrevIgnore,
	}

	_, err := m.KAPI.Set(context.Background(), key, m.Name, opts)

	return err
}

// Set the time the minion was last seen in seconds since the Epoch
func (m *EtcdMinion) SetLastseen(s int64) error {
	key := filepath.Join(m.MinionRootDir, "lastseen")
	lastseen := strconv.FormatInt(s, 10)
	opts := &client.SetOptions{
		PrevExist: client.PrevIgnore,
	}

	_, err := m.KAPI.Set(context.Background(), key, lastseen, opts)

	return err
}

// Get classifier for a minion
func (m *EtcdMinion) GetClassifier(key string) (MinionClassifier, error) {
	valueKey := filepath.Join(m.ClassifierDir, key, "value")
	descriptionKey := filepath.Join(m.ClassifierDir, key, "description")

	// Get value
	resp, err := m.KAPI.Get(context.Background(), valueKey, nil)
	if err != nil {
		return &SimpleClassifier{}, err
	}
	value := resp.Node.Value

	// Get description
	resp, err = m.KAPI.Get(context.Background(), descriptionKey, nil)
	if err != nil {
		return &SimpleClassifier{}, nil
	}
	description := resp.Node.Value

	c := NewSimpleClassifier(key, description, value)

	return c, nil
}

// Classify a minion with a given key and value
func (m *EtcdMinion) SetClassifier(c MinionClassifier) error {
	opts := &client.SetOptions{
		PrevExist: client.PrevIgnore,
		TTL: MinionClassifierTTL,
	}

	// Get classifier values
	key, err := c.GetKey()
	description, err := c.GetDescription()
	value, err := c.GetValue(m)

	if err != nil {
		log.Printf("Failed to classify %s\n", key)
		return err
	}

	// TODO: Use JSON object for the classifier value/description/etc

	// Set classifier value
	valueKey := filepath.Join(m.ClassifierDir, key, "value")
	_, err = m.KAPI.Set(context.Background(), valueKey, value, opts)

	if err != nil {
		return err
	}

	// Set classifier description
	descriptionKey := filepath.Join(m.ClassifierDir, key, "description")
	_, err = m.KAPI.Set(context.Background(), descriptionKey, description, opts)

	if err != nil {
		return err
	}

	return nil
}

// Runs periodic jobs such as refreshing classifiers and updating lastseen
func (m *EtcdMinion) Refresh(ticker *time.Ticker) error {
	for {
		// Update classifiers
		for _, classifier := range ClassifierRegistry {
			m.SetClassifier(classifier)
		}

		// Update lastseen time
		now := time.Now().Unix()
		err := m.SetLastseen(now)
		if err != nil {
			log.Printf("Failed to update lastseen time: %s\n", err)
		}

		<- ticker.C
	}

	return nil
}

// Unmarshals task from etcd and removes it from the queue
func UnmarshalEtcdTask(node *client.Node) (*EtcdTask, error) {
	var task *EtcdTask = new(EtcdTask)
	err := json.Unmarshal([]byte(node.Value), &task)

	if err != nil {
		log.Printf("Invalid task: key: %s\n", node.Key)
		log.Printf("Invalid task: value: %s\n", node.Value)
		log.Printf("Invalid task: error: %s\n", err)
	}

	return task, err
}

// Monitors etcd for new tasks for processing
func (m *EtcdMinion) TaskListener(c chan<- MinionTask) error {
	log.Printf("Starting task listener")

	watcherOpts := &client.WatcherOptions{
		Recursive: true,
	}
	watcher := m.KAPI.Watcher(m.QueueDir, watcherOpts)

	for {
		resp, err := watcher.Next(context.Background())
		if err != nil {
			log.Printf("Failed to read task: %s\n", err)
			continue
		}

		// Ignore "delete" events when removing a task from the queue
		action := strings.ToLower(resp.Action)
		if strings.EqualFold(action, "delete") {
			continue
		}

		task, err := UnmarshalEtcdTask(resp.Node)
		m.KAPI.Delete(context.Background(), resp.Node.Key, nil)

		if err != nil {
			continue
		}

		c <- task
	}

	return nil
}

// Processes new tasks
func (m *EtcdMinion) TaskRunner(c <-chan MinionTask) error {
	for {
		task := <-c
		task.Process()
	}
}

// Checks for any tasks in backlog
func (m *EtcdMinion) CheckForBacklog(c chan<- MinionTask) error {
	opts := &client.GetOptions{
		Recursive: true,
		Sort: true,
	}

	// Get backlog tasks if any
	resp, err := m.KAPI.Get(context.Background(), m.QueueDir, opts)
	if err != nil {
		return nil
	}

	backlog := resp.Node.Nodes

	if len(backlog) == 0 {
		// No backlog tasks found
		return nil
	}

	log.Printf("Found %d tasks in backlog", len(backlog))
	for _, node := range backlog {
		task, err := UnmarshalEtcdTask(node)
		m.KAPI.Delete(context.Background(), node.Key, nil)

		if err != nil {
			continue
		}

		c <- task
	}

	return nil
}

// Main entry point of the minion
func (m *EtcdMinion) Serve() error {
	// Channel on which we send the quit signal
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt)

	// Start the periodic runner
	ticker := time.NewTicker(time.Minute * 1)
	go m.Refresh(ticker)

	// Check for backlog tasks and start task listener and runner
	tasks := make(chan MinionTask)
	go m.TaskListener(tasks)
	go m.CheckForBacklog(tasks)
	go m.TaskRunner(tasks)

	// Block until a signal is received
	s := <-quit
	log.Printf("Received %s signal, shutting down", s)
	close(quit)
	close(tasks)

	return nil
}

<|endoftext|>


<commit_before>// errchk $G -e $D/$F.go

// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

type xyz struct {
    ch chan
} // ERROR "unexpected } in channel type"

func Foo(y chan) { // ERROR "unexpected \) in channel type"
}

func Bar(x chan, y int) { // ERROR "unexpected comma in channel type"
}
<commit_msg>test: match gccgo error messages for syntax/chan.go.<commit_after>// errchk $G -e $D/$F.go

// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

type xyz struct {
    ch chan
} // ERROR "unexpected .*}.* in channel type"

func Foo(y chan) { // ERROR "unexpected .*\).* in channel type"
}

func Bar(x chan, y int) { // ERROR "unexpected comma in channel type"
}
<|endoftext|>


<commit_before>package model

import (
	"gogogo/ai"
	"fmt"
	"net/http"
	"database/sql"
	"github.com/mattn/sql-lite3"
)

//Main handler for requests
func Handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "You have reached %s\n", r.URL.Path[1:]);
	//Find gameID in database
		//Send game via JSON if found
	//Otherwise create new game
		//Send new game via JSON
	//Deal with POST requests for moves
}

//Process board
func processBoard() {
	//Processes the current game state
	//Takes out pieces as needed
}

func ServerStart() {
	http.HandleFunc("/", Handler);
	http.ListenAndServe(":8080", nil);
}

//TODO:
//Database work<commit_msg>started doing handlers<commit_after>package model

import (
	"gogogo/ai"
	"html/template"
	"net/http"
	"database/sql"
	"github.com/mattn/sql-lite3"
)

//Handler to create or load game
func gameHandler(w http.ResponseWriter, r *http.Request) {
	//Find gameID in database
		//Send game via JSON if found
	//Otherwise create new game
		//Send new game via JSON
}

//Handler for moves
func moveHandler(w http.ResponseWriter, r *http.Request) {
	//Handle moves as needed
	//Refresh view
}

func ServerStart() {
	http.HandleFunc("/game/", gameHandler);
	http.HandleFunc("/game/move/", moveHandler);
	http.ListenAndServe(":8080", nil);
}

//TODO:
//Database work<|endoftext|>


<commit_before>package ec2

import (
	"fmt"
	"io"
	"launchpad.net/goamz/ec2"
	"launchpad.net/goamz/s3"
	"launchpad.net/juju/go/environs"
	"sync"
)

func init() {
	environs.RegisterProvider("ec2", environProvider{})
}

type environProvider struct{}

var _ environs.EnvironProvider = environProvider{}

type environ struct {
	name             string
	config           *providerConfig
	ec2              *ec2.EC2
	s3               *s3.S3
	checkBucket      sync.Once
	checkBucketError error
}

var _ environs.Environ = (*environ)(nil)

type instance struct {
	*ec2.Instance
}

var _ environs.Instance = (*instance)(nil)

func (inst *instance) Id() string {
	return inst.InstanceId
}

func (inst *instance) DNSName() string {
	return inst.Instance.DNSName
}

func (environProvider) Open(name string, config interface{}) (e environs.Environ, err error) {
	cfg := config.(*providerConfig)
	if Regions[cfg.region].EC2Endpoint == "" {
		return nil, fmt.Errorf("no ec2 endpoint found for region %q, opening %q", cfg.region, name)
	}
	return &environ{
		name:   name,
		config: cfg,
		ec2:    ec2.New(cfg.auth, Regions[cfg.region]),
		s3:     s3.New(cfg.auth, Regions[cfg.region]),
	}, nil
}

func (e *environ) findBootstrapMachine() (environs.Instance, error) {
	_, err := e.Instances()
	if err != nil {
		return nil, fmt.Errorf("cannot list machines: %v", err)
	}
	return nil, nil
}

func (e *environ) zookeeperAddrs() ([]string, error) {
	return nil, fmt.Errorf("not implemented zookeeper addtrs")
}

func (e *environ) Bootstrap() error {
	addrs, err := e.zookeeperAddrs()
	if err != nil {
		return fmt.Errorf("cannot get zookeeper machine addresses: %v", err)
	}
	if len(addrs) > 0 {
		return fmt.Errorf("environment is already bootstrapped")
	}
	_, err = e.startInstance(0, true)
	return err
}

func (e *environ) StartInstance(machineId int) (environs.Instance, error) {
	if machineId <= 0 {
		panic(fmt.Errorf("StartInstance:invalid machine id: %d", machineId))
	}
	return e.startInstance(machineId, false)
}

// startInstance is the internal version of StartInstance, used by Bootstrap
// as well as via StartInstance itself. If master is true, a bootstrap
// instance will be started.
func (e *environ) startInstance(machineId int, master bool) (environs.Instance, error) {
	image, err := FindImageSpec(DefaultImageConstraint)
	if err != nil {
		return nil, fmt.Errorf("cannot find image: %v", err)
	}
	groups, err := e.setUpGroups(machineId)
	if err != nil {
		return nil, fmt.Errorf("cannot set up groups: %v", err)
	}
	instances, err := e.ec2.RunInstances(&ec2.RunInstances{
		ImageId:        image.ImageId,
		MinCount:       1,
		MaxCount:       1,
		UserData:       nil,
		InstanceType:   "m1.small",
		SecurityGroups: groups,
	})
	if err != nil {
		return nil, fmt.Errorf("cannot run instances: %v", err)
	}
	if len(instances.Instances) != 1 {
		return nil, fmt.Errorf("expected 1 started instance, got %d", len(instances.Instances))
	}
	return &instance{&instances.Instances[0]}, nil
}

func (e *environ) StopInstances(insts []environs.Instance) error {
	if len(insts) == 0 {
		return nil
	}
	names := make([]string, len(insts))
	for i, inst := range insts {
		names[i] = inst.(*instance).InstanceId
	}
	_, err := e.ec2.TerminateInstances(names)
	return err
}

func (e *environ) Instances() ([]environs.Instance, error) {
	filter := ec2.NewFilter()
	filter.Add("instance-state-name", "pending", "running")

	resp, err := e.ec2.Instances(nil, filter)
	if err != nil {
		return nil, err
	}
	var insts []environs.Instance
	for i := range resp.Reservations {
		r := &resp.Reservations[i]
		for j := range r.Instances {
			insts = append(insts, &instance{&r.Instances[j]})
		}
	}
	return insts, nil
}

func (e *environ) makeControlBucket() error {
	e.checkBucket.Do(func() {
		b := e.controlBucket()
		// As bucket LIST isn't implemented for the s3test server yet,
		// we try to get an object from the control bucket
		// and determine whether the bucket exists using the resulting
		// error message.
		r, testErr := b.GetReader("testing123")
		if testErr == nil {
			r.Close()
			return
		}
		if testErr, _ := testErr.(*s3.Error); testErr == nil || testErr.Code != "NoSuchBucket" {
			return
		}
		// The bucket doesn't exist, so try to make it.
		e.checkBucketError = b.PutBucket(s3.Private)
	})
	return e.checkBucketError
}

func (e *environ) PutFile(file string, r io.Reader, length int64) error {
	if err := e.makeControlBucket(); err != nil {
		return fmt.Errorf("cannot make S3 control bucket: %v", err)
	}
	err := e.controlBucket().PutReader(file, r, length, "binary/octet-stream", s3.Private)
	if err != nil {
		return fmt.Errorf("cannot read file %q from control bucket: %v", file)
	}
	return nil
}

func (e *environ) GetFile(file string) (io.ReadCloser, error) {
	return e.controlBucket().GetReader(file)
}

func (e *environ) RemoveFile(file string) error {
	return e.controlBucket().Del(file)
}

func (e *environ) controlBucket() *s3.Bucket {
	return e.s3.Bucket(e.config.controlBucket)
}

func (e *environ) Destroy() error {
	// TODO should we ignore error from this or give a warning or what?
	e.controlBucket().DelBucket()

	insts, err := e.Instances()
	if err != nil {
		return err
	}
	return e.StopInstances(insts)
}

func (e *environ) machineGroupName(machineId int) string {
	return fmt.Sprintf("%s-%d", e.groupName(), machineId)
}

func (e *environ) groupName() string {
	return "juju-" + e.name
}

// setUpGroups creates the security groups for the new machine, and
// returns them.
//
// Instances are tagged with a group so they can be distinguished from
// other instances that might be running on the same EC2 account.  In
// addition, a specific machine security group is created for each
// machine, so that its firewall rules can be configured per machine.
func (e *environ) setUpGroups(machineId int) ([]ec2.SecurityGroup, error) {
	jujuGroup := ec2.SecurityGroup{Name: e.groupName()}
	jujuMachineGroup := ec2.SecurityGroup{Name: e.machineGroupName(machineId)}
	groups, err := e.ec2.SecurityGroups([]ec2.SecurityGroup{jujuGroup, jujuMachineGroup}, nil)
	if err != nil {
		return nil, fmt.Errorf("cannot get security groups: %v", err)
	}

	for _, g := range groups.Groups {
		switch g.Name {
		case jujuGroup.Name:
			jujuGroup = g.SecurityGroup
		case jujuMachineGroup.Name:
			jujuMachineGroup = g.SecurityGroup
		}
	}

	// Create the provider group if doesn't exist.
	if jujuGroup.Id == "" {
		r, err := e.ec2.CreateSecurityGroup(jujuGroup.Name, "juju group for "+e.name)
		if err != nil {
			return nil, fmt.Errorf("cannot create juju security group: %v", err)
		}
		jujuGroup = r.SecurityGroup
	}

	// Create the machine-specific group, but first see if there's
	// one already existing from a previous machine launch;
	// if so, delete it, since it can have the wrong firewall setup
	if jujuMachineGroup.Id != "" {
		_, err := e.ec2.DeleteSecurityGroup(jujuMachineGroup)
		if err != nil {
			return nil, fmt.Errorf("cannot delete old security group %q: %v", jujuMachineGroup.Name, err)
		}
	}
	descr := fmt.Sprintf("juju group for %s machine %d", e.name, machineId)
	r, err := e.ec2.CreateSecurityGroup(jujuMachineGroup.Name, descr)
	if err != nil {
		return nil, fmt.Errorf("cannot create machine group %q: %v", jujuMachineGroup.Name, err)
	}
	return []ec2.SecurityGroup{jujuGroup, r.SecurityGroup}, nil
}
<commit_msg>remove bootstrap method from environs/ec2<commit_after>package ec2

import (
	"fmt"
	"io"
	"launchpad.net/goamz/ec2"
	"launchpad.net/goamz/s3"
	"launchpad.net/juju/go/environs"
	"sync"
)

func init() {
	environs.RegisterProvider("ec2", environProvider{})
}

type environProvider struct{}

var _ environs.EnvironProvider = environProvider{}

type environ struct {
	name             string
	config           *providerConfig
	ec2              *ec2.EC2
	s3               *s3.S3
	checkBucket      sync.Once
	checkBucketError error
}

var _ environs.Environ = (*environ)(nil)

type instance struct {
	*ec2.Instance
}

var _ environs.Instance = (*instance)(nil)

func (inst *instance) Id() string {
	return inst.InstanceId
}

func (inst *instance) DNSName() string {
	return inst.Instance.DNSName
}

func (environProvider) Open(name string, config interface{}) (e environs.Environ, err error) {
	cfg := config.(*providerConfig)
	if Regions[cfg.region].EC2Endpoint == "" {
		return nil, fmt.Errorf("no ec2 endpoint found for region %q, opening %q", cfg.region, name)
	}
	return &environ{
		name:   name,
		config: cfg,
		ec2:    ec2.New(cfg.auth, Regions[cfg.region]),
		s3:     s3.New(cfg.auth, Regions[cfg.region]),
	}, nil
}

func (e *environ) findBootstrapMachine() (environs.Instance, error) {
	_, err := e.Instances()
	if err != nil {
		return nil, fmt.Errorf("cannot list machines: %v", err)
	}
	return nil, nil
}

func (e *environ) StartInstance(machineId int) (environs.Instance, error) {
	image, err := FindImageSpec(DefaultImageConstraint)
	if err != nil {
		return nil, fmt.Errorf("cannot find image: %v", err)
	}
	groups, err := e.setUpGroups(machineId)
	if err != nil {
		return nil, fmt.Errorf("cannot set up groups: %v", err)
	}
	instances, err := e.ec2.RunInstances(&ec2.RunInstances{
		ImageId:        image.ImageId,
		MinCount:       1,
		MaxCount:       1,
		UserData:       nil,
		InstanceType:   "m1.small",
		SecurityGroups: groups,
	})
	if err != nil {
		return nil, fmt.Errorf("cannot run instances: %v", err)
	}
	if len(instances.Instances) != 1 {
		return nil, fmt.Errorf("expected 1 started instance, got %d", len(instances.Instances))
	}
	return &instance{&instances.Instances[0]}, nil
}

func (e *environ) StopInstances(insts []environs.Instance) error {
	if len(insts) == 0 {
		return nil
	}
	names := make([]string, len(insts))
	for i, inst := range insts {
		names[i] = inst.(*instance).InstanceId
	}
	_, err := e.ec2.TerminateInstances(names)
	return err
}

func (e *environ) Instances() ([]environs.Instance, error) {
	filter := ec2.NewFilter()
	filter.Add("instance-state-name", "pending", "running")

	resp, err := e.ec2.Instances(nil, filter)
	if err != nil {
		return nil, err
	}
	var insts []environs.Instance
	for i := range resp.Reservations {
		r := &resp.Reservations[i]
		for j := range r.Instances {
			insts = append(insts, &instance{&r.Instances[j]})
		}
	}
	return insts, nil
}

func (e *environ) makeControlBucket() error {
	e.checkBucket.Do(func() {
		b := e.controlBucket()
		// As bucket LIST isn't implemented for the s3test server yet,
		// we try to get an object from the control bucket
		// and determine whether the bucket exists using the resulting
		// error message.
		r, testErr := b.GetReader("testing123")
		if testErr == nil {
			r.Close()
			return
		}
		if testErr, _ := testErr.(*s3.Error); testErr == nil || testErr.Code != "NoSuchBucket" {
			return
		}
		// The bucket doesn't exist, so try to make it.
		e.checkBucketError = b.PutBucket(s3.Private)
	})
	return e.checkBucketError
}

func (e *environ) PutFile(file string, r io.Reader, length int64) error {
	if err := e.makeControlBucket(); err != nil {
		return fmt.Errorf("cannot make S3 control bucket: %v", err)
	}
	err := e.controlBucket().PutReader(file, r, length, "binary/octet-stream", s3.Private)
	if err != nil {
		return fmt.Errorf("cannot read file %q from control bucket: %v", file)
	}
	return nil
}

func (e *environ) GetFile(file string) (io.ReadCloser, error) {
	return e.controlBucket().GetReader(file)
}

func (e *environ) RemoveFile(file string) error {
	return e.controlBucket().Del(file)
}

func (e *environ) controlBucket() *s3.Bucket {
	return e.s3.Bucket(e.config.controlBucket)
}

func (e *environ) Destroy() error {
	// TODO should we ignore error from this or give a warning or what?
	e.controlBucket().DelBucket()

	insts, err := e.Instances()
	if err != nil {
		return err
	}
	return e.StopInstances(insts)
}

func (e *environ) machineGroupName(machineId int) string {
	return fmt.Sprintf("%s-%d", e.groupName(), machineId)
}

func (e *environ) groupName() string {
	return "juju-" + e.name
}

// setUpGroups creates the security groups for the new machine, and
// returns them.
//
// Instances are tagged with a group so they can be distinguished from
// other instances that might be running on the same EC2 account.  In
// addition, a specific machine security group is created for each
// machine, so that its firewall rules can be configured per machine.
func (e *environ) setUpGroups(machineId int) ([]ec2.SecurityGroup, error) {
	jujuGroup := ec2.SecurityGroup{Name: e.groupName()}
	jujuMachineGroup := ec2.SecurityGroup{Name: e.machineGroupName(machineId)}
	groups, err := e.ec2.SecurityGroups([]ec2.SecurityGroup{jujuGroup, jujuMachineGroup}, nil)
	if err != nil {
		return nil, fmt.Errorf("cannot get security groups: %v", err)
	}

	for _, g := range groups.Groups {
		switch g.Name {
		case jujuGroup.Name:
			jujuGroup = g.SecurityGroup
		case jujuMachineGroup.Name:
			jujuMachineGroup = g.SecurityGroup
		}
	}

	// Create the provider group if doesn't exist.
	if jujuGroup.Id == "" {
		r, err := e.ec2.CreateSecurityGroup(jujuGroup.Name, "juju group for "+e.name)
		if err != nil {
			return nil, fmt.Errorf("cannot create juju security group: %v", err)
		}
		jujuGroup = r.SecurityGroup
	}

	// Create the machine-specific group, but first see if there's
	// one already existing from a previous machine launch;
	// if so, delete it, since it can have the wrong firewall setup
	if jujuMachineGroup.Id != "" {
		_, err := e.ec2.DeleteSecurityGroup(jujuMachineGroup)
		if err != nil {
			return nil, fmt.Errorf("cannot delete old security group %q: %v", jujuMachineGroup.Name, err)
		}
	}
	descr := fmt.Sprintf("juju group for %s machine %d", e.name, machineId)
	r, err := e.ec2.CreateSecurityGroup(jujuMachineGroup.Name, descr)
	if err != nil {
		return nil, fmt.Errorf("cannot create machine group %q: %v", jujuMachineGroup.Name, err)
	}
	return []ec2.SecurityGroup{jujuGroup, r.SecurityGroup}, nil
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"

	"github.com/jinzhu/gorm"
	"gopkg.in/robfig/cron.v2"
)

//MasterCron system
var MasterCron *cron.Cron

//InitCron system
func InitCron() {
	MasterCron = cron.New()
	MasterCron.Start()
	// Gdb.Model(Task{}).Where("cron_id != 0").Updates(Task{CronID: 0})

	//Loads the tasks on the cron system
	var tasks []Task
	Gdb.Find(&tasks)
	fmt.Printf("***STARTING %d PROJECTS***\f", len(tasks))
	InTx(func(txn *gorm.DB) bool {
		for _, task := range tasks {
			if err := task.Start(txn); err != nil {
				return false
			}
		}
		return true
	})
}
<commit_msg>added some logs<commit_after>package models

import (
	"fmt"

	"github.com/jinzhu/gorm"
	"gopkg.in/robfig/cron.v2"
)

//MasterCron system
var MasterCron *cron.Cron

//InitCron system
func InitCron() {
	MasterCron = cron.New()
	MasterCron.Start()

	//Loads the tasks on the cron system
	var tasks []Task
	Gdb.Find(&tasks)
	fmt.Printf("***STARTING %d PROJECTS***\n", len(tasks))
	InTx(func(txn *gorm.DB) bool {
		for _, task := range tasks {
			if err := task.Start(txn); err != nil {
				fmt.Print(err)
				return false
			}
		}
		return true
	})
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"

	"github.com/hashicorp/aws-sdk-go/aws"
	awsr53 "github.com/hashicorp/aws-sdk-go/gen/route53"
)

func TestAccRoute53Record(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckRoute53RecordDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccRoute53RecordConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRoute53RecordExists("aws_route53_record.default"),
				),
			},
		},
	})
}

func TestAccRoute53Record_generatesSuffix(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckRoute53RecordDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccRoute53RecordConfigSuffix,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRoute53RecordExists("aws_route53_record.default"),
				),
			},
		},
	})
}

func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).r53conn
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_route53_record" {
			continue
		}

		parts := strings.Split(rs.Primary.ID, "_")
		zone := parts[0]
		name := parts[1]
		rType := parts[2]

		lopts := &awsr53.ListResourceRecordSetsRequest{
			HostedZoneID:    aws.String(cleanZoneID(zone)),
			StartRecordName: aws.String(name),
			StartRecordType: aws.String(rType),
		}

		resp, err := conn.ListResourceRecordSets(lopts)
		if err != nil {
			return err
		}
		if len(resp.ResourceRecordSets) == 0 {
			return nil
		}
		rec := resp.ResourceRecordSets[0]
		if FQDN(*rec.Name) == FQDN(name) && *rec.Type == rType {
			return fmt.Errorf("Record still exists: %#v", rec)
		}
	}
	return nil
}

func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		conn := testAccProvider.Meta().(*AWSClient).r53conn
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No hosted zone ID is set")
		}

		parts := strings.Split(rs.Primary.ID, "_")
		zone := parts[0]
		name := parts[1]
		rType := parts[2]

		lopts := &awsr53.ListResourceRecordSetsRequest{
			HostedZoneID:    aws.String(cleanZoneID(zone)),
			StartRecordName: aws.String(name),
			StartRecordType: aws.String(rType),
		}

		resp, err := conn.ListResourceRecordSets(lopts)
		if err != nil {
			return err
		}
		if len(resp.ResourceRecordSets) == 0 {
			return fmt.Errorf("Record does not exist")
		}
		rec := resp.ResourceRecordSets[0]
		if FQDN(*rec.Name) == FQDN(name) && *rec.Type == rType {
			return nil
		}
		return fmt.Errorf("Record does not exist: %#v", rec)
	}
}

const testAccRoute53RecordConfig = `
resource "aws_route53_zone" "main" {
	name = "notexample.com"
}

resource "aws_route53_record" "default" {
	zone_id = "${aws_route53_zone.main.zone_id}"
	name = "www.notexample.com"
	type = "A"
	ttl = "30"
	records = ["127.0.0.1", "127.0.0.27"]
}
`

const testAccRoute53RecordConfigSuffix = `
resource "aws_route53_zone" "main" {
	name = "notexample.com"
}

resource "aws_route53_record" "default" {
	zone_id = "${aws_route53_zone.main.zone_id}"
	name = "subdomain"
	type = "A"
	ttl = "30"
	records = ["127.0.0.1", "127.0.0.27"]
}
`
<commit_msg>provider/aws: Add test for TXT route53 record<commit_after>package aws

import (
	"fmt"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"

	"github.com/hashicorp/aws-sdk-go/aws"
	awsr53 "github.com/hashicorp/aws-sdk-go/gen/route53"
)

func TestAccRoute53Record(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckRoute53RecordDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccRoute53RecordConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRoute53RecordExists("aws_route53_record.default"),
				),
			},
		},
	})
}

func TestAccRoute53Record_txtSupport(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckRoute53RecordDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccRoute53RecordConfigTXT,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRoute53RecordExists("aws_route53_record.default"),
				),
			},
		},
	})
}

func TestAccRoute53Record_generatesSuffix(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckRoute53RecordDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccRoute53RecordConfigSuffix,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRoute53RecordExists("aws_route53_record.default"),
				),
			},
		},
	})
}

func testAccCheckRoute53RecordDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).r53conn
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_route53_record" {
			continue
		}

		parts := strings.Split(rs.Primary.ID, "_")
		zone := parts[0]
		name := parts[1]
		rType := parts[2]

		lopts := &awsr53.ListResourceRecordSetsRequest{
			HostedZoneID:    aws.String(cleanZoneID(zone)),
			StartRecordName: aws.String(name),
			StartRecordType: aws.String(rType),
		}

		resp, err := conn.ListResourceRecordSets(lopts)
		if err != nil {
			return err
		}
		if len(resp.ResourceRecordSets) == 0 {
			return nil
		}
		rec := resp.ResourceRecordSets[0]
		if FQDN(*rec.Name) == FQDN(name) && *rec.Type == rType {
			return fmt.Errorf("Record still exists: %#v", rec)
		}
	}
	return nil
}

func testAccCheckRoute53RecordExists(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		conn := testAccProvider.Meta().(*AWSClient).r53conn
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No hosted zone ID is set")
		}

		parts := strings.Split(rs.Primary.ID, "_")
		zone := parts[0]
		name := parts[1]
		rType := parts[2]

		lopts := &awsr53.ListResourceRecordSetsRequest{
			HostedZoneID:    aws.String(cleanZoneID(zone)),
			StartRecordName: aws.String(name),
			StartRecordType: aws.String(rType),
		}

		resp, err := conn.ListResourceRecordSets(lopts)
		if err != nil {
			return err
		}
		if len(resp.ResourceRecordSets) == 0 {
			return fmt.Errorf("Record does not exist")
		}
		rec := resp.ResourceRecordSets[0]
		if FQDN(*rec.Name) == FQDN(name) && *rec.Type == rType {
			return nil
		}
		return fmt.Errorf("Record does not exist: %#v", rec)
	}
}

const testAccRoute53RecordConfig = `
resource "aws_route53_zone" "main" {
	name = "notexample.com"
}

resource "aws_route53_record" "default" {
	zone_id = "${aws_route53_zone.main.zone_id}"
	name = "www.notexample.com"
	type = "A"
	ttl = "30"
	records = ["127.0.0.1", "127.0.0.27"]
}
`

const testAccRoute53RecordConfigSuffix = `
resource "aws_route53_zone" "main" {
	name = "notexample.com"
}

resource "aws_route53_record" "default" {
	zone_id = "${aws_route53_zone.main.zone_id}"
	name = "subdomain"
	type = "A"
	ttl = "30"
	records = ["127.0.0.1", "127.0.0.27"]
}
`

const testAccRoute53RecordConfigTXT = `
resource "aws_route53_zone" "main" {
	name = "notexample.com"
}

resource "aws_route53_record" "default" {
	zone_id = "${aws_route53_zone.main.zone_id}"
	name = "subdomain"
	type = "TXT"
	ttl = "30"
	records = ["lalalala"]
}
`
<|endoftext|>


<commit_before>package models

import (
  "crypto/sha256"
  "github.com/gokyle/pbkdf2"
  "github.com/spacedock-io/registry/db"
)

func init() {
  pbkdf2.HashFunc = sha256.New
}

type Access struct {
  Id        int64
  UserId    int64
  Repo      string  `sql:"not null;unique"`
  Access    string  `sql:"not null"`
}

type Email struct {
  Id        int64
  Email     string  `sql:"not null;unique"`
  UserId    int64
}

type User struct {
  Id        int64
  Username  string
  Admin     bool
  Access    []Access
  Emails    []Email
  Hash      []byte
  Salt      []byte
}

// @TODO: Make this not return a bool
func AuthUser(user string, pass string) (*User, bool) {
  u, err := GetUser(user)
  if err != nil { return nil, false }
  res := u.MatchPassword(pass)
  if !res { return nil, false }
  return u, true
}

func GetUser(username string) (*User, error) {
  u := &User{}
  q := db.DB.Where("Username = ?", username).Find(u)
  if q.Error != nil {
    if q.RecordNotFound() {
      return nil, NotFoundErr
    } else {
      return nil, q.Error
    }
  }
  return u, nil
}

func (user *User) Create(password string) error {
  user.SetPassword(password)
  q := db.DB.Save(user)
  if q.Error != nil {
    return SaveErr
  }
  return nil
}

func (user *User) GetAccess(ns, repo string) string {
  if len(ns) > 0 {
    repo = ns + "/" + repo
  }

  a :=  Access{}
  q := db.DB.Where(&Access{UserId: user.Id, Repo: repo}).First(&a)
  if q.Error != nil {
    return ""
  }
  return a.Access
}

func (user *User) SetAccess(ns, repo, access string) bool {
  if len(ns) > 0 {
    repo = ns + "/" + repo
  }

  if len(repo) == 0 {
    return false
  }

  var perms []Access

  a := Access{
    Repo: repo,
    Access: access,
  }

  q := db.DB.Model(user).Related(&perms)
  if q.Error != nil {
    return false
  }

  perms = append(perms, a)
  user.Access = perms

  q = db.DB.Save(user)
  if q.Error != nil {
    return false
  }

  return true
}

func (user *User) SetPassword(pass string) {
  ph := pbkdf2.HashPassword(pass)
  user.Salt = ph.Salt
  user.Hash = ph.Hash
}

func (user *User) MatchPassword(pass string) bool {
  ph := &pbkdf2.PasswordHash{ Hash: user.Hash, Salt: user.Salt}
  return pbkdf2.MatchPassword(pass, ph)
}

func (user *User) Update(email, password string) error {
  if len(password) > 5 {
    user.SetPassword(password)
  }

  if len(email) > 0 {
    user.Emails = append(user.Emails, Email{Email: email})
  }

  q := db.DB.Save(user)
  if q.Error != nil {
    return DBErr
  }
  return nil
}
<commit_msg>Repo name does not need to be unique in access model<commit_after>package models

import (
  "crypto/sha256"
  "github.com/gokyle/pbkdf2"
  "github.com/spacedock-io/registry/db"
)

func init() {
  pbkdf2.HashFunc = sha256.New
}

type Access struct {
  Id        int64
  UserId    int64
  Repo      string
  Access    string  `sql:"not null"`
}

type Email struct {
  Id        int64
  Email     string  `sql:"not null;unique"`
  UserId    int64
}

type User struct {
  Id        int64
  Username  string
  Admin     bool
  Access    []Access
  Emails    []Email
  Hash      []byte
  Salt      []byte
}

// @TODO: Make this not return a bool
func AuthUser(user string, pass string) (*User, bool) {
  u, err := GetUser(user)
  if err != nil { return nil, false }
  res := u.MatchPassword(pass)
  if !res { return nil, false }
  return u, true
}

func GetUser(username string) (*User, error) {
  u := &User{}
  q := db.DB.Where("Username = ?", username).Find(u)
  if q.Error != nil {
    if q.RecordNotFound() {
      return nil, NotFoundErr
    } else {
      return nil, q.Error
    }
  }
  return u, nil
}

func (user *User) Create(password string) error {
  user.SetPassword(password)
  q := db.DB.Save(user)
  if q.Error != nil {
    return SaveErr
  }
  return nil
}

func (user *User) GetAccess(ns, repo string) string {
  if len(ns) > 0 {
    repo = ns + "/" + repo
  }

  a :=  Access{}
  q := db.DB.Where(&Access{UserId: user.Id, Repo: repo}).First(&a)
  if q.Error != nil {
    return ""
  }
  return a.Access
}

func (user *User) SetAccess(ns, repo, access string) bool {
  if len(ns) > 0 {
    repo = ns + "/" + repo
  }

  if len(repo) == 0 {
    return false
  }

  var perms []Access

  a := Access{
    Repo: repo,
    Access: access,
  }

  q := db.DB.Model(user).Related(&perms)
  if q.Error != nil {
    return false
  }

  perms = append(perms, a)
  user.Access = perms

  q = db.DB.Save(user)
  if q.Error != nil {
    return false
  }

  return true
}

func (user *User) SetPassword(pass string) {
  ph := pbkdf2.HashPassword(pass)
  user.Salt = ph.Salt
  user.Hash = ph.Hash
}

func (user *User) MatchPassword(pass string) bool {
  ph := &pbkdf2.PasswordHash{ Hash: user.Hash, Salt: user.Salt}
  return pbkdf2.MatchPassword(pass, ph)
}

func (user *User) Update(email, password string) error {
  if len(password) > 5 {
    user.SetPassword(password)
  }

  if len(email) > 0 {
    user.Emails = append(user.Emails, Email{Email: email})
  }

  q := db.DB.Save(user)
  if q.Error != nil {
    return DBErr
  }
  return nil
}
<|endoftext|>


<commit_before>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"errors"
	"testing"

	"github.com/issue9/assert"
)

func TestModule_NewTag(t *testing.T) {
	a := assert.New(t)
	m := newModule("user1", "user1 desc")
	a.NotNil(m)

	v := m.NewTag("0.1.0")
	a.NotNil(v).NotNil(m.tags["0.1.0"])
	v.AddInit(nil, "title1")
	a.Equal(v.inits[0].title, "title1")

	vv := m.NewTag("0.1.0")
	a.Equal(vv, v)

	v2 := m.NewTag("0.2.0")
	a.NotEqual(v2, v)
}

func TestModule_Plugin(t *testing.T) {
	a := assert.New(t)

	m := newModule("user1", "user1 desc")
	a.NotNil(m)

	a.Panic(func() {
		m.Plugin("p1", "p1 desc")
	})

	m = newModule("", "")
	a.NotPanic(func() {
		m.Plugin("p1", "p1 desc")
	})
}

func TestModule_AddInit(t *testing.T) {
	a := assert.New(t)
	m := newModule("m1", "m1 desc")
	a.NotNil(m)

	a.Nil(m.inits)
	m.AddInit(func() error { return nil }, "t1")
	a.Equal(len(m.inits), 1).
		Equal(m.inits[0].title, "t1").
		NotNil(m.inits[0].f)

	m.AddInit(func() error { return nil }, "t1")
	a.Equal(len(m.inits), 2).
		Equal(m.inits[1].title, "t1").
		NotNil(m.inits[1].f)

	m.AddInit(func() error { return nil }, "t1")
	a.Equal(len(m.inits), 3).
		Equal(m.inits[2].title, "t1").
		NotNil(m.inits[2].f)
}

/*
func TestApp_Init(t *testing.T) {
	a := assert.New(t)

	m1 := NewModule("users1", "user1 module", "users2", "users3")
	srv1, start1, exit1 := buildSrv1()
	m1.AddService(srv1, "服务 1")
	srv2, start2, exit2 := buildSrv1()
	m1.AddService(srv2, "服务 2")
	a.Equal(len(app.services), 0)
	m1.NewTag("v1").
		AddInit(func() error { return errors.New("falid message") }, "安装数据表 users1")

	m2 := NewModule("users2", "user2 module", "users3")
	srv3, start3, exit3 := buildSrv1()
	m2.AddService(srv3, "服务 3")
	m2.NewTag("v1").AddInit(func() error { return nil }, "安装数据表 users2")
	a.Equal(len(app.services), 0)

	m3 := app.NewModule("users3", "user3 mdoule")
	tag := m3.NewTag("v1")
	tag.AddInit(func() error { return nil }, "安装数据表 users3-1")
	tag.AddInit(func() error { return nil }, "安装数据表 users3-2")
	tag.AddInit(func() error { return nil }, "安装数据表 users3-3")
	a.Equal(len(tag.inits), 3)
	a.Equal(len(app.services), 0)

	a.Error(app.Init("v1", nil))            // 出错后中断
	time.Sleep(5 * tickTimer)               // 等待 app.Init 中的服务结束
	a.NotError(app.Init("not exists", nil)) // 不存在
	time.Sleep(5 * tickTimer)               // 等待 app.Init 中的服务结束

	a.Equal(0, len(app.Services()))
	a.NotError(app.Init("", log.New(os.Stdout, "", 0)))
	a.Equal(4, len(app.Services())) // 自带 app.scheduled

	// 等待启动完成
	wg := &sync.WaitGroup{}
	wg.Add(3)
	go func() {
		<-start1
		wg.Done()
	}()
	go func() {
		<-start2
		wg.Done()
	}()
	go func() {
		<-start3
		wg.Done()
	}()
	wg.Wait()

	app.Stop()

	// 等待停止
	wg = &sync.WaitGroup{}
	wg.Add(3)
	go func() {
		<-exit1
		wg.Done()
	}()
	go func() {
		<-exit2
		wg.Done()
	}()
	go func() {
		<-exit3
		wg.Done()
	}()
	wg.Wait()
	for _, srv := range app.Services() {
		a.Equal(srv.State(), ServiceStop)
	}
}
*/

func TestApp_Tags(t *testing.T) {
	a := assert.New(t)
	modules = modules[:0]

	m1 := NewModule("users1", "user1 module", "users2", "users3")
	m1.NewTag("v1").
		AddInit(func() error { return errors.New("falid message") }, "安装数据表 users1")
	m1.NewTag("v2")

	m2 := NewModule("users2", "user2 module", "users3")
	m2.NewTag("v1").AddInit(func() error { return nil }, "安装数据表 users2")
	m2.NewTag("v3")

	m3 := NewModule("users3", "user3 mdoule")
	tag := m3.NewTag("v1")
	tag.AddInit(func() error { return nil }, "安装数据表 users3-1")
	tag.AddInit(func() error { return nil }, "安装数据表 users3-2")
	m3.NewTag("v4")

	tags := Tags()
	a.Equal(tags, []string{"v1", "v2", "v3", "v4"})
}
<commit_msg>删除无用的测试内容<commit_after>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"errors"
	"testing"

	"github.com/issue9/assert"
)

func TestModule_NewTag(t *testing.T) {
	a := assert.New(t)
	m := newModule("user1", "user1 desc")
	a.NotNil(m)

	v := m.NewTag("0.1.0")
	a.NotNil(v).NotNil(m.tags["0.1.0"])
	v.AddInit(nil, "title1")
	a.Equal(v.inits[0].title, "title1")

	vv := m.NewTag("0.1.0")
	a.Equal(vv, v)

	v2 := m.NewTag("0.2.0")
	a.NotEqual(v2, v)
}

func TestModule_Plugin(t *testing.T) {
	a := assert.New(t)

	m := newModule("user1", "user1 desc")
	a.NotNil(m)

	a.Panic(func() {
		m.Plugin("p1", "p1 desc")
	})

	m = newModule("", "")
	a.NotPanic(func() {
		m.Plugin("p1", "p1 desc")
	})
}

func TestModule_AddInit(t *testing.T) {
	a := assert.New(t)
	m := newModule("m1", "m1 desc")
	a.NotNil(m)

	a.Nil(m.inits)
	m.AddInit(func() error { return nil }, "t1")
	a.Equal(len(m.inits), 1).
		Equal(m.inits[0].title, "t1").
		NotNil(m.inits[0].f)

	m.AddInit(func() error { return nil }, "t1")
	a.Equal(len(m.inits), 2).
		Equal(m.inits[1].title, "t1").
		NotNil(m.inits[1].f)

	m.AddInit(func() error { return nil }, "t1")
	a.Equal(len(m.inits), 3).
		Equal(m.inits[2].title, "t1").
		NotNil(m.inits[2].f)
}

func TestApp_Tags(t *testing.T) {
	a := assert.New(t)
	modules = modules[:0]

	m1 := NewModule("users1", "user1 module", "users2", "users3")
	m1.NewTag("v1").
		AddInit(func() error { return errors.New("falid message") }, "安装数据表 users1")
	m1.NewTag("v2")

	m2 := NewModule("users2", "user2 module", "users3")
	m2.NewTag("v1").AddInit(func() error { return nil }, "安装数据表 users2")
	m2.NewTag("v3")

	m3 := NewModule("users3", "user3 mdoule")
	tag := m3.NewTag("v1")
	tag.AddInit(func() error { return nil }, "安装数据表 users3-1")
	tag.AddInit(func() error { return nil }, "安装数据表 users3-2")
	m3.NewTag("v4")

	tags := Tags()
	a.Equal(tags, []string{"v1", "v2", "v3", "v4"})
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// TODO(thockin): This whole pkg is pretty linux-centric.  As soon as we have
// an alternate platform, we will need to abstract further.

package mount

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	utilexec "k8s.io/utils/exec"
)

const (
	// Default mount command if mounter path is not specified.
	defaultMountCommand = "mount"
	// Log message where sensitive mount options were removed
	sensitiveOptionsRemoved = "<masked>"
)

// Interface defines the set of methods to allow for mount operations on a system.
type Interface interface {
	// Mount mounts source to target as fstype with given options.
	// options MUST not contain sensitive material (like passwords).
	Mount(source string, target string, fstype string, options []string) error
	// MountSensitive is the same as Mount() but this method allows
	// sensitiveOptions to be passed in a separate parameter from the normal
	// mount options and ensures the sensitiveOptions are never logged. This
	// method should be used by callers that pass sensitive material (like
	// passwords) as mount options.
	MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error
	// Unmount unmounts given target.
	Unmount(target string) error
	// List returns a list of all mounted filesystems.  This can be large.
	// On some platforms, reading mounts directly from the OS is not guaranteed
	// consistent (i.e. it could change between chunked reads). This is guaranteed
	// to be consistent.
	List() ([]MountPoint, error)
	// IsLikelyNotMountPoint uses heuristics to determine if a directory
	// is not a mountpoint.
	// It should return ErrNotExist when the directory does not exist.
	// IsLikelyNotMountPoint does NOT properly detect all mountpoint types
	// most notably linux bind mounts and symbolic link. For callers that do not
	// care about such situations, this is a faster alternative to calling List()
	// and scanning that output.
	IsLikelyNotMountPoint(file string) (bool, error)
	// GetMountRefs finds all mount references to pathname, returning a slice of
	// paths. Pathname can be a mountpoint path or a normal	directory
	// (for bind mount). On Linux, pathname is excluded from the slice.
	// For example, if /dev/sdc was mounted at /path/a and /path/b,
	// GetMountRefs("/path/a") would return ["/path/b"]
	// GetMountRefs("/path/b") would return ["/path/a"]
	// On Windows there is no way to query all mount points; as long as pathname is
	// a valid mount, it will be returned.
	GetMountRefs(pathname string) ([]string, error)
}

// Compile-time check to ensure all Mounter implementations satisfy
// the mount interface.
var _ Interface = &Mounter{}

// MountPoint represents a single line in /proc/mounts or /etc/fstab.
type MountPoint struct { // nolint: golint
	Device string
	Path   string
	Type   string
	Opts   []string // Opts may contain sensitive mount options (like passwords) and MUST be treated as such (e.g. not logged).
	Freq   int
	Pass   int
}

type MountErrorType string // nolint: golint

const (
	FilesystemMismatch  MountErrorType = "FilesystemMismatch"
	HasFilesystemErrors MountErrorType = "HasFilesystemErrors"
	UnformattedReadOnly MountErrorType = "UnformattedReadOnly"
	FormatFailed        MountErrorType = "FormatFailed"
	GetDiskFormatFailed MountErrorType = "GetDiskFormatFailed"
	UnknownMountError   MountErrorType = "UnknownMountError"
)

type MountError struct { // nolint: golint
	Type    MountErrorType
	Message string
}

func (mountError MountError) String() string {
	return mountError.Message
}

func (mountError MountError) Error() string {
	return mountError.Message
}

func NewMountError(mountErrorValue MountErrorType, format string, args ...interface{}) error {
	mountError := MountError{
		Type:    mountErrorValue,
		Message: fmt.Sprintf(format, args...),
	}
	return mountError
}

// SafeFormatAndMount probes a device to see if it is formatted.
// Namely it checks to see if a file system is present. If so it
// mounts it otherwise the device is formatted first then mounted.
type SafeFormatAndMount struct {
	Interface
	Exec utilexec.Interface
}

// FormatAndMount formats the given disk, if needed, and mounts it.
// That is if the disk is not formatted and it is not being mounted as
// read-only it will format it first then mount it. Otherwise, if the
// disk is already formatted or it is being mounted as read-only, it
// will be mounted without formatting.
// options MUST not contain sensitive material (like passwords).
func (mounter *SafeFormatAndMount) FormatAndMount(source string, target string, fstype string, options []string) error {
	return mounter.FormatAndMountSensitive(source, target, fstype, options, nil /* sensitiveOptions */)
}

// FormatAndMountSensitive is the same as FormatAndMount but this method allows
// sensitiveOptions to be passed in a separate parameter from the normal mount
// options and ensures the sensitiveOptions are never logged. This method should
// be used by callers that pass sensitive material (like passwords) as mount
// options.
func (mounter *SafeFormatAndMount) FormatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return mounter.formatAndMountSensitive(source, target, fstype, options, sensitiveOptions)
}

// getMountRefsByDev finds all references to the device provided
// by mountPath; returns a list of paths.
// Note that mountPath should be path after the evaluation of any symblolic links.
func getMountRefsByDev(mounter Interface, mountPath string) ([]string, error) {
	mps, err := mounter.List()
	if err != nil {
		return nil, err
	}

	// Finding the device mounted to mountPath.
	diskDev := ""
	for i := range mps {
		if mountPath == mps[i].Path {
			diskDev = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	var refs []string
	for i := range mps {
		if mps[i].Device == diskDev || mps[i].Device == mountPath {
			if mps[i].Path != mountPath {
				refs = append(refs, mps[i].Path)
			}
		}
	}
	return refs, nil
}

// GetDeviceNameFromMount given a mnt point, find the device from /proc/mounts
// returns the device name, reference count, and error code.
func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, error) {
	mps, err := mounter.List()
	if err != nil {
		return "", 0, err
	}

	// Find the device name.
	// FIXME if multiple devices mounted on the same mount path, only the first one is returned.
	device := ""
	// If mountPath is symlink, need get its target path.
	slTarget, err := filepath.EvalSymlinks(mountPath)
	if err != nil {
		slTarget = mountPath
	}
	for i := range mps {
		if mps[i].Path == slTarget {
			device = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	refCount := 0
	for i := range mps {
		if mps[i].Device == device {
			refCount++
		}
	}
	return device, refCount, nil
}

// IsNotMountPoint determines if a directory is a mountpoint.
// It should return ErrNotExist when the directory does not exist.
// IsNotMountPoint is more expensive than IsLikelyNotMountPoint.
// IsNotMountPoint detects bind mounts in linux.
// IsNotMountPoint enumerates all the mountpoints using List() and
// the list of mountpoints may be large, then it uses
// isMountPointMatch to evaluate whether the directory is a mountpoint.
func IsNotMountPoint(mounter Interface, file string) (bool, error) {
	// IsLikelyNotMountPoint provides a quick check
	// to determine whether file IS A mountpoint.
	notMnt, notMntErr := mounter.IsLikelyNotMountPoint(file)
	if notMntErr != nil && os.IsPermission(notMntErr) {
		// We were not allowed to do the simple stat() check, e.g. on NFS with
		// root_squash. Fall back to /proc/mounts check below.
		notMnt = true
		notMntErr = nil
	}
	if notMntErr != nil {
		return notMnt, notMntErr
	}
	// identified as mountpoint, so return this fact.
	if notMnt == false {
		return notMnt, nil
	}

	// Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts.
	resolvedFile, err := filepath.EvalSymlinks(file)
	if err != nil {
		return true, err
	}

	// check all mountpoints since IsLikelyNotMountPoint
	// is not reliable for some mountpoint types.
	mountPoints, mountPointsErr := mounter.List()
	if mountPointsErr != nil {
		return notMnt, mountPointsErr
	}
	for _, mp := range mountPoints {
		if isMountPointMatch(mp, resolvedFile) {
			notMnt = false
			break
		}
	}
	return notMnt, nil
}

// MakeBindOpts detects whether a bind mount is being requested and makes the remount options to
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
// The list equals:
//   options - 'bind' + 'remount' (no duplicate)
func MakeBindOpts(options []string) (bool, []string, []string) {
	bind, bindOpts, bindRemountOpts, _ := MakeBindOptsSensitive(options, nil /* sensitiveOptions */)
	return bind, bindOpts, bindRemountOpts
}

// MakeBindOptsSensitive is the same as MakeBindOpts but this method allows
// sensitiveOptions to be passed in a separate parameter from the normal mount
// options and ensures the sensitiveOptions are never logged. This method should
// be used by callers that pass sensitive material (like passwords) as mount
// options.
func MakeBindOptsSensitive(options []string, sensitiveOptions []string) (bool, []string, []string, []string) {
	// Because we have an FD opened on the subpath bind mount, the "bind" option
	// needs to be included, otherwise the mount target will error as busy if you
	// remount as readonly.
	//
	// As a consequence, all read only bind mounts will no longer change the underlying
	// volume mount to be read only.
	bindRemountOpts := []string{"bind", "remount"}
	bindRemountSensitiveOpts := []string{}
	bind := false
	bindOpts := []string{"bind"}

	// _netdev is a userspace mount option and does not automatically get added when
	// bind mount is created and hence we must carry it over.
	if checkForNetDev(options, sensitiveOptions) {
		bindOpts = append(bindOpts, "_netdev")
	}

	for _, option := range options {
		switch option {
		case "bind":
			bind = true
			break
		case "remount":
			break
		default:
			bindRemountOpts = append(bindRemountOpts, option)
		}
	}

	for _, sensitiveOption := range sensitiveOptions {
		switch sensitiveOption {
		case "bind":
			bind = true
			break
		case "remount":
			break
		default:
			bindRemountSensitiveOpts = append(bindRemountSensitiveOpts, sensitiveOption)
		}
	}

	return bind, bindOpts, bindRemountOpts, bindRemountSensitiveOpts
}

func checkForNetDev(options []string, sensitiveOptions []string) bool {
	for _, option := range options {
		if option == "_netdev" {
			return true
		}
	}
	for _, sensitiveOption := range sensitiveOptions {
		if sensitiveOption == "_netdev" {
			return true
		}
	}
	return false
}

// PathWithinBase checks if give path is within given base directory.
func PathWithinBase(fullPath, basePath string) bool {
	rel, err := filepath.Rel(basePath, fullPath)
	if err != nil {
		return false
	}
	if StartsWithBackstep(rel) {
		// Needed to escape the base path.
		return false
	}
	return true
}

// StartsWithBackstep checks if the given path starts with a backstep segment.
func StartsWithBackstep(rel string) bool {
	// normalize to / and check for ../
	return rel == ".." || strings.HasPrefix(filepath.ToSlash(rel), "../")
}

// sanitizedOptionsForLogging will return a comma separated string containing
// options and sensitiveOptions. Each entry in sensitiveOptions will be
// replaced with the string sensitiveOptionsRemoved
// e.g. o1,o2,<masked>,<masked>
func sanitizedOptionsForLogging(options []string, sensitiveOptions []string) string {
	separator := ""
	if len(options) > 0 && len(sensitiveOptions) > 0 {
		separator = ","
	}

	sensitiveOptionsStart := ""
	sensitiveOptionsEnd := ""
	if len(sensitiveOptions) > 0 {
		sensitiveOptionsStart = strings.Repeat(sensitiveOptionsRemoved+",", len(sensitiveOptions)-1)
		sensitiveOptionsEnd = sensitiveOptionsRemoved
	}

	return strings.Join(options, ",") +
		separator +
		sensitiveOptionsStart +
		sensitiveOptionsEnd
}
<commit_msg>Ineffective break statements triggering SA4011<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// TODO(thockin): This whole pkg is pretty linux-centric.  As soon as we have
// an alternate platform, we will need to abstract further.

package mount

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	utilexec "k8s.io/utils/exec"
)

const (
	// Default mount command if mounter path is not specified.
	defaultMountCommand = "mount"
	// Log message where sensitive mount options were removed
	sensitiveOptionsRemoved = "<masked>"
)

// Interface defines the set of methods to allow for mount operations on a system.
type Interface interface {
	// Mount mounts source to target as fstype with given options.
	// options MUST not contain sensitive material (like passwords).
	Mount(source string, target string, fstype string, options []string) error
	// MountSensitive is the same as Mount() but this method allows
	// sensitiveOptions to be passed in a separate parameter from the normal
	// mount options and ensures the sensitiveOptions are never logged. This
	// method should be used by callers that pass sensitive material (like
	// passwords) as mount options.
	MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error
	// Unmount unmounts given target.
	Unmount(target string) error
	// List returns a list of all mounted filesystems.  This can be large.
	// On some platforms, reading mounts directly from the OS is not guaranteed
	// consistent (i.e. it could change between chunked reads). This is guaranteed
	// to be consistent.
	List() ([]MountPoint, error)
	// IsLikelyNotMountPoint uses heuristics to determine if a directory
	// is not a mountpoint.
	// It should return ErrNotExist when the directory does not exist.
	// IsLikelyNotMountPoint does NOT properly detect all mountpoint types
	// most notably linux bind mounts and symbolic link. For callers that do not
	// care about such situations, this is a faster alternative to calling List()
	// and scanning that output.
	IsLikelyNotMountPoint(file string) (bool, error)
	// GetMountRefs finds all mount references to pathname, returning a slice of
	// paths. Pathname can be a mountpoint path or a normal	directory
	// (for bind mount). On Linux, pathname is excluded from the slice.
	// For example, if /dev/sdc was mounted at /path/a and /path/b,
	// GetMountRefs("/path/a") would return ["/path/b"]
	// GetMountRefs("/path/b") would return ["/path/a"]
	// On Windows there is no way to query all mount points; as long as pathname is
	// a valid mount, it will be returned.
	GetMountRefs(pathname string) ([]string, error)
}

// Compile-time check to ensure all Mounter implementations satisfy
// the mount interface.
var _ Interface = &Mounter{}

// MountPoint represents a single line in /proc/mounts or /etc/fstab.
type MountPoint struct { // nolint: golint
	Device string
	Path   string
	Type   string
	Opts   []string // Opts may contain sensitive mount options (like passwords) and MUST be treated as such (e.g. not logged).
	Freq   int
	Pass   int
}

type MountErrorType string // nolint: golint

const (
	FilesystemMismatch  MountErrorType = "FilesystemMismatch"
	HasFilesystemErrors MountErrorType = "HasFilesystemErrors"
	UnformattedReadOnly MountErrorType = "UnformattedReadOnly"
	FormatFailed        MountErrorType = "FormatFailed"
	GetDiskFormatFailed MountErrorType = "GetDiskFormatFailed"
	UnknownMountError   MountErrorType = "UnknownMountError"
)

type MountError struct { // nolint: golint
	Type    MountErrorType
	Message string
}

func (mountError MountError) String() string {
	return mountError.Message
}

func (mountError MountError) Error() string {
	return mountError.Message
}

func NewMountError(mountErrorValue MountErrorType, format string, args ...interface{}) error {
	mountError := MountError{
		Type:    mountErrorValue,
		Message: fmt.Sprintf(format, args...),
	}
	return mountError
}

// SafeFormatAndMount probes a device to see if it is formatted.
// Namely it checks to see if a file system is present. If so it
// mounts it otherwise the device is formatted first then mounted.
type SafeFormatAndMount struct {
	Interface
	Exec utilexec.Interface
}

// FormatAndMount formats the given disk, if needed, and mounts it.
// That is if the disk is not formatted and it is not being mounted as
// read-only it will format it first then mount it. Otherwise, if the
// disk is already formatted or it is being mounted as read-only, it
// will be mounted without formatting.
// options MUST not contain sensitive material (like passwords).
func (mounter *SafeFormatAndMount) FormatAndMount(source string, target string, fstype string, options []string) error {
	return mounter.FormatAndMountSensitive(source, target, fstype, options, nil /* sensitiveOptions */)
}

// FormatAndMountSensitive is the same as FormatAndMount but this method allows
// sensitiveOptions to be passed in a separate parameter from the normal mount
// options and ensures the sensitiveOptions are never logged. This method should
// be used by callers that pass sensitive material (like passwords) as mount
// options.
func (mounter *SafeFormatAndMount) FormatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
	return mounter.formatAndMountSensitive(source, target, fstype, options, sensitiveOptions)
}

// getMountRefsByDev finds all references to the device provided
// by mountPath; returns a list of paths.
// Note that mountPath should be path after the evaluation of any symblolic links.
func getMountRefsByDev(mounter Interface, mountPath string) ([]string, error) {
	mps, err := mounter.List()
	if err != nil {
		return nil, err
	}

	// Finding the device mounted to mountPath.
	diskDev := ""
	for i := range mps {
		if mountPath == mps[i].Path {
			diskDev = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	var refs []string
	for i := range mps {
		if mps[i].Device == diskDev || mps[i].Device == mountPath {
			if mps[i].Path != mountPath {
				refs = append(refs, mps[i].Path)
			}
		}
	}
	return refs, nil
}

// GetDeviceNameFromMount given a mnt point, find the device from /proc/mounts
// returns the device name, reference count, and error code.
func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, error) {
	mps, err := mounter.List()
	if err != nil {
		return "", 0, err
	}

	// Find the device name.
	// FIXME if multiple devices mounted on the same mount path, only the first one is returned.
	device := ""
	// If mountPath is symlink, need get its target path.
	slTarget, err := filepath.EvalSymlinks(mountPath)
	if err != nil {
		slTarget = mountPath
	}
	for i := range mps {
		if mps[i].Path == slTarget {
			device = mps[i].Device
			break
		}
	}

	// Find all references to the device.
	refCount := 0
	for i := range mps {
		if mps[i].Device == device {
			refCount++
		}
	}
	return device, refCount, nil
}

// IsNotMountPoint determines if a directory is a mountpoint.
// It should return ErrNotExist when the directory does not exist.
// IsNotMountPoint is more expensive than IsLikelyNotMountPoint.
// IsNotMountPoint detects bind mounts in linux.
// IsNotMountPoint enumerates all the mountpoints using List() and
// the list of mountpoints may be large, then it uses
// isMountPointMatch to evaluate whether the directory is a mountpoint.
func IsNotMountPoint(mounter Interface, file string) (bool, error) {
	// IsLikelyNotMountPoint provides a quick check
	// to determine whether file IS A mountpoint.
	notMnt, notMntErr := mounter.IsLikelyNotMountPoint(file)
	if notMntErr != nil && os.IsPermission(notMntErr) {
		// We were not allowed to do the simple stat() check, e.g. on NFS with
		// root_squash. Fall back to /proc/mounts check below.
		notMnt = true
		notMntErr = nil
	}
	if notMntErr != nil {
		return notMnt, notMntErr
	}
	// identified as mountpoint, so return this fact.
	if notMnt == false {
		return notMnt, nil
	}

	// Resolve any symlinks in file, kernel would do the same and use the resolved path in /proc/mounts.
	resolvedFile, err := filepath.EvalSymlinks(file)
	if err != nil {
		return true, err
	}

	// check all mountpoints since IsLikelyNotMountPoint
	// is not reliable for some mountpoint types.
	mountPoints, mountPointsErr := mounter.List()
	if mountPointsErr != nil {
		return notMnt, mountPointsErr
	}
	for _, mp := range mountPoints {
		if isMountPointMatch(mp, resolvedFile) {
			notMnt = false
			break
		}
	}
	return notMnt, nil
}

// MakeBindOpts detects whether a bind mount is being requested and makes the remount options to
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
// The list equals:
//   options - 'bind' + 'remount' (no duplicate)
func MakeBindOpts(options []string) (bool, []string, []string) {
	bind, bindOpts, bindRemountOpts, _ := MakeBindOptsSensitive(options, nil /* sensitiveOptions */)
	return bind, bindOpts, bindRemountOpts
}

// MakeBindOptsSensitive is the same as MakeBindOpts but this method allows
// sensitiveOptions to be passed in a separate parameter from the normal mount
// options and ensures the sensitiveOptions are never logged. This method should
// be used by callers that pass sensitive material (like passwords) as mount
// options.
func MakeBindOptsSensitive(options []string, sensitiveOptions []string) (bool, []string, []string, []string) {
	// Because we have an FD opened on the subpath bind mount, the "bind" option
	// needs to be included, otherwise the mount target will error as busy if you
	// remount as readonly.
	//
	// As a consequence, all read only bind mounts will no longer change the underlying
	// volume mount to be read only.
	bindRemountOpts := []string{"bind", "remount"}
	bindRemountSensitiveOpts := []string{}
	bind := false
	bindOpts := []string{"bind"}

	// _netdev is a userspace mount option and does not automatically get added when
	// bind mount is created and hence we must carry it over.
	if checkForNetDev(options, sensitiveOptions) {
		bindOpts = append(bindOpts, "_netdev")
	}

	for _, option := range options {
		switch option {
		case "bind":
			bind = true
		case "remount": // Do nothing.
		default:
			bindRemountOpts = append(bindRemountOpts, option)
		}
	}

	for _, sensitiveOption := range sensitiveOptions {
		switch sensitiveOption {
		case "bind":
			bind = true
		case "remount": // Do nothing.
		default:
			bindRemountSensitiveOpts = append(bindRemountSensitiveOpts, sensitiveOption)
		}
	}

	return bind, bindOpts, bindRemountOpts, bindRemountSensitiveOpts
}

func checkForNetDev(options []string, sensitiveOptions []string) bool {
	for _, option := range options {
		if option == "_netdev" {
			return true
		}
	}
	for _, sensitiveOption := range sensitiveOptions {
		if sensitiveOption == "_netdev" {
			return true
		}
	}
	return false
}

// PathWithinBase checks if give path is within given base directory.
func PathWithinBase(fullPath, basePath string) bool {
	rel, err := filepath.Rel(basePath, fullPath)
	if err != nil {
		return false
	}
	if StartsWithBackstep(rel) {
		// Needed to escape the base path.
		return false
	}
	return true
}

// StartsWithBackstep checks if the given path starts with a backstep segment.
func StartsWithBackstep(rel string) bool {
	// normalize to / and check for ../
	return rel == ".." || strings.HasPrefix(filepath.ToSlash(rel), "../")
}

// sanitizedOptionsForLogging will return a comma separated string containing
// options and sensitiveOptions. Each entry in sensitiveOptions will be
// replaced with the string sensitiveOptionsRemoved
// e.g. o1,o2,<masked>,<masked>
func sanitizedOptionsForLogging(options []string, sensitiveOptions []string) string {
	separator := ""
	if len(options) > 0 && len(sensitiveOptions) > 0 {
		separator = ","
	}

	sensitiveOptionsStart := ""
	sensitiveOptionsEnd := ""
	if len(sensitiveOptions) > 0 {
		sensitiveOptionsStart = strings.Repeat(sensitiveOptionsRemoved+",", len(sensitiveOptions)-1)
		sensitiveOptionsEnd = sensitiveOptionsRemoved
	}

	return strings.Join(options, ",") +
		separator +
		sensitiveOptionsStart +
		sensitiveOptionsEnd
}
<|endoftext|>


<commit_before>package mpdb

import (
	"database/sql"
	"github.com/kierdavis/mealplanner/mpdata"
)

// SQL statements to delete tables.
var DeleteTablesSQLs = []string{
	"DROP TABLE IF EXISTS meal",
	"DROP TABLE IF EXISTS tag",
	"DROP TABLE IF EXISTS mealplan",
	"DROP TABLE IF EXISTS serving",
}

// SQL statements to create tables.
var CreateTablesSQLs = []string{
	"CREATE TABLE IF NOT EXISTS meal ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"name VARCHAR(255) NOT NULL, " +
		"recipe TEXT, " +
		"favourite BOOLEAN NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS tag ( " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"tag VARCHAR(64) NOT NULL, " +
		"PRIMARY KEY (mealid, tag) " +
		")",
	"CREATE TABLE IF NOT EXISTS mealplan ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"notes TEXT, " +
		"startdate DATE NOT NULL, " +
		"enddate DATE NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS serving ( " +
		"mealplanid BIGINT UNSIGNED NOT NULL, " +
		"dateserved DATE NOT NULL, " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"PRIMARY KEY (mealplanid, dateserved) " +
		")",
}

// SQL statements to clear tables.
var ClearTablesSQLs = []string{
	"DELETE FROM meal",
	"DELETE FROM tag",
	"DELETE FROM mealplan",
	"DELETE FROM serving",
}

// execList runs a list of SQL statements, discarding the results.
func execList(q Queryable, queries []string) (err error) {
	for _, query := range queries {
		_, err = q.Exec(query)
		if err != nil {
			return err
		}
	}

	return nil
}

// DeleteTables drops the database tables if they exist.
func DeleteTables(q Queryable) (err error) {
	return execList(q, DeleteTablesSQLs)
}

// CreateTables creates the database tables if they do not exist.
func CreateTables(q Queryable) (err error) {
	return execList(q, CreateTablesSQLs)
}

// ClearTables deletes all records from the entire database.
func ClearTables(q Queryable) (err error) {
	return execList(q, ClearTablesSQLs)
}

// InitDB creates the database tables if they don't exist. If 'clear' is true,
// the tables are also cleared (in the event that they did exist).
func InitDB(clear bool) (err error) {
	return WithConnection(func(db *sql.DB) (err error) {
		return WithTransaction(db, func(tx *sql.Tx) (err error) {
			err = CreateTables(tx)
			if err != nil {
				return err
			}

			if clear {
				err = ClearTables(tx)
				if err != nil {
					return err
				}
			}

			return InsertTestData(tx)
		})
	})
}

func InsertTestData(q Queryable) (err error) {
	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Chilli con carne",
			RecipeURL: "http://example.net/chilli",
			Favourite: false,
		},
		Tags: []string{
			"spicy",
			"lentil",
			"rice",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Carrot and lentil soup",
			RecipeURL: "http://example.net/soup",
			Favourite: false,
		},
		Tags: []string{
			"lentil",
			"soup",
			"quick",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Nachos",
			RecipeURL: "http://example.net/nachos",
			Favourite: true,
		},
		Tags: []string{
			"spicy",
			"mexican",
		},
	})

	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Add meal plan to test data loader<commit_after>package mpdb

import (
	"database/sql"
	"fmt"
	"github.com/kierdavis/mealplanner/mpdata"
	"time"
)

// SQL statements to delete tables.
var DeleteTablesSQLs = []string{
	"DROP TABLE IF EXISTS meal",
	"DROP TABLE IF EXISTS tag",
	"DROP TABLE IF EXISTS mealplan",
	"DROP TABLE IF EXISTS serving",
}

// SQL statements to create tables.
var CreateTablesSQLs = []string{
	"CREATE TABLE IF NOT EXISTS meal ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"name VARCHAR(255) NOT NULL, " +
		"recipe TEXT, " +
		"favourite BOOLEAN NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS tag ( " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"tag VARCHAR(64) NOT NULL, " +
		"PRIMARY KEY (mealid, tag) " +
		")",
	"CREATE TABLE IF NOT EXISTS mealplan ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"notes TEXT, " +
		"startdate DATE NOT NULL, " +
		"enddate DATE NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS serving ( " +
		"mealplanid BIGINT UNSIGNED NOT NULL, " +
		"dateserved DATE NOT NULL, " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"PRIMARY KEY (mealplanid, dateserved) " +
		")",
}

// SQL statements to clear tables.
var ClearTablesSQLs = []string{
	"DELETE FROM meal",
	"DELETE FROM tag",
	"DELETE FROM mealplan",
	"DELETE FROM serving",
}

// execList runs a list of SQL statements, discarding the results.
func execList(q Queryable, queries []string) (err error) {
	for _, query := range queries {
		_, err = q.Exec(query)
		if err != nil {
			return err
		}
	}

	return nil
}

// DeleteTables drops the database tables if they exist.
func DeleteTables(q Queryable) (err error) {
	return execList(q, DeleteTablesSQLs)
}

// CreateTables creates the database tables if they do not exist.
func CreateTables(q Queryable) (err error) {
	return execList(q, CreateTablesSQLs)
}

// ClearTables deletes all records from the entire database.
func ClearTables(q Queryable) (err error) {
	return execList(q, ClearTablesSQLs)
}

// InitDB creates the database tables if they don't exist. If 'clear' is true,
// the tables are also cleared (in the event that they did exist).
func InitDB(clear bool) (err error) {
	return WithConnection(func(db *sql.DB) (err error) {
		return WithTransaction(db, func(tx *sql.Tx) (err error) {
			err = CreateTables(tx)
			if err != nil {
				return err
			}

			if clear {
				err = ClearTables(tx)
				if err != nil {
					return err
				}
			}

			return InsertTestData(tx)
		})
	})
}

func InsertTestData(q Queryable) (err error) {
	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Chilli con carne",
			RecipeURL: "http://example.net/chilli",
			Favourite: false,
		},
		Tags: []string{
			"spicy",
			"lentil",
			"rice",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Carrot and lentil soup",
			RecipeURL: "http://example.net/soup",
			Favourite: false,
		},
		Tags: []string{
			"lentil",
			"soup",
			"quick",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Nachos",
			RecipeURL: "http://example.net/nachos",
			Favourite: true,
		},
		Tags: []string{
			"spicy",
			"mexican",
		},
	})

	if err != nil {
		return err
	}

	mp := &mpdata.MealPlan{
		Notes: "some notes",
		StartDate: time.Date(2014, time.January, 27, 0, 0, 0, 0, time.UTC),
		EndDate: time.Date(2014, time.January, 3, 0, 0, 0, 0, time.UTC),
	}

	err = AddMealPlan(q, mp)
	if err != nil {
		return err
	}

	fmt.Printf("Test meal plan is %d\n", mp.ID)

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/apache/thrift/lib/go/thrift"
	lightstep "github.com/lightstep/lightstep-tracer-go"
	stdopentracing "github.com/opentracing/opentracing-go"
	zipkin "github.com/openzipkin/zipkin-go-opentracing"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"sourcegraph.com/sourcegraph/appdash"
	appdashot "sourcegraph.com/sourcegraph/appdash/opentracing"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/examples/addsvc"
	"github.com/go-kit/kit/examples/addsvc/pb"
	thriftadd "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/pcp"
	"github.com/go-kit/kit/tracing/opentracing"
)

func main() {
	var (
		debugAddr        = flag.String("debug.addr", ":8080", "Debug and metrics listen address")
		httpAddr         = flag.String("http.addr", ":8081", "HTTP listen address")
		grpcAddr         = flag.String("grpc.addr", ":8082", "gRPC (HTTP) listen address")
		thriftAddr       = flag.String("thrift.addr", ":8083", "Thrift listen address")
		thriftProtocol   = flag.String("thrift.protocol", "binary", "binary, compact, json, simplejson")
		thriftBufferSize = flag.Int("thrift.buffer.size", 0, "0 for unbuffered")
		thriftFramed     = flag.Bool("thrift.framed", false, "true to enable framing")
		zipkinAddr       = flag.String("zipkin.addr", "", "Enable Zipkin tracing via a Kafka server host:port")
		appdashAddr      = flag.String("appdash.addr", "", "Enable Appdash tracing via an Appdash server host:port")
		lightstepToken   = flag.String("lightstep.token", "", "Enable LightStep tracing via a LightStep access token")
	)
	flag.Parse()

	// Logging domain.
	var logger log.Logger
	{
		logger = log.NewLogfmtLogger(os.Stdout)
		logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC)
		logger = log.NewContext(logger).With("caller", log.DefaultCaller)
	}
	logger.Log("msg", "hello")
	defer logger.Log("msg", "goodbye")

	// Metrics domain.
	var ints, chars metrics.Counter
	{
		// Business level metrics.
		ints = pcp.NewCounter("addsvc.integers_summed", "Total count of integers summed via the Sum method.")
		chars = pcp.NewCounter("addsvc.characters_concatenated", "Total count of characters concatenated via the Concat method.")
	}
	var duration metrics.Histogram
	{
		// Transport level metrics.
		duration = pcp.NewHistogram("addsvc.request_duration_ns", "Request duration in nanoseconds.")
	}

	// Tracing domain.
	var tracer stdopentracing.Tracer
	{
		if *zipkinAddr != "" {
			logger := log.NewContext(logger).With("tracer", "Zipkin")
			logger.Log("addr", *zipkinAddr)
			collector, err := zipkin.NewKafkaCollector(
				strings.Split(*zipkinAddr, ","),
				zipkin.KafkaLogger(logger),
			)
			if err != nil {
				logger.Log("err", err)
				os.Exit(1)
			}
			tracer, err = zipkin.NewTracer(
				zipkin.NewRecorder(collector, false, "localhost:80", "addsvc"),
			)
			if err != nil {
				logger.Log("err", err)
				os.Exit(1)
			}
		} else if *appdashAddr != "" {
			logger := log.NewContext(logger).With("tracer", "Appdash")
			logger.Log("addr", *appdashAddr)
			tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr))
		} else if *lightstepToken != "" {
			logger := log.NewContext(logger).With("tracer", "LightStep")
			logger.Log() // probably don't want to print out the token :)
			tracer = lightstep.NewTracer(lightstep.Options{
				AccessToken: *lightstepToken,
			})
			defer lightstep.FlushLightStepTracer(tracer)
		} else {
			logger := log.NewContext(logger).With("tracer", "none")
			logger.Log()
			tracer = stdopentracing.GlobalTracer() // no-op
		}
	}

	// Business domain.
	var service addsvc.Service
	{
		service = addsvc.NewBasicService()
		service = addsvc.ServiceLoggingMiddleware(logger)(service)
		service = addsvc.ServiceInstrumentingMiddleware(ints, chars)(service)
	}

	// Endpoint domain.
	var sumEndpoint endpoint.Endpoint
	{
		sumDuration := duration.With("method", "Sum")
		sumLogger := log.NewContext(logger).With("method", "Sum")

		sumEndpoint = addsvc.MakeSumEndpoint(service)
		sumEndpoint = opentracing.TraceServer(tracer, "Sum")(sumEndpoint)
		sumEndpoint = addsvc.EndpointInstrumentingMiddleware(sumDuration)(sumEndpoint)
		sumEndpoint = addsvc.EndpointLoggingMiddleware(sumLogger)(sumEndpoint)
	}
	var concatEndpoint endpoint.Endpoint
	{
		concatDuration := duration.With("method", "Concat")
		concatLogger := log.NewContext(logger).With("method", "Concat")

		concatEndpoint = addsvc.MakeConcatEndpoint(service)
		concatEndpoint = opentracing.TraceServer(tracer, "Concat")(concatEndpoint)
		concatEndpoint = addsvc.EndpointInstrumentingMiddleware(concatDuration)(concatEndpoint)
		concatEndpoint = addsvc.EndpointLoggingMiddleware(concatLogger)(concatEndpoint)
	}
	endpoints := addsvc.Endpoints{
		SumEndpoint:    sumEndpoint,
		ConcatEndpoint: concatEndpoint,
	}

	// Mechanical domain.
	errc := make(chan error)
	ctx := context.Background()

	// Interrupt handler.
	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		errc <- fmt.Errorf("%s", <-c)
	}()

	// Debug listener.
	go func() {
		logger := log.NewContext(logger).With("transport", "debug")

		m := http.NewServeMux()
		m.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
		m.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
		m.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
		m.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
		m.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

		logger.Log("addr", *debugAddr)
		errc <- http.ListenAndServe(*debugAddr, m)
	}()

	// HTTP transport.
	go func() {
		logger := log.NewContext(logger).With("transport", "HTTP")
		h := addsvc.MakeHTTPHandler(ctx, endpoints, tracer, logger)
		logger.Log("addr", *httpAddr)
		errc <- http.ListenAndServe(*httpAddr, h)
	}()

	// gRPC transport.
	go func() {
		logger := log.NewContext(logger).With("transport", "gRPC")

		ln, err := net.Listen("tcp", *grpcAddr)
		if err != nil {
			errc <- err
			return
		}

		srv := addsvc.MakeGRPCServer(ctx, endpoints, tracer, logger)
		s := grpc.NewServer()
		pb.RegisterAddServer(s, srv)

		logger.Log("addr", *grpcAddr)
		errc <- s.Serve(ln)
	}()

	// Thrift transport.
	go func() {
		logger := log.NewContext(logger).With("transport", "Thrift")

		var protocolFactory thrift.TProtocolFactory
		switch *thriftProtocol {
		case "binary":
			protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
		case "compact":
			protocolFactory = thrift.NewTCompactProtocolFactory()
		case "json":
			protocolFactory = thrift.NewTJSONProtocolFactory()
		case "simplejson":
			protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
		default:
			errc <- fmt.Errorf("invalid Thrift protocol %q", *thriftProtocol)
			return
		}

		var transportFactory thrift.TTransportFactory
		if *thriftBufferSize > 0 {
			transportFactory = thrift.NewTBufferedTransportFactory(*thriftBufferSize)
		} else {
			transportFactory = thrift.NewTTransportFactory()
		}
		if *thriftFramed {
			transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
		}

		transport, err := thrift.NewTServerSocket(*thriftAddr)
		if err != nil {
			errc <- err
			return
		}

		logger.Log("addr", *thriftAddr)
		errc <- thrift.NewTSimpleServer4(
			thriftadd.NewAddServiceProcessor(addsvc.MakeThriftHandler(ctx, endpoints)),
			transport,
			transportFactory,
			protocolFactory,
		).Serve()
	}()

	// Run!
	logger.Log("exit", <-errc)

	pcp.StartReporting("addsvc")
	defer pcp.StopReporting()
}
<commit_msg>examples: addsvc: update for new api<commit_after>package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/apache/thrift/lib/go/thrift"
	lightstep "github.com/lightstep/lightstep-tracer-go"
	stdopentracing "github.com/opentracing/opentracing-go"
	zipkin "github.com/openzipkin/zipkin-go-opentracing"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"sourcegraph.com/sourcegraph/appdash"
	appdashot "sourcegraph.com/sourcegraph/appdash/opentracing"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/examples/addsvc"
	"github.com/go-kit/kit/examples/addsvc/pb"
	thriftadd "github.com/go-kit/kit/examples/addsvc/thrift/gen-go/addsvc"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/pcp"
	"github.com/go-kit/kit/tracing/opentracing"
)

func main() {
	var (
		debugAddr        = flag.String("debug.addr", ":8080", "Debug and metrics listen address")
		httpAddr         = flag.String("http.addr", ":8081", "HTTP listen address")
		grpcAddr         = flag.String("grpc.addr", ":8082", "gRPC (HTTP) listen address")
		thriftAddr       = flag.String("thrift.addr", ":8083", "Thrift listen address")
		thriftProtocol   = flag.String("thrift.protocol", "binary", "binary, compact, json, simplejson")
		thriftBufferSize = flag.Int("thrift.buffer.size", 0, "0 for unbuffered")
		thriftFramed     = flag.Bool("thrift.framed", false, "true to enable framing")
		zipkinAddr       = flag.String("zipkin.addr", "", "Enable Zipkin tracing via a Kafka server host:port")
		appdashAddr      = flag.String("appdash.addr", "", "Enable Appdash tracing via an Appdash server host:port")
		lightstepToken   = flag.String("lightstep.token", "", "Enable LightStep tracing via a LightStep access token")
	)
	flag.Parse()

	// Logging domain.
	var logger log.Logger
	{
		logger = log.NewLogfmtLogger(os.Stdout)
		logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC)
		logger = log.NewContext(logger).With("caller", log.DefaultCaller)
	}
	logger.Log("msg", "hello")
	defer logger.Log("msg", "goodbye")

	reporter := pcp.NewReporter("addsvc")

	// Metrics domain.
	var ints, chars metrics.Counter
	{
		// Business level metrics.
		ints = reporter.NewCounter("integers_summed", "Total count of integers summed via the Sum method.")
		chars = reporter.NewCounter("characters_concatenated", "Total count of characters concatenated via the Concat method.")
	}
	var duration metrics.Histogram
	{
		// Transport level metrics.
		duration = reporter.NewHistogram("request_duration_ns", "Request duration in nanoseconds.")
	}

	// Tracing domain.
	var tracer stdopentracing.Tracer
	{
		if *zipkinAddr != "" {
			logger := log.NewContext(logger).With("tracer", "Zipkin")
			logger.Log("addr", *zipkinAddr)
			collector, err := zipkin.NewKafkaCollector(
				strings.Split(*zipkinAddr, ","),
				zipkin.KafkaLogger(logger),
			)
			if err != nil {
				logger.Log("err", err)
				os.Exit(1)
			}
			tracer, err = zipkin.NewTracer(
				zipkin.NewRecorder(collector, false, "localhost:80", "addsvc"),
			)
			if err != nil {
				logger.Log("err", err)
				os.Exit(1)
			}
		} else if *appdashAddr != "" {
			logger := log.NewContext(logger).With("tracer", "Appdash")
			logger.Log("addr", *appdashAddr)
			tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr))
		} else if *lightstepToken != "" {
			logger := log.NewContext(logger).With("tracer", "LightStep")
			logger.Log() // probably don't want to print out the token :)
			tracer = lightstep.NewTracer(lightstep.Options{
				AccessToken: *lightstepToken,
			})
			defer lightstep.FlushLightStepTracer(tracer)
		} else {
			logger := log.NewContext(logger).With("tracer", "none")
			logger.Log()
			tracer = stdopentracing.GlobalTracer() // no-op
		}
	}

	// Business domain.
	var service addsvc.Service
	{
		service = addsvc.NewBasicService()
		service = addsvc.ServiceLoggingMiddleware(logger)(service)
		service = addsvc.ServiceInstrumentingMiddleware(ints, chars)(service)
	}

	// Endpoint domain.
	var sumEndpoint endpoint.Endpoint
	{
		sumDuration := duration.With("method", "Sum")
		sumLogger := log.NewContext(logger).With("method", "Sum")

		sumEndpoint = addsvc.MakeSumEndpoint(service)
		sumEndpoint = opentracing.TraceServer(tracer, "Sum")(sumEndpoint)
		sumEndpoint = addsvc.EndpointInstrumentingMiddleware(sumDuration)(sumEndpoint)
		sumEndpoint = addsvc.EndpointLoggingMiddleware(sumLogger)(sumEndpoint)
	}
	var concatEndpoint endpoint.Endpoint
	{
		concatDuration := duration.With("method", "Concat")
		concatLogger := log.NewContext(logger).With("method", "Concat")

		concatEndpoint = addsvc.MakeConcatEndpoint(service)
		concatEndpoint = opentracing.TraceServer(tracer, "Concat")(concatEndpoint)
		concatEndpoint = addsvc.EndpointInstrumentingMiddleware(concatDuration)(concatEndpoint)
		concatEndpoint = addsvc.EndpointLoggingMiddleware(concatLogger)(concatEndpoint)
	}
	endpoints := addsvc.Endpoints{
		SumEndpoint:    sumEndpoint,
		ConcatEndpoint: concatEndpoint,
	}

	// Mechanical domain.
	errc := make(chan error)
	ctx := context.Background()

	// Interrupt handler.
	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		errc <- fmt.Errorf("%s", <-c)
	}()

	// Debug listener.
	go func() {
		logger := log.NewContext(logger).With("transport", "debug")

		m := http.NewServeMux()
		m.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
		m.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
		m.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
		m.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
		m.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

		logger.Log("addr", *debugAddr)
		errc <- http.ListenAndServe(*debugAddr, m)
	}()

	// HTTP transport.
	go func() {
		logger := log.NewContext(logger).With("transport", "HTTP")
		h := addsvc.MakeHTTPHandler(ctx, endpoints, tracer, logger)
		logger.Log("addr", *httpAddr)
		errc <- http.ListenAndServe(*httpAddr, h)
	}()

	// gRPC transport.
	go func() {
		logger := log.NewContext(logger).With("transport", "gRPC")

		ln, err := net.Listen("tcp", *grpcAddr)
		if err != nil {
			errc <- err
			return
		}

		srv := addsvc.MakeGRPCServer(ctx, endpoints, tracer, logger)
		s := grpc.NewServer()
		pb.RegisterAddServer(s, srv)

		logger.Log("addr", *grpcAddr)
		errc <- s.Serve(ln)
	}()

	// Thrift transport.
	go func() {
		logger := log.NewContext(logger).With("transport", "Thrift")

		var protocolFactory thrift.TProtocolFactory
		switch *thriftProtocol {
		case "binary":
			protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
		case "compact":
			protocolFactory = thrift.NewTCompactProtocolFactory()
		case "json":
			protocolFactory = thrift.NewTJSONProtocolFactory()
		case "simplejson":
			protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
		default:
			errc <- fmt.Errorf("invalid Thrift protocol %q", *thriftProtocol)
			return
		}

		var transportFactory thrift.TTransportFactory
		if *thriftBufferSize > 0 {
			transportFactory = thrift.NewTBufferedTransportFactory(*thriftBufferSize)
		} else {
			transportFactory = thrift.NewTTransportFactory()
		}
		if *thriftFramed {
			transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
		}

		transport, err := thrift.NewTServerSocket(*thriftAddr)
		if err != nil {
			errc <- err
			return
		}

		logger.Log("addr", *thriftAddr)
		errc <- thrift.NewTSimpleServer4(
			thriftadd.NewAddServiceProcessor(addsvc.MakeThriftHandler(ctx, endpoints)),
			transport,
			transportFactory,
			protocolFactory,
		).Serve()
	}()

	// Run!
	logger.Log("exit", <-errc)

	reporter.Start()
	defer reporter.Stop()
}
<|endoftext|>