<commit_before>package errorcollector

import (
	"errors"
	"testing"
)

func TestErrorCollector(t *testing.T) {
	tests := []struct {
		funcs         []func() error
		notNil        bool
		expectedError string
	}{
		{
			[]func() error{},
			false,
			"",
		},
		{
			[]func() error{
				func() error { return nil },
				func() error { return nil },
				func() error { return nil },
			},
			false,
			"",
		},
		{
			[]func() error{
				func() error { return errors.New("beep") },
				func() error { return nil },
				func() error { return nil },
			},
			true,
			"collected errors: beep",
		},
		{
			[]func() error{
				func() error { return errors.New("beep") },
				func() error { return nil },
				func() error { return errors.New("boop") },
			},
			true,
			"collected errors: beep, boop",
		},
		{
			[]func() error{
				func() error {
					collector := New()
					subCollector := New()
					collector.Collect(errors.New("beep"))
					collector.Collect(errors.New("boop"))
					subCollector.Collect(errors.New("biip"))
					subCollector.Collect(nil)
					collector.Collect(subCollector)
					return collector
				},
				func() error { return nil },
				func() error { return errors.New("baap") },
			},
			true,
			"collected errors: beep, boop, biip, baap",
		},
		{
			[]func() error{
				func() error {
					collector := New()
					subCollector := New()
					collector.Collect(subCollector)
					return collector
				},
				func() error { return nil },
				func() error { return nil },
			},
			false,
			"",
		},
	}

	for _, test := range tests {
		errors := New()
		for _, fn := range test.funcs {
			errors.Collect(fn())
		}
		if (errors != nil) != test.notNil {
			t.Errorf(
				"Expected error to be %v, error was %v",
				test.notNil,
				errors)
		}
		if errors != nil && errors.Error() != test.expectedError {
			t.Errorf(
				"Expected error to return %v, got %v",
				test.expectedError,
				errors.Error())
		}

	}
}

func BenchmarkErrorCollector(b *testing.B) {
	for i := 0; i < b.N; i++ {
		collector := New()
		childCollector := New()
		collector.Collect(errors.New("beep"))
		childCollector.Collect(errors.New("boop"))
		collector.Collect(childCollector)
		collector.Error()
	}
}
<commit_msg>add example to test file<commit_after>package errorcollector

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

func TestErrorCollector(t *testing.T) {
	tests := []struct {
		funcs         []func() error
		notNil        bool
		expectedError string
	}{
		{
			[]func() error{},
			false,
			"",
		},
		{
			[]func() error{
				func() error { return nil },
				func() error { return nil },
				func() error { return nil },
			},
			false,
			"",
		},
		{
			[]func() error{
				func() error { return errors.New("beep") },
				func() error { return nil },
				func() error { return nil },
			},
			true,
			"collected errors: beep",
		},
		{
			[]func() error{
				func() error { return errors.New("beep") },
				func() error { return nil },
				func() error { return errors.New("boop") },
			},
			true,
			"collected errors: beep, boop",
		},
		{
			[]func() error{
				func() error {
					collector := New()
					subCollector := New()
					collector.Collect(errors.New("beep"))
					collector.Collect(errors.New("boop"))
					subCollector.Collect(errors.New("biip"))
					subCollector.Collect(nil)
					collector.Collect(subCollector)
					return collector
				},
				func() error { return nil },
				func() error { return errors.New("baap") },
			},
			true,
			"collected errors: beep, boop, biip, baap",
		},
		{
			[]func() error{
				func() error {
					collector := New()
					subCollector := New()
					collector.Collect(subCollector)
					return collector
				},
				func() error { return nil },
				func() error { return nil },
			},
			false,
			"",
		},
	}

	for _, test := range tests {
		errors := New()
		for _, fn := range test.funcs {
			errors.Collect(fn())
		}
		if (errors != nil) != test.notNil {
			t.Errorf(
				"Expected error to be %v, error was %v",
				test.notNil,
				errors)
		}
		if errors != nil && errors.Error() != test.expectedError {
			t.Errorf(
				"Expected error to return %v, got %v",
				test.expectedError,
				errors.Error())
		}

	}
}

func BenchmarkErrorCollector(b *testing.B) {
	for i := 0; i < b.N; i++ {
		collector := New()
		childCollector := New()
		collector.Collect(errors.New("beep"))
		childCollector.Collect(errors.New("boop"))
		collector.Collect(childCollector)
		collector.Error()
	}
}

func isLowerCase(str string) error {
	if strings.ToLower(str) != str {
		return fmt.Errorf("string %v wasn't all lowercase", str)
	}
	return nil
}

func ExampleErrorCollector() {
	list := []string{"beep", "boOp", "Baap"}
	err := New()
	for _, str := range list {
		if strings.ToLower(str) != str {
			lcErr := isLowerCase(str)
			err.Collect(lcErr)
		}
	}
	if err != nil {
		fmt.Printf("got error: %v", err)
		// Output:
		// got error: collected errors: string boOp wasn't all lowercase, string Baap wasn't all lowercase
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	var wg sync.WaitGroup
	p := mpb.New(mpb.WithWaitGroup(&wg))
	total := 100
	numBars := 3
	wg.Add(numBars)

	for i := 0; i < numBars; i++ {
		var name string
		name = fmt.Sprintf("Bar#%d:", i)
		b := p.AddBar(int64(total), mpb.BarID(i),
			mpb.PrependDecorators(
				decor.StaticName(name, 0, decor.DwidthSync|decor.DidentRight),
				decor.ETA(4, decor.DSyncSpace),
			),
			mpb.AppendDecorators(
				decor.Percentage(5, 0),
			),
		)
		go func() {
			defer wg.Done()
			max := 100 * time.Millisecond
			for i := 0; i < total; i++ {
				if b.ID() == 1 && i == 42 {
					p.RemoveBar(b)
					return
				}
				time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
				b.Increment()
			}
			if b.ID() == 0 {
				p.RemoveBar(b)
			}
		}()
	}

	p.Wait()
	fmt.Println("done")
}
<commit_msg>Update remove example<commit_after>package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	var wg sync.WaitGroup
	p := mpb.New(mpb.WithWaitGroup(&wg))
	total := 100
	numBars := 3
	wg.Add(numBars)

	for i := 0; i < numBars; i++ {
		var name string
		name = fmt.Sprintf("Bar#%d:", i)

		var bOption mpb.BarOption
		if i == 0 {
			bOption = mpb.BarRemoveOnComplete()
		}

		b := p.AddBar(int64(total), mpb.BarID(i),
			mpb.PrependDecorators(
				decor.StaticName(name, 0, decor.DwidthSync|decor.DidentRight),
				decor.ETA(4, decor.DSyncSpace),
			),
			mpb.AppendDecorators(
				decor.Percentage(5, 0),
			),
			bOption,
		)
		go func() {
			defer wg.Done()
			max := 100 * time.Millisecond
			for i := 0; i < total; i++ {
				if b.ID() == 2 && i == 42 {
					p.Abort(b)
					return
				}
				time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
				b.Increment()
			}
		}()
	}

	p.Wait()
	fmt.Println("done")
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. 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 main

import (
	"fmt"
	"log"
	"os"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/internal/fs"
	"github.com/googlecloudplatform/gcsfuse/internal/perms"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fsutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/timeutil"
)

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *flagStorage,
	conn gcs.Conn) (mfs *fuse.MountedFileSystem, err error) {
	// Sanity check: make sure the temporary directory exists and is writable
	// currently. This gives a better user experience than harder to debug EIO
	// errors when reading files in the future.
	if flags.TempDir != "" {
		var f *os.File
		f, err = fsutil.AnonymousFile(flags.TempDir)
		f.Close()

		if err != nil {
			err = fmt.Errorf(
				"Error writing to temporary directory (%q); are you sure it exists "+
					"with the correct permissions?",
				err.Error())
			return
		}
	}

	// Sanity check: make sure the mount point exists and is a directory. This
	// saves us from some confusing errors later on OS X.
	fi, err := os.Stat(mountPoint)
	switch {
	case os.IsNotExist(err):
		return

	case err != nil:
		err = fmt.Errorf("Statting mount point: %v", err)
		return

	case !fi.IsDir():
		err = fmt.Errorf("Mount point %s is not a directory", mountPoint)
		return
	}

	// Choose UID and GID.
	uid, gid, err := perms.MyUserAndGroup()
	if err != nil {
		err = fmt.Errorf("MyUserAndGroup: %v", err)
		return
	}

	if flags.Uid >= 0 {
		uid = uint32(flags.Uid)
	}

	if flags.Gid >= 0 {
		gid = uint32(flags.Gid)
	}

	// Set up the bucket.
	bucket, err := setUpBucket(
		ctx,
		flags,
		conn,
		bucketName)

	if err != nil {
		err = fmt.Errorf("setUpBucket: %v", err)
		return
	}

	// Create a file system server.
	serverCfg := &fs.ServerConfig{
		Clock:               timeutil.RealClock(),
		Bucket:              bucket,
		TempDir:             flags.TempDir,
		ImplicitDirectories: flags.ImplicitDirs,
		DirTypeCacheTTL:     flags.TypeCacheTTL,
		Uid:                 uid,
		Gid:                 gid,
		FilePerms:           os.FileMode(flags.FileMode),
		DirPerms:            os.FileMode(flags.DirMode),

		AppendThreshold: 1 << 21, // 2 MiB, a total guess.
		TmpObjectPrefix: ".gcsfuse_tmp/",
	}

	server, err := fs.NewServer(serverCfg)
	if err != nil {
		err = fmt.Errorf("fs.NewServer: %v", err)
		return
	}

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:      bucket.Name(),
		Options:     flags.MountOptions,
		ErrorLogger: log.New(os.Stderr, "fuse: ", log.Flags()),
	}

	if flags.DebugFuse {
		mountCfg.DebugLogger = log.New(os.Stderr, "fuse_debug: ", 0)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}
<commit_msg>Removed our now-redundant check for the mount point.<commit_after>// Copyright 2015 Google Inc. 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 main

import (
	"fmt"
	"log"
	"os"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/internal/fs"
	"github.com/googlecloudplatform/gcsfuse/internal/perms"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fsutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/timeutil"
)

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *flagStorage,
	conn gcs.Conn) (mfs *fuse.MountedFileSystem, err error) {
	// Sanity check: make sure the temporary directory exists and is writable
	// currently. This gives a better user experience than harder to debug EIO
	// errors when reading files in the future.
	if flags.TempDir != "" {
		var f *os.File
		f, err = fsutil.AnonymousFile(flags.TempDir)
		f.Close()

		if err != nil {
			err = fmt.Errorf(
				"Error writing to temporary directory (%q); are you sure it exists "+
					"with the correct permissions?",
				err.Error())
			return
		}
	}

	// Choose UID and GID.
	uid, gid, err := perms.MyUserAndGroup()
	if err != nil {
		err = fmt.Errorf("MyUserAndGroup: %v", err)
		return
	}

	if flags.Uid >= 0 {
		uid = uint32(flags.Uid)
	}

	if flags.Gid >= 0 {
		gid = uint32(flags.Gid)
	}

	// Set up the bucket.
	bucket, err := setUpBucket(
		ctx,
		flags,
		conn,
		bucketName)

	if err != nil {
		err = fmt.Errorf("setUpBucket: %v", err)
		return
	}

	// Create a file system server.
	serverCfg := &fs.ServerConfig{
		Clock:               timeutil.RealClock(),
		Bucket:              bucket,
		TempDir:             flags.TempDir,
		ImplicitDirectories: flags.ImplicitDirs,
		DirTypeCacheTTL:     flags.TypeCacheTTL,
		Uid:                 uid,
		Gid:                 gid,
		FilePerms:           os.FileMode(flags.FileMode),
		DirPerms:            os.FileMode(flags.DirMode),

		AppendThreshold: 1 << 21, // 2 MiB, a total guess.
		TmpObjectPrefix: ".gcsfuse_tmp/",
	}

	server, err := fs.NewServer(serverCfg)
	if err != nil {
		err = fmt.Errorf("fs.NewServer: %v", err)
		return
	}

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:      bucket.Name(),
		Options:     flags.MountOptions,
		ErrorLogger: log.New(os.Stderr, "fuse: ", log.Flags()),
	}

	if flags.DebugFuse {
		mountCfg.DebugLogger = log.New(os.Stderr, "fuse_debug: ", 0)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}
