<commit_before>package main

import (
	"os"
	"strings"
	"syscall"
	"time"

	"github.com/lxc/lxd/shared"
)

// Export the mount options map since we might find it useful in other parts of
// LXD.
type mountOptions struct {
	capture bool
	flag    uintptr
}

var MountOptions = map[string]mountOptions{
	"async":         {false, syscall.MS_SYNCHRONOUS},
	"atime":         {false, syscall.MS_NOATIME},
	"bind":          {true, syscall.MS_BIND},
	"defaults":      {true, 0},
	"dev":           {false, syscall.MS_NODEV},
	"diratime":      {false, syscall.MS_NODIRATIME},
	"dirsync":       {true, syscall.MS_DIRSYNC},
	"exec":          {false, syscall.MS_NOEXEC},
	"lazytime":      {true, MS_LAZYTIME},
	"mand":          {true, syscall.MS_MANDLOCK},
	"noatime":       {true, syscall.MS_NOATIME},
	"nodev":         {true, syscall.MS_NODEV},
	"nodiratime":    {true, syscall.MS_NODIRATIME},
	"noexec":        {true, syscall.MS_NOEXEC},
	"nomand":        {false, syscall.MS_MANDLOCK},
	"norelatime":    {false, syscall.MS_RELATIME},
	"nostrictatime": {false, syscall.MS_STRICTATIME},
	"nosuid":        {true, syscall.MS_NOSUID},
	"rbind":         {true, syscall.MS_BIND | syscall.MS_REC},
	"relatime":      {true, syscall.MS_RELATIME},
	"remount":       {true, syscall.MS_REMOUNT},
	"ro":            {true, syscall.MS_RDONLY},
	"rw":            {false, syscall.MS_RDONLY},
	"strictatime":   {true, syscall.MS_STRICTATIME},
	"suid":          {false, syscall.MS_NOSUID},
	"sync":          {true, syscall.MS_SYNCHRONOUS},
}

func lxdResolveMountoptions(options string) (uintptr, string) {
	mountFlags := uintptr(0)
	tmp := strings.SplitN(options, ",", -1)
	for i := 0; i < len(tmp); i++ {
		opt := tmp[i]
		do, ok := MountOptions[opt]
		if !ok {
			continue
		}

		if do.capture {
			mountFlags |= do.flag
		} else {
			mountFlags &= ^do.flag
		}

		copy(tmp[i:], tmp[i+1:])
		tmp[len(tmp)-1] = ""
		tmp = tmp[:len(tmp)-1]
		i--
	}

	return mountFlags, strings.Join(tmp, ",")
}

// Useful functions for unreliable backends
func tryMount(src string, dst string, fs string, flags uintptr, options string) error {
	var err error

	for i := 0; i < 20; i++ {
		err = syscall.Mount(src, dst, fs, flags, options)
		if err == nil {
			break
		}

		time.Sleep(500 * time.Millisecond)
	}

	if err != nil {
		return err
	}

	return nil
}

func tryUnmount(path string, flags int) error {
	var err error

	for i := 0; i < 20; i++ {
		err = syscall.Unmount(path, flags)
		if err == nil {
			break
		}

		time.Sleep(500 * time.Millisecond)
	}

	if err != nil && err == syscall.EBUSY {
		return err
	}

	return nil
}

func storageValidName(value string) error {
	return nil
}

func storageConfigDiff(oldConfig map[string]string, newConfig map[string]string) ([]string, bool) {
	changedConfig := []string{}
	userOnly := true
	for key := range oldConfig {
		if oldConfig[key] != newConfig[key] {
			if !strings.HasPrefix(key, "user.") {
				userOnly = false
			}

			if !shared.StringInSlice(key, changedConfig) {
				changedConfig = append(changedConfig, key)
			}
		}
	}

	for key := range newConfig {
		if oldConfig[key] != newConfig[key] {
			if !strings.HasPrefix(key, "user.") {
				userOnly = false
			}

			if !shared.StringInSlice(key, changedConfig) {
				changedConfig = append(changedConfig, key)
			}
		}
	}

	// Skip on no change
	if len(changedConfig) == 0 {
		return nil, false
	}

	return changedConfig, userOnly
}

// Default permissions for folders in ${LXD_DIR}
const containersDirMode os.FileMode = 0755
const customDirMode os.FileMode = 0755
const imagesDirMode os.FileMode = 0700
const snapshotsDirMode os.FileMode = 0700
<commit_msg>storage: add helper to detect if pool is in use<commit_after>package main

import (
	"database/sql"
	"os"
	"strings"
	"syscall"
	"time"

	"github.com/lxc/lxd/shared"
)

// Export the mount options map since we might find it useful in other parts of
// LXD.
type mountOptions struct {
	capture bool
	flag    uintptr
}

var MountOptions = map[string]mountOptions{
	"async":         {false, syscall.MS_SYNCHRONOUS},
	"atime":         {false, syscall.MS_NOATIME},
	"bind":          {true, syscall.MS_BIND},
	"defaults":      {true, 0},
	"dev":           {false, syscall.MS_NODEV},
	"diratime":      {false, syscall.MS_NODIRATIME},
	"dirsync":       {true, syscall.MS_DIRSYNC},
	"exec":          {false, syscall.MS_NOEXEC},
	"lazytime":      {true, MS_LAZYTIME},
	"mand":          {true, syscall.MS_MANDLOCK},
	"noatime":       {true, syscall.MS_NOATIME},
	"nodev":         {true, syscall.MS_NODEV},
	"nodiratime":    {true, syscall.MS_NODIRATIME},
	"noexec":        {true, syscall.MS_NOEXEC},
	"nomand":        {false, syscall.MS_MANDLOCK},
	"norelatime":    {false, syscall.MS_RELATIME},
	"nostrictatime": {false, syscall.MS_STRICTATIME},
	"nosuid":        {true, syscall.MS_NOSUID},
	"rbind":         {true, syscall.MS_BIND | syscall.MS_REC},
	"relatime":      {true, syscall.MS_RELATIME},
	"remount":       {true, syscall.MS_REMOUNT},
	"ro":            {true, syscall.MS_RDONLY},
	"rw":            {false, syscall.MS_RDONLY},
	"strictatime":   {true, syscall.MS_STRICTATIME},
	"suid":          {false, syscall.MS_NOSUID},
	"sync":          {true, syscall.MS_SYNCHRONOUS},
}

func lxdResolveMountoptions(options string) (uintptr, string) {
	mountFlags := uintptr(0)
	tmp := strings.SplitN(options, ",", -1)
	for i := 0; i < len(tmp); i++ {
		opt := tmp[i]
		do, ok := MountOptions[opt]
		if !ok {
			continue
		}

		if do.capture {
			mountFlags |= do.flag
		} else {
			mountFlags &= ^do.flag
		}

		copy(tmp[i:], tmp[i+1:])
		tmp[len(tmp)-1] = ""
		tmp = tmp[:len(tmp)-1]
		i--
	}

	return mountFlags, strings.Join(tmp, ",")
}

// Useful functions for unreliable backends
func tryMount(src string, dst string, fs string, flags uintptr, options string) error {
	var err error

	for i := 0; i < 20; i++ {
		err = syscall.Mount(src, dst, fs, flags, options)
		if err == nil {
			break
		}

		time.Sleep(500 * time.Millisecond)
	}

	if err != nil {
		return err
	}

	return nil
}

func tryUnmount(path string, flags int) error {
	var err error

	for i := 0; i < 20; i++ {
		err = syscall.Unmount(path, flags)
		if err == nil {
			break
		}

		time.Sleep(500 * time.Millisecond)
	}

	if err != nil && err == syscall.EBUSY {
		return err
	}

	return nil
}

func storageValidName(value string) error {
	return nil
}

func storageConfigDiff(oldConfig map[string]string, newConfig map[string]string) ([]string, bool) {
	changedConfig := []string{}
	userOnly := true
	for key := range oldConfig {
		if oldConfig[key] != newConfig[key] {
			if !strings.HasPrefix(key, "user.") {
				userOnly = false
			}

			if !shared.StringInSlice(key, changedConfig) {
				changedConfig = append(changedConfig, key)
			}
		}
	}

	for key := range newConfig {
		if oldConfig[key] != newConfig[key] {
			if !strings.HasPrefix(key, "user.") {
				userOnly = false
			}

			if !shared.StringInSlice(key, changedConfig) {
				changedConfig = append(changedConfig, key)
			}
		}
	}

	// Skip on no change
	if len(changedConfig) == 0 {
		return nil, false
	}

	return changedConfig, userOnly
}

// Default permissions for folders in ${LXD_DIR}
const containersDirMode os.FileMode = 0755
const customDirMode os.FileMode = 0755
const imagesDirMode os.FileMode = 0700
const snapshotsDirMode os.FileMode = 0700

// Detect whether LXD already uses the given storage pool.
func lxdUsesPool(db *sql.DB, onDiskPoolName string, driver string, onDiskProperty string) (bool, string, error) {
	pools, err := dbStoragePools(db)
	if err != nil && err != NoSuchObjectError {
		return false, "", err
	}

	for _, pool := range pools {
		_, pl, err := dbStoragePoolGet(db, pool)
		if err != nil {
			continue
		}

		if pl.Driver != driver {
			continue
		}

		if pl.Config[onDiskProperty] == onDiskPoolName {
			return true, pl.Name, nil
		}
	}

	return false, "", nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/pivotal-golang/clock"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"github.com/xoebus/zest"

	"github.com/concourse/baggageclaim/api"
	"github.com/concourse/baggageclaim/reaper"
	"github.com/concourse/baggageclaim/uidjunk"
	"github.com/concourse/baggageclaim/volume"
	"github.com/concourse/baggageclaim/volume/driver"
)

var listenAddress = flag.String(
	"listenAddress",
	"0.0.0.0",
	"address to listen on",
)

var listenPort = flag.Int(
	"listenPort",
	7788,
	"port for the server to listen on",
)

var volumeDir = flag.String(
	"volumeDir",
	"",
	"directory where volumes and metadata will be stored",
)

var driverType = flag.String(
	"driverType",
	"",
	"the backend driver to use for filesystems",
)

var reapInterval = flag.Duration(
	"reapInterval",
	10*time.Second,
	"interval on which to reap expired containers",
)

var yellerAPIKey = flag.String(
	"yellerAPIKey",
	"",
	"API token to output error logs to Yeller",
)
var yellerEnvironment = flag.String(
	"yellerEnvironment",
	"development",
	"environment label for Yeller",
)

