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

// +build js,wasm

package syscall

import (
	"sync"
	"unsafe"
)

const direntSize = 8 + 8 + 2 + 256

type Dirent struct {
	Reclen uint16
	Name   [256]byte
}

func direntIno(buf []byte) (uint64, bool) {
	return 1, true
}

func direntReclen(buf []byte) (uint64, bool) {
	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
}

func direntNamlen(buf []byte) (uint64, bool) {
	reclen, ok := direntReclen(buf)
	if !ok {
		return 0, false
	}
	return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
}

const PathMax = 256

// An Errno is an unsigned number describing an error condition.
// It implements the error interface. The zero Errno is by convention
// a non-error, so code to convert from Errno to error should use:
//	err = nil
//	if errno != 0 {
//		err = errno
//	}
type Errno uintptr

func (e Errno) Error() string {
	if 0 <= int(e) && int(e) < len(errorstr) {
		s := errorstr[e]
		if s != "" {
			return s
		}
	}
	return "errno " + itoa(int(e))
}

func (e Errno) Temporary() bool {
	return e == EINTR || e == EMFILE || e.Timeout()
}

func (e Errno) Timeout() bool {
	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
}

// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int

const (
	_ Signal = iota
	SIGCHLD
	SIGINT
	SIGKILL
	SIGTRAP
	SIGQUIT
)

func (s Signal) Signal() {}

func (s Signal) String() string {
	if 0 <= s && int(s) < len(signals) {
		str := signals[s]
		if str != "" {
			return str
		}
	}
	return "signal " + itoa(int(s))
}

var signals = [...]string{}

// File system

const (
	Stdin  = 0
	Stdout = 1
	Stderr = 2
)

const (
	O_RDONLY = 0
	O_WRONLY = 1
	O_RDWR   = 2

	O_CREAT  = 0100
	O_CREATE = O_CREAT
	O_TRUNC  = 01000
	O_APPEND = 02000
	O_EXCL   = 0200
	O_SYNC   = 010000

	O_CLOEXEC = 0
)

const (
	F_DUPFD   = 0
	F_GETFD   = 1
	F_SETFD   = 2
	F_GETFL   = 3
	F_SETFL   = 4
	F_GETOWN  = 5
	F_SETOWN  = 6
	F_GETLK   = 7
	F_SETLK   = 8
	F_SETLKW  = 9
	F_RGETLK  = 10
	F_RSETLK  = 11
	F_CNVT    = 12
	F_RSETLKW = 13

	F_RDLCK   = 1
	F_WRLCK   = 2
	F_UNLCK   = 3
	F_UNLKSYS = 4
)

const (
	S_IFMT        = 0000370000
	S_IFSHM_SYSV  = 0000300000
	S_IFSEMA      = 0000270000
	S_IFCOND      = 0000260000
	S_IFMUTEX     = 0000250000
	S_IFSHM       = 0000240000
	S_IFBOUNDSOCK = 0000230000
	S_IFSOCKADDR  = 0000220000
	S_IFDSOCK     = 0000210000

	S_IFSOCK = 0000140000
	S_IFLNK  = 0000120000
	S_IFREG  = 0000100000
	S_IFBLK  = 0000060000
	S_IFDIR  = 0000040000
	S_IFCHR  = 0000020000
	S_IFIFO  = 0000010000

	S_UNSUP = 0000370000

	S_ISUID = 0004000
	S_ISGID = 0002000
	S_ISVTX = 0001000

	S_IREAD  = 0400
	S_IWRITE = 0200
	S_IEXEC  = 0100

	S_IRWXU = 0700
	S_IRUSR = 0400
	S_IWUSR = 0200
	S_IXUSR = 0100

	S_IRWXG = 070
	S_IRGRP = 040
	S_IWGRP = 020
	S_IXGRP = 010

	S_IRWXO = 07
	S_IROTH = 04
	S_IWOTH = 02
	S_IXOTH = 01
)

type Stat_t struct {
	Dev       int64
	Ino       uint64
	Mode      uint32
	Nlink     uint32
	Uid       uint32
	Gid       uint32
	Rdev      int64
	Size      int64
	Blksize   int32
	Blocks    int32
	Atime     int64
	AtimeNsec int64
	Mtime     int64
	MtimeNsec int64
	Ctime     int64
	CtimeNsec int64
}

// Processes
// Not supported - just enough for package os.

var ForkLock sync.RWMutex

type WaitStatus uint32

func (w WaitStatus) Exited() bool       { return false }
func (w WaitStatus) ExitStatus() int    { return 0 }
func (w WaitStatus) Signaled() bool     { return false }
func (w WaitStatus) Signal() Signal     { return 0 }
func (w WaitStatus) CoreDump() bool     { return false }
func (w WaitStatus) Stopped() bool      { return false }
func (w WaitStatus) Continued() bool    { return false }
func (w WaitStatus) StopSignal() Signal { return 0 }
func (w WaitStatus) TrapCause() int     { return 0 }

// XXX made up
type Rusage struct {
	Utime Timeval
	Stime Timeval
}

// XXX made up
type ProcAttr struct {
	Dir   string
	Env   []string
	Files []uintptr
	Sys   *SysProcAttr
}

type SysProcAttr struct {
}

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func Sysctl(key string) (string, error) {
	if key == "kern.hostname" {
		return "js", nil
	}
	return "", ENOSYS
}

const ImplementsGetwd = true

func Getwd() (wd string, err error) {
	var buf [PathMax]byte
	n, err := Getcwd(buf[0:])
	if err != nil {
		return "", err
	}
	return string(buf[:n]), nil
}

func Getegid() int                      { return 1 }
func Geteuid() int                      { return 1 }
func Getgid() int                       { return 1 }
func Getgroups() ([]int, error)         { return []int{1}, nil }
func Getppid() int                      { return 2 }
func Getpid() int                       { return 3 }
func Gettimeofday(tv *Timeval) error    { return ENOSYS }
func Getuid() int                       { return 1 }
func Kill(pid int, signum Signal) error { return ENOSYS }
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
	return 0, ENOSYS
}
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
	return 0, 0, ENOSYS
}
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
	return 0, ENOSYS
}

type Iovec struct{} // dummy

type Timespec struct {
	Sec  int64
	Nsec int64
}

type Timeval struct {
	Sec  int64
	Usec int64
}

func setTimespec(sec, nsec int64) Timespec {
	return Timespec{Sec: sec, Nsec: nsec}
}

func setTimeval(sec, usec int64) Timeval {
	return Timeval{Sec: sec, Usec: usec}
}
<commit_msg>syscall: add dummy SIGTERM constant to js/wasm<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build js,wasm

package syscall

import (
	"sync"
	"unsafe"
)

const direntSize = 8 + 8 + 2 + 256

type Dirent struct {
	Reclen uint16
	Name   [256]byte
}

func direntIno(buf []byte) (uint64, bool) {
	return 1, true
}

func direntReclen(buf []byte) (uint64, bool) {
	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
}

func direntNamlen(buf []byte) (uint64, bool) {
	reclen, ok := direntReclen(buf)
	if !ok {
		return 0, false
	}
	return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
}

const PathMax = 256

// An Errno is an unsigned number describing an error condition.
// It implements the error interface. The zero Errno is by convention
// a non-error, so code to convert from Errno to error should use:
//	err = nil
//	if errno != 0 {
//		err = errno
//	}
type Errno uintptr

func (e Errno) Error() string {
	if 0 <= int(e) && int(e) < len(errorstr) {
		s := errorstr[e]
		if s != "" {
			return s
		}
	}
	return "errno " + itoa(int(e))
}

func (e Errno) Temporary() bool {
	return e == EINTR || e == EMFILE || e.Timeout()
}

func (e Errno) Timeout() bool {
	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
}

// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int

const (
	_ Signal = iota
	SIGCHLD
	SIGINT
	SIGKILL
	SIGTRAP
	SIGQUIT
	SIGTERM
)

func (s Signal) Signal() {}

func (s Signal) String() string {
	if 0 <= s && int(s) < len(signals) {
		str := signals[s]
		if str != "" {
			return str
		}
	}
	return "signal " + itoa(int(s))
}

var signals = [...]string{}

// File system

const (
	Stdin  = 0
	Stdout = 1
	Stderr = 2
)

const (
	O_RDONLY = 0
	O_WRONLY = 1
	O_RDWR   = 2

	O_CREAT  = 0100
	O_CREATE = O_CREAT
	O_TRUNC  = 01000
	O_APPEND = 02000
	O_EXCL   = 0200
	O_SYNC   = 010000

	O_CLOEXEC = 0
)

const (
	F_DUPFD   = 0
	F_GETFD   = 1
	F_SETFD   = 2
	F_GETFL   = 3
	F_SETFL   = 4
	F_GETOWN  = 5
	F_SETOWN  = 6
	F_GETLK   = 7
	F_SETLK   = 8
	F_SETLKW  = 9
	F_RGETLK  = 10
	F_RSETLK  = 11
	F_CNVT    = 12
	F_RSETLKW = 13

	F_RDLCK   = 1
	F_WRLCK   = 2
	F_UNLCK   = 3
	F_UNLKSYS = 4
)

const (
	S_IFMT        = 0000370000
	S_IFSHM_SYSV  = 0000300000
	S_IFSEMA      = 0000270000
	S_IFCOND      = 0000260000
	S_IFMUTEX     = 0000250000
	S_IFSHM       = 0000240000
	S_IFBOUNDSOCK = 0000230000
	S_IFSOCKADDR  = 0000220000
	S_IFDSOCK     = 0000210000

	S_IFSOCK = 0000140000
	S_IFLNK  = 0000120000
	S_IFREG  = 0000100000
	S_IFBLK  = 0000060000
	S_IFDIR  = 0000040000
	S_IFCHR  = 0000020000
	S_IFIFO  = 0000010000

	S_UNSUP = 0000370000

	S_ISUID = 0004000
	S_ISGID = 0002000
	S_ISVTX = 0001000

	S_IREAD  = 0400
	S_IWRITE = 0200
	S_IEXEC  = 0100

	S_IRWXU = 0700
	S_IRUSR = 0400
	S_IWUSR = 0200
	S_IXUSR = 0100

	S_IRWXG = 070
	S_IRGRP = 040
	S_IWGRP = 020
	S_IXGRP = 010

	S_IRWXO = 07
	S_IROTH = 04
	S_IWOTH = 02
	S_IXOTH = 01
)

type Stat_t struct {
	Dev       int64
	Ino       uint64
	Mode      uint32
	Nlink     uint32
	Uid       uint32
	Gid       uint32
	Rdev      int64
	Size      int64
	Blksize   int32
	Blocks    int32
	Atime     int64
	AtimeNsec int64
	Mtime     int64
	MtimeNsec int64
	Ctime     int64
	CtimeNsec int64
}

// Processes
// Not supported - just enough for package os.

var ForkLock sync.RWMutex

type WaitStatus uint32

func (w WaitStatus) Exited() bool       { return false }
func (w WaitStatus) ExitStatus() int    { return 0 }
func (w WaitStatus) Signaled() bool     { return false }
func (w WaitStatus) Signal() Signal     { return 0 }
func (w WaitStatus) CoreDump() bool     { return false }
func (w WaitStatus) Stopped() bool      { return false }
func (w WaitStatus) Continued() bool    { return false }
func (w WaitStatus) StopSignal() Signal { return 0 }
func (w WaitStatus) TrapCause() int     { return 0 }

// XXX made up
type Rusage struct {
	Utime Timeval
	Stime Timeval
}

// XXX made up
type ProcAttr struct {
	Dir   string
	Env   []string
	Files []uintptr
	Sys   *SysProcAttr
}

type SysProcAttr struct {
}

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	return 0, 0, ENOSYS
}

func Sysctl(key string) (string, error) {
	if key == "kern.hostname" {
		return "js", nil
	}
	return "", ENOSYS
}

const ImplementsGetwd = true

func Getwd() (wd string, err error) {
	var buf [PathMax]byte
	n, err := Getcwd(buf[0:])
	if err != nil {
		return "", err
	}
	return string(buf[:n]), nil
}