<|endoftext|>


<commit_before>package main

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

	"github.com/codegangsta/cli"
	"github.com/koding/klientctl/klientctlerrors"
	"github.com/koding/klientctl/util"
)

// MountCommand mounts a folder on remote machine to local folder by machine
// name.
func MountCommand(c *cli.Context) int {
	if len(c.Args()) < 2 {
		cli.ShowCommandHelp(c, "mount")
		return 1
	}

	var (
		name       = c.Args()[0]
		localPath  = c.Args()[1]
		remotePath = c.String("remotepath") // note the lowercase of all chars
		noIgnore   = c.Bool("noignore")     // note the lowercase of all chars
		noPrefetch = c.Bool("noprefetch")   // note the lowercase of all chars
		noWatch    = c.Bool("nowatch")      // note the lowercase of all chars
	)

	// allow scp like declaration, ie `<machine name>:/path/to/remote`
	if strings.Contains(name, ":") {
		names := strings.Split(name, ":")
		name, remotePath = names[0], names[1]
	}

	// send absolute local path to klient unless local path is empty
	if strings.TrimSpace(localPath) != "" {
		absoluteLocalPath, err := filepath.Abs(localPath)
		if err == nil {
			localPath = absoluteLocalPath
		}
	}

	// remove trailing slashes in remote argument
	remotePath = path.Clean(remotePath)

	// Ask the user if they want the localPath created, if it does not exist.
	if err := askToCreate(localPath, os.Stdin, os.Stdout); err != nil {
		// If the error is that the user cancelled, just return
		if err == klientctlerrors.ErrUserCancelled {
			fmt.Println("Cannot mount to a directory that does not exist, exiting..")
			return 0
		}

		fmt.Printf("Error: Unable to create specified localPath '%s'", localPath)
		return 1
	}

	k, err := CreateKlientClient(NewKlientOptions())
	if err != nil {
		fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
			"Error connecting to remote machine: '%s'", err,
		))
		return 1
	}

	if err := k.Dial(); err != nil {
		fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
			"Error connecting to remote machine: '%s'", err,
		))
		return 1
	}

	infos, err := getListOfMachines(k)
	if err != nil {
		fmt.Print(err)
		return 1
	}

	// allow for shortcuts when specifying name
	for _, info := range infos {
		if strings.HasPrefix(info.VMName, name) {
			name = info.VMName
		}
	}

	mountRequest := struct {
		Name       string `json:"name"`
		LocalPath  string `json:"localPath"`
		RemotePath string `json:"remotePath"`
		NoIgnore   bool   `json:"noIgnore"`
		NoPrefetch bool   `json:"noPrefetch"`
		NoWatch    bool   `json:"noWatch"`
	}{
		Name:       name,
		LocalPath:  localPath,
		NoIgnore:   noIgnore,
		NoPrefetch: noPrefetch,
		NoWatch:    noWatch,
	}

	// RemotePath is optional
	if remotePath != "" {
		mountRequest.RemotePath = remotePath
	}

	resp, err := k.Tell("remote.mountFolder", mountRequest)
	if err != nil && klientctlerrors.IsExistingMountErr(err) {
		util.MustConfirm("This folder is already mounted. Remount? [Y|n]")

		// unmount using mount path
		if err := unmount(k, "", localPath); err != nil {
			fmt.Printf("Error unmounting: %s\n", err)
			return 1
		}

		resp, err = k.Tell("remote.mountFolder", mountRequest)
		if err != nil {
			fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
				"Error mounting: %s\n", err,
			))
			return 1
		}
	}

	// catch errors other than klientctlerrors.IsExistingMountErr
	if err != nil {
		fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
			"Error mounting: %s\n", err,
		))
		return 1
	}

	// response can be nil even when there's no err
	if resp != nil {
		var warning string
		if err := resp.Unmarshal(&warning); err != nil {
			return 0
		}

		if len(warning) > 0 {
			fmt.Printf("Warning: %s\n", warning)
		}
	}

	if err := Lock(localPath, name); err != nil {
		fmt.Printf("Error locking: %s\n", err)
		return 1
	}

	fmt.Println("Mount success.")

	return 0
}

// askToCreate checks if the folder does not exist, and creates it
// if the user chooses to. If the user does *not* choose to create it,
// we return an IsNotExist error.
//
// TODO: Handle the case where a user types stuff in before being prompted,
// and then the prompt uses that. Ie, flush the input so that what we
// read is new input from the user. Not tested :)
func askToCreate(p string, r io.Reader, w io.Writer) error {
	_, err := os.Stat(p)

	// If we fail to stat the file, and it's *not* IsNotExist, we may be
	// having permission issues or some other related issue. Return
	// the error.
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	// If there was no error stating the path, it already exists -
	// we can return, as there's nothing we need to do.
	if err == nil {
		return nil
	}

	fmt.Fprint(w,
		"The mount folder does not exist, would you like to create it? [Y/n]",
	)

	// To understand why we're creating a bReader here, please see
	// the docstring on YesNoConfirmWithDefault().
	bReader := bufio.NewReader(r)

	// Retry YesNo confirmation 3 times if needed
	var createFolder bool
	for i := 0; i < 3; i++ {
		createFolder, err = util.YesNoConfirmWithDefault(bReader, true)
		// If the user supplied an accepted value, stop trying
		if err == nil {
			break
		}
		// If err != nil, then the error did not provide an understood
		// response.
		fmt.Fprintln(w, "Invalid response, please type 'yes' or 'no'")
	}

	// If the retry loop exited with an error, the user failed to give
	// a meaningful response to the YesNo confirmation.
	if err != nil {
		return err
	}

	// The user chose not to create the folder. We cannot mount something that
	// doesn't exist - so we must fail here with an error.
	if !createFolder {
		return klientctlerrors.ErrUserCancelled
	}

	return os.Mkdir(p, 0655)
}
<commit_msg>clean remote path only if it's not empty<commit_after>package main

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

	"github.com/codegangsta/cli"
	"github.com/koding/klientctl/klientctlerrors"
	"github.com/koding/klientctl/util"
)

// MountCommand mounts a folder on remote machine to local folder by machine
// name.
func MountCommand(c *cli.Context) int {
	if len(c.Args()) < 2 {
		cli.ShowCommandHelp(c, "mount")
		return 1
	}

	var (
		name       = c.Args()[0]
		localPath  = c.Args()[1]
		remotePath = c.String("remotepath") // note the lowercase of all chars
		noIgnore   = c.Bool("noignore")     // note the lowercase of all chars
		noPrefetch = c.Bool("noprefetch")   // note the lowercase of all chars
		noWatch    = c.Bool("nowatch")      // note the lowercase of all chars
	)

	// allow scp like declaration, ie `<machine name>:/path/to/remote`
	if strings.Contains(name, ":") {
		names := strings.Split(name, ":")
		name, remotePath = names[0], names[1]
	}

	// send absolute local path to klient unless local path is empty
	if strings.TrimSpace(localPath) != "" {
		absoluteLocalPath, err := filepath.Abs(localPath)
		if err == nil {
			localPath = absoluteLocalPath
		}
	}

	// remove trailing slashes in remote argument
	if remotePath != "" {
		remotePath = path.Clean(remotePath)
	}

	// Ask the user if they want the localPath created, if it does not exist.
	if err := askToCreate(localPath, os.Stdin, os.Stdout); err != nil {
		// If the error is that the user cancelled, just return
		if err == klientctlerrors.ErrUserCancelled {
			fmt.Println("Cannot mount to a directory that does not exist, exiting..")
			return 0
		}

		fmt.Printf("Error: Unable to create specified localPath '%s'", localPath)
		return 1
	}

	k, err := CreateKlientClient(NewKlientOptions())
	if err != nil {
		fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
			"Error connecting to remote machine: '%s'", err,
		))
		return 1
	}

	if err := k.Dial(); err != nil {
		fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
			"Error connecting to remote machine: '%s'", err,
		))
		return 1
	}

	infos, err := getListOfMachines(k)
	if err != nil {
		fmt.Print(err)
		return 1
	}

	// allow for shortcuts when specifying name
	for _, info := range infos {
		if strings.HasPrefix(info.VMName, name) {
			name = info.VMName
		}
	}

	mountRequest := struct {
		Name       string `json:"name"`
		LocalPath  string `json:"localPath"`
		RemotePath string `json:"remotePath"`
		NoIgnore   bool   `json:"noIgnore"`
		NoPrefetch bool   `json:"noPrefetch"`
		NoWatch    bool   `json:"noWatch"`
	}{
		Name:       name,
		LocalPath:  localPath,
		NoIgnore:   noIgnore,
		NoPrefetch: noPrefetch,
		NoWatch:    noWatch,
	}

	// RemotePath is optional
	if remotePath != "" {
		mountRequest.RemotePath = remotePath
	}

	resp, err := k.Tell("remote.mountFolder", mountRequest)
	if err != nil && klientctlerrors.IsExistingMountErr(err) {
		util.MustConfirm("This folder is already mounted. Remount? [Y|n]")

		// unmount using mount path
		if err := unmount(k, "", localPath); err != nil {
			fmt.Printf("Error unmounting: %s\n", err)
			return 1
		}

		resp, err = k.Tell("remote.mountFolder", mountRequest)
		if err != nil {
			fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
				"Error mounting: %s\n", err,
			))
			return 1
		}
	}

	// catch errors other than klientctlerrors.IsExistingMountErr
	if err != nil {
		fmt.Println(defaultHealthChecker.CheckAllFailureOrMessagef(
			"Error mounting: %s\n", err,
		))
		return 1
	}

	// response can be nil even when there's no err
	if resp != nil {
		var warning string
		if err := resp.Unmarshal(&warning); err != nil {
			return 0
		}

		if len(warning) > 0 {
			fmt.Printf("Warning: %s\n", warning)
		}
	}

	if err := Lock(localPath, name); err != nil {
		fmt.Printf("Error locking: %s\n", err)
		return 1
	}

	fmt.Println("Mount success.")

	return 0
}

// askToCreate checks if the folder does not exist, and creates it
// if the user chooses to. If the user does *not* choose to create it,
// we return an IsNotExist error.
//
// TODO: Handle the case where a user types stuff in before being prompted,
// and then the prompt uses that. Ie, flush the input so that what we
// read is new input from the user. Not tested :)
func askToCreate(p string, r io.Reader, w io.Writer) error {
	_, err := os.Stat(p)

	// If we fail to stat the file, and it's *not* IsNotExist, we may be
	// having permission issues or some other related issue. Return
	// the error.
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	// If there was no error stating the path, it already exists -
	// we can return, as there's nothing we need to do.
	if err == nil {
		return nil
	}

	fmt.Fprint(w,
		"The mount folder does not exist, would you like to create it? [Y/n]",
	)

	// To understand why we're creating a bReader here, please see
	// the docstring on YesNoConfirmWithDefault().
	bReader := bufio.NewReader(r)

	// Retry YesNo confirmation 3 times if needed
	var createFolder bool
	for i := 0; i < 3; i++ {
		createFolder, err = util.YesNoConfirmWithDefault(bReader, true)
		// If the user supplied an accepted value, stop trying
		if err == nil {
			break
		}
		// If err != nil, then the error did not provide an understood
		// response.
		fmt.Fprintln(w, "Invalid response, please type 'yes' or 'no'")
	}

	// If the retry loop exited with an error, the user failed to give
	// a meaningful response to the YesNo confirmation.
	if err != nil {
		return err
	}

	// The user chose not to create the folder. We cannot mount something that
	// doesn't exist - so we must fail here with an error.
	if !createFolder {
		return klientctlerrors.ErrUserCancelled
	}

	return os.Mkdir(p, 0655)
}
<|endoftext|>