func main() {
	flag.Parse()
	if *volumeDir == "" {
		fmt.Fprintln(os.Stderr, "-volumeDir must be specified")
		os.Exit(1)
	}

	logger := lager.NewLogger("baggageclaim")
	sink := lager.NewReconfigurableSink(lager.NewWriterSink(os.Stdout, lager.DEBUG), lager.INFO)
	logger.RegisterSink(sink)

	if *yellerAPIKey != "" {
		yellerSink := zest.NewYellerSink(*yellerAPIKey, *yellerEnvironment)
		logger.RegisterSink(yellerSink)
	}

	listenAddr := fmt.Sprintf("%s:%d", *listenAddress, *listenPort)

	var volumeDriver volume.Driver

	if *driverType == "btrfs" {
		volumeDriver = driver.NewBtrFSDriver(logger.Session("driver"))
	} else {
		volumeDriver = &driver.NaiveDriver{}
	}

	var namespacer uidjunk.Namespacer

	maxUID, maxUIDErr := uidjunk.DefaultUIDMap.MaxValid()
	maxGID, maxGIDErr := uidjunk.DefaultGIDMap.MaxValid()

	if runtime.GOOS == "linux" && maxUIDErr == nil && maxGIDErr == nil {
		maxId := uidjunk.Min(maxUID, maxGID)

		mappingList := uidjunk.MappingList{
			{
				FromID: 0,
				ToID:   maxId,
				Size:   1,
			},
			{
				FromID: 1,
				ToID:   1,
				Size:   maxId - 1,
			},
		}

		uidTranslator := uidjunk.NewUidTranslator(
			mappingList,
			mappingList,
		)

		namespacer = &uidjunk.UidNamespacer{
			Translator: uidTranslator,
			Logger:     logger.Session("uid-namespacer"),
		}
	} else {
		namespacer = uidjunk.NoopNamespacer{}
	}

	locker := volume.NewLockManager()

	filesystem, err := volume.NewFilesystem(volumeDriver, *volumeDir)
	if err != nil {
		logger.Fatal("failed-to-initialize-filesystem", err)
	}

	volumeRepo := volume.NewRepository(
		logger.Session("repository"),
		filesystem,
		locker,
	)

	apiHandler, err := api.NewHandler(
		logger.Session("api"),
		volumeRepo,
		namespacer,
	)
	if err != nil {
		logger.Fatal("failed-to-create-handler", err)
	}

	clock := clock.NewClock()

	morbidReality := reaper.NewReaper(clock, volumeRepo)

	memberGrouper := []grouper.Member{
		{"api", http_server.New(listenAddr, apiHandler)},
		{"reaper", reaper.NewRunner(logger, clock, *reapInterval, morbidReality.Reap)},
	}

	group := grouper.NewParallel(os.Interrupt, memberGrouper)
	running := ifrit.Invoke(sigmon.New(group))

	logger.Info("listening", lager.Data{
		"addr": listenAddr,
	})

	err = <-running.Wait()
	if err != nil {
		logger.Error("exited-with-failure", err)
		os.Exit(1)
	}
}
<commit_msg>fix main<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/pivotal-golang/clock"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"github.com/xoebus/zest"

	"github.com/concourse/baggageclaim/api"
	"github.com/concourse/baggageclaim/reaper"
	"github.com/concourse/baggageclaim/uidjunk"
	"github.com/concourse/baggageclaim/volume"
	"github.com/concourse/baggageclaim/volume/driver"
)

var listenAddress = flag.String(
	"listenAddress",
	"0.0.0.0",
	"address to listen on",
)

var listenPort = flag.Int(
	"listenPort",
	7788,
	"port for the server to listen on",
)

var volumeDir = flag.String(
	"volumeDir",
	"",
	"directory where volumes and metadata will be stored",
)

var driverType = flag.String(
	"driverType",
	"",
	"the backend driver to use for filesystems",
)

var reapInterval = flag.Duration(
	"reapInterval",
	10*time.Second,
	"interval on which to reap expired containers",
)

var yellerAPIKey = flag.String(
	"yellerAPIKey",
	"",
	"API token to output error logs to Yeller",
)
var yellerEnvironment = flag.String(
	"yellerEnvironment",
	"development",
	"environment label for Yeller",
)

func main() {
	flag.Parse()
	if *volumeDir == "" {
		fmt.Fprintln(os.Stderr, "-volumeDir must be specified")
		os.Exit(1)
	}

	logger := lager.NewLogger("baggageclaim")
	sink := lager.NewReconfigurableSink(lager.NewWriterSink(os.Stdout, lager.DEBUG), lager.INFO)
	logger.RegisterSink(sink)

	if *yellerAPIKey != "" {
		yellerSink := zest.NewYellerSink(*yellerAPIKey, *yellerEnvironment)
		logger.RegisterSink(yellerSink)
	}

	listenAddr := fmt.Sprintf("%s:%d", *listenAddress, *listenPort)

	var volumeDriver volume.Driver

	if *driverType == "btrfs" {
		volumeDriver = driver.NewBtrFSDriver(logger.Session("driver"))
	} else {
		volumeDriver = &driver.NaiveDriver{}
	}

	var namespacer uidjunk.Namespacer

	maxUID, maxUIDErr := uidjunk.DefaultUIDMap.MaxValid()
	maxGID, maxGIDErr := uidjunk.DefaultGIDMap.MaxValid()

	if runtime.GOOS == "linux" && maxUIDErr == nil && maxGIDErr == nil {
		maxId := uidjunk.Min(maxUID, maxGID)

		mappingList := uidjunk.MappingList{
			{
				FromID: 0,
				ToID:   maxId,
				Size:   1,
			},
			{
				FromID: 1,
				ToID:   1,
				Size:   maxId - 1,
			},
		}

		uidTranslator := uidjunk.NewUidTranslator(
			mappingList,
			mappingList,
		)

		namespacer = &uidjunk.UidNamespacer{
			Translator: uidTranslator,
			Logger:     logger.Session("uid-namespacer"),
		}
	} else {
		namespacer = uidjunk.NoopNamespacer{}
	}

	locker := volume.NewLockManager()

	filesystem, err := volume.NewFilesystem(volumeDriver, *volumeDir)
	if err != nil {
		logger.Fatal("failed-to-initialize-filesystem", err)
	}

	volumeRepo := volume.NewRepository(
		logger.Session("repository"),
		filesystem,
		locker,
	)

	strategerizer := volume.NewStrategerizer(namespacer, locker)

	apiHandler, err := api.NewHandler(
		logger.Session("api"),
		strategerizer,
		volumeRepo,
	)
	if err != nil {
		logger.Fatal("failed-to-create-handler", err)
	}

	clock := clock.NewClock()

	morbidReality := reaper.NewReaper(clock, volumeRepo)

	memberGrouper := []grouper.Member{
		{"api", http_server.New(listenAddr, apiHandler)},
		{"reaper", reaper.NewRunner(logger, clock, *reapInterval, morbidReality.Reap)},
	}

	group := grouper.NewParallel(os.Interrupt, memberGrouper)
	running := ifrit.Invoke(sigmon.New(group))

	logger.Info("listening", lager.Data{
		"addr": listenAddr,
	})

	err = <-running.Wait()
	if err != nil {
		logger.Error("exited-with-failure", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/watcher"
	"launchpad.net/tomb"

	// register providers
	_ "launchpad.net/juju-core/environs/ec2"
)

type Provisioner struct {
	st      *state.State
	info    *state.Info
	environ environs.Environ
	tomb    tomb.Tomb

	// machine.Id => environs.Instance
	instances map[int]environs.Instance
	// instance.Id => *state.Machine
	machines map[string]*state.Machine
}

// NewProvisioner returns a Provisioner.
func NewProvisioner(info *state.Info) (*Provisioner, error) {
	st, err := state.Open(info)
	if err != nil {
		return nil, err
	}
	p := &Provisioner{
		st:        st,
		info:      info,
		instances: make(map[int]environs.Instance),
		machines:  make(map[string]*state.Machine),
	}
	go p.loop()
	return p, nil
}

func (p *Provisioner) loop() {
	defer p.tomb.Done()
	defer p.st.Close()
	environWatcher := p.st.WatchEnvironConfig()
	defer watcher.Stop(environWatcher, &p.tomb)

	// Get a new StateInfo from the environment: the one used to
	// launch the agent may refer to localhost, which will be
	// unhelpful when attempting to run an agent on a new machine.
refreshState:
	for {
		select {
		case <-p.tomb.Dying():
			return
		case config, ok := <-environWatcher.Changes():
			if !ok {
				p.tomb.Kill(watcher.MustErr(environWatcher))
				return
			}
			var err error
			p.environ, err = environs.NewEnviron(config.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			log.Printf("provisioner loaded new environment configuration")
			if p.info, err = p.environ.StateInfo(); err != nil {
				p.tomb.Kill(err)
				return
			}
			break refreshState
		}
	}

	// Call processMachines to stop any unknown instances before watching machines.
	if err := p.processMachines(nil, nil); err != nil {
		p.tomb.Kill(err)
		return
	}

	// Start responding to changes in machines, and to any further updates
	// to the environment config.
	machinesWatcher := p.st.WatchMachines()
	defer watcher.Stop(machinesWatcher, &p.tomb)
	for {
		select {
		case <-p.tomb.Dying():
			return
		case change, ok := <-environWatcher.Changes():
			if !ok {
				p.tomb.Kill(watcher.MustErr(environWatcher))
				return
			}
			config, err := environs.NewConfig(change.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			p.environ.SetConfig(config)
			log.Printf("provisioner loaded new environment configuration")
		case machines, ok := <-machinesWatcher.Changes():
			if !ok {
				p.tomb.Kill(watcher.MustErr(machinesWatcher))
				return
			}
			// TODO(dfc) fire process machines periodically to shut down unknown
			// instances.
			if err := p.processMachines(machines.Added, machines.Removed); err != nil {
				p.tomb.Kill(err)
				return
			}
		}
	}
}

// Wait waits for the Provisioner to exit.
func (p *Provisioner) Wait() error {
	return p.tomb.Wait()
}

// Stop stops the Provisioner and returns any error encountered while
// provisioning.
func (p *Provisioner) Stop() error {
	p.tomb.Kill(nil)
	return p.tomb.Wait()
}

func (p *Provisioner) processMachines(added, removed []*state.Machine) error {
	// step 1. find which of the added machines have not
	// yet been allocated a started instance.
	notstarted, err := p.findNotStarted(added)
	if err != nil {
		return err
	}

	// step 2. start an instance for any machines we found.
	if err := p.startMachines(notstarted); err != nil {
		return err
	}

	// step 3. stop all machines that were removed from the state.
	stopping, err := p.instancesForMachines(removed)
	if err != nil {
		return err
	}

	// step 4. find instances which are running but have no machine
	// associated with them.
	unknown, err := p.findUnknownInstances()
	if err != nil {
		return err
	}

	return p.stopInstances(append(stopping, unknown...))
}

// findUnknownInstances finds instances which are not associated with a machine.
func (p *Provisioner) findUnknownInstances() ([]environs.Instance, error) {
	all, err := p.environ.AllInstances()
	if err != nil {
		return nil, err
	}
	instances := make(map[string]environs.Instance)
	for _, i := range all {
		instances[i.Id()] = i
	}
	// TODO(dfc) this is very inefficient, p.machines cache may help.
	machines, err := p.st.AllMachines()
	if err != nil {
		return nil, err
	}
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			if _, ok := err.(*state.NoInstanceIdError); !ok {
				return nil, err
			}
		}
		delete(instances, id)
	}
	var unknown []environs.Instance
	for _, i := range instances {
		unknown = append(unknown, i)
	}
	return unknown, nil
}

// findNotStarted finds machines without an InstanceId set, these are defined as not started.
func (p *Provisioner) findNotStarted(machines []*state.Machine) ([]*state.Machine, error) {
	var notstarted []*state.Machine
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			if _, ok := err.(*state.NoInstanceIdError); !ok {
				return nil, err
			}
			notstarted = append(notstarted, m)
		} else {
			log.Printf("machine %s already started as instance %q", m, id)
		}
	}
	return notstarted, nil
}