func Getegid() int                      { return 1 }
func Geteuid() int                      { return 1 }
func Getgid() int                       { return 1 }
func Getgroups() ([]int, error)         { return []int{1}, nil }
func Getppid() int                      { return 2 }
func Getpid() int                       { return 3 }
func Gettimeofday(tv *Timeval) error    { return ENOSYS }
func Getuid() int                       { return 1 }
func Kill(pid int, signum Signal) error { return ENOSYS }
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
	return 0, ENOSYS
}
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
	return 0, 0, ENOSYS
}
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
	return 0, ENOSYS
}

type Iovec struct{} // dummy

type Timespec struct {
	Sec  int64
	Nsec int64
}

type Timeval struct {
	Sec  int64
	Usec int64
}

func setTimespec(sec, nsec int64) Timespec {
	return Timespec{Sec: sec, Nsec: nsec}
}

func setTimeval(sec, usec int64) Timeval {
	return Timeval{Sec: sec, Usec: usec}
}
<|endoftext|>


<commit_before>package ambientlight

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path"
	"runtime"
	"strings"
	"time"

	"github.com/eikeon/tsl2561"
	"github.com/nogiushi/marvin/nog"
)

var Root = ""

func init() {
	_, filename, _, _ := runtime.Caller(0)
	Root = path.Dir(filename)
}

type AmbientLight struct {
	Switch      map[string]bool
	DayLight    bool
	lightSensor *tsl2561.TSL2561

	lightChannel <-chan int
}

func Handler(in <-chan nog.Message, out chan<- nog.Message) {
	out <- nog.Message{What: "started"}
	a := &AmbientLight{}
	name := "ambientlight.html"
	if j, err := os.OpenFile(path.Join(Root, name), os.O_RDONLY, 0666); err == nil {
		if b, err := ioutil.ReadAll(j); err == nil {
			out <- nog.Message{What: string(b), Why: "template"}
		} else {
			log.Println("ERROR reading:", err)
		}
	} else {
		log.Println("WARNING: could not open ", name, err)
	}

	var dayLightTime time.Time
	if t, err := tsl2561.NewTSL2561(1, tsl2561.ADDRESS_FLOAT); err == nil {
		a.lightSensor = t
		a.lightChannel = t.Broadband()
	} else {
		log.Println("Warning: Light sensor off: ", err)
		out <- nog.Message{What: "no light sensor found"}
		goto done
		return
	}

	for {
		select {
		case m, ok := <-in:
			if !ok {
				goto done
			}
			if m.Why == "statechanged" {
				dec := json.NewDecoder(strings.NewReader(m.What))
				if err := dec.Decode(a); err != nil {
					log.Println("ambientlight decode err:", err)
				}
			}
		case light := <-a.lightChannel:
			if time.Since(dayLightTime) > time.Duration(60*time.Second) {
				if light > 5000 && (a.DayLight != true) {
					a.DayLight = true
					dayLightTime = time.Now()
					out <- nog.Message{What: "it is light"}
				} else if light < 4900 && (a.DayLight != false) {
					a.DayLight = false
					dayLightTime = time.Now()
					out <- nog.Message{What: "it is dark"}
				}
			}
		}
	}
done:
	out <- nog.Message{What: "stopped"}
	close(out)

}

func (a *AmbientLight) LightSensor() bool {
	return a.lightChannel != nil
}
<commit_msg>Finish if light channel closes.<commit_after>package ambientlight

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path"
	"runtime"
	"strings"
	"time"

	"github.com/eikeon/tsl2561"
	"github.com/nogiushi/marvin/nog"
)

var Root = ""

func init() {
	_, filename, _, _ := runtime.Caller(0)
	Root = path.Dir(filename)
}

type AmbientLight struct {
	Switch      map[string]bool
	DayLight    bool
	lightSensor *tsl2561.TSL2561

	lightChannel <-chan int
}

func Handler(in <-chan nog.Message, out chan<- nog.Message) {
	out <- nog.Message{What: "started"}
	a := &AmbientLight{}
	name := "ambientlight.html"
	if j, err := os.OpenFile(path.Join(Root, name), os.O_RDONLY, 0666); err == nil {
		if b, err := ioutil.ReadAll(j); err == nil {
			out <- nog.Message{What: string(b), Why: "template"}
		} else {
			log.Println("ERROR reading:", err)
		}
	} else {
		log.Println("WARNING: could not open ", name, err)
	}

	var dayLightTime time.Time
	if t, err := tsl2561.NewTSL2561(1, tsl2561.ADDRESS_FLOAT); err == nil {
		a.lightSensor = t
		a.lightChannel = t.Broadband()
	} else {
		log.Println("Warning: Light sensor off: ", err)
		out <- nog.Message{What: "no light sensor found"}
		goto done
		return
	}

	for {
		select {
		case m, ok := <-in:
			if !ok {
				goto done
			}
			if m.Why == "statechanged" {
				dec := json.NewDecoder(strings.NewReader(m.What))
				if err := dec.Decode(a); err != nil {
					log.Println("ambientlight decode err:", err)
				}
			}
		case light, ok := <-a.lightChannel:
			if !ok {
				goto done
			}
			if time.Since(dayLightTime) > time.Duration(60*time.Second) {
				if light > 5000 && (a.DayLight != true) {
					a.DayLight = true
					dayLightTime = time.Now()
					out <- nog.Message{What: "it is light"}
				} else if light < 4900 && (a.DayLight != false) {
					a.DayLight = false
					dayLightTime = time.Now()
					out <- nog.Message{What: "it is dark"}
				}
			}
		}
	}
done:
	out <- nog.Message{What: "stopped"}
	close(out)

}

func (a *AmbientLight) LightSensor() bool {
	return a.lightChannel != nil
}
<|endoftext|>


<commit_before>package sqliteStorage

import (
	"errors"
	"fmt"
	"path/filepath"
	"testing"
	"time"

	_ "github.com/anacrolix/envpprof"
	"github.com/anacrolix/squirrel"
	"github.com/anacrolix/torrent/storage"
	test_storage "github.com/anacrolix/torrent/storage/test"
	"github.com/dustin/go-humanize"
	qt "github.com/frankban/quicktest"
)

func BenchmarkMarkComplete(b *testing.B) {
	const pieceSize = test_storage.DefaultPieceSize
	const noTriggers = false
	const noCacheBlobs = false
	var capacity int64 = test_storage.DefaultNumPieces * pieceSize / 2
	if noTriggers {
		// Since we won't push out old pieces, we have to mark them incomplete manually.
		capacity = 0
	}
	runBench := func(b *testing.B, ci storage.ClientImpl) {
		test_storage.BenchmarkPieceMarkComplete(b, ci, pieceSize, test_storage.DefaultNumPieces, capacity)
	}
	c := qt.New(b)
	b.Run("CustomDirect", func(b *testing.B) {
		var opts squirrel.NewCacheOpts
		opts.Capacity = capacity
		opts.NoTriggers = noTriggers
		opts.NoCacheBlobs = noCacheBlobs
		benchOpts := func(b *testing.B) {
			opts.Path = filepath.Join(b.TempDir(), "storage.db")
			ci, err := NewDirectStorage(opts)
			c.Assert(err, qt.IsNil)
			defer ci.Close()
			runBench(b, ci)
		}
		b.Run("Default", benchOpts)
	})
	for _, memory := range []bool{false, true} {
		b.Run(fmt.Sprintf("Memory=%v", memory), func(b *testing.B) {
			b.Run("Direct", func(b *testing.B) {
				var opts NewDirectStorageOpts
				opts.Memory = memory
				opts.Capacity = capacity
				// opts.GcBlobs = true
				opts.BlobFlushInterval = time.Second
				opts.NoTriggers = noTriggers
				opts.NoCacheBlobs = noCacheBlobs
				directBench := func(b *testing.B) {
					opts.Path = filepath.Join(b.TempDir(), "storage.db")
					ci, err := NewDirectStorage(opts)
					var ujm squirrel.ErrUnexpectedJournalMode
					if errors.As(err, &ujm) {
						b.Skipf("setting journal mode %q: %v", opts.SetJournalMode, err)
					}
					c.Assert(err, qt.IsNil)
					defer ci.Close()
					runBench(b, ci)
				}
				for _, journalMode := range []string{"", "wal", "off", "truncate", "delete", "persist", "memory"} {
					opts.SetJournalMode = journalMode
					b.Run("JournalMode="+journalMode, func(b *testing.B) {
						for _, mmapSize := range []int64{-1} {
							if memory && mmapSize >= 0 {
								continue
							}
							b.Run(fmt.Sprintf("MmapSize=%s", func() string {
								if mmapSize < 0 {
									return "default"
								} else {
									return humanize.IBytes(uint64(mmapSize))
								}
							}()), func(b *testing.B) {
								opts.MmapSize = mmapSize
								opts.MmapSizeOk = true
								directBench(b)
							})
						}
					})
				}
			})
		})
	}
}
<commit_msg>Don't build storage/sqlite tests without cgo<commit_after>//go:build cgo
// +build cgo

package sqliteStorage

import (
	"errors"
	"fmt"
	"path/filepath"
	"testing"
	"time"

	_ "github.com/anacrolix/envpprof"
	"github.com/anacrolix/squirrel"
	"github.com/anacrolix/torrent/storage"
	test_storage "github.com/anacrolix/torrent/storage/test"
	"github.com/dustin/go-humanize"
	qt "github.com/frankban/quicktest"
)

func BenchmarkMarkComplete(b *testing.B) {
	const pieceSize = test_storage.DefaultPieceSize
	const noTriggers = false
	const noCacheBlobs = false
	var capacity int64 = test_storage.DefaultNumPieces * pieceSize / 2
	if noTriggers {
		// Since we won't push out old pieces, we have to mark them incomplete manually.
		capacity = 0
	}
	runBench := func(b *testing.B, ci storage.ClientImpl) {
		test_storage.BenchmarkPieceMarkComplete(b, ci, pieceSize, test_storage.DefaultNumPieces, capacity)
	}
	c := qt.New(b)
	b.Run("CustomDirect", func(b *testing.B) {
		var opts squirrel.NewCacheOpts
		opts.Capacity = capacity
		opts.NoTriggers = noTriggers
		opts.NoCacheBlobs = noCacheBlobs
		benchOpts := func(b *testing.B) {
			opts.Path = filepath.Join(b.TempDir(), "storage.db")
			ci, err := NewDirectStorage(opts)
			c.Assert(err, qt.IsNil)
			defer ci.Close()
			runBench(b, ci)
		}
		b.Run("Default", benchOpts)
	})
	for _, memory := range []bool{false, true} {
		b.Run(fmt.Sprintf("Memory=%v", memory), func(b *testing.B) {
			b.Run("Direct", func(b *testing.B) {
				var opts NewDirectStorageOpts
				opts.Memory = memory
				opts.Capacity = capacity
				// opts.GcBlobs = true
				opts.BlobFlushInterval = time.Second
				opts.NoTriggers = noTriggers
				opts.NoCacheBlobs = noCacheBlobs
				directBench := func(b *testing.B) {
					opts.Path = filepath.Join(b.TempDir(), "storage.db")
					ci, err := NewDirectStorage(opts)
					var ujm squirrel.ErrUnexpectedJournalMode
					if errors.As(err, &ujm) {
						b.Skipf("setting journal mode %q: %v", opts.SetJournalMode, err)
					}
					c.Assert(err, qt.IsNil)
					defer ci.Close()
					runBench(b, ci)
				}
				for _, journalMode := range []string{"", "wal", "off", "truncate", "delete", "persist", "memory"} {
					opts.SetJournalMode = journalMode
					b.Run("JournalMode="+journalMode, func(b *testing.B) {
						for _, mmapSize := range []int64{-1} {
							if memory && mmapSize >= 0 {
								continue
							}
							b.Run(fmt.Sprintf("MmapSize=%s", func() string {
								if mmapSize < 0 {
									return "default"
								} else {
									return humanize.IBytes(uint64(mmapSize))
								}
							}()), func(b *testing.B) {
								opts.MmapSize = mmapSize
								opts.MmapSizeOk = true
								directBench(b)
							})
						}
					})
				}
			})
		})
	}
}
<|endoftext|>


<commit_before>package test_storage

import (
	"bytes"
	"io"
	"io/ioutil"
	"math/rand"
	"sync"
	"testing"

	"github.com/anacrolix/torrent/metainfo"
	"github.com/anacrolix/torrent/storage"
	"github.com/bradfitz/iter"
	qt "github.com/frankban/quicktest"
)