<commit_before>package sudoku

// Sudoku has one rule - no value can be repeated horizontally, vertically,
// or in the same section. This gives rise to a few simple rules - and those
// rules are applied across each cluster - without even knowning the orientation
// of the cluster.
//
// In order to make solving possible however, that one rule is enforced with
// the following rules:
//
// 1) If all cells are solved, that cluster is solved.
// 2) If any cell is solved, it has no possibles.
// 3) If any cell is solved, that value is not possible in other cells.
// 4) If any cell only has one possible value, that is that cell's value.
// 5) If any x cells have x possible values, those values are not possible
//  outside of those cells - those values are constrained to those cells.
// 6) If any value only has one possible cell, that is that cell's value.
// 7) If any x values have x possible cells, those cells only have those
//  possible values - those cells are constrained to those values.
//
// Additional Helper functions are included and explained later.

// indexedCLuster is a datatype for an index for the values of the cluster.
// Each possible value is a key in the map. THe value of each key is an array of
// possible locations for that value - the index and order are not defined,
// instead the values of the array are the indexes of possible cells in for that
// value.
type intArray []int
type indexedCluster map[int]intArray

func indexCluster(in []cell) (out indexedCluster) {
	for id, each := range in {
		for onePossible, _ := range each.possible {
			out[onePossible] = append(out[onePossible], id)
		}
	}
	return out
}

// A helper function to determine the number of cells hit by working across a
// number of values.
func valuesCost(markedVals map[int]bool, index indexedCluster, cluseter []cell) int {
	var neededCells map[int]bool
	for value, _ := range markedVals {
		for oneCell, _ := range index[value] {
			neededCells[oneCell] = true
		}
	}
	return len(neededCells)
}

// This covers rule 1 from above:
// 1) If all cells are solved, that cluster is solved.
func clusterSolved(cluster []cell, u chan cell) (solved bool) {
	solved = true
	for _, each := range cluster {
		if each.actual == 0 {
			solved = false
		} else if len(each.possible) > 0 {
			solved = false
		}
	}
	return solved
}

// This covers rule 2 from above:
// 2) If any cell is solved, it has no possibles.
func solvedNoPossible(cluster []cell, u chan cell) (changed bool) {
	for _, each := range cluster {
		if each.actual == 0 {
			continue
		}
		if len(each.possible) > 0 {
			changed = true
			u <- cell{
				location: each.location,
				possible: each.possible,
			}
		}
	}
	return changed
}

// Removes known values from other possibles in the same cluster
// Covers rule 3 from above:
// 3) If any cell is solved, that value is not possible in other cells.
func eliminateKnowns(workingCluster []cell, u chan cell) bool {
	var solved map[int]bool
	var remove map[int]bool
	var changed bool

	// Loop thru and find all solved values.
	for _, each := range workingCluster {
		if each.actual != 0 {
			solved[each.actual] = true
		}
	}

	for _, each := range workingCluster {
		for i, potential := range each.possible {
			if potential && solved[i] {
				remove[i] = true
			}
		}
		if len(remove) > 0 {
			// send back removal of possibles & reset
			changed = true
			u <- cell{
				location: each.location,
				possible: remove,
			}
			remove = map[int]bool{}
		}
	}
	return changed
}

// This covers the 4th rule from above:
// 4) If any cell only has one possible value, that is that cell's value.
func singleValueSolver(cluster []cell, u chan cell) (changed bool) {
	for _, workingCell := range cluster {
		// if the cell is already solved, skip this.
		if workingCell.actual != 0 {
			continue
		}

		// if there is more than one possible value for this cell, you should be good
		if len(workingCell.possible) > 1 {
			continue
		}

		// should never happen - probably #TODO# to catch this
		if len(workingCell.possible) < 1 {
			panic("Found an unsolved cell with no possible values")
		}

		changed = true

		// this empty for loop will set value to each key in the map
		// since there's one key, it gives me that one key
		var key int
		for key, _ = range workingCell.possible {
		}

		// send back an update for this cell
		u <- cell{
			location: workingCell.location,
			actual:   key,
		}
	}
	return changed
}

// A helper function to determine the number of valus hit given a specific set
// of cells.
func cellsCost(markedCells map[int]bool, cluster []cell) int {
	var neededValues map[int]bool
	for cellPos, _ := range markedCells {
		for possibleValue, _ := range cluster[cellPos].possible {
			neededValues[possibleValue] = true
		}
	}
	return len(neededValues)
}

func cellLimiterChild(limit int, markedCells map[int]bool, cluster []cell, u chan cell) (changed bool) {
	valueCount := cellsCost(markedCells, cluster)
	// you have overspent - it's a no-go
	if len(markedCells) > limit {
		return false
	}

	// you have room to add more cells
	if len(markedCells) < limit {
		if valueCount < len(markedCells) {
			// #TODO# probably fix this? rework into error?
			panic("less possible values than squares to fill")
		}
		if valueCount > len(markedCells) {
			// you need to try adding each other cell
			for idCell, oneCell := range cluster {
				if oneCell.actual != 0 {
					continue
				}
				if markedCells[idCell] {
					// this cell is already in the map, skip
					continue
				}

				// decend down into looking at that cell
				childMarkedCells := markedCells // #TODO# map copy
				childMarkedCells[idCell] = true
				if cellLimiterChild(limit, childMarkedCells, cluster, u) {
					// if you got true from the child, pass it on
					return true
				}
			}
		}
	}

	// did you fill the cells? if so, mark it
	if valueCount == len(markedCells) {
		// it's a match - so remove values
		for idCell, oneCell := range cluster {
			if oneCell.actual != 0 {
				// already solved
				continue
			}
			if markedCells[idCell] {
				// this cell is a part of the list - no exclusions needed
				continue
			}
			remove := map[int]bool{}
			for potential, _ := range oneCell.possible {
				if markedCells[idCell] {
					// this possibility exists in the map - need to remove it
					remove[potential] = true
				}
			}
			if len(remove) > 0 {
				changed = true
				u <- cell{
					location: oneCell.location,
					possible: remove,
				}
			}
		}
	}
	return changed
}

// This covers rule 5:
// 5) If any x cells have x possible values, those values are not possible
//  outside of those cells - those values are constrained to those cells.
func cellLimiter(cluster []cell, u chan cell) (changed bool) {
	upperBound := len(cluster)
	for _, eachCell := range cluster{
		if eachCell.actual != 0{
			upperBound--
		}
	}
	for i :=2; i <= upperBound; i++ {
		if cellLimiterChild(i, map[int]bool{}, cluster, u) {
			changed = true
		}
	}
	return changed
}

// This covers rule 6 from above:
// 6) If any value only has one possible cell, that is that cell's value.
func singleCellSolver(index indexedCluster, workingCluster []cell, u chan cell) (changed bool) {
	for val, section := range index {
		if len(section) < 1 {
			// something went terribly wrong here - #TODO# add panic catch?
			panic("Found an unsolved cell with no possible values")
		} else if len(section) == 1 {
			u <- cell{
				location: workingCluster[section[0]].location,
				actual:   val,
			}
			changed = true
		}
	}
	return changed
}

func additionalCost(addVal int, markedVals map[int]bool, index indexedCluster) int {
	// skip this one if it's already marked
	if markedVals[addVal] {
		return -1
	}
	var newCols map[int]bool
	// for target, _ := range index[addVal].targets {
	for target, _ := range index[addVal] {
		newCols[target] = true
	}
	for preIndexed, _ := range markedVals {
		// for target, _ := range index[preIndexed].targets {
		for target, _ := range index[preIndexed] {
			delete(newCols, target)
		}
	}
	return len(newCols)
}

// Given certain premarked values, searches an index to find the next value to
// mark while staying under the given budget. If something is found to match
// the required values under the squares budget, changes are made.
func findPairsChild(markedVals map[int]bool, budget, required int, index indexedCluster, workingCluster []cell, u chan cell) (changed bool) {
	for possibleVal, locations := range index {
		if markedVals[possibleVal] {
			// this cell is already on the list, so skip it
			continue
		}
		// if len(locations.targets) > budget {
		if len(locations) > budget {
			// adding this cell will never fit in the budget, so skip it
			continue
		}
		// you can't add anything, so return false
		if budget < 1 {
			return false
		}
		if deduction := additionalCost(possibleVal, markedVals, index); deduction < budget {
			markedValsCopy := markedVals // #TODO# map copy
			markedValsCopy[possibleVal] = true
			// if you already have the hit, mark it
			if required >= len(markedValsCopy) {
				if processSquares() {

				}

			}

			// if you need to go down recursively, do it
			if findPairsChild(makredValsCopy, budget-deduction, required, index, workingCluster) {
				return true
			}
		}
	}
}
<commit_msg>committing down what i have for the moves rules - going to have to rewrite as this is too much<commit_after>package sudoku

// Sudoku has one rule - no value can be repeated horizontally, vertically,
// or in the same section. This gives rise to a few simple rules - and those
// rules are applied across each cluster - without even knowning the orientation
// of the cluster.
//
// In order to make solving possible however, that one rule is enforced with
// the following rules:
//
// 1) If all cells are solved, that cluster is solved.
// 2) If any cell is solved, it has no possibles.
// 3) If any cell is solved, that value is not possible in other cells.
// 4) If any cell only has one possible value, that is that cell's value.
// 5) If any x cells only have x possible values, those values are not possible
//  outside of those cells - those values are constrained to those cells.
// 6) If any value only has one possible cell, that is that cell's value.
// 7) If any x values only have x possible cells, those cells only have those
//  possible values - those cells are constrained to those values.
//
// Additional Helper functions are included and explained later.

// indexedCLuster is a datatype for an index for the values of the cluster.
// Each possible value is a key in the map. THe value of each key is an array of
// possible locations for that value - the index and order are not defined,
// instead the values of the array are the indexes of possible cells in for that
// value.
type intArray []int
type indexedCluster map[int]intArray

func indexCluster(in []cell) (out indexedCluster) {
	for id, each := range in {
		for onePossible, _ := range each.possible {
			out[onePossible] = append(out[onePossible], id)
		}
	}
	return out
}

// This covers rule 1 from above:
// 1) If all cells are solved, that cluster is solved.
func clusterSolved(cluster []cell, u chan cell) (solved bool) {
	solved = true
	for _, each := range cluster {
		if each.actual == 0 {
			solved = false
		} else if len(each.possible) > 0 {
			solved = false
		}
	}
	return solved
}

// This covers rule 2 from above:
// 2) If any cell is solved, it has no possibles.
func solvedNoPossible(cluster []cell, u chan cell) (changed bool) {
	for _, each := range cluster {
		if each.actual == 0 {
			continue
		}
		if len(each.possible) > 0 {
			changed = true
			u <- cell{
				location: each.location,
				possible: each.possible,
			}
		}
	}
	return changed
}