func (p *Provisioner) startMachines(machines []*state.Machine) error {
	for _, m := range machines {
		if err := p.startMachine(m); err != nil {
			return err
		}
	}
	return nil
}

func (p *Provisioner) startMachine(m *state.Machine) error {
	// TODO(dfc) the state.Info passed to environ.StartInstance remains contentious
	// however as the PA only knows one state.Info, and that info is used by MAs and
	// UAs to locate the ZK for this environment, it is logical to use the same
	// state.Info as the PA.
	inst, err := p.environ.StartInstance(m.Id(), p.info)
	if err != nil {
		log.Printf("provisioner can't start machine %s: %v", m, err)
		return err
	}

	// assign the instance id to the machine
	if err := m.SetInstanceId(inst.Id()); err != nil {
		return err
	}

	// populate the local cache
	p.instances[m.Id()] = inst
	p.machines[inst.Id()] = m
	log.Printf("provisioner started machine %s as instance %s", m, inst.Id())
	return nil
}

func (p *Provisioner) stopInstances(instances []environs.Instance) error {
	// Although calling StopInstance with an empty slice should produce no change in the
	// provider, environs like dummy do not consider this a noop.
	if len(instances) == 0 {
		return nil
	}
	if err := p.environ.StopInstances(instances); err != nil {
		return err
	}

	// cleanup cache
	for _, i := range instances {
		if m, ok := p.machines[i.Id()]; ok {
			delete(p.machines, i.Id())
			delete(p.instances, m.Id())
		}
	}
	return nil
}

// instanceForMachine returns the environs.Instance that represents this machine's instance.
func (p *Provisioner) instanceForMachine(m *state.Machine) (environs.Instance, error) {
	inst, ok := p.instances[m.Id()]
	if !ok {
		// not cached locally, ask the environ.
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		// TODO(dfc) this should be batched, or the cache preloaded at startup to
		// avoid N calls to the envirion.
		insts, err := p.environ.Instances([]string{id})
		if err != nil {
			// the provider doesn't know about this instance, give up.
			return nil, err
		}
		inst = insts[0]
	}
	return inst, nil
}

// instancesForMachines returns a list of environs.Instance that represent the list of machines running
// in the provider.
func (p *Provisioner) instancesForMachines(machines []*state.Machine) ([]environs.Instance, error) {
	var insts []environs.Instance
	for _, m := range machines {
		inst, err := p.instanceForMachine(m)
		if err != nil {
			return nil, err
		}
		insts = append(insts, inst)
	}
	return insts, nil
}
<commit_msg>remove unneeded import<commit_after>package main

import (
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/watcher"
	"launchpad.net/tomb"
)

type Provisioner struct {
	st      *state.State
	info    *state.Info
	environ environs.Environ
	tomb    tomb.Tomb

	// machine.Id => environs.Instance
	instances map[int]environs.Instance
	// instance.Id => *state.Machine
	machines map[string]*state.Machine
}

// NewProvisioner returns a Provisioner.
func NewProvisioner(info *state.Info) (*Provisioner, error) {
	st, err := state.Open(info)
	if err != nil {
		return nil, err
	}
	p := &Provisioner{
		st:        st,
		info:      info,
		instances: make(map[int]environs.Instance),
		machines:  make(map[string]*state.Machine),
	}
	go p.loop()
	return p, nil
}

func (p *Provisioner) loop() {
	defer p.tomb.Done()
	defer p.st.Close()
	environWatcher := p.st.WatchEnvironConfig()
	defer watcher.Stop(environWatcher, &p.tomb)

	// Get a new StateInfo from the environment: the one used to
	// launch the agent may refer to localhost, which will be
	// unhelpful when attempting to run an agent on a new machine.
refreshState:
	for {
		select {
		case <-p.tomb.Dying():
			return
		case config, ok := <-environWatcher.Changes():
			if !ok {
				p.tomb.Kill(watcher.MustErr(environWatcher))
				return
			}
			var err error
			p.environ, err = environs.NewEnviron(config.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			log.Printf("provisioner loaded new environment configuration")
			if p.info, err = p.environ.StateInfo(); err != nil {
				p.tomb.Kill(err)
				return
			}
			break refreshState
		}
	}

	// Call processMachines to stop any unknown instances before watching machines.
	if err := p.processMachines(nil, nil); err != nil {
		p.tomb.Kill(err)
		return
	}

	// Start responding to changes in machines, and to any further updates
	// to the environment config.
	machinesWatcher := p.st.WatchMachines()
	defer watcher.Stop(machinesWatcher, &p.tomb)
	for {
		select {
		case <-p.tomb.Dying():
			return
		case change, ok := <-environWatcher.Changes():
			if !ok {
				p.tomb.Kill(watcher.MustErr(environWatcher))
				return
			}
			config, err := environs.NewConfig(change.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			p.environ.SetConfig(config)
			log.Printf("provisioner loaded new environment configuration")
		case machines, ok := <-machinesWatcher.Changes():
			if !ok {
				p.tomb.Kill(watcher.MustErr(machinesWatcher))
				return
			}
			// TODO(dfc) fire process machines periodically to shut down unknown
			// instances.
			if err := p.processMachines(machines.Added, machines.Removed); err != nil {
				p.tomb.Kill(err)
				return
			}
		}
	}
}

// Wait waits for the Provisioner to exit.
func (p *Provisioner) Wait() error {
	return p.tomb.Wait()
}

// Stop stops the Provisioner and returns any error encountered while
// provisioning.
func (p *Provisioner) Stop() error {
	p.tomb.Kill(nil)
	return p.tomb.Wait()
}

func (p *Provisioner) processMachines(added, removed []*state.Machine) error {
	// step 1. find which of the added machines have not
	// yet been allocated a started instance.
	notstarted, err := p.findNotStarted(added)
	if err != nil {
		return err
	}

	// step 2. start an instance for any machines we found.
	if err := p.startMachines(notstarted); err != nil {
		return err
	}

	// step 3. stop all machines that were removed from the state.
	stopping, err := p.instancesForMachines(removed)
	if err != nil {
		return err
	}

	// step 4. find instances which are running but have no machine
	// associated with them.
	unknown, err := p.findUnknownInstances()
	if err != nil {
		return err
	}

	return p.stopInstances(append(stopping, unknown...))
}

// findUnknownInstances finds instances which are not associated with a machine.
func (p *Provisioner) findUnknownInstances() ([]environs.Instance, error) {
	all, err := p.environ.AllInstances()
	if err != nil {
		return nil, err
	}
	instances := make(map[string]environs.Instance)
	for _, i := range all {
		instances[i.Id()] = i
	}
	// TODO(dfc) this is very inefficient, p.machines cache may help.
	machines, err := p.st.AllMachines()
	if err != nil {
		return nil, err
	}
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			if _, ok := err.(*state.NoInstanceIdError); !ok {
				return nil, err
			}
		}
		delete(instances, id)
	}
	var unknown []environs.Instance
	for _, i := range instances {
		unknown = append(unknown, i)
	}
	return unknown, nil
}

// findNotStarted finds machines without an InstanceId set, these are defined as not started.
func (p *Provisioner) findNotStarted(machines []*state.Machine) ([]*state.Machine, error) {
	var notstarted []*state.Machine
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			if _, ok := err.(*state.NoInstanceIdError); !ok {
				return nil, err
			}
			notstarted = append(notstarted, m)
		} else {
			log.Printf("machine %s already started as instance %q", m, id)
		}
	}
	return notstarted, nil
}

func (p *Provisioner) startMachines(machines []*state.Machine) error {
	for _, m := range machines {
		if err := p.startMachine(m); err != nil {
			return err
		}
	}
	return nil
}

func (p *Provisioner) startMachine(m *state.Machine) error {
	// TODO(dfc) the state.Info passed to environ.StartInstance remains contentious
	// however as the PA only knows one state.Info, and that info is used by MAs and
	// UAs to locate the ZK for this environment, it is logical to use the same
	// state.Info as the PA.
	inst, err := p.environ.StartInstance(m.Id(), p.info)
	if err != nil {
		log.Printf("provisioner can't start machine %s: %v", m, err)
		return err
	}

	// assign the instance id to the machine
	if err := m.SetInstanceId(inst.Id()); err != nil {
		return err
	}

	// populate the local cache
	p.instances[m.Id()] = inst
	p.machines[inst.Id()] = m
	log.Printf("provisioner started machine %s as instance %s", m, inst.Id())
	return nil
}