const chunkSize = 1 << 14

func BenchmarkPieceMarkComplete(b *testing.B, ci storage.ClientImpl, pieceSize int64, numPieces int, capacity int64) {
	c := qt.New(b)
	ti, err := ci.OpenTorrent(nil, metainfo.Hash{})
	c.Assert(err, qt.IsNil)
	defer ti.Close()
	info := &metainfo.Info{
		Pieces:      make([]byte, numPieces*metainfo.HashSize),
		PieceLength: pieceSize,
		Length:      pieceSize * int64(numPieces),
	}
	rand.Read(info.Pieces)
	data := make([]byte, pieceSize)
	oneIter := func() {
		for pieceIndex := range iter.N(numPieces) {
			pi := ti.Piece(info.Piece(pieceIndex))
			rand.Read(data)
			var wg sync.WaitGroup
			for off := int64(0); off < int64(len(data)); off += chunkSize {
				wg.Add(1)
				go func(off int64) {
					defer wg.Done()
					n, err := pi.WriteAt(data[off:off+chunkSize], off)
					if err != nil {
						panic(err)
					}
					if n != chunkSize {
						panic(n)
					}
				}(off)
			}
			wg.Wait()
			if capacity == 0 {
				pi.MarkNotComplete()
			}
			// This might not apply if users of this benchmark don't cache with the expected capacity.
			c.Assert(pi.Completion(), qt.Equals, storage.Completion{Complete: false, Ok: true})
			c.Assert(pi.MarkComplete(), qt.IsNil)
			c.Assert(pi.Completion(), qt.Equals, storage.Completion{true, true})
			readData, err := ioutil.ReadAll(io.NewSectionReader(pi, 0, int64(len(data))))
			c.Assert(err, qt.IsNil)
			c.Assert(len(readData), qt.Equals, len(data))
			c.Assert(bytes.Equal(readData, data), qt.IsTrue)
		}
	}
	// Fill the cache
	if capacity > 0 {
		for range iter.N(int((capacity + info.TotalLength() - 1) / info.TotalLength())) {
			oneIter()
		}
	}
	b.ResetTimer()
	for range iter.N(b.N) {
		oneIter()
	}
}
<commit_msg>Fix panic in benchmark<commit_after>package test_storage

import (
	"bytes"
	"io"
	"io/ioutil"
	"math/rand"
	"sync"
	"testing"

	"github.com/anacrolix/torrent/metainfo"
	"github.com/anacrolix/torrent/storage"
	"github.com/bradfitz/iter"
	qt "github.com/frankban/quicktest"
)

const chunkSize = 1 << 14

func BenchmarkPieceMarkComplete(b *testing.B, ci storage.ClientImpl, pieceSize int64, numPieces int, capacity int64) {
	c := qt.New(b)
	ti, err := ci.OpenTorrent(&metainfo.Info{
		Pieces:      make([]byte, metainfo.HashSize*numPieces),
		PieceLength: pieceSize,
	}, metainfo.Hash{})
	c.Assert(err, qt.IsNil)
	defer ti.Close()
	info := &metainfo.Info{
		Pieces:      make([]byte, numPieces*metainfo.HashSize),
		PieceLength: pieceSize,
		Length:      pieceSize * int64(numPieces),
	}
	rand.Read(info.Pieces)
	data := make([]byte, pieceSize)
	oneIter := func() {
		for pieceIndex := range iter.N(numPieces) {
			pi := ti.Piece(info.Piece(pieceIndex))
			rand.Read(data)
			var wg sync.WaitGroup
			for off := int64(0); off < int64(len(data)); off += chunkSize {
				wg.Add(1)
				go func(off int64) {
					defer wg.Done()
					n, err := pi.WriteAt(data[off:off+chunkSize], off)
					if err != nil {
						panic(err)
					}
					if n != chunkSize {
						panic(n)
					}
				}(off)
			}
			wg.Wait()
			if capacity == 0 {
				pi.MarkNotComplete()
			}
			// This might not apply if users of this benchmark don't cache with the expected capacity.
			c.Assert(pi.Completion(), qt.Equals, storage.Completion{Complete: false, Ok: true})
			c.Assert(pi.MarkComplete(), qt.IsNil)
			c.Assert(pi.Completion(), qt.Equals, storage.Completion{true, true})
			readData, err := ioutil.ReadAll(io.NewSectionReader(pi, 0, int64(len(data))))
			c.Assert(err, qt.IsNil)
			c.Assert(len(readData), qt.Equals, len(data))
			c.Assert(bytes.Equal(readData, data), qt.IsTrue)
		}
	}
	// Fill the cache
	if capacity > 0 {
		for range iter.N(int((capacity + info.TotalLength() - 1) / info.TotalLength())) {
			oneIter()
		}
	}
	b.ResetTimer()
	for range iter.N(b.N) {
		oneIter()
	}
}
<|endoftext|>


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

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

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

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

package latest

import (
	"encoding/json"
	"testing"

	internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
)

func TestResourceVersioner(t *testing.T) {
	pod := internal.Pod{ObjectMeta: internal.ObjectMeta{ResourceVersion: "10"}}
	version, err := accessor.ResourceVersion(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}

	podList := internal.PodList{ListMeta: internal.ListMeta{ResourceVersion: "10"}}
	version, err = accessor.ResourceVersion(&podList)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}
}

func TestCodec(t *testing.T) {
	pod := internal.Pod{}
	data, err := Codec.Encode(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	other := internal.Pod{}
	if err := json.Unmarshal(data, &other); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if other.APIVersion != Version || other.Kind != "Pod" {
		t.Errorf("unexpected unmarshalled object %#v", other)
	}
}

func TestInterfacesFor(t *testing.T) {
	if _, err := InterfacesFor(""); err == nil {
		t.Fatalf("unexpected non-error: %v", err)
	}
	for i, version := range append([]string{Version, OldestVersion}, Versions...) {
		if vi, err := InterfacesFor(version); err != nil || vi == nil {
			t.Fatalf("%d: unexpected result: %v", i, err)
		}
	}
}

func TestRESTMapper(t *testing.T) {
	if v, k, err := RESTMapper.VersionAndKindForResource("replicationControllers"); err != nil || v != "v1beta3" || k != "ReplicationController" {
		t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
	}
	if v, k, err := RESTMapper.VersionAndKindForResource("replicationcontrollers"); err != nil || v != "v1beta3" || k != "ReplicationController" {
		t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
	}

	if m, err := RESTMapper.RESTMapping("PodTemplate", ""); err != nil || m.APIVersion != "v1beta3" || m.Resource != "podtemplates" {
		t.Errorf("unexpected version mapping: %#v %v", m, err)
	}

	for _, version := range Versions {
		mapping, err := RESTMapper.RESTMapping("ReplicationController", version)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}

		if mapping.Resource != "replicationControllers" && mapping.Resource != "replicationcontrollers" {
			t.Errorf("incorrect resource name: %#v", mapping)
		}
		if mapping.APIVersion != version {
			t.Errorf("incorrect version: %v", mapping)
		}

		interfaces, _ := InterfacesFor(version)
		if mapping.Codec != interfaces.Codec {
			t.Errorf("unexpected codec: %#v, expected: %#v", mapping, interfaces)
		}

		rc := &internal.ReplicationController{ObjectMeta: internal.ObjectMeta{Name: "foo"}}
		name, err := mapping.MetadataAccessor.Name(rc)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if name != "foo" {
			t.Errorf("unable to retrieve object meta with: %v", mapping.MetadataAccessor)
		}
	}
}
<commit_msg>fix<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package latest

import (
	"encoding/json"
	"testing"

	internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)

func TestResourceVersioner(t *testing.T) {
	pod := internal.Pod{ObjectMeta: internal.ObjectMeta{ResourceVersion: "10"}}
	version, err := accessor.ResourceVersion(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}

	podList := internal.PodList{ListMeta: internal.ListMeta{ResourceVersion: "10"}}
	version, err = accessor.ResourceVersion(&podList)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if version != "10" {
		t.Errorf("unexpected version %v", version)
	}
}

func TestCodec(t *testing.T) {
	pod := internal.Pod{}
	data, err := Codec.Encode(&pod)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	other := internal.Pod{}
	if err := json.Unmarshal(data, &other); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if other.APIVersion != Version || other.Kind != "Pod" {
		t.Errorf("unexpected unmarshalled object %#v", other)
	}
}

func TestInterfacesFor(t *testing.T) {
	if _, err := InterfacesFor(""); err == nil {
		t.Fatalf("unexpected non-error: %v", err)
	}
	for i, version := range append([]string{Version, OldestVersion}, Versions...) {
		if vi, err := InterfacesFor(version); err != nil || vi == nil {
			t.Fatalf("%d: unexpected result: %v", i, err)
		}
	}
}

func TestRESTMapper(t *testing.T) {
	if v, k, err := RESTMapper.VersionAndKindForResource("replicationControllers"); err != nil || v != "v1beta3" || k != "ReplicationController" {
		t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
	}
	if v, k, err := RESTMapper.VersionAndKindForResource("replicationcontrollers"); err != nil || v != "v1beta3" || k != "ReplicationController" {
		t.Errorf("unexpected version mapping: %s %s %v", v, k, err)
	}

	if m, err := RESTMapper.RESTMapping("PodTemplate", ""); err != nil || m.APIVersion != "v1beta3" || m.Resource != "podtemplates" {
		t.Errorf("unexpected version mapping: %#v %v", m, err)
	}

	for _, version := range Versions {
		mapping, err := RESTMapper.RESTMapping("ReplicationController", version)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}

		if mapping.Resource != "replicationControllers" && mapping.Resource != "replicationcontrollers" {
			t.Errorf("incorrect resource name: %#v", mapping)
		}
		if mapping.APIVersion != version {
			t.Errorf("incorrect version: %v", mapping)
		}

		interfaces, _ := InterfacesFor(version)
		if mapping.Codec != interfaces.Codec {
			t.Errorf("unexpected codec: %#v, expected: %#v", mapping, interfaces)
		}

		rc := &internal.ReplicationController{ObjectMeta: internal.ObjectMeta{Name: "foo"}}
		name, err := mapping.MetadataAccessor.Name(rc)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if name != "foo" {
			t.Errorf("unable to retrieve object meta with: %v", mapping.MetadataAccessor)
		}
	}
}
<|endoftext|>


<commit_before>package armhelpers

import (
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/compute"
	"github.com/Azure/azure-sdk-for-go/arm/network"
	"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
	"github.com/Azure/azure-sdk-for-go/arm/resources/subscriptions"
	"github.com/Azure/azure-sdk-for-go/arm/storage"
	"github.com/Azure/go-autorest/autorest"
	"github.com/Azure/go-autorest/autorest/adal"
	"github.com/Azure/go-autorest/autorest/azure"
	"github.com/Azure/go-autorest/autorest/to"
	log "github.com/Sirupsen/logrus"
	"github.com/mitchellh/go-homedir"

	"github.com/Azure/acs-engine/pkg/acsengine"
)

const (
	// AcsEngineClientID is the AAD ClientID for the CLI native application
	AcsEngineClientID = "76e0feec-6b7f-41f0-81a7-b1b944520261"

	// ApplicationDir is the name of the dir where the token is cached
	ApplicationDir = ".acsengine"
)

var (
	// RequiredResourceProviders is the list of Azure Resource Providers needed for ACS-Engine to function
	RequiredResourceProviders = []string{"Microsoft.Compute", "Microsoft.Storage", "Microsoft.Network"}
)

// AzureClient implements the `ACSEngineClient` interface.
// This client is backed by real Azure clients talking to an ARM endpoint.
type AzureClient struct {
	environment azure.Environment

	deploymentsClient             resources.DeploymentsClient
	resourcesClient               resources.GroupClient
	storageAccountsClient         storage.AccountsClient
	interfacesClient              network.InterfacesClient
	groupsClient                  resources.GroupsClient
	providersClient               resources.ProvidersClient
	subscriptionsClient           subscriptions.GroupClient
	virtualMachinesClient         compute.VirtualMachinesClient
	virtualMachineScaleSetsClient compute.VirtualMachineScaleSetsClient
}