// Removes known values from other possibles in the same cluster
// Covers rule 3 from above:
// 3) If any cell is solved, that value is not possible in other cells.
func eliminateKnowns(workingCluster []cell, u chan cell) bool {
	var solved map[int]bool
	var remove map[int]bool
	var changed bool

	// Loop thru and find all solved values.
	for _, each := range workingCluster {
		if each.actual != 0 {
			solved[each.actual] = true
		}
	}

	for _, each := range workingCluster {
		for i, potential := range each.possible {
			if potential && solved[i] {
				remove[i] = true
			}
		}
		if len(remove) > 0 {
			// send back removal of possibles & reset
			changed = true
			u <- cell{
				location: each.location,
				possible: remove,
			}
			remove = map[int]bool{}
		}
	}
	return changed
}

// This covers the 4th rule from above:
// 4) If any cell only has one possible value, that is that cell's value.
func singleValueSolver(cluster []cell, u chan cell) (changed bool) {
	for _, workingCell := range cluster {
		// if the cell is already solved, skip this.
		if workingCell.actual != 0 {
			continue
		}

		// if there is more than one possible value for this cell, you should be good
		if len(workingCell.possible) > 1 {
			continue
		}

		// should never happen - probably #TODO# to catch this
		if len(workingCell.possible) < 1 {
			panic("Found an unsolved cell with no possible values")
		}

		changed = true

		// this empty for loop will set value to each key in the map
		// since there's one key, it gives me that one key
		var key int
		for key, _ = range workingCell.possible {
		}

		// send back an update for this cell
		u <- cell{
			location: workingCell.location,
			actual:   key,
		}
	}
	return changed
}

// A helper function to determine the number of valus hit given a specific set
// of cells.
func cellsCost(markedCells map[int]bool, cluster []cell) int {
	var neededValues map[int]bool
	for cellPos, _ := range markedCells {
		for possibleValue, _ := range cluster[cellPos].possible {
			neededValues[possibleValue] = true
		}
	}
	return len(neededValues)
}

func cellLimiterChild(limit int, markedCells map[int]bool, cluster []cell, u chan cell) (changed bool) {
	valueCount := cellsCost(markedCells, cluster)
	// you have overspent - it's a no-go
	if len(markedCells) > limit {
		return false
	}

	// you have room to add more cells (depth first?)
	if len(markedCells) < limit {
		if valueCount < len(markedCells) {
			// #TODO# probably fix this? rework into error?
			panic("less possible values than squares to fill")
		}
		if valueCount > len(markedCells) {
			// you need to try adding each other cell
			for idCell, oneCell := range cluster {
				if oneCell.actual != 0 {
					continue
				}
				if markedCells[idCell] {
					// this cell is already in the map, skip
					continue
				}

				// decend down into looking at that cell
				childMarkedCells := markedCells // #TODO# map copy
				childMarkedCells[idCell] = true
				if cellLimiterChild(limit, childMarkedCells, cluster, u) {
					// if you got true from the child, pass it on
					return true
				}
			}
		}
	}

	// did you fill the cells? if so, mark it
	if valueCount == len(markedCells) {
		// it's a match - so remove values
		for idCell, oneCell := range cluster {
			if oneCell.actual != 0 {
				// already solved
				continue
			}
			if markedCells[idCell] {
				// this cell is a part of the list - no exclusions needed
				continue
			}
			remove := map[int]bool{}
			for potential, _ := range oneCell.possible {
				if markedCells[idCell] {
					// this possibility exists in the map - need to remove it
					remove[potential] = true
				}
			}
			if len(remove) > 0 {
				changed = true
				u <- cell{
					location: oneCell.location,
					possible: remove,
				}
			}
		}
	}
	return changed
}

// This covers rule 5:
// 5) If any x cells have x possible values, those values are not possible
//  outside of those cells - those values are constrained to those cells.
func cellLimiter(cluster []cell, u chan cell) (changed bool) {
	upperBound := len(cluster)
	for _, eachCell := range cluster {
		if eachCell.actual != 0 {
			upperBound--
		}
	}
	for i := 2; i <= upperBound; i++ {
		if cellLimiterChild(i, map[int]bool{}, cluster, u) {
			changed = true
		}
	}
	return changed
}

// This covers rule 6 from above:
// 6) If any value only has one possible cell, that is that cell's value.
func singleCellSolver(index indexedCluster, workingCluster []cell, u chan cell) (changed bool) {
	for val, section := range index {
		if len(section) < 1 {
			// something went terribly wrong here - #TODO# add panic catch?
			panic("Found an unsolved cell with no possible values")
		} else if len(section) == 1 {
			u <- cell{
				location: workingCluster[section[0]].location,
				actual:   val,
			}
			changed = true
		}
	}
	return changed
}

// A helper function to determine the number of cells hit by working across a map
// of values.
func valuesCost(markedVals map[int]bool, index indexedCluster, cluseter []cell) int {
	var neededCells map[int]bool
	for value, _ := range markedVals {
		for oneCell, _ := range index[value] {
			neededCells[oneCell] = true
		}
	}
	return len(neededCells)
}

func valueLimiterChild(limit int, markedValues map[int]bool, index indexedCluster,
	cluster []cell, u chan cell) (changed bool) {
	if len(markedValues) > limit {
		// we have marked more values
		return false
	}
	currentCost := valuesCost(markedVals, index, cluster)
	if currentCost > limit {
		// you're over the budget to spend
		return false
	}

}

// THis covers rule 7 from above:
// 7) If any x values have only x possible cells, those cells only have those
//  possible values - those cells are constrained to those values.
func valueLimiter(index indexedCluster, cluster []cell, u chan cell) (changed bool) {

}
<|endoftext|>


<commit_before>// +build selinux,linux

package label

import (
	"fmt"
	"strings"

	"github.com/docker/libcontainer/selinux"
)

// InitLabels returns the process label and file labels to be used within
// the container.  A list of options can be passed into this function to alter
// the labels.  The labels returned will include a random MCS String, that is
// guaranteed to be unique.
func InitLabels(options []string) (string, string, error) {
	if !selinux.SelinuxEnabled() {
		return "", "", nil
	}
	processLabel, mountLabel := selinux.GetLxcContexts()
	if processLabel != "" {
		pcon := selinux.NewContext(processLabel)
		mcon := selinux.NewContext(mountLabel)
		for _, opt := range options {
			if opt == "disable" {
				return "", "", nil
			}
			if i := strings.Index(opt, ":"); i == -1 {
				return "", "", fmt.Errorf("Bad SELinux Option")
			}
			con := strings.SplitN(opt, ":", 2)
			pcon[con[0]] = con[1]
			if con[0] == "level" || con[0] == "user" {
				mcon[con[0]] = con[1]
			}
		}
		processLabel = pcon.Get()
		mountLabel = mcon.Get()
	}
	return processLabel, mountLabel, nil
}

// DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
func GenLabels(options string) (string, string, error) {
	return InitLabels(strings.Fields(options))
}

// FormatMountLabel returns a string to be used by the mount command.
// The format of this string will be used to alter the labeling of the mountpoint.
// The string returned is suitable to be used as the options field of the mount command.
// If you need to have additional mount point options, you can pass them in as
// the first parameter.  Second parameter is the label that you wish to apply
// to all content in the mount point.
func FormatMountLabel(src, mountLabel string) string {
	if mountLabel != "" {
		switch src {
		case "":
			src = fmt.Sprintf("context=%q", mountLabel)
		default:
			src = fmt.Sprintf("%s,context=%q", src, mountLabel)
		}
	}
	return src
}

// SetProcessLabel takes a process label and tells the kernel to assign the
// label to the next program executed by the current process.
func SetProcessLabel(processLabel string) error {
	if processLabel == "" {
		return nil
	}
	return selinux.Setexeccon(processLabel)
}

// GetProcessLabel returns the process label that the kernel will assign
// to the next program executed by the current process.  If "" is returned
// this indicates that the default labeling will happen for the process.
func GetProcessLabel() (string, error) {
	return selinux.Getexeccon()
}

// SetFileLabel modifies the "path" label to the specified file label
func SetFileLabel(path string, fileLabel string) error {
	if selinux.SelinuxEnabled() && fileLabel != "" {
		return selinux.Setfilecon(path, fileLabel)
	}
	return nil
}

// Tell the kernel the label for all files to be created
func SetFileCreateLabel(fileLabel string) error {
	if selinux.SelinuxEnabled() {
		return selinux.Setfscreatecon(fileLabel)
	}
	return nil
}

// Change the label of path to the filelabel string.  If the relabel string
// is "z", relabel will change the MCS label to s0.  This will allow all
// containers to share the content.  If the relabel string is a "Z" then
// the MCS label should continue to be used.  SELinux will use this field
// to make sure the content can not be shared by other containes.
func Relabel(path string, fileLabel string, relabel string) error {
	exclude_path := []string{"/", "/usr", "/etc"}
	if fileLabel == "" {
		return nil
	}
	for _, p := range exclude_path {
		if path == p {
			return fmt.Errorf("Relabeling of %s is not allowed", path)
		}
	}
	if !strings.ContainsAny(relabel, "zZ") {
		return nil
	}
	if strings.Contains(relabel, "z") && strings.Contains(relabel, "Z") {
		return fmt.Errorf("Bad SELinux option z and Z can not be used together")
	}
	if strings.Contains(relabel, "z") {
		c := selinux.NewContext(fileLabel)
		c["level"] = "s0"
		fileLabel = c.Get()
	}
	return selinux.Chcon(path, fileLabel, true)
}

// GetPidLabel will return the label of the process running with the specified pid
func GetPidLabel(pid int) (string, error) {
	return selinux.Getpidcon(pid)
}

// Init initialises the labeling system
func Init() {
	selinux.SelinuxEnabled()
}

// ReserveLabel will record the fact that the MCS label has already been used.
// This will prevent InitLabels from using the MCS label in a newly created
// container
func ReserveLabel(label string) error {
	selinux.ReserveLabel(label)
	return nil
}

// UnreserveLabel will remove the reservation of the MCS label.
// This will allow InitLabels to use the MCS label in a newly created
// containers
func UnreserveLabel(label string) error {
	selinux.FreeLxcContexts(label)
	return nil
}

// DupSecOpt takes an process label and returns security options that
// can be used to set duplicate labels on future container processes
func DupSecOpt(src string) []string {
	return selinux.DupSecOpt(src)
}

// DisableSecOpt returns a security opt that can disable labeling
// support for future container processes
func DisableSecOpt() []string {
	return selinux.DisableSecOpt()
}
<commit_msg>Fix relabel to allow volume mounting of /<commit_after>// +build selinux,linux

package label

import (
	"fmt"
	"strings"

	"github.com/docker/libcontainer/selinux"
)

// InitLabels returns the process label and file labels to be used within
// the container.  A list of options can be passed into this function to alter
// the labels.  The labels returned will include a random MCS String, that is
// guaranteed to be unique.
func InitLabels(options []string) (string, string, error) {
	if !selinux.SelinuxEnabled() {
		return "", "", nil
	}
	processLabel, mountLabel := selinux.GetLxcContexts()
	if processLabel != "" {
		pcon := selinux.NewContext(processLabel)
		mcon := selinux.NewContext(mountLabel)
		for _, opt := range options {
			if opt == "disable" {
				return "", "", nil
			}
			if i := strings.Index(opt, ":"); i == -1 {
				return "", "", fmt.Errorf("Bad SELinux Option")
			}
			con := strings.SplitN(opt, ":", 2)
			pcon[con[0]] = con[1]
			if con[0] == "level" || con[0] == "user" {
				mcon[con[0]] = con[1]
			}
		}
		processLabel = pcon.Get()
		mountLabel = mcon.Get()
	}
	return processLabel, mountLabel, nil
}

// DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
func GenLabels(options string) (string, string, error) {
	return InitLabels(strings.Fields(options))
}

// FormatMountLabel returns a string to be used by the mount command.
// The format of this string will be used to alter the labeling of the mountpoint.
// The string returned is suitable to be used as the options field of the mount command.
// If you need to have additional mount point options, you can pass them in as
// the first parameter.  Second parameter is the label that you wish to apply
// to all content in the mount point.
func FormatMountLabel(src, mountLabel string) string {
	if mountLabel != "" {
		switch src {
		case "":
			src = fmt.Sprintf("context=%q", mountLabel)
		default:
			src = fmt.Sprintf("%s,context=%q", src, mountLabel)
		}
	}
	return src
}

// SetProcessLabel takes a process label and tells the kernel to assign the
// label to the next program executed by the current process.
func SetProcessLabel(processLabel string) error {
	if processLabel == "" {
		return nil
	}
	return selinux.Setexeccon(processLabel)
}

// GetProcessLabel returns the process label that the kernel will assign
// to the next program executed by the current process.  If "" is returned
// this indicates that the default labeling will happen for the process.
func GetProcessLabel() (string, error) {
	return selinux.Getexeccon()
}

// SetFileLabel modifies the "path" label to the specified file label
func SetFileLabel(path string, fileLabel string) error {
	if selinux.SelinuxEnabled() && fileLabel != "" {
		return selinux.Setfilecon(path, fileLabel)
	}
	return nil
}

// Tell the kernel the label for all files to be created
func SetFileCreateLabel(fileLabel string) error {
	if selinux.SelinuxEnabled() {
		return selinux.Setfscreatecon(fileLabel)
	}
	return nil
}

// Change the label of path to the filelabel string.  If the relabel string
// is "z", relabel will change the MCS label to s0.  This will allow all
// containers to share the content.  If the relabel string is a "Z" then
// the MCS label should continue to be used.  SELinux will use this field
// to make sure the content can not be shared by other containes.
func Relabel(path string, fileLabel string, relabel string) error {
	exclude_path := []string{"/", "/usr", "/etc"}
	if fileLabel == "" {
		return nil
	}
	if !strings.ContainsAny(relabel, "zZ") {
		return nil
	}
	for _, p := range exclude_path {
		if path == p {
			return fmt.Errorf("Relabeling of %s is not allowed", path)
		}
	}
	if strings.Contains(relabel, "z") && strings.Contains(relabel, "Z") {
		return fmt.Errorf("Bad SELinux option z and Z can not be used together")
	}
	if strings.Contains(relabel, "z") {
		c := selinux.NewContext(fileLabel)
		c["level"] = "s0"
		fileLabel = c.Get()
	}
	return selinux.Chcon(path, fileLabel, true)
}

// GetPidLabel will return the label of the process running with the specified pid
func GetPidLabel(pid int) (string, error) {
	return selinux.Getpidcon(pid)
}

// Init initialises the labeling system
func Init() {
	selinux.SelinuxEnabled()
}

// ReserveLabel will record the fact that the MCS label has already been used.
// This will prevent InitLabels from using the MCS label in a newly created
// container
func ReserveLabel(label string) error {
	selinux.ReserveLabel(label)
	return nil
}

// UnreserveLabel will remove the reservation of the MCS label.
// This will allow InitLabels to use the MCS label in a newly created
// containers
func UnreserveLabel(label string) error {
	selinux.FreeLxcContexts(label)
	return nil
}

// DupSecOpt takes an process label and returns security options that
// can be used to set duplicate labels on future container processes
func DupSecOpt(src string) []string {
	return selinux.DupSecOpt(src)
}

// DisableSecOpt returns a security opt that can disable labeling
// support for future container processes
func DisableSecOpt() []string {
	return selinux.DisableSecOpt()
}
<|endoftext|>


<commit_before>package easygen_test

import (
	"fmt"
	"os"
	"strings"

	"github.com/go-easygen/easygen"
	"github.com/go-easygen/easygen/egCal"
	"github.com/go-easygen/easygen/egVar"
	"gopkg.in/easygen.v2/egFilePath"
)

type variable struct {
	Name string
}

// for standalone test, change package to `main` and the next func def to,
// func main() {
func ExampleExecute() {
	easygen.Opts.Debug = 1

	tmpl0 := easygen.NewTemplate().Customize()
	tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egFilePath.FuncDefs()).
		Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs())

	// define driving data of any tye
	v0 := variable{"some-init-method"}
	// https://godoc.org/github.com/go-easygen/easygen#Execute
	// provide full template file name with extension
	easygen.Execute(tmpl, os.Stdout, "test/var0.tmpl", v0)

	// Demo of using driving data of pure slice/array
	v1 := []string{"red", "blue", "white"}
	easygen.Execute(tmpl, os.Stdout, "test/list00.tmpl", v1)

	// Demo output to string
	var b strings.Builder
	easygen.Execute(tmpl, &b, "test/list00f.tmpl", v1)
	fmt.Print(b.String())

	// Output:
	// Input: "some-init-method"
	// Output 1: "SomeInitMethod"
	// Output 2: "SOME_INIT_METHOD"
	// The colors are: red, blue, white, .
	// The colors are: red, blue, white.
}
<commit_msg>- [!] fix egFilePath import path<commit_after>package easygen_test

import (
	"fmt"
	"os"
	"strings"

	"github.com/go-easygen/easygen"
	"github.com/go-easygen/easygen/egCal"
	"github.com/go-easygen/easygen/egFilePath"
	"github.com/go-easygen/easygen/egVar"
)

type variable struct {
	Name string
}

// for standalone test, change package to `main` and the next func def to,
// func main() {
func ExampleExecute() {
	easygen.Opts.Debug = 1

	tmpl0 := easygen.NewTemplate().Customize()
	tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egFilePath.FuncDefs()).
		Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs())

	// define driving data of any tye
	v0 := variable{"some-init-method"}
	// https://godoc.org/github.com/go-easygen/easygen#Execute
	// provide full template file name with extension
	easygen.Execute(tmpl, os.Stdout, "test/var0.tmpl", v0)

	// Demo of using driving data of pure slice/array
	v1 := []string{"red", "blue", "white"}
	easygen.Execute(tmpl, os.Stdout, "test/list00.tmpl", v1)

	// Demo output to string
	var b strings.Builder
	easygen.Execute(tmpl, &b, "test/list00f.tmpl", v1)
	fmt.Print(b.String())

	// Output:
	// Input: "some-init-method"
	// Output 1: "SomeInitMethod"
	// Output 2: "SOME_INIT_METHOD"
	// The colors are: red, blue, white, .
	// The colors are: red, blue, white.
}
<|endoftext|>


<commit_before>package conn

import (
	"sync"
	"time"

	"github.com/berkaroad/uuid"
)

type Topic struct {
	name         string
	MsgChan      chan *Message
	FailMsgChan  chan *Message
	ExitChan     chan int
	producterMgr *ClientManager
	consumerMgr  *ClientManager
}

func NewTopic(name string, client *Client) *Topic {
	t := new(Topic)
	t.name = name
	t.MsgChan = make(chan *Message, 1000)
	t.FailMsgChan = make(chan *Message, 1000)
	t.ExitChan = make(chan int)
	t.producterMgr = NewClientManager()
	t.consumerMgr = NewClientManager()

	switch client.ClientType() {
	case CLIENT_TYPE_PRODUCTER:
		t.producterMgr.AddClient(client)
	case CLIENT_TYPE_CONSUMER:
		t.consumerMgr.AddClient(client)
	default:
		return nil
	}
	return t
}

func (t *Topic) Name() string {
	return t.name
}

func (t *Topic) AddClient(client *Client) {
	switch client.ClientType() {
	case CLIENT_TYPE_PRODUCTER:
		t.producterMgr.AddClient(client)
	case CLIENT_TYPE_CONSUMER:
		t.consumerMgr.AddClient(client)
	}
}

func (t *Topic) RemoveClient(clientID uuid.UUID, clientType ClientType) {
	switch clientType {
	case CLIENT_TYPE_PRODUCTER:
		t.producterMgr.RemoveClient(clientID)
	case CLIENT_TYPE_CONSUMER:
		t.consumerMgr.RemoveClient(clientID)
	}
}

func (t *Topic) SendWithLB() {
	if t.consumerMgr.Len() == 0 {
		time.Sleep(3 * time.Second)
	} else {
		t.consumerMgr.SendWithLB(t.MsgChan, t.FailMsgChan)
	}
}

func (t *Topic) Close() {
	t.producterMgr.RemoveAllClient()
	t.consumerMgr.RemoveAllClient()
	close(t.MsgChan)
	close(t.FailMsgChan)
	close(t.ExitChan)
}

type TopicManager struct {
	l         *sync.Mutex
	topicList map[string]*Topic
}

func NewTopicManager() *TopicManager {
	tm := new(TopicManager)
	tm.l = new(sync.Mutex)
	tm.topicList = make(map[string]*Topic)
	return tm
}

func (tm *TopicManager) CreateOrJoinTopic(topicName string, client *Client) *Topic {
	defer tm.l.Unlock()
	tm.l.Lock()

	topic, ok := tm.topicList[topicName]
	if ok {
		topic.AddClient(client)
	} else {
		topic = NewTopic(topicName, client)
		tm.topicList[topicName] = topic
		go func() {
			for {
				select {
				case <-topic.ExitChan:
					topic.Close()
					break
				default:
					topic.SendWithLB()
				}
			}
		}()
	}
	return topic
}

func (tm *TopicManager) RemoveTopic(topicName string) {
	defer tm.l.Unlock()
	tm.l.Lock()
	defer tm.l.Unlock()
	tm.l.Lock()

	topic, ok := tm.topicList[topicName]
	if ok {
		topic.ExitChan <- 1
		delete(tm.topicList, topicName)
	}
}

func (tm *TopicManager) Len() int {
	defer tm.l.Unlock()
	tm.l.Lock()

	return len(tm.topicList)
}
<commit_msg>缓冲区大小改为1W条消息<commit_after>package conn

import (
	"sync"
	"time"

	"github.com/berkaroad/uuid"
)

type Topic struct {
	name         string
	MsgChan      chan *Message
	FailMsgChan  chan *Message
	ExitChan     chan int
	producterMgr *ClientManager
	consumerMgr  *ClientManager
}

func NewTopic(name string, client *Client) *Topic {
	t := new(Topic)
	t.name = name
	t.MsgChan = make(chan *Message, 10000)
	t.FailMsgChan = make(chan *Message, 10000)
	t.ExitChan = make(chan int)
	t.producterMgr = NewClientManager()
	t.consumerMgr = NewClientManager()

	switch client.ClientType() {
	case CLIENT_TYPE_PRODUCTER:
		t.producterMgr.AddClient(client)
	case CLIENT_TYPE_CONSUMER:
		t.consumerMgr.AddClient(client)
	default:
		return nil
	}
	return t
}

func (t *Topic) Name() string {
	return t.name
}

func (t *Topic) AddClient(client *Client) {
	switch client.ClientType() {
	case CLIENT_TYPE_PRODUCTER:
		t.producterMgr.AddClient(client)
	case CLIENT_TYPE_CONSUMER:
		t.consumerMgr.AddClient(client)
	}
}

func (t *Topic) RemoveClient(clientID uuid.UUID, clientType ClientType) {
	switch clientType {
	case CLIENT_TYPE_PRODUCTER:
		t.producterMgr.RemoveClient(clientID)
	case CLIENT_TYPE_CONSUMER:
		t.consumerMgr.RemoveClient(clientID)
	}
}