func (p *Provisioner) stopInstances(instances []environs.Instance) error {
	// Although calling StopInstance with an empty slice should produce no change in the
	// provider, environs like dummy do not consider this a noop.
	if len(instances) == 0 {
		return nil
	}
	if err := p.environ.StopInstances(instances); err != nil {
		return err
	}

	// cleanup cache
	for _, i := range instances {
		if m, ok := p.machines[i.Id()]; ok {
			delete(p.machines, i.Id())
			delete(p.instances, m.Id())
		}
	}
	return nil
}

// instanceForMachine returns the environs.Instance that represents this machine's instance.
func (p *Provisioner) instanceForMachine(m *state.Machine) (environs.Instance, error) {
	inst, ok := p.instances[m.Id()]
	if !ok {
		// not cached locally, ask the environ.
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		// TODO(dfc) this should be batched, or the cache preloaded at startup to
		// avoid N calls to the envirion.
		insts, err := p.environ.Instances([]string{id})
		if err != nil {
			// the provider doesn't know about this instance, give up.
			return nil, err
		}
		inst = insts[0]
	}
	return inst, nil
}

// instancesForMachines returns a list of environs.Instance that represent the list of machines running
// in the provider.
func (p *Provisioner) instancesForMachines(machines []*state.Machine) ([]environs.Instance, error) {
	var insts []environs.Instance
	for _, m := range machines {
		inst, err := p.instanceForMachine(m)
		if err != nil {
			return nil, err
		}
		insts = append(insts, inst)
	}
	return insts, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"k8s.io/release/pkg/http"
	"k8s.io/release/pkg/mail"
	"k8s.io/release/pkg/release"
	"k8s.io/release/pkg/util"
)

const (
	sendgridAPIKeyFlag   = "sendgrid-api-key"
	sendgridAPIKeyEnvKey = "SENDGRID_API_KEY"
	nameFlag             = "name"
	emailFlag            = "email"
	tagFlag              = "tag"
	printOnlyFlag        = "print-only"
)

// announceCmd represents the subcommand for `krel announce`
var announceCmd = &cobra.Command{
	Use:   "announce",
	Short: "Announce Kubernetes releases",
	Long: fmt.Sprintf(`krel announce

krel announce can be used to announce already built Kubernetes releases to the
%q and %q Google Group.

If --nomock=true (the default), then the mail will be sent only to a test
Google Group %q.

It is necessary to either set a valid --%s,-s or export the
$%s environment variable. An API key can be created by
registering a sendgrid.com account and adding the key here:

https://app.sendgrid.com/settings/api_keys

Beside this, if the flags for a valid sender name (--%s,-n) and sender email
address (--%s,-e) are not set, then it tries to retrieve those values directly
from the Sendgrid API.

Setting a valid Kubernetes tag (--%s,-t) is always necessary.

If --%s,-p is given, then krel announce will only print the email content
without doing anything else.`,
		mail.KubernetesAnnounceGoogleGroup,
		mail.KubernetesDevGoogleGroup,
		mail.KubernetesAnnounceTestGoogleGroup,
		sendgridAPIKeyFlag,
		sendgridAPIKeyEnvKey,
		nameFlag,
		emailFlag,
		tagFlag,
		printOnlyFlag,
	),
	SilenceUsage:  true,
	SilenceErrors: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runAnnounce(announceOpts, rootOpts)
	},
}

type announceOptions struct {
	sendgridAPIKey string
	name           string
	email          string
	tag            string
	printOnly      bool
}

var announceOpts = &announceOptions{}

func init() {
	announceCmd.PersistentFlags().StringVarP(
		&announceOpts.sendgridAPIKey,
		sendgridAPIKeyFlag,
		"s",
		util.EnvDefault(sendgridAPIKeyEnvKey, ""),
		fmt.Sprintf(
			"API key for sendgrid, can be set via %s too",
			sendgridAPIKeyEnvKey,
		),
	)

	announceCmd.PersistentFlags().StringVarP(
		&announceOpts.name,
		nameFlag,
		"n",
		"",
		"mail sender name",
	)

	announceCmd.PersistentFlags().StringVarP(
		&announceOpts.email,
		emailFlag,
		"e",
		"",
		"email address",
	)

	announceCmd.PersistentFlags().StringVarP(
		&announceOpts.tag,
		tagFlag,
		"t",
		"",
		"built tag to be announced, will be used for fetching the "+
			"announcement from the google cloud bucket",
	)
	if err := announceCmd.MarkPersistentFlagRequired(tagFlag); err != nil {
		logrus.Fatal(err)
	}

	announceCmd.PersistentFlags().BoolVarP(
		&announceOpts.printOnly,
		printOnlyFlag,
		"p",
		false,
		"print the mail contents without sending it",
	)

	rootCmd.AddCommand(announceCmd)
}

func runAnnounce(opts *announceOptions, rootOpts *rootOptions) error {
	logrus.Info("Retrieving release announcement from Google Cloud Bucket")

	tag := util.AddTagPrefix(opts.tag)
	u := fmt.Sprintf(
		"%s/archive/anago-%s/announcement.html",
		release.URLPrefixForBucket(release.ProductionBucket), tag,
	)
	logrus.Infof("Using announcement remote URL: %s", u)

	content, err := http.GetURLResponse(u, false)
	if err != nil {
		return errors.Wrapf(err,
			"unable to retrieve release announcement form url: %s", u,
		)
	}

	if opts.printOnly {
		logrus.Infof("The email content is:")
		fmt.Print(content)
		return nil
	}

	if opts.sendgridAPIKey == "" {
		return errors.Errorf(
			"Neither --sendgrid-api-key,-s nor $%s is set", sendgridAPIKeyEnvKey,
		)
	}

	logrus.Info("Preparing mail sender")
	m := mail.NewSender(opts.sendgridAPIKey)

	if opts.name != "" && opts.email != "" {
		if err := m.SetSender(opts.name, opts.email); err != nil {
			return errors.Wrap(err, "unable to set mail sender")
		}
	} else {
		logrus.Info("Retrieving default sender from sendgrid API")
		if err := m.SetDefaultSender(); err != nil {
			return errors.Wrap(err, "setting default sender")
		}
	}

	groups := []mail.GoogleGroup{mail.KubernetesAnnounceTestGoogleGroup}
	if rootOpts.nomock {
		groups = []mail.GoogleGroup{
			mail.KubernetesAnnounceGoogleGroup,
			mail.KubernetesDevGoogleGroup,
		}
	}
	logrus.Infof("Using Google Groups as announcement target: %v", groups)

	if err := m.SetGoogleGroupRecipients(groups...); err != nil {
		return errors.Wrap(err, "unable to set mail recipients")
	}

	logrus.Info("Sending mail")
	subject := fmt.Sprintf("Kubernetes %s is live!", tag)
	if err := m.Send(content, subject); err != nil {
		return errors.Wrap(err, "unable to send mail")
	}

	return nil
}
<commit_msg>krel/announce: remove --sendgrid-api-key flag in favor to env var only<commit_after>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"k8s.io/release/pkg/http"
	"k8s.io/release/pkg/mail"
	"k8s.io/release/pkg/release"
	"k8s.io/release/pkg/util"
)

const (
	sendgridAPIKeyEnvKey = "SENDGRID_API_KEY"
	nameFlag             = "name"
	emailFlag            = "email"
	tagFlag              = "tag"
	printOnlyFlag        = "print-only"
)

// announceCmd represents the subcommand for `krel announce`
var announceCmd = &cobra.Command{
	Use:   "announce",
	Short: "Announce Kubernetes releases",
	Long: fmt.Sprintf(`krel announce

krel announce can be used to announce already built Kubernetes releases to the
%q and %q Google Group.

If --nomock=true (the default), then the mail will be sent only to a test
Google Group %q.

It is necessary to export the $%s environment variable. An API key can be created by
registering a sendgrid.com account and adding the key here:

https://app.sendgrid.com/settings/api_keys

Beside this, if the flags for a valid sender name (--%s,-n) and sender email
address (--%s,-e) are not set, then it tries to retrieve those values directly
from the Sendgrid API.

Setting a valid Kubernetes tag (--%s,-t) is always necessary.

If --%s,-p is given, then krel announce will only print the email content
without doing anything else.`,
		mail.KubernetesAnnounceGoogleGroup,
		mail.KubernetesDevGoogleGroup,
		mail.KubernetesAnnounceTestGoogleGroup,
		sendgridAPIKeyEnvKey,
		nameFlag,
		emailFlag,
		tagFlag,
		printOnlyFlag,
	),
	SilenceUsage:  true,
	SilenceErrors: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runAnnounce(announceOpts, rootOpts)
	},
}

type announceOptions struct {
	sendgridAPIKey string
	name           string
	email          string
	tag            string
	printOnly      bool
}

var announceOpts = &announceOptions{}

func init() {
	announceOpts.sendgridAPIKey = util.EnvDefault(sendgridAPIKeyEnvKey, "")

	announceCmd.PersistentFlags().StringVarP(
		&announceOpts.name,
		nameFlag,
		"n",
		"",
		"mail sender name",
	)

	announceCmd.PersistentFlags().StringVarP(
		&announceOpts.email,
		emailFlag,
		"e",
		"",
		"email address",
	)

	announceCmd.PersistentFlags().StringVarP(
		&announceOpts.tag,
		tagFlag,
		"t",
		"",
		"built tag to be announced, will be used for fetching the "+
			"announcement from the google cloud bucket",
	)
	if err := announceCmd.MarkPersistentFlagRequired(tagFlag); err != nil {
		logrus.Fatal(err)
	}

	announceCmd.PersistentFlags().BoolVarP(
		&announceOpts.printOnly,
		printOnlyFlag,
		"p",
		false,
		"print the mail contents without sending it",
	)

	rootCmd.AddCommand(announceCmd)
}