// NewAzureClientWithDeviceAuth returns an AzureClient by having a user complete a device authentication flow
func NewAzureClientWithDeviceAuth(env azure.Environment, subscriptionID string) (*AzureClient, error) {
	oauthConfig, tenantID, err := getOAuthConfig(env, subscriptionID)
	if err != nil {
		return nil, err
	}

	home, err := homedir.Dir()
	if err != nil {
		return nil, fmt.Errorf("Failed to get user home directory to look for cached token: %q", err)
	}
	cachePath := filepath.Join(home, ApplicationDir, "cache", fmt.Sprintf("%s_%s.token.json", tenantID, AcsEngineClientID))

	rawToken, err := tryLoadCachedToken(cachePath)
	if err != nil {
		return nil, err
	}

	var armSpt *adal.ServicePrincipalToken
	if rawToken != nil {
		armSpt, err = adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.ServiceManagementEndpoint, *rawToken, tokenCallback(cachePath))
		if err != nil {
			return nil, err
		}
		err = armSpt.Refresh()
		if err != nil {
			log.Warnf("Refresh token failed. Will fallback to device auth. %q", err)
		} else {
			adSpt, err := adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.GraphEndpoint, armSpt.Token)
			if err != nil {
				return nil, err
			}
			return getClient(env, subscriptionID, armSpt, adSpt)
		}
	}

	client := &autorest.Client{}

	deviceCode, err := adal.InitiateDeviceAuth(client, *oauthConfig, AcsEngineClientID, env.ServiceManagementEndpoint)
	if err != nil {
		return nil, err
	}
	log.Warnln(*deviceCode.Message)
	deviceToken, err := adal.WaitForUserCompletion(client, deviceCode)
	if err != nil {
		return nil, err
	}

	armSpt, err = adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.ServiceManagementEndpoint, *deviceToken, tokenCallback(cachePath))
	if err != nil {
		return nil, err
	}
	armSpt.Refresh()

	adRawToken := armSpt.Token
	adRawToken.Resource = env.GraphEndpoint
	adSpt, err := adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.GraphEndpoint, adRawToken)
	if err != nil {
		return nil, err
	}

	return getClient(env, subscriptionID, armSpt, adSpt)
}

// NewAzureClientWithClientSecret returns an AzureClient via client_id and client_secret
func NewAzureClientWithClientSecret(env azure.Environment, subscriptionID, clientID, clientSecret string) (*AzureClient, error) {
	oauthConfig, _, err := getOAuthConfig(env, subscriptionID)
	if err != nil {
		return nil, err
	}

	armSpt, err := adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, env.ServiceManagementEndpoint)
	if err != nil {
		return nil, err
	}
	adSpt, err := adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, env.GraphEndpoint)
	if err != nil {
		return nil, err
	}

	return getClient(env, subscriptionID, armSpt, adSpt)
}

// NewAzureClientWithClientCertificate returns an AzureClient via client_id and jwt certificate assertion
func NewAzureClientWithClientCertificate(env azure.Environment, subscriptionID, clientID, certificatePath, privateKeyPath string) (*AzureClient, error) {
	oauthConfig, _, err := getOAuthConfig(env, subscriptionID)
	if err != nil {
		return nil, err
	}

	certificateData, err := ioutil.ReadFile(certificatePath)
	if err != nil {
		return nil, fmt.Errorf("Failed to read certificate: %q", err)
	}

	block, _ := pem.Decode(certificateData)
	if block == nil {
		return nil, fmt.Errorf("Failed to decode pem block from certificate")
	}

	certificate, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse certificate: %q", err)
	}

	privateKey, err := parseRsaPrivateKey(privateKeyPath)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse rsa private key: %q", err)
	}

	armSpt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, clientID, certificate, privateKey, env.ServiceManagementEndpoint)
	if err != nil {
		return nil, err
	}
	adSpt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, clientID, certificate, privateKey, env.GraphEndpoint)
	if err != nil {
		return nil, err
	}

	return getClient(env, subscriptionID, armSpt, adSpt)
}

func tokenCallback(path string) func(t adal.Token) error {
	return func(token adal.Token) error {
		err := adal.SaveToken(path, 0600, token)
		if err != nil {
			return err
		}
		log.Debugf("Saved token to cache. path=%q", path)
		return nil
	}
}

func tryLoadCachedToken(cachePath string) (*adal.Token, error) {
	log.Debugf("Attempting to load token from cache. path=%q", cachePath)

	// Check for file not found so we can suppress the file not found error
	// LoadToken doesn't discern and returns error either way
	if _, err := os.Stat(cachePath); err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}

	token, err := adal.LoadToken(cachePath)
	if err != nil {
		return nil, fmt.Errorf("Failed to load token from file: %v", err)
	}

	return token, nil
}

func getOAuthConfig(env azure.Environment, subscriptionID string) (*adal.OAuthConfig, string, error) {
	tenantID, err := acsengine.GetTenantID(env, subscriptionID)
	if err != nil {
		return nil, "", err
	}

	oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID)
	if err != nil {
		return nil, "", err
	}

	return oauthConfig, tenantID, nil
}

func getClient(env azure.Environment, subscriptionID string, armSpt *adal.ServicePrincipalToken, adSpt *adal.ServicePrincipalToken) (*AzureClient, error) {
	c := &AzureClient{
		environment:                   env,
		deploymentsClient:             resources.NewDeploymentsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		resourcesClient:               resources.NewGroupClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		storageAccountsClient:         storage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		interfacesClient:              network.NewInterfacesClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		groupsClient:                  resources.NewGroupsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		providersClient:               resources.NewProvidersClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		virtualMachinesClient:         compute.NewVirtualMachinesClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		virtualMachineScaleSetsClient: compute.NewVirtualMachineScaleSetsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
	}

	authorizer := autorest.NewBearerAuthorizer(armSpt)
	c.deploymentsClient.Authorizer = authorizer
	c.resourcesClient.Authorizer = authorizer
	c.storageAccountsClient.Authorizer = authorizer
	c.interfacesClient.Authorizer = authorizer
	c.groupsClient.Authorizer = authorizer
	c.providersClient.Authorizer = authorizer
	c.virtualMachinesClient.Authorizer = authorizer

	c.deploymentsClient.PollingDelay = time.Second * 5

	err := c.ensureProvidersRegistered(subscriptionID)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (az *AzureClient) ensureProvidersRegistered(subscriptionID string) error {
	registeredProviders, err := az.providersClient.List(to.Int32Ptr(100), "")
	if err != nil {
		return err
	}
	if registeredProviders.Value == nil {
		return fmt.Errorf("Providers list was nil. subscription=%q", subscriptionID)
	}

	m := make(map[string]bool)
	for _, provider := range *registeredProviders.Value {
		m[strings.ToLower(to.String(provider.Namespace))] = to.String(provider.RegistrationState) == "Registered"
	}

	for _, provider := range RequiredResourceProviders {
		registered, ok := m[strings.ToLower(provider)]
		if !ok {
			return fmt.Errorf("Unknown resource provider %q", provider)
		}
		if registered {
			log.Debugf("Already registered for %q", provider)
		} else {
			log.Info("Registering subscription to resource provider. provider=%q subscription=%q", provider, subscriptionID)
			if _, err := az.providersClient.Register(provider); err != nil {
				return err
			}
		}
	}
	return nil
}

func parseRsaPrivateKey(path string) (*rsa.PrivateKey, error) {
	privateKeyData, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(privateKeyData)
	if block == nil {
		return nil, fmt.Errorf("Failed to decode a pem block from private key")
	}

	privatePkcs1Key, errPkcs1 := x509.ParsePKCS1PrivateKey(block.Bytes)
	if errPkcs1 == nil {
		return privatePkcs1Key, nil
	}

	privatePkcs8Key, errPkcs8 := x509.ParsePKCS8PrivateKey(block.Bytes)
	if errPkcs8 == nil {
		privatePkcs8RsaKey, ok := privatePkcs8Key.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("pkcs8 contained non-RSA key. Expected RSA key")
		}
		return privatePkcs8RsaKey, nil
	}

	return nil, fmt.Errorf("failed to parse private key as Pkcs#1 or Pkcs#8. (%s). (%s)", errPkcs1, errPkcs8)
}
<commit_msg>adding auth headers to vmss list operations (#762)<commit_after>package armhelpers

import (
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/compute"
	"github.com/Azure/azure-sdk-for-go/arm/network"
	"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
	"github.com/Azure/azure-sdk-for-go/arm/resources/subscriptions"
	"github.com/Azure/azure-sdk-for-go/arm/storage"
	"github.com/Azure/go-autorest/autorest"
	"github.com/Azure/go-autorest/autorest/adal"
	"github.com/Azure/go-autorest/autorest/azure"
	"github.com/Azure/go-autorest/autorest/to"
	log "github.com/Sirupsen/logrus"
	"github.com/mitchellh/go-homedir"

	"github.com/Azure/acs-engine/pkg/acsengine"
)

const (
	// AcsEngineClientID is the AAD ClientID for the CLI native application
	AcsEngineClientID = "76e0feec-6b7f-41f0-81a7-b1b944520261"

	// ApplicationDir is the name of the dir where the token is cached
	ApplicationDir = ".acsengine"
)

var (
	// RequiredResourceProviders is the list of Azure Resource Providers needed for ACS-Engine to function
	RequiredResourceProviders = []string{"Microsoft.Compute", "Microsoft.Storage", "Microsoft.Network"}
)

// AzureClient implements the `ACSEngineClient` interface.
// This client is backed by real Azure clients talking to an ARM endpoint.
type AzureClient struct {
	environment azure.Environment

	deploymentsClient             resources.DeploymentsClient
	resourcesClient               resources.GroupClient
	storageAccountsClient         storage.AccountsClient
	interfacesClient              network.InterfacesClient
	groupsClient                  resources.GroupsClient
	providersClient               resources.ProvidersClient
	subscriptionsClient           subscriptions.GroupClient
	virtualMachinesClient         compute.VirtualMachinesClient
	virtualMachineScaleSetsClient compute.VirtualMachineScaleSetsClient
}

// NewAzureClientWithDeviceAuth returns an AzureClient by having a user complete a device authentication flow
func NewAzureClientWithDeviceAuth(env azure.Environment, subscriptionID string) (*AzureClient, error) {
	oauthConfig, tenantID, err := getOAuthConfig(env, subscriptionID)
	if err != nil {
		return nil, err
	}

	home, err := homedir.Dir()
	if err != nil {
		return nil, fmt.Errorf("Failed to get user home directory to look for cached token: %q", err)
	}
	cachePath := filepath.Join(home, ApplicationDir, "cache", fmt.Sprintf("%s_%s.token.json", tenantID, AcsEngineClientID))

	rawToken, err := tryLoadCachedToken(cachePath)
	if err != nil {
		return nil, err
	}

	var armSpt *adal.ServicePrincipalToken
	if rawToken != nil {
		armSpt, err = adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.ServiceManagementEndpoint, *rawToken, tokenCallback(cachePath))
		if err != nil {
			return nil, err
		}
		err = armSpt.Refresh()
		if err != nil {
			log.Warnf("Refresh token failed. Will fallback to device auth. %q", err)
		} else {
			adSpt, err := adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.GraphEndpoint, armSpt.Token)
			if err != nil {
				return nil, err
			}
			return getClient(env, subscriptionID, armSpt, adSpt)
		}
	}

	client := &autorest.Client{}

	deviceCode, err := adal.InitiateDeviceAuth(client, *oauthConfig, AcsEngineClientID, env.ServiceManagementEndpoint)
	if err != nil {
		return nil, err
	}
	log.Warnln(*deviceCode.Message)
	deviceToken, err := adal.WaitForUserCompletion(client, deviceCode)
	if err != nil {
		return nil, err
	}

	armSpt, err = adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.ServiceManagementEndpoint, *deviceToken, tokenCallback(cachePath))
	if err != nil {
		return nil, err
	}
	armSpt.Refresh()

	adRawToken := armSpt.Token
	adRawToken.Resource = env.GraphEndpoint
	adSpt, err := adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, AcsEngineClientID, env.GraphEndpoint, adRawToken)
	if err != nil {
		return nil, err
	}

	return getClient(env, subscriptionID, armSpt, adSpt)
}