func (t *Topic) SendWithLB() {
	if t.consumerMgr.Len() == 0 {
		time.Sleep(3 * time.Second)
	} else {
		t.consumerMgr.SendWithLB(t.MsgChan, t.FailMsgChan)
	}
}

func (t *Topic) Close() {
	t.producterMgr.RemoveAllClient()
	t.consumerMgr.RemoveAllClient()
	close(t.MsgChan)
	close(t.FailMsgChan)
	close(t.ExitChan)
}

type TopicManager struct {
	l         *sync.Mutex
	topicList map[string]*Topic
}

func NewTopicManager() *TopicManager {
	tm := new(TopicManager)
	tm.l = new(sync.Mutex)
	tm.topicList = make(map[string]*Topic)
	return tm
}

func (tm *TopicManager) CreateOrJoinTopic(topicName string, client *Client) *Topic {
	defer tm.l.Unlock()
	tm.l.Lock()

	topic, ok := tm.topicList[topicName]
	if ok {
		topic.AddClient(client)
	} else {
		topic = NewTopic(topicName, client)
		tm.topicList[topicName] = topic
		go func() {
			for {
				select {
				case <-topic.ExitChan:
					topic.Close()
					break
				default:
					topic.SendWithLB()
				}
			}
		}()
	}
	return topic
}

func (tm *TopicManager) RemoveTopic(topicName string) {
	defer tm.l.Unlock()
	tm.l.Lock()
	defer tm.l.Unlock()
	tm.l.Lock()

	topic, ok := tm.topicList[topicName]
	if ok {
		topic.ExitChan <- 1
		delete(tm.topicList, topicName)
	}
}

func (tm *TopicManager) Len() int {
	defer tm.l.Unlock()
	tm.l.Lock()

	return len(tm.topicList)
}
<|endoftext|>


<commit_before>package gumble

import (
	"code.google.com/p/goprotobuf/proto"
	"github.com/bontibon/gumble/gumble/MumbleProto"
)

type Channel struct {
	client *Client

	id              uint32
	parent          *Channel
	children        Channels
	name            string
	description     string
	descriptionHash []byte
	position        int32
	temporary       bool
}

// Id returns the channel's unique Id.
func (c *Channel) Id() uint {
	return uint(c.id)
}

// Parent returns a pointer to the parent channel, or nil if the channel is the
// root of the server.
func (c *Channel) Parent() *Channel {
	return c.parent
}

// DescriptionHash returns the channel's description hash. This function can
// return nil.
func (c *Channel) DescriptionHash() []byte {
	return c.descriptionHash
}

// Position returns the position at which the channel should be displayed in
// an ordered list.
func (c *Channel) Position() int {
	return int(c.position)
}

// Temporary returns true if the channel is temporary.
func (c *Channel) Temporary() bool {
	return c.temporary
}

// IsRoot returns true if the channel is the server's root channel, false
// otherwise.
func (c *Channel) IsRoot() bool {
	return c.id == 0
}

// Add will add a sub-channel to the given channel.
func (c *Channel) Add(name string, temporary bool) {
	packet := MumbleProto.ChannelState{
		Parent:    &c.id,
		Name:      &name,
		Temporary: proto.Bool(temporary),
	}
	c.client.Send(protoMessage{&packet})
}

// Remove will remove the given channel and all sub-channels from the server's
// channel tree.
func (c *Channel) Remove() {
	packet := MumbleProto.ChannelRemove{
		ChannelId: &c.id,
	}
	c.client.Send(protoMessage{&packet})
}

// Name returns the channel name.
func (c *Channel) Name() string {
	return c.name
}

// SetName will set the name of the channel. This will have no effect if the
// channel is the server's root channel.
func (c *Channel) SetName(name string) {
	packet := MumbleProto.ChannelState{
		ChannelId: &c.id,
		Name:      &name,
	}
	c.client.Send(protoMessage{&packet})
}

// Description returns the channel's description.
func (c *Channel) Description() string {
	return c.description
}

// SetDescription will set the description of the channel.
func (c *Channel) SetDescription(description string) {
	packet := MumbleProto.ChannelState{
		ChannelId:   &c.id,
		Description: &description,
	}
	c.client.Send(protoMessage{&packet})
}

// Children returns a container containing the channels directly underneath the
// current channel.
func (c *Channel) Children() Channels {
	return c.children
}

// Find returns a channel whose path (by channel name) from the current channel
// is equal to the arguments passed.
func (c *Channel) Find(names ...string) *Channel {
	if names == nil || len(names) == 0 {
		return c
	}
	for _, child := range c.children {
		if child.name == names[0] {
			return child.Find(names[1:]...)
		}
	}
	return nil
}

// Request requests channel information that has not yet been sent to the
// client.
func (c *Channel) Request(request Request) {
	if (request & RequestDescription) != 0 {
		packet := MumbleProto.RequestBlob{
			ChannelDescription: []uint32{c.id},
		}
		c.client.Send(protoMessage{&packet})
	}
}
<commit_msg>change Channel.Temporary() to Channel.IsTemporary()<commit_after>package gumble

import (
	"code.google.com/p/goprotobuf/proto"
	"github.com/bontibon/gumble/gumble/MumbleProto"
)

type Channel struct {
	client *Client

	id              uint32
	parent          *Channel
	children        Channels
	name            string
	description     string
	descriptionHash []byte
	position        int32
	temporary       bool
}

// Id returns the channel's unique Id.
func (c *Channel) Id() uint {
	return uint(c.id)
}

// Parent returns a pointer to the parent channel, or nil if the channel is the
// root of the server.
func (c *Channel) Parent() *Channel {
	return c.parent
}

// DescriptionHash returns the channel's description hash. This function can
// return nil.
func (c *Channel) DescriptionHash() []byte {
	return c.descriptionHash
}

// Position returns the position at which the channel should be displayed in
// an ordered list.
func (c *Channel) Position() int {
	return int(c.position)
}

// IsTemporary returns true if the channel is temporary.
func (c *Channel) IsTemporary() bool {
	return c.temporary
}

// IsRoot returns true if the channel is the server's root channel, false
// otherwise.
func (c *Channel) IsRoot() bool {
	return c.id == 0
}

// Add will add a sub-channel to the given channel.
func (c *Channel) Add(name string, temporary bool) {
	packet := MumbleProto.ChannelState{
		Parent:    &c.id,
		Name:      &name,
		Temporary: proto.Bool(temporary),
	}
	c.client.Send(protoMessage{&packet})
}

// Remove will remove the given channel and all sub-channels from the server's
// channel tree.
func (c *Channel) Remove() {
	packet := MumbleProto.ChannelRemove{
		ChannelId: &c.id,
	}
	c.client.Send(protoMessage{&packet})
}

// Name returns the channel name.
func (c *Channel) Name() string {
	return c.name
}

// SetName will set the name of the channel. This will have no effect if the
// channel is the server's root channel.
func (c *Channel) SetName(name string) {
	packet := MumbleProto.ChannelState{
		ChannelId: &c.id,
		Name:      &name,
	}
	c.client.Send(protoMessage{&packet})
}

// Description returns the channel's description.
func (c *Channel) Description() string {
	return c.description
}

// SetDescription will set the description of the channel.
func (c *Channel) SetDescription(description string) {
	packet := MumbleProto.ChannelState{
		ChannelId:   &c.id,
		Description: &description,
	}
	c.client.Send(protoMessage{&packet})
}

// Children returns a container containing the channels directly underneath the
// current channel.
func (c *Channel) Children() Channels {
	return c.children
}

// Find returns a channel whose path (by channel name) from the current channel
// is equal to the arguments passed.
func (c *Channel) Find(names ...string) *Channel {
	if names == nil || len(names) == 0 {
		return c
	}
	for _, child := range c.children {
		if child.name == names[0] {
			return child.Find(names[1:]...)
		}
	}
	return nil
}

// Request requests channel information that has not yet been sent to the
// client.
func (c *Channel) Request(request Request) {
	if (request & RequestDescription) != 0 {
		packet := MumbleProto.RequestBlob{
			ChannelDescription: []uint32{c.id},
		}
		c.client.Send(protoMessage{&packet})
	}
}
<|endoftext|>


<commit_before>package heroku

import (
	"fmt"
	"log"
	"strings"
	"sync"

	"github.com/cyberdelia/heroku-go/v3"
	"github.com/hashicorp/terraform/helper/schema"
)

// Global lock to prevent parallelism for heroku_addon since
// the Heroku API cannot handle a single application requesting
// multiple addons simultaneously.
var addonLock sync.Mutex

func resourceHerokuAddon() *schema.Resource {
	return &schema.Resource{
		Create: resourceHerokuAddonCreate,
		Read:   resourceHerokuAddonRead,
		Update: resourceHerokuAddonUpdate,
		Delete: resourceHerokuAddonDelete,

		Schema: map[string]*schema.Schema{
			"app": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"plan": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"config": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Schema{
					Type: schema.TypeMap,
				},
			},

			"provider_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"config_vars": &schema.Schema{
				Type:     schema.TypeList,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeMap},
			},
		},
	}
}

func resourceHerokuAddonCreate(d *schema.ResourceData, meta interface{}) error {
	addonLock.Lock()
	defer addonLock.Unlock()

	client := meta.(*heroku.Service)

	app := d.Get("app").(string)
	opts := heroku.AddonCreateOpts{Plan: d.Get("plan").(string)}

	if v := d.Get("config"); v != nil {
		config := make(map[string]string)
		for _, v := range v.([]interface{}) {
			for k, v := range v.(map[string]interface{}) {
				config[k] = v.(string)
			}
		}

		opts.Config = &config
	}

	log.Printf("[DEBUG] Addon create configuration: %#v, %#v", app, opts)
	a, err := client.AddonCreate(app, opts)
	if err != nil {
		return err
	}

	d.SetId(a.ID)
	log.Printf("[INFO] Addon ID: %s", d.Id())

	return resourceHerokuAddonRead(d, meta)
}

func resourceHerokuAddonRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	addon, err := resourceHerokuAddonRetrieve(
		d.Get("app").(string), d.Id(), client)
	if err != nil {
		return err
	}

	// Determine the plan. If we were configured without a specific plan,
	// then just avoid the plan altogether (accepting anything that
	// Heroku sends down).
	plan := addon.Plan.Name
	if v := d.Get("plan").(string); v != "" {
		if idx := strings.IndexRune(v, ':'); idx == -1 {
			idx = strings.IndexRune(plan, ':')
			if idx > -1 {
				plan = plan[:idx]
			}
		}
	}

	d.Set("name", addon.Name)
	d.Set("plan", plan)
	d.Set("provider_id", addon.ProviderID)
	d.Set("config_vars", []interface{}{addon.ConfigVars})

	return nil
}

func resourceHerokuAddonUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	app := d.Get("app").(string)

	if d.HasChange("plan") {
		ad, err := client.AddonUpdate(
			app, d.Id(), heroku.AddonUpdateOpts{Plan: d.Get("plan").(string)})
		if err != nil {
			return err
		}

		// Store the new ID
		d.SetId(ad.ID)
	}

	return resourceHerokuAddonRead(d, meta)
}

func resourceHerokuAddonDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	log.Printf("[INFO] Deleting Addon: %s", d.Id())

	// Destroy the app
	err := client.AddonDelete(d.Get("app").(string), d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting addon: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceHerokuAddonRetrieve(app string, id string, client *heroku.Service) (*heroku.Addon, error) {
	addon, err := client.AddonInfo(app, id)

	if err != nil {
		return nil, fmt.Errorf("Error retrieving addon: %s", err)
	}

	return addon, nil
}
<commit_msg>The type returned from heroku API is a string array, while our schema says []map[string]interface{}.<commit_after>package heroku

import (
	"fmt"
	"log"
	"strings"
	"sync"

	"github.com/cyberdelia/heroku-go/v3"
	"github.com/hashicorp/terraform/helper/schema"
)

// Global lock to prevent parallelism for heroku_addon since
// the Heroku API cannot handle a single application requesting
// multiple addons simultaneously.
var addonLock sync.Mutex

func resourceHerokuAddon() *schema.Resource {
	return &schema.Resource{
		Create: resourceHerokuAddonCreate,
		Read:   resourceHerokuAddonRead,
		Update: resourceHerokuAddonUpdate,
		Delete: resourceHerokuAddonDelete,

		Schema: map[string]*schema.Schema{
			"app": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"plan": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"config": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Schema{
					Type: schema.TypeMap,
				},
			},

			"provider_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"config_vars": &schema.Schema{
				Type:     schema.TypeList,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeMap},
			},
		},
	}
}

func resourceHerokuAddonCreate(d *schema.ResourceData, meta interface{}) error {
	addonLock.Lock()
	defer addonLock.Unlock()

	client := meta.(*heroku.Service)

	app := d.Get("app").(string)
	opts := heroku.AddonCreateOpts{Plan: d.Get("plan").(string)}

	if v := d.Get("config"); v != nil {
		config := make(map[string]string)
		for _, v := range v.([]interface{}) {
			for k, v := range v.(map[string]interface{}) {
				config[k] = v.(string)
			}
		}

		opts.Config = &config
	}

	log.Printf("[DEBUG] Addon create configuration: %#v, %#v", app, opts)
	a, err := client.AddonCreate(app, opts)
	if err != nil {
		return err
	}

	d.SetId(a.ID)
	log.Printf("[INFO] Addon ID: %s", d.Id())

	return resourceHerokuAddonRead(d, meta)
}

func resourceHerokuAddonRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	addon, err := resourceHerokuAddonRetrieve(
		d.Get("app").(string), d.Id(), client)
	if err != nil {
		return err
	}

	// Determine the plan. If we were configured without a specific plan,
	// then just avoid the plan altogether (accepting anything that
	// Heroku sends down).
	plan := addon.Plan.Name
	if v := d.Get("plan").(string); v != "" {
		if idx := strings.IndexRune(v, ':'); idx == -1 {
			idx = strings.IndexRune(plan, ':')
			if idx > -1 {
				plan = plan[:idx]
			}
		}
	}

	d.Set("name", addon.Name)
	d.Set("plan", plan)
	d.Set("provider_id", addon.ProviderID)

	configVarsMap := make(map[string]interface{})
	for i := range addon.ConfigVars {
		configVarsMap[addon.ConfigVars[i]] = addon.ConfigVars[i]
	}
	d.Set("config_vars", []interface{}{configVarsMap})

	return nil
}

func resourceHerokuAddonUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	app := d.Get("app").(string)

	if d.HasChange("plan") {
		ad, err := client.AddonUpdate(
			app, d.Id(), heroku.AddonUpdateOpts{Plan: d.Get("plan").(string)})
		if err != nil {
			return err
		}

		// Store the new ID
		d.SetId(ad.ID)
	}

	return resourceHerokuAddonRead(d, meta)
}

func resourceHerokuAddonDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*heroku.Service)

	log.Printf("[INFO] Deleting Addon: %s", d.Id())

	// Destroy the app
	err := client.AddonDelete(d.Get("app").(string), d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting addon: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceHerokuAddonRetrieve(app string, id string, client *heroku.Service) (*heroku.Addon, error) {
	addon, err := client.AddonInfo(app, id)

	if err != nil {
		return nil, fmt.Errorf("Error retrieving addon: %s", err)
	}

	return addon, nil
}
<|endoftext|>


<commit_before>package file

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/hashicorp/terraform/helper/config"
	helper "github.com/hashicorp/terraform/helper/ssh"
	"github.com/hashicorp/terraform/terraform"
)

type ResourceProvisioner struct{}

func (p *ResourceProvisioner) Apply(
	o terraform.UIOutput,
	s *terraform.InstanceState,
	c *terraform.ResourceConfig) error {
	// Ensure the connection type is SSH
	if err := helper.VerifySSH(s); err != nil {
		return err
	}

	// Get the SSH configuration
	conf, err := helper.ParseSSHConfig(s)
	if err != nil {
		return err
	}

	// Get the source and destination
	sRaw := c.Config["source"]
	src, ok := sRaw.(string)
	if !ok {
		return fmt.Errorf("Unsupported 'source' type! Must be string.")
	}

	dRaw := c.Config["destination"]
	dst, ok := dRaw.(string)
	if !ok {
		return fmt.Errorf("Unsupported 'destination' type! Must be string.")
	}
	return p.copyFiles(conf, src, dst)
}

func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
	v := &config.Validator{
		Required: []string{
			"source",
			"destination",
		},
	}
	return v.Validate(c)
}

// copyFiles is used to copy the files from a source to a destination
func (p *ResourceProvisioner) copyFiles(conf *helper.SSHConfig, src, dst string) error {
	// Get the SSH client config
	config, err := helper.PrepareConfig(conf)
	if err != nil {
		return err
	}
	defer config.CleanupConfig()

	// Wait and retry until we establish the SSH connection
	var comm *helper.SSHCommunicator
	err = retryFunc(conf.TimeoutVal, func() error {
		host := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
		comm, err = helper.New(host, config)
		return err
	})
	if err != nil {
		return err
	}

	info, err := os.Stat(src)
	if err != nil {
		return err
	}

	// If we're uploading a directory, short circuit and do that
	if info.IsDir() {
		if err := comm.UploadDir(dst, src, nil); err != nil {
			return fmt.Errorf("Upload failed: %v", err)
		}
		return nil
	}

	// We're uploading a file...
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	err = comm.Upload(dst, f)
	if err != nil {
		return fmt.Errorf("Upload failed: %v", err)
	}
	return err
}

// retryFunc is used to retry a function for a given duration
func retryFunc(timeout time.Duration, f func() error) error {
	finish := time.After(timeout)
	for {
		err := f()
		if err == nil {
			return nil
		}
		log.Printf("Retryable error: %v", err)

		select {
		case <-finish:
			return err
		case <-time.After(3 * time.Second):
		}
	}
}
<commit_msg>provisioner/file: expand ~ in source<commit_after>package file

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/hashicorp/terraform/helper/config"
	helper "github.com/hashicorp/terraform/helper/ssh"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/go-homedir"
)

type ResourceProvisioner struct{}

func (p *ResourceProvisioner) Apply(
	o terraform.UIOutput,
	s *terraform.InstanceState,
	c *terraform.ResourceConfig) error {
	// Ensure the connection type is SSH
	if err := helper.VerifySSH(s); err != nil {
		return err
	}

	// Get the SSH configuration
	conf, err := helper.ParseSSHConfig(s)
	if err != nil {
		return err
	}

	// Get the source and destination
	sRaw := c.Config["source"]
	src, ok := sRaw.(string)
	if !ok {
		return fmt.Errorf("Unsupported 'source' type! Must be string.")
	}

	src, err = homedir.Expand(src)
	if err != nil {
		return err
	}

	dRaw := c.Config["destination"]
	dst, ok := dRaw.(string)
	if !ok {
		return fmt.Errorf("Unsupported 'destination' type! Must be string.")
	}
	return p.copyFiles(conf, src, dst)
}

func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
	v := &config.Validator{
		Required: []string{
			"source",
			"destination",
		},
	}
	return v.Validate(c)
}

// copyFiles is used to copy the files from a source to a destination
func (p *ResourceProvisioner) copyFiles(conf *helper.SSHConfig, src, dst string) error {
	// Get the SSH client config
	config, err := helper.PrepareConfig(conf)
	if err != nil {
		return err
	}
	defer config.CleanupConfig()

	// Wait and retry until we establish the SSH connection
	var comm *helper.SSHCommunicator
	err = retryFunc(conf.TimeoutVal, func() error {
		host := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
		comm, err = helper.New(host, config)
		return err
	})
	if err != nil {
		return err
	}

	info, err := os.Stat(src)
	if err != nil {
		return err
	}

	// If we're uploading a directory, short circuit and do that
	if info.IsDir() {
		if err := comm.UploadDir(dst, src, nil); err != nil {
			return fmt.Errorf("Upload failed: %v", err)
		}
		return nil
	}

	// We're uploading a file...
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	err = comm.Upload(dst, f)
	if err != nil {
		return fmt.Errorf("Upload failed: %v", err)
	}
	return err
}

// retryFunc is used to retry a function for a given duration
func retryFunc(timeout time.Duration, f func() error) error {
	finish := time.After(timeout)
	for {
		err := f()
		if err == nil {
			return nil
		}
		log.Printf("Retryable error: %v", err)

		select {
		case <-finish:
			return err
		case <-time.After(3 * time.Second):
		}
	}
}
<|endoftext|>


<commit_before>// Package ratelimit implements a rate limiter to avoid calling APIs too often.
package ratelimit

import (
	"fmt"
	"time"

	gocontext "context"

	"github.com/garyburd/redigo/redis"
	"github.com/sirupsen/logrus"
	"github.com/travis-ci/worker/context"
	"go.opencensus.io/trace"
)

const (
	redisRateLimiterPoolMaxActive   = 1
	redisRateLimiterPoolMaxIdle     = 1
	redisRateLimiterPoolIdleTimeout = 3 * time.Minute
)

// RateLimiter checks if a call can be let through and returns true if it can.
//
// The name should be the same for all calls that should be affected by the
// same rate limit. The maxCalls and per arguments must be the same for all
// calls that use the same name, otherwise the behaviour is undefined.
//
// The rate limiter lets through maxCalls calls in a window of time specified
// by the "per" argument. Note that the window is not sliding, so if you say 10
// calls per minute, and 10 calls happen in the first second, no further calls
// will be let through for another 59 seconds.
//
// The actual call should only be made if (true, nil) is returned. If (false,
// nil) is returned, it means that the number of requests in the time window is
// met, and you should sleep for a bit and try again.
//
// In case an error happens, (false, err) is returned.
type RateLimiter interface {
	RateLimit(ctx gocontext.Context, name string, maxCalls uint64, per time.Duration) (bool, error)
}

type redisRateLimiter struct {
	pool   *redis.Pool
	prefix string

	dynamicConfig         bool
	dynamicConfigCacheTTL time.Duration

	cachedMaxCalls *uint64
	cachedDuration *time.Duration
	cacheExpiresAt *time.Time
}

type nullRateLimiter struct{}

// NewRateLimiter creates a RateLimiter that's backed by Redis. The prefix can
// be used to allow multiple rate limiters with the same name on the same Redis
// server.
func NewRateLimiter(redisURL string, prefix string, dynamicConfig bool, dynamicConfigCacheTTL time.Duration) RateLimiter {
	return &redisRateLimiter{
		pool: &redis.Pool{
			Dial: func() (redis.Conn, error) {
				return redis.DialURL(redisURL)
			},
			TestOnBorrow: func(c redis.Conn, _ time.Time) error {
				_, err := c.Do("PING")
				return err
			},
			MaxIdle:     redisRateLimiterPoolMaxIdle,
			MaxActive:   redisRateLimiterPoolMaxActive,
			IdleTimeout: redisRateLimiterPoolIdleTimeout,
			Wait:        true,
		},
		prefix: prefix,

		dynamicConfig:         dynamicConfig,
		dynamicConfigCacheTTL: dynamicConfigCacheTTL,
	}
}

// NewNullRateLimiter creates a valid RateLimiter that always lets all requests
// through immediately.
func NewNullRateLimiter() RateLimiter {
	return nullRateLimiter{}
}