func runAnnounce(opts *announceOptions, rootOpts *rootOptions) error {
	logrus.Info("Retrieving release announcement from Google Cloud Bucket")

	tag := util.AddTagPrefix(opts.tag)
	u := fmt.Sprintf(
		"%s/archive/anago-%s/announcement.html",
		release.URLPrefixForBucket(release.ProductionBucket), tag,
	)
	logrus.Infof("Using announcement remote URL: %s", u)

	content, err := http.GetURLResponse(u, false)
	if err != nil {
		return errors.Wrapf(err,
			"unable to retrieve release announcement form url: %s", u,
		)
	}

	if opts.printOnly {
		logrus.Infof("The email content is:")
		fmt.Print(content)
		return nil
	}

	if opts.sendgridAPIKey == "" {
		return errors.Errorf(
			"$%s is not set", sendgridAPIKeyEnvKey,
		)
	}

	logrus.Info("Preparing mail sender")
	m := mail.NewSender(opts.sendgridAPIKey)

	if opts.name != "" && opts.email != "" {
		if err := m.SetSender(opts.name, opts.email); err != nil {
			return errors.Wrap(err, "unable to set mail sender")
		}
	} else {
		logrus.Info("Retrieving default sender from sendgrid API")
		if err := m.SetDefaultSender(); err != nil {
			return errors.Wrap(err, "setting default sender")
		}
	}

	groups := []mail.GoogleGroup{mail.KubernetesAnnounceTestGoogleGroup}
	if rootOpts.nomock {
		groups = []mail.GoogleGroup{
			mail.KubernetesAnnounceGoogleGroup,
			mail.KubernetesDevGoogleGroup,
		}
	}
	logrus.Infof("Using Google Groups as announcement target: %v", groups)

	if err := m.SetGoogleGroupRecipients(groups...); err != nil {
		return errors.Wrap(err, "unable to set mail recipients")
	}

	logrus.Info("Sending mail")
	subject := fmt.Sprintf("Kubernetes %s is live!", tag)
	if err := m.Send(content, subject); err != nil {
		return errors.Wrap(err, "unable to send mail")
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package cmd

import (
	goflag "flag"
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"github.com/docker/machine/libmachine/log"
	"github.com/golang/glog"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	configCmd "k8s.io/minikube/cmd/minikube/cmd/config"
	"k8s.io/minikube/cmd/util"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/notify"
)

var dirs = [...]string{
	constants.GetMinipath(),
	constants.MakeMiniPath("certs"),
	constants.MakeMiniPath("machines"),
	constants.MakeMiniPath("cache"),
	constants.MakeMiniPath("cache", "iso"),
	constants.MakeMiniPath("cache", "localkube"),
	constants.MakeMiniPath("config"),
	constants.MakeMiniPath("addons"),
	constants.MakeMiniPath("logs"),
}

var (
	enableUpdateNotification = true
)

var viperWhiteList = []string{
	"v",
	"alsologtostderr",
	"log_dir",
}

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "minikube",
	Short: "Minikube is a tool for managing local Kubernetes clusters.",
	Long:  `Minikube is a CLI tool that provisions and manages single-node Kubernetes clusters optimized for development workflows.`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		for _, path := range dirs {
			if err := os.MkdirAll(path, 0777); err != nil {
				glog.Exitf("Error creating minikube directory: %s", err)
			}
		}

		// Log level 3 or greater enables libmachine logs
		if !glog.V(3) {
			log.SetOutWriter(ioutil.Discard)
			log.SetErrWriter(ioutil.Discard)
		}

		// Log level 7 or greater enables debug level logs
		if glog.V(7) {
			log.SetDebug(true)
		}

		logDir := pflag.Lookup("log_dir")
		if !logDir.Changed {
			logDir.Value.Set(constants.MakeMiniPath("logs"))
		}

		if enableUpdateNotification {
			notify.MaybePrintUpdateTextFromGithub(os.Stderr)
		}
		util.MaybePrintKubectlDownloadMsg(runtime.GOOS, os.Stderr)
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	_ = RootCmd.Execute()
}

// Handle config values for flags used in external packages (e.g. glog)
// by setting them directly, using values from viper when not passed in as args
func setFlagsUsingViper() {
	for _, config := range viperWhiteList {
		var a = pflag.Lookup(config)
		viper.SetDefault(a.Name, a.DefValue)
		// If the flag is set, override viper value
		if a.Changed {
			viper.Set(a.Name, a.Value.String())
		}
		// Viper will give precedence first to calls to the Set command,
		// then to values from the config.yml
		a.Value.Set(viper.GetString(a.Name))
		a.Changed = true
	}
}

func init() {
	RootCmd.PersistentFlags().StringP(config.MachineProfile, "p", constants.DefaultMachineName, `The name of the minikube VM being used.
	This can be modified to allow for multiple minikube instances to be run independently`)
	RootCmd.AddCommand(configCmd.ConfigCmd)
	RootCmd.AddCommand(configCmd.AddonsCmd)
	RootCmd.AddCommand(configCmd.ProfileCmd)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	viper.BindPFlags(RootCmd.PersistentFlags())

	cobra.OnInitialize(initConfig)

}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	configPath := constants.ConfigFile
	viper.SetConfigFile(configPath)
	viper.SetConfigType("json")
	err := viper.ReadInConfig()
	if err != nil {
		glog.Warningf("Error reading config file at %s: %s", configPath, err)
	}
	setupViper()
}

func setupViper() {
	viper.SetEnvPrefix(constants.MinikubeEnvPrefix)
	// Replaces '-' in flags with '_' in env variables
	// e.g. iso-url => $ENVPREFIX_ISO_URL
	viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
	viper.AutomaticEnv()

	viper.SetDefault(config.WantUpdateNotification, true)
	viper.SetDefault(config.ReminderWaitPeriodInHours, 24)
	viper.SetDefault(config.WantReportError, false)
	viper.SetDefault(config.WantReportErrorPrompt, true)
	viper.SetDefault(config.WantKubectlDownloadMsg, true)
	viper.SetDefault("network-plugin", "kubenet")
	setFlagsUsingViper()
}
<commit_msg>Don't default to kubenet network plugin<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package cmd

import (
	goflag "flag"
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"github.com/docker/machine/libmachine/log"
	"github.com/golang/glog"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	configCmd "k8s.io/minikube/cmd/minikube/cmd/config"
	"k8s.io/minikube/cmd/util"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/notify"
)

var dirs = [...]string{
	constants.GetMinipath(),
	constants.MakeMiniPath("certs"),
	constants.MakeMiniPath("machines"),
	constants.MakeMiniPath("cache"),
	constants.MakeMiniPath("cache", "iso"),
	constants.MakeMiniPath("cache", "localkube"),
	constants.MakeMiniPath("config"),
	constants.MakeMiniPath("addons"),
	constants.MakeMiniPath("logs"),
}

var (
	enableUpdateNotification = true
)

var viperWhiteList = []string{
	"v",
	"alsologtostderr",
	"log_dir",
}

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "minikube",
	Short: "Minikube is a tool for managing local Kubernetes clusters.",
	Long:  `Minikube is a CLI tool that provisions and manages single-node Kubernetes clusters optimized for development workflows.`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		for _, path := range dirs {
			if err := os.MkdirAll(path, 0777); err != nil {
				glog.Exitf("Error creating minikube directory: %s", err)
			}
		}

		// Log level 3 or greater enables libmachine logs
		if !glog.V(3) {
			log.SetOutWriter(ioutil.Discard)
			log.SetErrWriter(ioutil.Discard)
		}

		// Log level 7 or greater enables debug level logs
		if glog.V(7) {
			log.SetDebug(true)
		}

		logDir := pflag.Lookup("log_dir")
		if !logDir.Changed {
			logDir.Value.Set(constants.MakeMiniPath("logs"))
		}

		if enableUpdateNotification {
			notify.MaybePrintUpdateTextFromGithub(os.Stderr)
		}
		util.MaybePrintKubectlDownloadMsg(runtime.GOOS, os.Stderr)
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	_ = RootCmd.Execute()
}

// Handle config values for flags used in external packages (e.g. glog)
// by setting them directly, using values from viper when not passed in as args
func setFlagsUsingViper() {
	for _, config := range viperWhiteList {
		var a = pflag.Lookup(config)
		viper.SetDefault(a.Name, a.DefValue)
		// If the flag is set, override viper value
		if a.Changed {
			viper.Set(a.Name, a.Value.String())
		}
		// Viper will give precedence first to calls to the Set command,
		// then to values from the config.yml
		a.Value.Set(viper.GetString(a.Name))
		a.Changed = true
	}
}

func init() {
	RootCmd.PersistentFlags().StringP(config.MachineProfile, "p", constants.DefaultMachineName, `The name of the minikube VM being used.
	This can be modified to allow for multiple minikube instances to be run independently`)
	RootCmd.AddCommand(configCmd.ConfigCmd)
	RootCmd.AddCommand(configCmd.AddonsCmd)
	RootCmd.AddCommand(configCmd.ProfileCmd)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	viper.BindPFlags(RootCmd.PersistentFlags())

	cobra.OnInitialize(initConfig)

}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	configPath := constants.ConfigFile
	viper.SetConfigFile(configPath)
	viper.SetConfigType("json")
	err := viper.ReadInConfig()
	if err != nil {
		glog.Warningf("Error reading config file at %s: %s", configPath, err)
	}
	setupViper()
}

func setupViper() {
	viper.SetEnvPrefix(constants.MinikubeEnvPrefix)
	// Replaces '-' in flags with '_' in env variables
	// e.g. iso-url => $ENVPREFIX_ISO_URL
	viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
	viper.AutomaticEnv()

	viper.SetDefault(config.WantUpdateNotification, true)
	viper.SetDefault(config.ReminderWaitPeriodInHours, 24)
	viper.SetDefault(config.WantReportError, false)
	viper.SetDefault(config.WantReportErrorPrompt, true)
	viper.SetDefault(config.WantKubectlDownloadMsg, true)
	setFlagsUsingViper()
}
<|endoftext|>


<commit_before>// -*- coding: utf-8-unix -*-
package main

import (
	"./process"
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"os"
)

type BootJSON struct {
	Name  string      `json:"name"      binding:"required"`
	Param interface{} `json:"parameter" binding:"required"`
}

type JubatusServer struct {
	Filepath string
	Proc     process.JubatusProcess
}

func (j *JubatusServer) Call(method string, arg []interface{}) (interface{}, error) {
	return j.Proc.Call(method, arg)
}

func (j *JubatusServer) Kill() {
	os.Remove(j.Filepath)
}

func NewJubatusServer(jubatype string, arg interface{}) (*JubatusServer, error) {
	jtype := jubatype
	filename := uuid.New() + ".json"
	data, _ := json.Marshal(arg)
	filepath := "/tmp/" + filename

	fp, err := os.Create(filepath)
	if err != nil {
		return nil, err
	}
	fp.Write(data)
	fp.Close()
	fmt.Println(arg)

	new_process, err := process.NewJubatusProcess("juba"+jtype, filepath)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	return &JubatusServer{filepath, *new_process}, err
}