// NewAzureClientWithClientSecret returns an AzureClient via client_id and client_secret
func NewAzureClientWithClientSecret(env azure.Environment, subscriptionID, clientID, clientSecret string) (*AzureClient, error) {
	oauthConfig, _, err := getOAuthConfig(env, subscriptionID)
	if err != nil {
		return nil, err
	}

	armSpt, err := adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, env.ServiceManagementEndpoint)
	if err != nil {
		return nil, err
	}
	adSpt, err := adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, env.GraphEndpoint)
	if err != nil {
		return nil, err
	}

	return getClient(env, subscriptionID, armSpt, adSpt)
}

// NewAzureClientWithClientCertificate returns an AzureClient via client_id and jwt certificate assertion
func NewAzureClientWithClientCertificate(env azure.Environment, subscriptionID, clientID, certificatePath, privateKeyPath string) (*AzureClient, error) {
	oauthConfig, _, err := getOAuthConfig(env, subscriptionID)
	if err != nil {
		return nil, err
	}

	certificateData, err := ioutil.ReadFile(certificatePath)
	if err != nil {
		return nil, fmt.Errorf("Failed to read certificate: %q", err)
	}

	block, _ := pem.Decode(certificateData)
	if block == nil {
		return nil, fmt.Errorf("Failed to decode pem block from certificate")
	}

	certificate, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse certificate: %q", err)
	}

	privateKey, err := parseRsaPrivateKey(privateKeyPath)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse rsa private key: %q", err)
	}

	armSpt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, clientID, certificate, privateKey, env.ServiceManagementEndpoint)
	if err != nil {
		return nil, err
	}
	adSpt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, clientID, certificate, privateKey, env.GraphEndpoint)
	if err != nil {
		return nil, err
	}

	return getClient(env, subscriptionID, armSpt, adSpt)
}

func tokenCallback(path string) func(t adal.Token) error {
	return func(token adal.Token) error {
		err := adal.SaveToken(path, 0600, token)
		if err != nil {
			return err
		}
		log.Debugf("Saved token to cache. path=%q", path)
		return nil
	}
}

func tryLoadCachedToken(cachePath string) (*adal.Token, error) {
	log.Debugf("Attempting to load token from cache. path=%q", cachePath)

	// Check for file not found so we can suppress the file not found error
	// LoadToken doesn't discern and returns error either way
	if _, err := os.Stat(cachePath); err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}

	token, err := adal.LoadToken(cachePath)
	if err != nil {
		return nil, fmt.Errorf("Failed to load token from file: %v", err)
	}

	return token, nil
}

func getOAuthConfig(env azure.Environment, subscriptionID string) (*adal.OAuthConfig, string, error) {
	tenantID, err := acsengine.GetTenantID(env, subscriptionID)
	if err != nil {
		return nil, "", err
	}

	oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID)
	if err != nil {
		return nil, "", err
	}

	return oauthConfig, tenantID, nil
}

func getClient(env azure.Environment, subscriptionID string, armSpt *adal.ServicePrincipalToken, adSpt *adal.ServicePrincipalToken) (*AzureClient, error) {
	c := &AzureClient{
		environment:                   env,
		deploymentsClient:             resources.NewDeploymentsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		resourcesClient:               resources.NewGroupClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		storageAccountsClient:         storage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		interfacesClient:              network.NewInterfacesClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		groupsClient:                  resources.NewGroupsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		providersClient:               resources.NewProvidersClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		virtualMachinesClient:         compute.NewVirtualMachinesClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
		virtualMachineScaleSetsClient: compute.NewVirtualMachineScaleSetsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID),
	}

	authorizer := autorest.NewBearerAuthorizer(armSpt)
	c.deploymentsClient.Authorizer = authorizer
	c.resourcesClient.Authorizer = authorizer
	c.storageAccountsClient.Authorizer = authorizer
	c.interfacesClient.Authorizer = authorizer
	c.groupsClient.Authorizer = authorizer
	c.providersClient.Authorizer = authorizer
	c.virtualMachinesClient.Authorizer = authorizer
	c.virtualMachineScaleSetsClient.Authorizer = authorizer

	c.deploymentsClient.PollingDelay = time.Second * 5

	err := c.ensureProvidersRegistered(subscriptionID)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (az *AzureClient) ensureProvidersRegistered(subscriptionID string) error {
	registeredProviders, err := az.providersClient.List(to.Int32Ptr(100), "")
	if err != nil {
		return err
	}
	if registeredProviders.Value == nil {
		return fmt.Errorf("Providers list was nil. subscription=%q", subscriptionID)
	}

	m := make(map[string]bool)
	for _, provider := range *registeredProviders.Value {
		m[strings.ToLower(to.String(provider.Namespace))] = to.String(provider.RegistrationState) == "Registered"
	}

	for _, provider := range RequiredResourceProviders {
		registered, ok := m[strings.ToLower(provider)]
		if !ok {
			return fmt.Errorf("Unknown resource provider %q", provider)
		}
		if registered {
			log.Debugf("Already registered for %q", provider)
		} else {
			log.Info("Registering subscription to resource provider. provider=%q subscription=%q", provider, subscriptionID)
			if _, err := az.providersClient.Register(provider); err != nil {
				return err
			}
		}
	}
	return nil
}

func parseRsaPrivateKey(path string) (*rsa.PrivateKey, error) {
	privateKeyData, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(privateKeyData)
	if block == nil {
		return nil, fmt.Errorf("Failed to decode a pem block from private key")
	}

	privatePkcs1Key, errPkcs1 := x509.ParsePKCS1PrivateKey(block.Bytes)
	if errPkcs1 == nil {
		return privatePkcs1Key, nil
	}

	privatePkcs8Key, errPkcs8 := x509.ParsePKCS8PrivateKey(block.Bytes)
	if errPkcs8 == nil {
		privatePkcs8RsaKey, ok := privatePkcs8Key.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("pkcs8 contained non-RSA key. Expected RSA key")
		}
		return privatePkcs8RsaKey, nil
	}

	return nil, fmt.Errorf("failed to parse private key as Pkcs#1 or Pkcs#8. (%s). (%s)", errPkcs1, errPkcs8)
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Rook Authors. All rights reserved.

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

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

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

package osd

import (
	"fmt"
	kerrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"strconv"

	"github.com/pkg/errors"
	"github.com/rook/rook/pkg/clusterd"
	"github.com/rook/rook/pkg/daemon/ceph/client"
	"github.com/rook/rook/pkg/operator/k8sutil"
)

// RemoveOSDs purges a list of OSDs from the cluster
func RemoveOSDs(context *clusterd.Context, clusterInfo *client.ClusterInfo, osdsToRemove []string) error {

	// Generate the ceph config for running ceph commands similar to the operator
	if err := writeCephConfig(context, clusterInfo); err != nil {
		return errors.Wrap(err, "failed to write the ceph config")
	}

	osdDump, err := client.GetOSDDump(context, clusterInfo)
	if err != nil {
		return errors.Wrap(err, "failed to get osd dump")
	}

	for _, osdIDStr := range osdsToRemove {
		osdID, err := strconv.Atoi(osdIDStr)
		if err != nil {
			logger.Errorf("invalid OSD ID: %s. %v", osdIDStr, err)
			continue
		}
		logger.Debugf("validating status of osd.%d", osdID)
		status, _, err := osdDump.StatusByID(int64(osdID))
		if err != nil {
			return errors.Wrapf(err, "failed to get osd status for osd %d", osdID)

		}
		const upStatus int64 = 1
		if status == upStatus {
			logger.Debugf("osd.%d is healthy. It cannot be removed unless it is 'down'", osdID)
			continue
		}
		logger.Debugf("osd.%d is marked 'DOWN'. Removing it", osdID)
		removeOSD(context, clusterInfo, osdID)
	}

	return nil
}