// BUG(sarahhodne): The Redis rate limiter is known to let through too many
// requests when there are many clients talking to the same Redis. The reason
// for this is unknown, but it's probably wise to limit the number of clients
// to 5 or 6 for the time being.
func (rl *redisRateLimiter) RateLimit(ctx gocontext.Context, name string, maxCalls uint64, per time.Duration) (bool, error) {
	if trace.FromContext(ctx) != nil {
		var span *trace.Span
		ctx, span = trace.StartSpan(ctx, "Redis.RateLimit")
		defer span.End()
	}

	conn := rl.pool.Get()
	defer conn.Close()

	if trace.FromContext(ctx) != nil {
		var span *trace.Span
		ctx, span = trace.StartSpan(ctx, "Redis.RateLimit.WithPool")
		defer span.End()
	}

	if rl.dynamicConfig {
		err := rl.loadDynamicConfig(ctx, conn, name, &maxCalls, &per)
		if err != nil && err != redis.ErrNil {
			return false, err
		}
	}

	now := time.Now()
	timestamp := now.Unix() - (now.Unix() % int64(per.Seconds()))

	key := fmt.Sprintf("%s:%s:%d", rl.prefix, name, timestamp)

	cur, err := redis.Int64(conn.Do("GET", key))
	if err != nil && err != redis.ErrNil {
		return false, err
	}

	if err != redis.ErrNil && uint64(cur) >= maxCalls {
		return false, nil
	}

	_, err = conn.Do("WATCH", key)
	if err != nil {
		return false, err
	}

	connSend := func(commandName string, args ...interface{}) {
		if err != nil && err != redis.ErrNil {
			return
		}
		err = conn.Send(commandName, args...)
	}
	connSend("MULTI")
	connSend("INCR", key)
	connSend("EXPIRE", key, int64(per.Seconds()))
	if err != nil {
		return false, err
	}

	reply, err := conn.Do("EXEC")
	if err != nil {
		return false, err
	}
	if reply == nil {
		return false, nil
	}

	return true, nil
}

// if dynamic config is enabled, it is possible to override
// max_calls and duration at runtime by setting redis keys:
//
// * <prefix>:<name>:max_calls
// * <prefix>:<name>:duration
//
// for example:
//
// * worker-rate-limit-gce-api-1:gce-api:max_calls 3000
// * worker-rate-limit-gce-api-1:gce-api:duration  100s
func (rl *redisRateLimiter) loadDynamicConfig(ctx gocontext.Context, conn redis.Conn, name string, maxCalls *uint64, per *time.Duration) error {
	if rl.cacheExpiresAt != nil && rl.cacheExpiresAt.Before(time.Now()) {
		rl.cachedMaxCalls = nil
		rl.cachedDuration = nil
	}

	// load from cache
	if rl.cachedMaxCalls != nil || rl.cachedDuration != nil {
		if rl.cachedMaxCalls != nil {
			*maxCalls = *rl.cachedMaxCalls
		}
		if rl.cachedDuration != nil {
			*per = *rl.cachedDuration
		}
		return nil
	}

	// load from redis
	key := fmt.Sprintf("%s:%s:max_calls", rl.prefix, name)
	dynMaxCalls, err := redis.Uint64(conn.Do("GET", key))
	if err != nil && err != redis.ErrNil {
		return err
	}
	if err != redis.ErrNil {
		*maxCalls = dynMaxCalls
	}

	key = fmt.Sprintf("%s:%s:duration", rl.prefix, name)
	dynDurationStr, err := redis.String(conn.Do("GET", key))
	if err != nil && err != redis.ErrNil {
		return err
	}
	if err != redis.ErrNil {
		dynDuration, err := time.ParseDuration(dynDurationStr)
		if err == nil {
			*per = dynDuration
		}
	}

	expires := time.Now().Add(time.Second * 10)

	logger := context.LoggerFromContext(ctx).WithField("self", "ratelimit/redis")
	logger.WithFields(logrus.Fields{
		"max_calls": *maxCalls,
		"duration":  *per,
	}).Info("refreshed dynamic config")

	rl.cachedMaxCalls = maxCalls
	rl.cachedDuration = per
	rl.cacheExpiresAt = &expires

	return nil
}

func (rl nullRateLimiter) RateLimit(ctx gocontext.Context, name string, maxCalls uint64, per time.Duration) (bool, error) {
	return true, nil
}
<commit_msg>ratelimit: track cumulative pool checkout wait time in honeycomb<commit_after>// Package ratelimit implements a rate limiter to avoid calling APIs too often.
package ratelimit

import (
	"fmt"
	"time"

	gocontext "context"

	"github.com/garyburd/redigo/redis"
	"github.com/sirupsen/logrus"
	"github.com/travis-ci/worker/context"
	"go.opencensus.io/trace"
)

const (
	redisRateLimiterPoolMaxActive   = 1
	redisRateLimiterPoolMaxIdle     = 1
	redisRateLimiterPoolIdleTimeout = 3 * time.Minute
)

// RateLimiter checks if a call can be let through and returns true if it can.
//
// The name should be the same for all calls that should be affected by the
// same rate limit. The maxCalls and per arguments must be the same for all
// calls that use the same name, otherwise the behaviour is undefined.
//
// The rate limiter lets through maxCalls calls in a window of time specified
// by the "per" argument. Note that the window is not sliding, so if you say 10
// calls per minute, and 10 calls happen in the first second, no further calls
// will be let through for another 59 seconds.
//
// The actual call should only be made if (true, nil) is returned. If (false,
// nil) is returned, it means that the number of requests in the time window is
// met, and you should sleep for a bit and try again.
//
// In case an error happens, (false, err) is returned.
type RateLimiter interface {
	RateLimit(ctx gocontext.Context, name string, maxCalls uint64, per time.Duration) (bool, error)
}

type redisRateLimiter struct {
	pool   *redis.Pool
	prefix string

	dynamicConfig         bool
	dynamicConfigCacheTTL time.Duration

	cachedMaxCalls *uint64
	cachedDuration *time.Duration
	cacheExpiresAt *time.Time
}

type nullRateLimiter struct{}

// NewRateLimiter creates a RateLimiter that's backed by Redis. The prefix can
// be used to allow multiple rate limiters with the same name on the same Redis
// server.
func NewRateLimiter(redisURL string, prefix string, dynamicConfig bool, dynamicConfigCacheTTL time.Duration) RateLimiter {
	return &redisRateLimiter{
		pool: &redis.Pool{
			Dial: func() (redis.Conn, error) {
				return redis.DialURL(redisURL)
			},
			TestOnBorrow: func(c redis.Conn, _ time.Time) error {
				_, err := c.Do("PING")
				return err
			},
			MaxIdle:     redisRateLimiterPoolMaxIdle,
			MaxActive:   redisRateLimiterPoolMaxActive,
			IdleTimeout: redisRateLimiterPoolIdleTimeout,
			Wait:        true,
		},
		prefix: prefix,

		dynamicConfig:         dynamicConfig,
		dynamicConfigCacheTTL: dynamicConfigCacheTTL,
	}
}

// NewNullRateLimiter creates a valid RateLimiter that always lets all requests
// through immediately.
func NewNullRateLimiter() RateLimiter {
	return nullRateLimiter{}
}

// BUG(sarahhodne): The Redis rate limiter is known to let through too many
// requests when there are many clients talking to the same Redis. The reason
// for this is unknown, but it's probably wise to limit the number of clients
// to 5 or 6 for the time being.
func (rl *redisRateLimiter) RateLimit(ctx gocontext.Context, name string, maxCalls uint64, per time.Duration) (bool, error) {
	if trace.FromContext(ctx) != nil {
		var span *trace.Span
		ctx, span = trace.StartSpan(ctx, "Redis.RateLimit")
		defer span.End()
	}

	poolCheckoutStart := time.Now()

	conn := rl.pool.Get()
	defer conn.Close()

	context.TimeSince(ctx, "rate_limit_redis_pool_wait", poolCheckoutStart)

	if trace.FromContext(ctx) != nil {
		var span *trace.Span
		ctx, span = trace.StartSpan(ctx, "Redis.RateLimit.WithPool")
		defer span.End()
	}

	if rl.dynamicConfig {
		err := rl.loadDynamicConfig(ctx, conn, name, &maxCalls, &per)
		if err != nil && err != redis.ErrNil {
			return false, err
		}
	}

	now := time.Now()
	timestamp := now.Unix() - (now.Unix() % int64(per.Seconds()))

	key := fmt.Sprintf("%s:%s:%d", rl.prefix, name, timestamp)

	cur, err := redis.Int64(conn.Do("GET", key))
	if err != nil && err != redis.ErrNil {
		return false, err
	}

	if err != redis.ErrNil && uint64(cur) >= maxCalls {
		return false, nil
	}

	_, err = conn.Do("WATCH", key)
	if err != nil {
		return false, err
	}

	connSend := func(commandName string, args ...interface{}) {
		if err != nil && err != redis.ErrNil {
			return
		}
		err = conn.Send(commandName, args...)
	}
	connSend("MULTI")
	connSend("INCR", key)
	connSend("EXPIRE", key, int64(per.Seconds()))
	if err != nil {
		return false, err
	}

	reply, err := conn.Do("EXEC")
	if err != nil {
		return false, err
	}
	if reply == nil {
		return false, nil
	}

	return true, nil
}

// if dynamic config is enabled, it is possible to override
// max_calls and duration at runtime by setting redis keys:
//
// * <prefix>:<name>:max_calls
// * <prefix>:<name>:duration
//
// for example:
//
// * worker-rate-limit-gce-api-1:gce-api:max_calls 3000
// * worker-rate-limit-gce-api-1:gce-api:duration  100s
func (rl *redisRateLimiter) loadDynamicConfig(ctx gocontext.Context, conn redis.Conn, name string, maxCalls *uint64, per *time.Duration) error {
	if rl.cacheExpiresAt != nil && rl.cacheExpiresAt.Before(time.Now()) {
		rl.cachedMaxCalls = nil
		rl.cachedDuration = nil
	}

	// load from cache
	if rl.cachedMaxCalls != nil || rl.cachedDuration != nil {
		if rl.cachedMaxCalls != nil {
			*maxCalls = *rl.cachedMaxCalls
		}
		if rl.cachedDuration != nil {
			*per = *rl.cachedDuration
		}
		return nil
	}

	// load from redis
	key := fmt.Sprintf("%s:%s:max_calls", rl.prefix, name)
	dynMaxCalls, err := redis.Uint64(conn.Do("GET", key))
	if err != nil && err != redis.ErrNil {
		return err
	}
	if err != redis.ErrNil {
		*maxCalls = dynMaxCalls
	}

	key = fmt.Sprintf("%s:%s:duration", rl.prefix, name)
	dynDurationStr, err := redis.String(conn.Do("GET", key))
	if err != nil && err != redis.ErrNil {
		return err
	}
	if err != redis.ErrNil {
		dynDuration, err := time.ParseDuration(dynDurationStr)
		if err == nil {
			*per = dynDuration
		}
	}

	expires := time.Now().Add(time.Second * 10)

	logger := context.LoggerFromContext(ctx).WithField("self", "ratelimit/redis")
	logger.WithFields(logrus.Fields{
		"max_calls": *maxCalls,
		"duration":  *per,
	}).Info("refreshed dynamic config")

	rl.cachedMaxCalls = maxCalls
	rl.cachedDuration = per
	rl.cacheExpiresAt = &expires

	return nil
}

func (rl nullRateLimiter) RateLimit(ctx gocontext.Context, name string, maxCalls uint64, per time.Duration) (bool, error) {
	return true, nil
}
<|endoftext|>