func main() {
	router := gin.Default()

	servers := make(map[string]map[string]*JubatusServer)
	modules := []string{"classifier", "recommender", "regression"}

	for _, module := range modules {
		local_module := module

		router.POST("/"+local_module, func(c *gin.Context) {
			/*
			   Create new jubatus model
			   Name => unique name of new model
			   Param => jubatus boot parameter passed with -f option
			*/

			fmt.Println("" + local_module)
			var arg BootJSON
			c.Bind(&arg)
			if _, ok := servers[local_module][arg.Name]; ok {
				c.String(409, local_module+"/"+arg.Name+" is already exists\n")
				return
			}
			newServer, err := NewJubatusServer(local_module, arg.Param)
			if err != nil {
				fmt.Println(err)
				c.String(500, err.Error())
				return
			}

			if servers[local_module] == nil {
				servers[local_module] = make(map[string]*JubatusServer)
			}
			servers[local_module][arg.Name] = newServer

			c.String(200, "ok")
		})

		router.POST("/"+local_module+"/:name/:method", func(c *gin.Context) {
			/*
			   Do machine learning
			   you can use Jubatus via HTTP rpc
			*/
			var argument []interface{}
			c.Bind(&argument)

			name := c.Params.ByName("name")
			method := c.Params.ByName("method")

			if server, ok := servers[local_module][name]; ok {
				fmt.Println(argument)
				ret, err := server.Call(method, argument)
				fmt.Println("return: ", ret, err)
				c.JSON(200, gin.H{"result": ret})
			} else {
				c.String(404, "target "+name+" not found")
			}
		})

		router.GET("/"+local_module, func(c *gin.Context) {
			/*
			   get list of names of machine learning models
			*/
			ret := []string{}
			for _, local_module := range modules {
				for name, _ := range servers[local_module] {
					ret = append(ret, local_module+"/"+name)
				}
			}
			c.JSON(200, gin.H{"servers": ret})
		})

		router.DELETE("/"+local_module+"/:name", func(c *gin.Context) {
			/*
			   delete machine learning model
			*/
			name := c.Params.ByName("name")
			if server, ok := servers[local_module][name]; ok {
				server.Kill()
				delete(servers[local_module], name)
				c.String(200, "deleted")
			} else {
				c.String(404, "target "+name+" not found")
			}
		})
	}

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "3000"
	}

	router.Run(":" + port)
}
<commit_msg>Fix router.DELETE to kill process<commit_after>// -*- coding: utf-8-unix -*-
package main

import (
	"./process"
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"os"
)

type BootJSON struct {
	Name  string      `json:"name"      binding:"required"`
	Param interface{} `json:"parameter" binding:"required"`
}

type JubatusServer struct {
	Filepath string
	Proc     process.JubatusProcess
}

func (j *JubatusServer) Call(method string, arg []interface{}) (interface{}, error) {
	return j.Proc.Call(method, arg)
}

func (j *JubatusServer) Kill() {
	os.Remove(j.Filepath)
}

func NewJubatusServer(jubatype string, arg interface{}) (*JubatusServer, error) {
	jtype := jubatype
	filename := uuid.New() + ".json"
	data, _ := json.Marshal(arg)
	filepath := "/tmp/" + filename

	fp, err := os.Create(filepath)
	if err != nil {
		return nil, err
	}
	fp.Write(data)
	fp.Close()
	fmt.Println(arg)

	new_process, err := process.NewJubatusProcess("juba"+jtype, filepath)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	return &JubatusServer{filepath, *new_process}, err
}