func removeOSD(context *clusterd.Context, clusterInfo *client.ClusterInfo, osdID int) {
	// Get the host where the OSD is found
	hostName, err := client.GetCrushHostName(context, clusterInfo, osdID)
	if err != nil {
		logger.Errorf("failed to get the host where osd.%d is running. %v", osdID, err)
	}

	// Mark the OSD as out.
	args := []string{"osd", "out", fmt.Sprintf("osd.%d", osdID)}
	_, err = client.NewCephCommand(context, clusterInfo, args).Run()
	if err != nil {
		logger.Errorf("failed to exclude osd.%d out of the crush map. %v", osdID, err)
	}

	// Remove the OSD deployment
	deploymentName := fmt.Sprintf("rook-ceph-osd-%d", osdID)
	deployment, err := context.Clientset.AppsV1().Deployments(clusterInfo.Namespace).Get(deploymentName, metav1.GetOptions{})
	if err != nil {
		logger.Errorf("failed to fetch the deployment %q. %v", deploymentName, err)
	} else {
		logger.Infof("removing the OSD deployment %q", deploymentName)
		if err := k8sutil.DeleteDeployment(context.Clientset, clusterInfo.Namespace, deploymentName); err != nil {
			if err != nil {
				// Continue purging the OSD even if the deployment fails to be deleted
				logger.Errorf("failed to delete deployment for OSD %d. %v", osdID, err)
			}
		}
		const pvcLabelName = "ceph.rook.io/pvc"
		if pvcName, ok := deployment.GetLabels()[pvcLabelName]; ok {
			prepareJobList, err := context.Clientset.BatchV1().Jobs(clusterInfo.Namespace).List(metav1.ListOptions{LabelSelector: pvcLabelName + pvcName})
			if err != nil && !kerrors.IsNotFound(err) {
				logger.Errorf("failed to list prepareJobs with labels %q. %v ", pvcLabelName+pvcName, err)
			}
			// Remove osd prepare job
			for _, prepareJob := range prepareJobList.Items {
				logger.Infof("removing the osd prepare job %q", prepareJob.GetName())
				if err := k8sutil.DeleteBatchJob(context.Clientset, clusterInfo.Namespace, prepareJob.GetName(), false); err != nil {
					if err != nil {
						// Continue deleting the OSD prepare job even if the deployment fails to be deleted
						logger.Errorf("failed to delete prepare job for osd %q. %v", prepareJob.GetName(), err)
					}
				}

				logger.Infof("removing the OSD PVC %q", pvcName)
				if err := context.Clientset.CoreV1().PersistentVolumeClaims(clusterInfo.Namespace).Delete(pvcName, &metav1.DeleteOptions{}); err != nil {
					if err != nil {
						// Continue deleting the OSD PVC even if PVC deletion fails
						logger.Errorf("failed to delete pvc for OSD %q. %v", pvcName, err)
					}
				}
			}
		}
	}

	// purge the osd
	purgeosdargs := []string{"osd", "purge", fmt.Sprintf("osd.%d", osdID), "--force", "--yes-i-really-mean-it"}
	_, err = client.NewCephCommand(context, clusterInfo, purgeosdargs).Run()
	if err != nil {
		logger.Errorf("failed to purge osd.%d. %v", osdID, err)
	}

	// Attempting to remove the parent host. Errors can be ignored if there are other OSDs on the same host
	hostargs := []string{"osd", "crush", "rm", hostName}
	_, err = client.NewCephCommand(context, clusterInfo, hostargs).Run()
	if err != nil {
		logger.Errorf("failed to remove CRUSH host %q. %v", hostName, err)
	}

	logger.Infof("completed removal of OSD %d", osdID)
}
<commit_msg>ceph: update remove.go<commit_after>/*
Copyright 2020 The Rook Authors. All rights reserved.

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

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

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

package osd

import (
	"fmt"
	kerrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"strconv"

	"github.com/pkg/errors"
	"github.com/rook/rook/pkg/clusterd"
	"github.com/rook/rook/pkg/daemon/ceph/client"
	"github.com/rook/rook/pkg/operator/k8sutil"
)

// RemoveOSDs purges a list of OSDs from the cluster
func RemoveOSDs(context *clusterd.Context, clusterInfo *client.ClusterInfo, osdsToRemove []string) error {

	// Generate the ceph config for running ceph commands similar to the operator
	if err := writeCephConfig(context, clusterInfo); err != nil {
		return errors.Wrap(err, "failed to write the ceph config")
	}

	osdDump, err := client.GetOSDDump(context, clusterInfo)
	if err != nil {
		return errors.Wrap(err, "failed to get osd dump")
	}

	for _, osdIDStr := range osdsToRemove {
		osdID, err := strconv.Atoi(osdIDStr)
		if err != nil {
			logger.Errorf("invalid OSD ID: %s. %v", osdIDStr, err)
			continue
		}
		logger.Infof("validating status of osd.%d", osdID)
		status, _, err := osdDump.StatusByID(int64(osdID))
		if err != nil {
			return errors.Wrapf(err, "failed to get osd status for osd %d", osdID)
		}
		const upStatus int64 = 1
		if status == upStatus {
			logger.Infof("osd.%d is healthy. It cannot be removed unless it is 'down'", osdID)
			continue
		}
		logger.Infof("osd.%d is marked 'DOWN'. Removing it", osdID)
		removeOSD(context, clusterInfo, osdID)
	}

	return nil
}

func removeOSD(context *clusterd.Context, clusterInfo *client.ClusterInfo, osdID int) {
	// Get the host where the OSD is found
	hostName, err := client.GetCrushHostName(context, clusterInfo, osdID)
	if err != nil {
		logger.Errorf("failed to get the host where osd.%d is running. %v", osdID, err)
	}

	// Mark the OSD as out.
	args := []string{"osd", "out", fmt.Sprintf("osd.%d", osdID)}
	_, err = client.NewCephCommand(context, clusterInfo, args).Run()
	if err != nil {
		logger.Errorf("failed to exclude osd.%d out of the crush map. %v", osdID, err)
	}

	// Remove the OSD deployment
	deploymentName := fmt.Sprintf("rook-ceph-osd-%d", osdID)
	deployment, err := context.Clientset.AppsV1().Deployments(clusterInfo.Namespace).Get(deploymentName, metav1.GetOptions{})
	if err != nil {
		logger.Errorf("failed to fetch the deployment %q. %v", deploymentName, err)
	} else {
		logger.Infof("removing the OSD deployment %q", deploymentName)
		if err := k8sutil.DeleteDeployment(context.Clientset, clusterInfo.Namespace, deploymentName); err != nil {
			if err != nil {
				// Continue purging the OSD even if the deployment fails to be deleted
				logger.Errorf("failed to delete deployment for OSD %d. %v", osdID, err)
			}
		}
		const pvcLabelName = "ceph.rook.io/pvc"
		if pvcName, ok := deployment.GetLabels()[pvcLabelName]; ok {
			prepareJobList, err := context.Clientset.BatchV1().Jobs(clusterInfo.Namespace).List(metav1.ListOptions{LabelSelector: pvcLabelName + pvcName})
			if err != nil && !kerrors.IsNotFound(err) {
				logger.Errorf("failed to list prepareJobs with labels %q. %v ", pvcLabelName+pvcName, err)
			}
			// Remove osd prepare job
			for _, prepareJob := range prepareJobList.Items {
				logger.Infof("removing the osd prepare job %q", prepareJob.GetName())
				if err := k8sutil.DeleteBatchJob(context.Clientset, clusterInfo.Namespace, prepareJob.GetName(), false); err != nil {
					if err != nil {
						// Continue deleting the OSD prepare job even if the deployment fails to be deleted
						logger.Errorf("failed to delete prepare job for osd %q. %v", prepareJob.GetName(), err)
					}
				}

				logger.Infof("removing the OSD PVC %q", pvcName)
				if err := context.Clientset.CoreV1().PersistentVolumeClaims(clusterInfo.Namespace).Delete(pvcName, &metav1.DeleteOptions{}); err != nil {
					if err != nil {
						// Continue deleting the OSD PVC even if PVC deletion fails
						logger.Errorf("failed to delete pvc for OSD %q. %v", pvcName, err)
					}
				}
			}
		}
	}

	// purge the osd
	purgeosdargs := []string{"osd", "purge", fmt.Sprintf("osd.%d", osdID), "--force", "--yes-i-really-mean-it"}
	_, err = client.NewCephCommand(context, clusterInfo, purgeosdargs).Run()
	if err != nil {
		logger.Errorf("failed to purge osd.%d. %v", osdID, err)
	}

	// Attempting to remove the parent host. Errors can be ignored if there are other OSDs on the same host
	hostargs := []string{"osd", "crush", "rm", hostName}
	_, err = client.NewCephCommand(context, clusterInfo, hostargs).Run()
	if err != nil {
		logger.Errorf("failed to remove CRUSH host %q. %v", hostName, err)
	}

	logger.Infof("completed removal of OSD %d", osdID)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package features

import (
	apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
)

const (
	// Every feature gate should add method here following this template:
	//
	// // owner: @username
	// // alpha: v1.X
	// MyFeature utilfeature.Feature = "MyFeature"

	// owner: @tallclair
	// beta: v1.4
	AppArmor utilfeature.Feature = "AppArmor"

	// owner: @mtaufen
	// alpha: v1.4
	DynamicKubeletConfig utilfeature.Feature = "DynamicKubeletConfig"

	// owner: @pweil-
	// alpha: v1.5
	//
	// Default userns=host for containers that are using other host namespaces, host mounts, the pod
	// contains a privileged container, or specific non-namespaced capabilities (MKNOD, SYS_MODULE,
	// SYS_TIME). This should only be enabled if user namespace remapping is enabled in the docker daemon.
	ExperimentalHostUserNamespaceDefaultingGate utilfeature.Feature = "ExperimentalHostUserNamespaceDefaulting"

	// owner: @vishh
	// alpha: v1.5
	//
	// Ensures guaranteed scheduling of pods marked with a special pod annotation `scheduler.alpha.kubernetes.io/critical-pod`
	// and also prevents them from being evicted from a node.
	// Note: This feature is not supported for `BestEffort` pods.
	ExperimentalCriticalPodAnnotation utilfeature.Feature = "ExperimentalCriticalPodAnnotation"

	// owner: @vishh
	// alpha: v1.6
	//
	// This is deprecated and will be removed in v1.11. Use DevicePlugins instead.
	//
	// Enables support for GPUs as a schedulable resource.
	// Only Nvidia GPUs are supported as of v1.6.
	// Works only with Docker Container Runtime.
	Accelerators utilfeature.Feature = "Accelerators"

	// owner: @jiayingz
	// alpha: v1.8
	//
	// Enables support for Device Plugins
	// Only Nvidia GPUs are tested as of v1.8.
	DevicePlugins utilfeature.Feature = "DevicePlugins"

	// owner: @gmarek
	// alpha: v1.6
	//
	// Changes the logic behind evicting Pods from not ready Nodes
	// to take advantage of NoExecute Taints and Tolerations.
	TaintBasedEvictions utilfeature.Feature = "TaintBasedEvictions"

	// owner: @jcbsmpsn
	// alpha: v1.7
	//
	// Gets a server certificate for the kubelet from the Certificate Signing
	// Request API instead of generating one self signed and auto rotates the
	// certificate as expiration approaches.
	RotateKubeletServerCertificate utilfeature.Feature = "RotateKubeletServerCertificate"

	// owner: @jcbsmpsn
	// alpha: v1.7
	//
	// Automatically renews the client certificate used for communicating with
	// the API server as the certificate approaches expiration.
	RotateKubeletClientCertificate utilfeature.Feature = "RotateKubeletClientCertificate"

	// owner: @msau42
	// alpha: v1.7
	//
	// A new volume type that supports local disks on a node.
	PersistentLocalVolumes utilfeature.Feature = "PersistentLocalVolumes"

	// owner: @jinxu
	// alpha: v1.7
	//
	// New local storage types to support local storage capacity isolation
	LocalStorageCapacityIsolation utilfeature.Feature = "LocalStorageCapacityIsolation"

	// owner: @gnufied
	// alpha: v1.8
	// Ability to Expand persistent volumes
	ExpandPersistentVolumes utilfeature.Feature = "ExpandPersistentVolumes"

	// owner: @verb
	// alpha: v1.10
	//
	// Allows running a "debug container" in a pod namespaces to troubleshoot a running pod.
	DebugContainers utilfeature.Feature = "DebugContainers"

	// owner: @verb
	// alpha: v1.10
	//
	// Allows all containers in a pod to share a process namespace.
	PodShareProcessNamespace utilfeature.Feature = "PodShareProcessNamespace"

	// owner: @bsalamat
	// alpha: v1.8
	//
	// Add priority to pods. Priority affects scheduling and preemption of pods.
	PodPriority utilfeature.Feature = "PodPriority"

	// owner: @resouer
	// alpha: v1.8
	//
	// Enable equivalence class cache for scheduler.
	EnableEquivalenceClassCache utilfeature.Feature = "EnableEquivalenceClassCache"

	// owner: @k82cn
	// alpha: v1.8
	//
	// Taint nodes based on their condition status for 'NetworkUnavailable',
	// 'MemoryPressure', 'OutOfDisk' and 'DiskPressure'.
	TaintNodesByCondition utilfeature.Feature = "TaintNodesByCondition"

	// owner: @jsafrane
	// alpha: v1.8
	//
	// Enable mount propagation of volumes.
	MountPropagation utilfeature.Feature = "MountPropagation"

	// owner: @ConnorDoyle
	// alpha: v1.8
	//
	// Alternative container-level CPU affinity policies.
	CPUManager utilfeature.Feature = "CPUManager"

	// owner: @derekwaynecarr
	// beta: v1.10
	//
	// Enable pods to consume pre-allocated huge pages of varying page sizes
	HugePages utilfeature.Feature = "HugePages"

	// owner @brendandburns
	// alpha: v1.9
	//
	// Enable nodes to exclude themselves from service load balancers
	ServiceNodeExclusion utilfeature.Feature = "ServiceNodeExclusion"

	// owner @brendandburns
	// deprecated: v1.10
	//
	// Enable the service proxy to contact external IP addresses. Note this feature is present
	// only for backward compatability, it will be removed in the 1.11 release.
	ServiceProxyAllowExternalIPs utilfeature.Feature = "ServiceProxyAllowExternalIPs"

	// owner: @jsafrane
	// alpha: v1.9
	//
	// Enable running mount utilities in containers.
	MountContainers utilfeature.Feature = "MountContainers"

	// owner: @msau42
	// alpha: v1.9
	//
	// Extend the default scheduler to be aware of PV topology and handle PV binding
	// Before moving to beta, resolve Kubernetes issue #56180
	VolumeScheduling utilfeature.Feature = "VolumeScheduling"

	// owner: @vladimirvivien
	// alpha: v1.9
	//
	// Enable mount/attachment of Container Storage Interface (CSI) backed PVs
	CSIPersistentVolume utilfeature.Feature = "CSIPersistentVolume"

	// owner @MrHohn
	// alpha: v1.9
	//
	// Support configurable pod DNS parameters.
	CustomPodDNS utilfeature.Feature = "CustomPodDNS"

	// owner: @screeley44
	// alpha: v1.9
	//
	// Enable Block volume support in containers.
	BlockVolume utilfeature.Feature = "BlockVolume"

	// owner: @pospispa
	// alpha: v1.9
	//
	// Postpone deletion of a PV or a PVC when they are being used
	StorageProtection utilfeature.Feature = "StorageProtection"

	// owner: @aveshagarwal
	// alpha: v1.9
	//
	// Enable resource limits priority function
	ResourceLimitsPriorityFunction utilfeature.Feature = "ResourceLimitsPriorityFunction"

	// owner: @m1093782566
	// beta: v1.9
	//
	// Implement IPVS-based in-cluster service load balancing
	SupportIPVSProxyMode utilfeature.Feature = "SupportIPVSProxyMode"

	// owner: @dims
	// alpha: v1.10
	//
	// Implement support for limiting pids in pods
	SupportPodPidsLimit utilfeature.Feature = "SupportPodPidsLimit"

	// owner: @feiskyer
	// alpha: v1.10
	//
	// Enable Hyper-V containers on Windows
	HyperVContainer utilfeature.Feature = "HyperVContainer"
)

func init() {
	utilfeature.DefaultFeatureGate.Add(defaultKubernetesFeatureGates)
}

// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
// To add a new feature, define a key for it above and add it here. The features will be
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureSpec{
	AppArmor:                                    {Default: true, PreRelease: utilfeature.Beta},
	DynamicKubeletConfig:                        {Default: false, PreRelease: utilfeature.Alpha},
	ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: utilfeature.Beta},
	ExperimentalCriticalPodAnnotation:           {Default: false, PreRelease: utilfeature.Alpha},
	Accelerators:                                {Default: false, PreRelease: utilfeature.Alpha},
	DevicePlugins:                               {Default: false, PreRelease: utilfeature.Alpha},
	TaintBasedEvictions:                         {Default: false, PreRelease: utilfeature.Alpha},
	RotateKubeletServerCertificate:              {Default: false, PreRelease: utilfeature.Alpha},
	RotateKubeletClientCertificate:              {Default: true, PreRelease: utilfeature.Beta},
	PersistentLocalVolumes:                      {Default: false, PreRelease: utilfeature.Alpha},
	LocalStorageCapacityIsolation:               {Default: false, PreRelease: utilfeature.Alpha},
	HugePages:                                   {Default: true, PreRelease: utilfeature.Beta},
	DebugContainers:                             {Default: false, PreRelease: utilfeature.Alpha},
	PodShareProcessNamespace:                    {Default: false, PreRelease: utilfeature.Alpha},
	PodPriority:                                 {Default: false, PreRelease: utilfeature.Alpha},
	EnableEquivalenceClassCache:                 {Default: false, PreRelease: utilfeature.Alpha},
	TaintNodesByCondition:                       {Default: false, PreRelease: utilfeature.Alpha},
	MountPropagation:                            {Default: false, PreRelease: utilfeature.Alpha},
	ExpandPersistentVolumes:                     {Default: false, PreRelease: utilfeature.Alpha},
	CPUManager:                                  {Default: true, PreRelease: utilfeature.Beta},
	ServiceNodeExclusion:                        {Default: false, PreRelease: utilfeature.Alpha},
	MountContainers:                             {Default: false, PreRelease: utilfeature.Alpha},
	VolumeScheduling:                            {Default: false, PreRelease: utilfeature.Alpha},
	CSIPersistentVolume:                         {Default: true, PreRelease: utilfeature.Beta},
	CustomPodDNS:                                {Default: false, PreRelease: utilfeature.Alpha},
	BlockVolume:                                 {Default: false, PreRelease: utilfeature.Alpha},
	StorageProtection:                           {Default: false, PreRelease: utilfeature.Alpha},
	ResourceLimitsPriorityFunction:              {Default: false, PreRelease: utilfeature.Alpha},
	SupportIPVSProxyMode:                        {Default: false, PreRelease: utilfeature.Beta},
	SupportPodPidsLimit:                         {Default: false, PreRelease: utilfeature.Alpha},
	HyperVContainer:                             {Default: false, PreRelease: utilfeature.Alpha},

	// inherited features from generic apiserver, relisted here to get a conflict if it is changed
	// unintentionally on either side:
	genericfeatures.StreamingProxyRedirects: {Default: true, PreRelease: utilfeature.Beta},
	genericfeatures.AdvancedAuditing:        {Default: true, PreRelease: utilfeature.Beta},
	genericfeatures.APIResponseCompression:  {Default: false, PreRelease: utilfeature.Alpha},
	genericfeatures.Initializers:            {Default: false, PreRelease: utilfeature.Alpha},
	genericfeatures.APIListChunking:         {Default: true, PreRelease: utilfeature.Beta},

	// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
	// unintentionally on either side:
	apiextensionsfeatures.CustomResourceValidation: {Default: true, PreRelease: utilfeature.Beta},

	// features that enable backwards compatability but are scheduled to be removed
	ServiceProxyAllowExternalIPs: {Default: false, PreRelease: utilfeature.Deprecated},
}
<commit_msg>Move MountPropagation to beta.<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package features

import (
	apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
)

const (
	// Every feature gate should add method here following this template:
	//
	// // owner: @username
	// // alpha: v1.X
	// MyFeature utilfeature.Feature = "MyFeature"

	// owner: @tallclair
	// beta: v1.4
	AppArmor utilfeature.Feature = "AppArmor"

	// owner: @mtaufen
	// alpha: v1.4
	DynamicKubeletConfig utilfeature.Feature = "DynamicKubeletConfig"

	// owner: @pweil-
	// alpha: v1.5
	//
	// Default userns=host for containers that are using other host namespaces, host mounts, the pod
	// contains a privileged container, or specific non-namespaced capabilities (MKNOD, SYS_MODULE,
	// SYS_TIME). This should only be enabled if user namespace remapping is enabled in the docker daemon.
	ExperimentalHostUserNamespaceDefaultingGate utilfeature.Feature = "ExperimentalHostUserNamespaceDefaulting"

	// owner: @vishh
	// alpha: v1.5
	//
	// Ensures guaranteed scheduling of pods marked with a special pod annotation `scheduler.alpha.kubernetes.io/critical-pod`
	// and also prevents them from being evicted from a node.
	// Note: This feature is not supported for `BestEffort` pods.
	ExperimentalCriticalPodAnnotation utilfeature.Feature = "ExperimentalCriticalPodAnnotation"

	// owner: @vishh
	// alpha: v1.6
	//
	// This is deprecated and will be removed in v1.11. Use DevicePlugins instead.
	//
	// Enables support for GPUs as a schedulable resource.
	// Only Nvidia GPUs are supported as of v1.6.
	// Works only with Docker Container Runtime.
	Accelerators utilfeature.Feature = "Accelerators"

	// owner: @jiayingz
	// alpha: v1.8
	//
	// Enables support for Device Plugins
	// Only Nvidia GPUs are tested as of v1.8.
	DevicePlugins utilfeature.Feature = "DevicePlugins"

	// owner: @gmarek
	// alpha: v1.6
	//
	// Changes the logic behind evicting Pods from not ready Nodes
	// to take advantage of NoExecute Taints and Tolerations.
	TaintBasedEvictions utilfeature.Feature = "TaintBasedEvictions"

	// owner: @jcbsmpsn
	// alpha: v1.7
	//
	// Gets a server certificate for the kubelet from the Certificate Signing
	// Request API instead of generating one self signed and auto rotates the
	// certificate as expiration approaches.
	RotateKubeletServerCertificate utilfeature.Feature = "RotateKubeletServerCertificate"

	// owner: @jcbsmpsn
	// alpha: v1.7
	//
	// Automatically renews the client certificate used for communicating with
	// the API server as the certificate approaches expiration.
	RotateKubeletClientCertificate utilfeature.Feature = "RotateKubeletClientCertificate"

	// owner: @msau42
	// alpha: v1.7
	//
	// A new volume type that supports local disks on a node.
	PersistentLocalVolumes utilfeature.Feature = "PersistentLocalVolumes"

	// owner: @jinxu
	// alpha: v1.7
	//
	// New local storage types to support local storage capacity isolation
	LocalStorageCapacityIsolation utilfeature.Feature = "LocalStorageCapacityIsolation"

	// owner: @gnufied
	// alpha: v1.8
	// Ability to Expand persistent volumes
	ExpandPersistentVolumes utilfeature.Feature = "ExpandPersistentVolumes"

	// owner: @verb
	// alpha: v1.10
	//
	// Allows running a "debug container" in a pod namespaces to troubleshoot a running pod.
	DebugContainers utilfeature.Feature = "DebugContainers"

	// owner: @verb
	// alpha: v1.10
	//
	// Allows all containers in a pod to share a process namespace.
	PodShareProcessNamespace utilfeature.Feature = "PodShareProcessNamespace"

	// owner: @bsalamat
	// alpha: v1.8
	//
	// Add priority to pods. Priority affects scheduling and preemption of pods.
	PodPriority utilfeature.Feature = "PodPriority"

	// owner: @resouer
	// alpha: v1.8
	//
	// Enable equivalence class cache for scheduler.
	EnableEquivalenceClassCache utilfeature.Feature = "EnableEquivalenceClassCache"

	// owner: @k82cn
	// alpha: v1.8
	//
	// Taint nodes based on their condition status for 'NetworkUnavailable',
	// 'MemoryPressure', 'OutOfDisk' and 'DiskPressure'.
	TaintNodesByCondition utilfeature.Feature = "TaintNodesByCondition"

	// owner: @jsafrane
	// beta: v1.10
	//
	// Enable mount propagation of volumes.
	MountPropagation utilfeature.Feature = "MountPropagation"

	// owner: @ConnorDoyle
	// alpha: v1.8
	//
	// Alternative container-level CPU affinity policies.
	CPUManager utilfeature.Feature = "CPUManager"

	// owner: @derekwaynecarr
	// beta: v1.10
	//
	// Enable pods to consume pre-allocated huge pages of varying page sizes
	HugePages utilfeature.Feature = "HugePages"

	// owner @brendandburns
	// alpha: v1.9
	//
	// Enable nodes to exclude themselves from service load balancers
	ServiceNodeExclusion utilfeature.Feature = "ServiceNodeExclusion"

	// owner @brendandburns
	// deprecated: v1.10
	//
	// Enable the service proxy to contact external IP addresses. Note this feature is present
	// only for backward compatability, it will be removed in the 1.11 release.
	ServiceProxyAllowExternalIPs utilfeature.Feature = "ServiceProxyAllowExternalIPs"

	// owner: @jsafrane
	// alpha: v1.9
	//
	// Enable running mount utilities in containers.
	MountContainers utilfeature.Feature = "MountContainers"

	// owner: @msau42
	// alpha: v1.9
	//
	// Extend the default scheduler to be aware of PV topology and handle PV binding
	// Before moving to beta, resolve Kubernetes issue #56180
	VolumeScheduling utilfeature.Feature = "VolumeScheduling"

	// owner: @vladimirvivien
	// alpha: v1.9
	//
	// Enable mount/attachment of Container Storage Interface (CSI) backed PVs
	CSIPersistentVolume utilfeature.Feature = "CSIPersistentVolume"

	// owner @MrHohn
	// alpha: v1.9
	//
	// Support configurable pod DNS parameters.
	CustomPodDNS utilfeature.Feature = "CustomPodDNS"

	// owner: @screeley44
	// alpha: v1.9
	//
	// Enable Block volume support in containers.
	BlockVolume utilfeature.Feature = "BlockVolume"

	// owner: @pospispa
	// alpha: v1.9
	//
	// Postpone deletion of a PV or a PVC when they are being used
	StorageProtection utilfeature.Feature = "StorageProtection"

	// owner: @aveshagarwal
	// alpha: v1.9
	//
	// Enable resource limits priority function
	ResourceLimitsPriorityFunction utilfeature.Feature = "ResourceLimitsPriorityFunction"

	// owner: @m1093782566
	// beta: v1.9
	//
	// Implement IPVS-based in-cluster service load balancing
	SupportIPVSProxyMode utilfeature.Feature = "SupportIPVSProxyMode"

	// owner: @dims
	// alpha: v1.10
	//
	// Implement support for limiting pids in pods
	SupportPodPidsLimit utilfeature.Feature = "SupportPodPidsLimit"

	// owner: @feiskyer
	// alpha: v1.10
	//
	// Enable Hyper-V containers on Windows
	HyperVContainer utilfeature.Feature = "HyperVContainer"
)

func init() {
	utilfeature.DefaultFeatureGate.Add(defaultKubernetesFeatureGates)
}

// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
// To add a new feature, define a key for it above and add it here. The features will be
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureSpec{
	AppArmor:                                    {Default: true, PreRelease: utilfeature.Beta},
	DynamicKubeletConfig:                        {Default: false, PreRelease: utilfeature.Alpha},
	ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: utilfeature.Beta},
	ExperimentalCriticalPodAnnotation:           {Default: false, PreRelease: utilfeature.Alpha},
	Accelerators:                                {Default: false, PreRelease: utilfeature.Alpha},
	DevicePlugins:                               {Default: false, PreRelease: utilfeature.Alpha},
	TaintBasedEvictions:                         {Default: false, PreRelease: utilfeature.Alpha},
	RotateKubeletServerCertificate:              {Default: false, PreRelease: utilfeature.Alpha},
	RotateKubeletClientCertificate:              {Default: true, PreRelease: utilfeature.Beta},
	PersistentLocalVolumes:                      {Default: false, PreRelease: utilfeature.Alpha},
	LocalStorageCapacityIsolation:               {Default: false, PreRelease: utilfeature.Alpha},
	HugePages:                                   {Default: true, PreRelease: utilfeature.Beta},
	DebugContainers:                             {Default: false, PreRelease: utilfeature.Alpha},
	PodShareProcessNamespace:                    {Default: false, PreRelease: utilfeature.Alpha},
	PodPriority:                                 {Default: false, PreRelease: utilfeature.Alpha},
	EnableEquivalenceClassCache:                 {Default: false, PreRelease: utilfeature.Alpha},
	TaintNodesByCondition:                       {Default: false, PreRelease: utilfeature.Alpha},
	MountPropagation:                            {Default: true, PreRelease: utilfeature.Beta},
	ExpandPersistentVolumes:                     {Default: false, PreRelease: utilfeature.Alpha},
	CPUManager:                                  {Default: true, PreRelease: utilfeature.Beta},
	ServiceNodeExclusion:                        {Default: false, PreRelease: utilfeature.Alpha},
	MountContainers:                             {Default: false, PreRelease: utilfeature.Alpha},
	VolumeScheduling:                            {Default: false, PreRelease: utilfeature.Alpha},
	CSIPersistentVolume:                         {Default: true, PreRelease: utilfeature.Beta},
	CustomPodDNS:                                {Default: false, PreRelease: utilfeature.Alpha},
	BlockVolume:                                 {Default: false, PreRelease: utilfeature.Alpha},
	StorageProtection:                           {Default: false, PreRelease: utilfeature.Alpha},
	ResourceLimitsPriorityFunction:              {Default: false, PreRelease: utilfeature.Alpha},
	SupportIPVSProxyMode:                        {Default: false, PreRelease: utilfeature.Beta},
	SupportPodPidsLimit:                         {Default: false, PreRelease: utilfeature.Alpha},
	HyperVContainer:                             {Default: false, PreRelease: utilfeature.Alpha},

	// inherited features from generic apiserver, relisted here to get a conflict if it is changed
	// unintentionally on either side:
	genericfeatures.StreamingProxyRedirects: {Default: true, PreRelease: utilfeature.Beta},
	genericfeatures.AdvancedAuditing:        {Default: true, PreRelease: utilfeature.Beta},
	genericfeatures.APIResponseCompression:  {Default: false, PreRelease: utilfeature.Alpha},
	genericfeatures.Initializers:            {Default: false, PreRelease: utilfeature.Alpha},
	genericfeatures.APIListChunking:         {Default: true, PreRelease: utilfeature.Beta},

	// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
	// unintentionally on either side:
	apiextensionsfeatures.CustomResourceValidation: {Default: true, PreRelease: utilfeature.Beta},

	// features that enable backwards compatability but are scheduled to be removed
	ServiceProxyAllowExternalIPs: {Default: false, PreRelease: utilfeature.Deprecated},
}
<|endoftext|>


<commit_before>package survey

import (
	"database/sql"
	"github.com/curt-labs/GoSurvey/helpers/database"
	_ "github.com/go-sql-driver/mysql"
	"time"
)

// SQL Statements
var (
	getSurveyQuestions = `select id, question, date_modified,
												date_added, userID, deleted
												from SurveyQuestion
												where surveyID = ? && deleted = 0
												order by date_added`
	getQuestionRevisions = `select qr.ID as revisionID, qr.new_question,
													qr.old_question, qr.date, qr.changeType,
													u.id as userID, u.fname, u.lname, u.username
													from SurveyQuestion_Revisions as qr
													join admin.user as u on qr.userID = u.id
													where qr.questionID = ?
													order by date desc`
	insertQuestion = `insert into SurveyQuestion(question, date_added, userID, surveyID)
										values(?,NOW(),?,?)`
	updateQuestion = `update SurveyQuestion
										set question = ?, userID = ?, surveyID = ?
										where id = ?`
	deleteQuestion = `update SurveyQuestion
										set deleted = 0, userID = ?
										where id = ?`
)

// Question contains information for a question
// on a survey. It contains answers and revision history
// for both the question an each answer.
type Question struct {
	ID           int                `json:"id"`
	Question     string             `json:"question"`
	DateModified time.Time          `json:"date_modified"`
	DateAdded    time.Time          `json:"date_added"`
	UserID       int                `json:"-"`
	Deleted      bool               `json:"-"`
	Revisions    []QuestionRevision `json:"revisions"`
	Answers      []Answer           `json:"answers"`
}

// QuestionRevision is a change record for a Question.
type QuestionRevision struct {
	ID          int          `json:"id"`
	User        RevisionUser `json:"user"`
	NewQuestion string       `json:"new_question"`
	OldQuestion string       `json:"old_question"`
	Date        time.Time    `json:"date"`
	ChangeType  string       `json:"change_type"`
}

// AddQuestion will commit a new question to a
// referenced Survey.
func (s *Survey) AddQuestion(q Question) error {
	var err error

	if q.ID == 0 {
		err = q.insert(s.ID)
	} else {
		err = q.update(s.ID)
	}

	if err != nil {
		return err
	}

	for _, answer := range q.Answers {
		if err = q.AddAnswer(answer); err != nil {
			return err
		}
	}

	return err
}

// Delete will mark the referenced Question
// as deleted.
func (q *Question) Delete() error {
	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}

	stmt, err := db.Prepare(deleteQuestion)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(q.UserID, q.ID)
	return err
}

// insert will insert a new Question and bint it
// to the given Survey.
func (q *Question) insert(surveyID int) error {

	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}

	stmt, err := db.Prepare(insertQuestion)
	if err != nil {
		return err
	}

	res, err := stmt.Exec(q.Question, q.UserID, surveyID)
	if err != nil {
		return err
	}

	id, err := res.LastInsertId()
	if err != nil {
		return err
	}

	q.ID = int(id)

	return nil
}

// update will update the question, userID, and surveyID
// properties for the given Question.
func (q *Question) update(surveyID int) error {
	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}

	stmt, err := db.Prepare(updateQuestion)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(q.Question, q.UserID, surveyID, q.ID)

	return err
}

// questions will retrieve all possible questions
// for the referenced Survey.
func (s *Survey) questions() error {
	s.Questions = make([]Question, 0)
	var err error

	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}
	defer db.Close()

	stmt, err := db.Prepare(getSurveyQuestions)
	if err != nil {
		return err
	}
	defer stmt.Close()

	res, err := stmt.Query(s.ID)
	if err != nil {
		return err
	}

	for res.Next() {
		var q Question
		err = res.Scan(&q.ID, &q.Question, &q.DateModified, &q.DateAdded, &q.UserID, &q.Deleted)
		if err == nil {
			q.revisions()
			s.Questions = append(s.Questions, q)
		}
	}

	return nil
}

// revisions will retrieve all revision history
// for the referenced Question and push them onto
// the Revisions slice.
func (q *Question) revisions() error {
	var err error

	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}
	defer db.Close()

	stmt, err := db.Prepare(getQuestionRevisions)
	if err != nil {
		return err
	}
	defer stmt.Close()

	res, err := stmt.Query(q.ID)
	if err != nil {
		return err
	}

	for res.Next() {
		var qr QuestionRevision
		err = res.Scan(&qr.ID, &qr.NewQuestion, &qr.OldQuestion, &qr.Date,
			&qr.ChangeType, &qr.User.ID, &qr.User.FirstName, &qr.User.LastName,
			&qr.User.Username)
		if err == nil {
			q.Revisions = append(q.Revisions, qr)
		}
	}

	return nil
}
<commit_msg>AddQuestion now returns the question<commit_after>package survey

import (
	"database/sql"
	"github.com/curt-labs/GoSurvey/helpers/database"
	_ "github.com/go-sql-driver/mysql"
	"time"
)

// SQL Statements
var (
	getSurveyQuestions = `select id, question, date_modified,
												date_added, userID, deleted
												from SurveyQuestion
												where surveyID = ? && deleted = 0
												order by date_added`
	getQuestionRevisions = `select qr.ID as revisionID, qr.new_question,
													qr.old_question, qr.date, qr.changeType,
													u.id as userID, u.fname, u.lname, u.username
													from SurveyQuestion_Revisions as qr
													join admin.user as u on qr.userID = u.id
													where qr.questionID = ?
													order by date desc`
	insertQuestion = `insert into SurveyQuestion(question, date_added, userID, surveyID)
										values(?,NOW(),?,?)`
	updateQuestion = `update SurveyQuestion
										set question = ?, userID = ?, surveyID = ?
										where id = ?`
	deleteQuestion = `update SurveyQuestion
										set deleted = 0, userID = ?
										where id = ?`
)

// Question contains information for a question
// on a survey. It contains answers and revision history
// for both the question an each answer.
type Question struct {
	ID           int                `json:"id"`
	Question     string             `json:"question"`
	DateModified time.Time          `json:"date_modified"`
	DateAdded    time.Time          `json:"date_added"`
	UserID       int                `json:"-"`
	Deleted      bool               `json:"-"`
	Revisions    []QuestionRevision `json:"revisions"`
	Answers      []Answer           `json:"answers"`
}

// QuestionRevision is a change record for a Question.
type QuestionRevision struct {
	ID          int          `json:"id"`
	User        RevisionUser `json:"user"`
	NewQuestion string       `json:"new_question"`
	OldQuestion string       `json:"old_question"`
	Date        time.Time    `json:"date"`
	ChangeType  string       `json:"change_type"`
}

// AddQuestion will commit a new question to a
// referenced Survey.
func (s *Survey) AddQuestion(q Question) (Question, error) {
	var err error

	if q.ID == 0 {
		err = q.insert(s.ID)
	} else {
		err = q.update(s.ID)
	}

	if err != nil {
		return q, err
	}

	for _, answer := range q.Answers {
		if err = q.AddAnswer(answer); err != nil {
			return q, err
		}
	}

	return q, err
}

// Delete will mark the referenced Question
// as deleted.
func (q *Question) Delete() error {
	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}

	stmt, err := db.Prepare(deleteQuestion)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(q.UserID, q.ID)
	return err
}

// insert will insert a new Question and bint it
// to the given Survey.
func (q *Question) insert(surveyID int) error {

	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}

	stmt, err := db.Prepare(insertQuestion)
	if err != nil {
		return err
	}

	res, err := stmt.Exec(q.Question, q.UserID, surveyID)
	if err != nil {
		return err
	}

	id, err := res.LastInsertId()
	if err != nil {
		return err
	}

	q.ID = int(id)

	return nil
}

// update will update the question, userID, and surveyID
// properties for the given Question.
func (q *Question) update(surveyID int) error {
	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}

	stmt, err := db.Prepare(updateQuestion)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(q.Question, q.UserID, surveyID, q.ID)

	return err
}

// questions will retrieve all possible questions
// for the referenced Survey.
func (s *Survey) questions() error {
	s.Questions = make([]Question, 0)
	var err error

	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}
	defer db.Close()

	stmt, err := db.Prepare(getSurveyQuestions)
	if err != nil {
		return err
	}
	defer stmt.Close()

	res, err := stmt.Query(s.ID)
	if err != nil {
		return err
	}

	for res.Next() {
		var q Question
		err = res.Scan(&q.ID, &q.Question, &q.DateModified, &q.DateAdded, &q.UserID, &q.Deleted)
		if err == nil {
			q.revisions()
			s.Questions = append(s.Questions, q)
		}
	}

	return nil
}

// revisions will retrieve all revision history
// for the referenced Question and push them onto
// the Revisions slice.
func (q *Question) revisions() error {
	var err error

	db, err := sql.Open("mysql", database.ConnectionString())
	if err != nil {
		return err
	}
	defer db.Close()

	stmt, err := db.Prepare(getQuestionRevisions)
	if err != nil {
		return err
	}
	defer stmt.Close()

	res, err := stmt.Query(q.ID)
	if err != nil {
		return err
	}

	for res.Next() {
		var qr QuestionRevision
		err = res.Scan(&qr.ID, &qr.NewQuestion, &qr.OldQuestion, &qr.Date,
			&qr.ChangeType, &qr.User.ID, &qr.User.FirstName, &qr.User.LastName,
			&qr.User.Username)
		if err == nil {
			q.Revisions = append(q.Revisions, qr)
		}
	}

	return nil
}
<|endoftext|>