func main() {
	router := gin.Default()

	servers := make(map[string]map[string]*JubatusServer)
	modules := []string{"classifier", "recommender", "regression"}

	for _, module := range modules {
		local_module := module

		router.POST("/"+local_module, func(c *gin.Context) {
			/*
			   Create new jubatus model
			   Name => unique name of new model
			   Param => jubatus boot parameter passed with -f option
			*/

			fmt.Println("" + local_module)
			var arg BootJSON
			c.Bind(&arg)
			if _, ok := servers[local_module][arg.Name]; ok {
				c.String(409, local_module+"/"+arg.Name+" is already exists\n")
				return
			}
			newServer, err := NewJubatusServer(local_module, arg.Param)
			if err != nil {
				fmt.Println(err)
				c.String(500, err.Error())
				return
			}

			if servers[local_module] == nil {
				servers[local_module] = make(map[string]*JubatusServer)
			}
			servers[local_module][arg.Name] = newServer

			c.String(200, "ok")
		})

		router.POST("/"+local_module+"/:name/:method", func(c *gin.Context) {
			/*
			   Do machine learning
			   you can use Jubatus via HTTP rpc
			*/
			var argument []interface{}
			c.Bind(&argument)

			name := c.Params.ByName("name")
			method := c.Params.ByName("method")

			if server, ok := servers[local_module][name]; ok {
				fmt.Println(argument)
				ret, err := server.Call(method, argument)
				fmt.Println("return: ", ret, err)
				c.JSON(200, gin.H{"result": ret})
			} else {
				c.String(404, "target "+name+" not found")
			}
		})

		router.GET("/"+local_module, func(c *gin.Context) {
			/*
			   get list of names of machine learning models
			*/
			ret := []string{}
			for _, local_module := range modules {
				for name, _ := range servers[local_module] {
					ret = append(ret, local_module+"/"+name)
				}
			}
			c.JSON(200, gin.H{"servers": ret})
		})

		router.DELETE("/"+local_module+"/:name", func(c *gin.Context) {
			/*
			   delete machine learning model
			*/
			name := c.Params.ByName("name")
			if server, ok := servers[local_module][name]; ok {
				server.Proc.Kill() // kill process
				server.Kill()      // delete .json
				delete(servers[local_module], name)
				c.String(200, "deleted")
			} else {
				c.String(404, "target "+name+" not found")
			}
		})
	}

	port := os.Getenv("PORT")
	if len(port) == 0 {
		port = "3000"
	}

	router.Run(":" + port)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package cmd

import (
	"time"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/mcnerror"
	"github.com/golang/glog"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/driver"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/kubeconfig"
	"k8s.io/minikube/pkg/minikube/localpath"
	"k8s.io/minikube/pkg/minikube/machine"
	"k8s.io/minikube/pkg/minikube/mustload"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/out/register"
	"k8s.io/minikube/pkg/util/retry"
)

var stopAll bool

// stopCmd represents the stop command
var stopCmd = &cobra.Command{
	Use:   "stop",
	Short: "Stops a running local Kubernetes cluster",
	Long: `Stops a local Kubernetes cluster running in Virtualbox. This command stops the VM
itself, leaving all files intact. The cluster can be started again with the "start" command.`,
	Run: runStop,
}

func init() {

	stopCmd.Flags().BoolVar(&stopAll, "all", false, "Set flag to stop all profiles (clusters)")

	if err := viper.GetViper().BindPFlags(stopCmd.Flags()); err != nil {
		exit.WithError("unable to bind flags", err)
	}

	RootCmd.AddCommand(stopCmd)
}

// runStop handles the executes the flow of "minikube stop"
func runStop(cmd *cobra.Command, args []string) {
	register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
	register.Reg.SetStep(register.Stopping)

	// new code
	var profilesToStop []string
	if stopAll {
		validProfiles, _, err := config.ListProfiles()
		if err != nil {
			glog.Warningf("'error loading profiles in minikube home %q: %v", localpath.MiniPath(), err)
		}
		for _, profile := range validProfiles {
			profilesToStop = append(profilesToStop, profile.Name)
		}
	} else {
		cname := ClusterFlagValue()
		profilesToStop = append(profilesToStop, cname)
	}

	stoppedNodes := 0

	for _, profile := range profilesToStop {
		register.Reg.SetStep(register.Stopping)

		// end new code
		api, cc := mustload.Partial(profile)
		defer api.Close()

		for _, n := range cc.Nodes {
			machineName := driver.MachineName(*cc, n)

			nonexistent := stop(api, machineName)
			if !nonexistent {
				stoppedNodes += 1
			}
		}

		if err := killMountProcess(); err != nil {
			out.WarningT("Unable to kill mount process: {{.error}}", out.V{"error": err})
		}

		if err := kubeconfig.UnsetCurrentContext(profile, kubeconfig.PathFromEnv()); err != nil {
			exit.WithError("update config", err)
		}
	}

	register.Reg.SetStep(register.Done)
	if stoppedNodes > 0 {
		out.T(out.Stopped, `{{.count}} nodes stopped.`, out.V{"count": stoppedNodes})
	}
}

func stop(api libmachine.API, machineName string) bool {
	nonexistent := false

	tryStop := func() (err error) {
		err = machine.StopHost(api, machineName)
		if err == nil {
			return nil
		}
		glog.Warningf("stop host returned error: %v", err)

		switch err := errors.Cause(err).(type) {
		case mcnerror.ErrHostDoesNotExist:
			out.T(out.Meh, `"{{.machineName}}" does not exist, nothing to stop`, out.V{"machineName": machineName})
			nonexistent = true
			return nil
		default:
			return err
		}
	}

	if err := retry.Expo(tryStop, 1*time.Second, 120*time.Second, 5); err != nil {
		exit.WithError("Unable to stop VM", err)
	}

	return nonexistent
}
<commit_msg>lint error<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package cmd

import (
	"time"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/mcnerror"
	"github.com/golang/glog"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/driver"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/kubeconfig"
	"k8s.io/minikube/pkg/minikube/localpath"
	"k8s.io/minikube/pkg/minikube/machine"
	"k8s.io/minikube/pkg/minikube/mustload"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/out/register"
	"k8s.io/minikube/pkg/util/retry"
)

var stopAll bool

// stopCmd represents the stop command
var stopCmd = &cobra.Command{
	Use:   "stop",
	Short: "Stops a running local Kubernetes cluster",
	Long: `Stops a local Kubernetes cluster running in Virtualbox. This command stops the VM
itself, leaving all files intact. The cluster can be started again with the "start" command.`,
	Run: runStop,
}

func init() {

	stopCmd.Flags().BoolVar(&stopAll, "all", false, "Set flag to stop all profiles (clusters)")

	if err := viper.GetViper().BindPFlags(stopCmd.Flags()); err != nil {
		exit.WithError("unable to bind flags", err)
	}

	RootCmd.AddCommand(stopCmd)
}

// runStop handles the executes the flow of "minikube stop"
func runStop(cmd *cobra.Command, args []string) {
	register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
	register.Reg.SetStep(register.Stopping)

	// new code
	var profilesToStop []string
	if stopAll {
		validProfiles, _, err := config.ListProfiles()
		if err != nil {
			glog.Warningf("'error loading profiles in minikube home %q: %v", localpath.MiniPath(), err)
		}
		for _, profile := range validProfiles {
			profilesToStop = append(profilesToStop, profile.Name)
		}
	} else {
		cname := ClusterFlagValue()
		profilesToStop = append(profilesToStop, cname)
	}

	stoppedNodes := 0

	for _, profile := range profilesToStop {
		register.Reg.SetStep(register.Stopping)

		// end new code
		api, cc := mustload.Partial(profile)
		defer api.Close()

		for _, n := range cc.Nodes {
			machineName := driver.MachineName(*cc, n)

			nonexistent := stop(api, machineName)
			if !nonexistent {
				stoppedNodes++
			}
		}

		if err := killMountProcess(); err != nil {
			out.WarningT("Unable to kill mount process: {{.error}}", out.V{"error": err})
		}

		if err := kubeconfig.UnsetCurrentContext(profile, kubeconfig.PathFromEnv()); err != nil {
			exit.WithError("update config", err)
		}
	}

	register.Reg.SetStep(register.Done)
	if stoppedNodes > 0 {
		out.T(out.Stopped, `{{.count}} nodes stopped.`, out.V{"count": stoppedNodes})
	}
}

func stop(api libmachine.API, machineName string) bool {
	nonexistent := false

	tryStop := func() (err error) {
		err = machine.StopHost(api, machineName)
		if err == nil {
			return nil
		}
		glog.Warningf("stop host returned error: %v", err)

		switch err := errors.Cause(err).(type) {
		case mcnerror.ErrHostDoesNotExist:
			out.T(out.Meh, `"{{.machineName}}" does not exist, nothing to stop`, out.V{"machineName": machineName})
			nonexistent = true
			return nil
		default:
			return err
		}
	}

	if err := retry.Expo(tryStop, 1*time.Second, 120*time.Second, 5); err != nil {
		exit.WithError("Unable to stop VM", err)
	}

	return nonexistent
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package api

import (
	"errors"
	"fmt"
	"strings"
)

// TopicType represents the type of a topic
type TopicType string

const (
	// Devices indicates a topic for devices
	Devices TopicType = "devices"
)

// DeviceTopicType represents the type of a device topic
type DeviceTopicType string

const (
	// Activations of devices
	Activations DeviceTopicType = "activations"
	// Uplink data from devices
	Uplink DeviceTopicType = "up"
	// Downlink data to devices
	Downlink DeviceTopicType = "down"
)

// DeviceTopic represents a publish/subscribe topic for application devices
type DeviceTopic struct {
	AppEUI string
	DevEUI string
	Type   DeviceTopicType
}

// GetTopicType returns the type of the specified topic
func GetTopicType(topic string) (TopicType, error) {
	parts := strings.Split(topic, "/")
	if len(parts) < 2 {
		return "", errors.New("Invalid format")
	}
	return TopicType(parts[1]), nil
}

// DecodeDeviceTopic decodes the specified topic in a DeviceTopic structure
func DecodeDeviceTopic(topic string) (*DeviceTopic, error) {
	parts := strings.Split(topic, "/")
	if len(parts) < 4 {
		return nil, errors.New("Invalid format")
	}
	if TopicType(parts[1]) != Devices {
		return nil, errors.New("Not a device topic")
	}

	return &DeviceTopic{parts[0], parts[2], DeviceTopicType(parts[3])}, nil
}

// Encode encodes the DeviceTopic to a topic
func (t *DeviceTopic) Encode() (string, error) {
	return fmt.Sprintf("%s/%s/%s/%s", t.AppEUI, Devices, t.DevEUI, t.Type), nil
}
<commit_msg>Uppercase parsed AppEUI and DevEUI<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package api

import (
	"errors"
	"fmt"
	"strings"
)

// TopicType represents the type of a topic
type TopicType string

const (
	// Devices indicates a topic for devices
	Devices TopicType = "devices"
)

// DeviceTopicType represents the type of a device topic
type DeviceTopicType string

const (
	// Activations of devices
	Activations DeviceTopicType = "activations"
	// Uplink data from devices
	Uplink DeviceTopicType = "up"
	// Downlink data to devices
	Downlink DeviceTopicType = "down"
)

// DeviceTopic represents a publish/subscribe topic for application devices
type DeviceTopic struct {
	AppEUI string
	DevEUI string
	Type   DeviceTopicType
}

// GetTopicType returns the type of the specified topic
func GetTopicType(topic string) (TopicType, error) {
	parts := strings.Split(topic, "/")
	if len(parts) < 2 {
		return "", errors.New("Invalid format")
	}
	return TopicType(parts[1]), nil
}

// DecodeDeviceTopic decodes the specified topic in a DeviceTopic structure
func DecodeDeviceTopic(topic string) (*DeviceTopic, error) {
	parts := strings.Split(topic, "/")
	if len(parts) < 4 {
		return nil, errors.New("Invalid format")
	}
	if TopicType(parts[1]) != Devices {
		return nil, errors.New("Not a device topic")
	}

	return &DeviceTopic{strings.ToUpper(parts[0]), strings.ToUpper(parts[2]), DeviceTopicType(parts[3])}, nil
}

// Encode encodes the DeviceTopic to a topic
func (t *DeviceTopic) Encode() (string, error) {
	return fmt.Sprintf("%s/%s/%s/%s", t.AppEUI, Devices, t.DevEUI, t.Type), nil
}
<|endoftext|>


<commit_before>package http

import (
	"github.com/mcuadros/dockership/core"

	"gopkg.in/igm/sockjs-go.v2/sockjs"
)

type StatusResult struct {
	Project *core.Project
	Status  map[string]*StatusRecord
	Error   []error
}

type StatusRecord struct {
	LastRevisionLabel string
	*core.ProjectStatus
}

func (s *server) HandleStatus(msg Message, session sockjs.Session) {
	var project string
	project, _ = msg.Request["project"]

	result := make(map[string]*StatusResult, 0)
	for name, p := range s.config.Projects {
		if project != "" && project != name {
			continue
		}

		record := &StatusResult{Project: p}
		sl, err := p.Status()
		if len(err) != 0 {
			record.Error = err
		} else {
			record.Status = make(map[string]*StatusRecord, 0)
			for _, s := range sl {
				record.Status[s.Environment.Name] = &StatusRecord{s.LastRevision.Get(), s}
			}
		}

		result[p.Name] = record
	}

	s.sockjs.Send("status", result, false)
}
<commit_msg>http: better error handling<commit_after>package http

import (
	"github.com/mcuadros/dockership/core"

	"gopkg.in/igm/sockjs-go.v2/sockjs"
)

type StatusResult struct {
	Project *core.Project
	Status  map[string]*StatusRecord
	Error   []error
}

type StatusRecord struct {
	LastRevisionLabel string
	*core.ProjectStatus
}

func (s *server) HandleStatus(msg Message, session sockjs.Session) {
	var project string
	project, _ = msg.Request["project"]

	result := make(map[string]*StatusResult, 0)
	for name, p := range s.config.Projects {
		if project != "" && project != name {
			continue
		}

		record := &StatusResult{Project: p}
		sl, errs := p.Status()
		if len(errs) != 0 {
			for _, err := range errs {
				core.Error(err.Error(), "project", p)
			}

			record.Error = errs
		} else {
			record.Status = make(map[string]*StatusRecord, 0)
			for _, s := range sl {
				record.Status[s.Environment.Name] = &StatusRecord{s.LastRevision.Get(), s}
			}
		}

		result[p.Name] = record
	}

	s.sockjs.Send("status", result, false)
}
<|endoftext|>


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

// TODO(adg): support other kinds?

// Command upspinserver is a combined DirServer and StoreServer for use on
// stand-alone machines. It provides only the production implementations of the
// dir and store servers (dir/server and store/gcp).
package main

import (
	"flag"
	"net/http"
	"strings"

	"upspin.io/cloud/https"
	"upspin.io/config"
	"upspin.io/dir/server"
	"upspin.io/flags"
	"upspin.io/log"
	"upspin.io/serverutil/perm"
	"upspin.io/store/gcp"
	"upspin.io/transport/dirserver"
	"upspin.io/transport/storeserver"
	"upspin.io/upspin"

	// Load useful packers
	_ "upspin.io/pack/debug"
	_ "upspin.io/pack/ee"
	_ "upspin.io/pack/eeintegrity"
	_ "upspin.io/pack/plain"
	_ "upspin.io/pack/symm"

	// Load required transports
	_ "upspin.io/transports"
)

func main() {
	// TODO(adg): replace these flags with a server configuration file
	var (
		storeServerConfig []string
		storeCfgFile      = flag.String("store_config", "", "store config `file`")
		storeAddr         = flag.String("store_addr", "", "store `host:port`")
		dirServerConfig   []string
		dirCfgFile        = flag.String("dir_config", "", "directory config `file`")
		dirAddr           = flag.String("dir_addr", "", "directory `host:port`")
	)
	flag.Var(configFlag{&storeServerConfig}, "store_serverconfig", "store configuration")
	flag.Var(configFlag{&dirServerConfig}, "dir_serverconfig", "directory configuration")
	flags.Parse("https", "storeservername", "letscache", "log", "tls")

	// Parse configs.
	storeCfg, err := config.FromFile(*storeCfgFile)
	if err != nil {
		log.Fatal(err)
	}
	dirCfg, err := config.FromFile(*dirCfgFile)
	if err != nil {
		log.Fatal(err)
	}

	ready := make(chan struct{})

	// Set up StoreServer.
	store, err := gcp.New(storeServerConfig...)
	if err != nil {
		log.Fatal(err)
	}
	store, err = perm.WrapStore(storeCfg, ready, store)
	if err != nil {
		log.Fatalf("Error wrapping store: %s", err)
	}

	// Set up DirServer.
	dir, err := server.New(dirCfg, dirServerConfig...)
	if err != nil {
		log.Fatal(err)
	}
	if flags.StoreServerUser != "" {
		dir, err = perm.WrapDir(dirCfg, ready, upspin.UserName(flags.StoreServerUser), dir)
		if err != nil {
			log.Fatalf("Can't wrap DirServer monitoring %s: %s", flags.StoreServerUser, err)
		}
	} else {
		log.Printf("Warning: no Writers Group file protection -- all access permitted")
	}

	// Set up RPC server.
	httpStore := storeserver.New(storeCfg, store, upspin.NetAddr(*storeAddr))
	httpDir := dirserver.New(dirCfg, dir, upspin.NetAddr(*dirAddr))
	http.Handle("/api/Store/", httpStore)
	http.Handle("/api/Dir/", httpDir)

	// Set up HTTPS server.
	https.ListenAndServeFromFlags(ready, "upspinserver")
}

type configFlag struct {
	s *[]string
}

// String implements flag.Value.
func (f configFlag) String() string {
	if f.s == nil {
		return ""
	}
	return strings.Join(*f.s, ",")
}

// Set implements flag.Value.
func (f configFlag) Set(s string) error {
	ss := strings.Split(strings.TrimSpace(s), ",")
	// Drop empty elements.
	for i := 0; i < len(ss); i++ {
		if ss[i] == "" {
			ss = append(ss[:i], ss[i+1:]...)
		}
	}
	*f.s = ss
	return nil
}

// Get implements flag.Getter.
func (f configFlag) Get() interface{} {
	if f.s == nil {
		return ""
	}
	return *f.s
}
<commit_msg>cmd/upspinserver: fix import<commit_after>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TODO(adg): support other kinds?

// Command upspinserver is a combined DirServer and StoreServer for use on
// stand-alone machines. It provides only the production implementations of the
// dir and store servers (dir/server and store/gcp).
package main

import (
	"flag"
	"net/http"
	"strings"

	"upspin.io/cloud/https"
	"upspin.io/config"
	"upspin.io/dir/server"
	"upspin.io/flags"
	"upspin.io/log"
	"upspin.io/rpc/dirserver"
	"upspin.io/rpc/storeserver"
	"upspin.io/serverutil/perm"
	"upspin.io/store/gcp"
	"upspin.io/upspin"

	// Load useful packers
	_ "upspin.io/pack/debug"
	_ "upspin.io/pack/ee"
	_ "upspin.io/pack/eeintegrity"
	_ "upspin.io/pack/plain"
	_ "upspin.io/pack/symm"

	// Load required transports
	_ "upspin.io/transports"
)

func main() {
	// TODO(adg): replace these flags with a server configuration file
	var (
		storeServerConfig []string
		storeCfgFile      = flag.String("store_config", "", "store config `file`")
		storeAddr         = flag.String("store_addr", "", "store `host:port`")
		dirServerConfig   []string
		dirCfgFile        = flag.String("dir_config", "", "directory config `file`")
		dirAddr           = flag.String("dir_addr", "", "directory `host:port`")
	)
	flag.Var(configFlag{&storeServerConfig}, "store_serverconfig", "store configuration")
	flag.Var(configFlag{&dirServerConfig}, "dir_serverconfig", "directory configuration")
	flags.Parse("https", "storeservername", "letscache", "log", "tls")

	// Parse configs.
	storeCfg, err := config.FromFile(*storeCfgFile)
	if err != nil {
		log.Fatal(err)
	}
	dirCfg, err := config.FromFile(*dirCfgFile)
	if err != nil {
		log.Fatal(err)
	}

	ready := make(chan struct{})

	// Set up StoreServer.
	store, err := gcp.New(storeServerConfig...)
	if err != nil {
		log.Fatal(err)
	}
	store, err = perm.WrapStore(storeCfg, ready, store)
	if err != nil {
		log.Fatalf("Error wrapping store: %s", err)
	}

	// Set up DirServer.
	dir, err := server.New(dirCfg, dirServerConfig...)
	if err != nil {
		log.Fatal(err)
	}
	if flags.StoreServerUser != "" {
		dir, err = perm.WrapDir(dirCfg, ready, upspin.UserName(flags.StoreServerUser), dir)
		if err != nil {
			log.Fatalf("Can't wrap DirServer monitoring %s: %s", flags.StoreServerUser, err)
		}
	} else {
		log.Printf("Warning: no Writers Group file protection -- all access permitted")
	}

	// Set up RPC server.
	httpStore := storeserver.New(storeCfg, store, upspin.NetAddr(*storeAddr))
	httpDir := dirserver.New(dirCfg, dir, upspin.NetAddr(*dirAddr))
	http.Handle("/api/Store/", httpStore)
	http.Handle("/api/Dir/", httpDir)

	// Set up HTTPS server.
	https.ListenAndServeFromFlags(ready, "upspinserver")
}

type configFlag struct {
	s *[]string
}

// String implements flag.Value.
func (f configFlag) String() string {
	if f.s == nil {
		return ""
	}
	return strings.Join(*f.s, ",")
}

// Set implements flag.Value.
func (f configFlag) Set(s string) error {
	ss := strings.Split(strings.TrimSpace(s), ",")
	// Drop empty elements.
	for i := 0; i < len(ss); i++ {
		if ss[i] == "" {
			ss = append(ss[:i], ss[i+1:]...)
		}
	}
	*f.s = ss
	return nil
}

// Get implements flag.Getter.
func (f configFlag) Get() interface{} {
	if f.s == nil {
		return ""
	}
	return *f.s
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"io"
	"os"
)

// WriteFile writes the given data to the file named by filename. If the file already
// exists and overwrite is false, it will return an error. If filename is empty or
// the string "-" it will write to os.Stdout.
func WriteFile(filename string, data []byte, overwrite bool, perm os.FileMode) error {
	var w io.Writer
	if filename != "" && filename != "-" {
		flags := os.O_CREATE | os.O_WRONLY | os.O_TRUNC
		if !overwrite {
			flags |= os.O_EXCL
		}
		f, err := os.OpenFile(filename, flags, perm)
		if err != nil {
			return fmt.Errorf("error creating output file %s: %s\n", filename, err)
		}
		defer f.Close()
		w = f
	} else {
		w = os.Stdout
	}
	_, err := w.Write(data)
	return err
}
<commit_msg>Add conveniency functions for checking if a file exists<commit_after>package util

import (
	"fmt"
	"io"
	"os"
)

// WriteFile writes the given data to the file named by filename. If the file already
// exists and overwrite is false, it will return an error. If filename is empty or
// the string "-" it will write to os.Stdout.
func WriteFile(filename string, data []byte, overwrite bool, perm os.FileMode) error {
	var w io.Writer
	if filename != "" && filename != "-" {
		flags := os.O_CREATE | os.O_WRONLY | os.O_TRUNC
		if !overwrite {
			flags |= os.O_EXCL
		}
		f, err := os.OpenFile(filename, flags, perm)
		if err != nil {
			return fmt.Errorf("error creating output file %s: %s\n", filename, err)
		}
		defer f.Close()
		w = f
	} else {
		w = os.Stdout
	}
	_, err := w.Write(data)
	return err
}

// Exists returns wheter an item at the given path exists
// and if it's a directory.
func Exists(filename string) (exists bool, isDir bool) {
	st, err := os.Stat(filename)
	if err == nil {
		return true, st.IsDir()
	}
	return false, false
}

// FileExists returns true iff a file exists at the given
// path and it's not a directory.
func FileExists(filename string) bool {
	ex, isDir := Exists(filename)
	return ex && !isDir
}

// FileExists returns true iff a directory exists
// at the given path.
func DirExists(filename string) bool {
	ex, isDir := Exists(filename)
	return ex && isDir
}
<|endoftext|>


<commit_before>package ole

import (
	"unicode/utf16"
	"unsafe"
)

func IsEqualGUID(guid1 *GUID, guid2 *GUID) bool {
	return guid1.Data1 == guid2.Data1 &&
		guid1.Data2 == guid2.Data2 &&
		guid1.Data3 == guid2.Data3 &&
		guid1.Data4[0] == guid2.Data4[0] &&
		guid1.Data4[1] == guid2.Data4[1] &&
		guid1.Data4[2] == guid2.Data4[2] &&
		guid1.Data4[3] == guid2.Data4[3] &&
		guid1.Data4[4] == guid2.Data4[4] &&
		guid1.Data4[5] == guid2.Data4[5] &&
		guid1.Data4[6] == guid2.Data4[6] &&
		guid1.Data4[7] == guid2.Data4[7]
}

func BytePtrToString(p *byte) string {
	a := (*[10000]uint8)(unsafe.Pointer(p))
	i := 0
	for a[i] != 0 {
		i++
	}
	return string(a[:i])
}

func UTF16PtrToString(p *uint16) string {
	a := (*[10000]uint16)(unsafe.Pointer(p))
	i := 0
	for a[i] != 0 {
		i++
	}
	return string(utf16.Decode(a[:i]))
}

func convertHresultToError(hr uintptr, r2 uintptr, ignore error) (err error) {
	if hr != 0 {
		err = NewError(hr)
	}
	return
}
<commit_msg>Don't panic on null string<commit_after>package ole

import (
	"unicode/utf16"
	"unsafe"
)

func IsEqualGUID(guid1 *GUID, guid2 *GUID) bool {
	return guid1.Data1 == guid2.Data1 &&
		guid1.Data2 == guid2.Data2 &&
		guid1.Data3 == guid2.Data3 &&
		guid1.Data4[0] == guid2.Data4[0] &&
		guid1.Data4[1] == guid2.Data4[1] &&
		guid1.Data4[2] == guid2.Data4[2] &&
		guid1.Data4[3] == guid2.Data4[3] &&
		guid1.Data4[4] == guid2.Data4[4] &&
		guid1.Data4[5] == guid2.Data4[5] &&
		guid1.Data4[6] == guid2.Data4[6] &&
		guid1.Data4[7] == guid2.Data4[7]
}

func BytePtrToString(p *byte) string {
	a := (*[10000]uint8)(unsafe.Pointer(p))
	i := 0
	for a[i] != 0 {
		i++
	}
	return string(a[:i])
}

func UTF16PtrToString(p *uint16) string {
	if p == nil {
		return ""
	}
	a := (*[10000]uint16)(unsafe.Pointer(p))
	i := 0
	for a[i] != 0 {
		i++
	}
	return string(utf16.Decode(a[:i]))
}

func convertHresultToError(hr uintptr, r2 uintptr, ignore error) (err error) {
	if hr != 0 {
		err = NewError(hr)
	}
	return
}
<|endoftext|>