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

package format

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"reflect"
	"strings"
)

type debugPrinter struct {
	buf     *bytes.Buffer
	ptrseen map[interface{}]int // ptr -> count seen
	ptrdone map[interface{}]bool
	indent  int
}

func (p *debugPrinter) collectPtrs(v reflect.Value) {
	switch v.Kind() {
	case reflect.Ptr:
		ptr := v.Interface()
		p.ptrseen[ptr]++
		if p.ptrseen[ptr] == 1 {
			p.collectPtrs(v.Elem())
		}
	case reflect.Interface:
		if repack := reflect.ValueOf(v.Interface()); repack.Kind() == reflect.Ptr {
			p.collectPtrs(repack)
		} else {
			p.collectPtrs(v.Elem())
		}
	case reflect.Map:
		for _, key := range v.MapKeys() {
			p.collectPtrs(key)
			p.collectPtrs(v.MapIndex(key))
		}
	case reflect.Array:
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			p.collectPtrs(v.Index(i))
		}
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			p.collectPtrs(v.Field(i))
		}
	}
}

func (p *debugPrinter) printf(format string, args ...interface{}) {
	fmt.Fprintf(p.buf, format, args...)
}

func (p *debugPrinter) newline() {
	p.buf.WriteByte('\n')
	for i := 0; i < p.indent; i++ {
		p.buf.WriteByte('\t')
	}
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		return v.IsNil()
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			if !isZero(v.Field(i)) {
				return false
			}
		}
		return true
	case reflect.Array:
		for i := 0; i < v.Len(); i++ {
			if !isZero(v.Index(i)) {
				return false
			}
		}
		return true
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Complex64, reflect.Complex128:
		return v.Complex() == 0
	}
	return false
}

func (p *debugPrinter) printv(v reflect.Value) {
	switch v.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if v.IsNil() {
			p.buf.WriteString("nil")
			return
		}
	}

	switch v.Kind() {
	case reflect.Ptr:
		p.printf("&")
		ptr := v.Interface()
		if p.ptrdone[ptr] {
			p.printf("%p", ptr)
		} else if p.ptrseen[ptr] > 1 {
			// TODO: p.printv(v.Elem())
			p.printf(" (TODO type %T)", ptr)
			p.ptrdone[ptr] = true
			p.printf(" (ptr %p)", ptr)
		} else {
			p.printv(v.Elem())
		}
	case reflect.Interface:
		if repack := reflect.ValueOf(v.Interface()); repack.Kind() == reflect.Ptr {
			p.printv(repack)
			return
		}
		p.printv(v.Elem())
	case reflect.Map:
		p.printf("%s{", v.Type())
		if v.Len() == 1 {
			key := v.MapKeys()[0]
			p.printf("%s: ", key)
			p.printv(v.MapIndex(key))
		} else if v.Len() > 0 {
			p.indent++
			for _, key := range v.MapKeys() {
				p.newline()
				p.printf("%s: ", key)
				p.printv(v.MapIndex(key))
				p.buf.WriteByte(',')
			}
			p.indent--
			p.newline()
		}
		p.buf.WriteByte('}')
	case reflect.Slice:
		if v.Type().Elem().Kind() == reflect.Int8 {
			s := v.Bytes()
			p.printf("%#q", s)
			return
		}
		fallthrough
	case reflect.Array:
		p.printf("%s{", v.Type())
		if v.Len() > 0 {
			p.indent++
			for i := 0; i < v.Len(); i++ {
				p.newline()
				p.printv(v.Index(i))
				p.buf.WriteByte(',')
			}
			p.indent--
			p.newline()
		}
		p.buf.WriteByte('}')
	case reflect.Struct:
		t := v.Type()
		p.printf("%s{", t)
		if v.NumField() > 0 {
			p.indent++
			for i := 0; i < v.NumField(); i++ {
				if isZero(v.Field(i)) {
					continue
				}
				p.newline()
				p.printf("%s: ", t.Field(i).Name)
				p.printv(v.Field(i))
				p.buf.WriteByte(',')
			}
			p.indent--
			p.newline()
		}
		p.buf.WriteByte('}')
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		p.printf("%s(%v)", v.Type().Name(), v)
	default:
		if !v.IsValid() {
			p.printf("?")
		} else if v.Kind() == reflect.String {
			p.printf("%q", v.String())
		} else if v.CanInterface() {
			p.printf("%#v", v.Interface())
		} else {
			p.printf("?")
		}
	}
}

func printToFile(x interface{}) (path string, err error) {
	f, err := ioutil.TempFile("", "neugram-diff-")
	if err != nil {
		return "", err
	}
	defer func() {
		err2 := f.Close()
		if err == nil {
			err = err2
		}
		if err != nil {
			os.Remove(f.Name())
		}
	}()

	str := Debug(x)
	if _, err := io.WriteString(f, str); err != nil {
		return "", err
	}
	return f.Name(), nil
}

func diffVal(x, y interface{}) (string, error) {
	fx, err := printToFile(x)
	if err != nil {
		return "", fmt.Errorf("diff print lhs error: %v", err)
	}
	defer os.Remove(fx)
	fy, err := printToFile(y)
	if err != nil {
		return "", fmt.Errorf("diff print rhs error: %v", err)
	}
	defer os.Remove(fy)

	b, _ := ioutil.ReadFile(fx)
	fmt.Printf("fx: %s\n", b)

	data, err := exec.Command("diff", "-U100", "-u", fx, fy).CombinedOutput()
	if err != nil && len(data) == 0 {
		// diff exits with a non-zero status when the files don't match.
		return "", fmt.Errorf("diff error: %v", err)
	}
	res := string(data)
	res = strings.Replace(res, fx, "/x", 1)
	res = strings.Replace(res, fy, "/y", 1)
	return res, nil
}

func WriteDebug(buf *bytes.Buffer, e interface{}) {
	p := debugPrinter{
		buf:     buf,
		ptrseen: make(map[interface{}]int),
		ptrdone: make(map[interface{}]bool),
	}
	v := reflect.ValueOf(e)
	p.collectPtrs(v)
	p.printv(v)
}

func Debug(e interface{}) string {
	buf := new(bytes.Buffer)
	WriteDebug(buf, e)
	return buf.String()
}

func Diff(x, y interface{}) string {
	s, err := diffVal(x, y)
	if err != nil {
		return fmt.Sprintf("format.Diff: %v", err)
	}
	return s
}
<commit_msg>format: do not panic printing unexported fields<commit_after>// Copyright 2017 The Neugram Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package format

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"reflect"
	"strings"
)

type debugPrinter struct {
	buf     *bytes.Buffer
	ptrseen map[interface{}]int // ptr -> count seen
	ptrdone map[interface{}]bool
	indent  int
}

func (p *debugPrinter) collectPtrs(v reflect.Value) {
	switch v.Kind() {
	case reflect.Ptr:
		if !v.CanInterface() {
			return
		}
		ptr := v.Interface()
		p.ptrseen[ptr]++
		if p.ptrseen[ptr] == 1 {
			p.collectPtrs(v.Elem())
		}
	case reflect.Interface:
		if repack := reflect.ValueOf(v.Interface()); repack.Kind() == reflect.Ptr {
			p.collectPtrs(repack)
		} else {
			p.collectPtrs(v.Elem())
		}
	case reflect.Map:
		for _, key := range v.MapKeys() {
			p.collectPtrs(key)
			p.collectPtrs(v.MapIndex(key))
		}
	case reflect.Array:
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			p.collectPtrs(v.Index(i))
		}
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			p.collectPtrs(v.Field(i))
		}
	}
}

func (p *debugPrinter) printf(format string, args ...interface{}) {
	fmt.Fprintf(p.buf, format, args...)
}

func (p *debugPrinter) newline() {
	p.buf.WriteByte('\n')
	for i := 0; i < p.indent; i++ {
		p.buf.WriteByte('\t')
	}
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		return v.IsNil()
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			if !isZero(v.Field(i)) {
				return false
			}
		}
		return true
	case reflect.Array:
		for i := 0; i < v.Len(); i++ {
			if !isZero(v.Index(i)) {
				return false
			}
		}
		return true
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Complex64, reflect.Complex128:
		return v.Complex() == 0
	}
	return false
}

func (p *debugPrinter) printv(v reflect.Value) {
	switch v.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if v.IsNil() {
			p.buf.WriteString("nil")
			return
		}
	}

	switch v.Kind() {
	case reflect.Ptr:
		if !v.CanInterface() {
			p.printf("unexported")
			return
		}
		p.printf("&")
		ptr := v.Interface()
		if p.ptrdone[ptr] {
			p.printf("%p", ptr)
		} else if p.ptrseen[ptr] > 1 {
			// TODO: p.printv(v.Elem())
			p.printf(" (TODO type %T)", ptr)
			p.ptrdone[ptr] = true
			p.printf(" (ptr %p)", ptr)
		} else {
			p.printv(v.Elem())
		}
	case reflect.Interface:
		if repack := reflect.ValueOf(v.Interface()); repack.Kind() == reflect.Ptr {
			p.printv(repack)
			return
		}
		p.printv(v.Elem())
	case reflect.Map:
		p.printf("%s{", v.Type())
		if v.Len() == 1 {
			key := v.MapKeys()[0]
			p.printf("%s: ", key)
			p.printv(v.MapIndex(key))
		} else if v.Len() > 0 {
			p.indent++
			for _, key := range v.MapKeys() {
				p.newline()
				p.printf("%s: ", key)
				p.printv(v.MapIndex(key))
				p.buf.WriteByte(',')
			}
			p.indent--
			p.newline()
		}
		p.buf.WriteByte('}')
	case reflect.Slice:
		if v.Type().Elem().Kind() == reflect.Int8 {
			s := v.Bytes()
			p.printf("%#q", s)
			return
		}
		fallthrough
	case reflect.Array:
		p.printf("%s{", v.Type())
		if v.Len() > 0 {
			p.indent++
			for i := 0; i < v.Len(); i++ {
				p.newline()
				p.printv(v.Index(i))
				p.buf.WriteByte(',')
			}
			p.indent--
			p.newline()
		}
		p.buf.WriteByte('}')
	case reflect.Struct:
		t := v.Type()
		p.printf("%s{", t)
		if v.NumField() > 0 {
			p.indent++
			for i := 0; i < v.NumField(); i++ {
				if isZero(v.Field(i)) {
					continue
				}
				p.newline()
				p.printf("%s: ", t.Field(i).Name)
				p.printv(v.Field(i))
				p.buf.WriteByte(',')
			}
			p.indent--
			p.newline()
		}
		p.buf.WriteByte('}')
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		p.printf("%s(%v)", v.Type().Name(), v)
	default:
		if !v.IsValid() {
			p.printf("?")
		} else if v.Kind() == reflect.String {
			p.printf("%q", v.String())
		} else if v.CanInterface() {
			p.printf("%#v", v.Interface())
		} else {
			p.printf("?")
		}
	}
}

func printToFile(x interface{}) (path string, err error) {
	f, err := ioutil.TempFile("", "neugram-diff-")
	if err != nil {
		return "", err
	}
	defer func() {
		err2 := f.Close()
		if err == nil {
			err = err2
		}
		if err != nil {
			os.Remove(f.Name())
		}
	}()

	str := Debug(x)
	if _, err := io.WriteString(f, str); err != nil {
		return "", err
	}
	return f.Name(), nil
}

func diffVal(x, y interface{}) (string, error) {
	fx, err := printToFile(x)
	if err != nil {
		return "", fmt.Errorf("diff print lhs error: %v", err)
	}
	defer os.Remove(fx)
	fy, err := printToFile(y)
	if err != nil {
		return "", fmt.Errorf("diff print rhs error: %v", err)
	}
	defer os.Remove(fy)

	b, _ := ioutil.ReadFile(fx)
	fmt.Printf("fx: %s\n", b)

	data, err := exec.Command("diff", "-U100", "-u", fx, fy).CombinedOutput()
	if err != nil && len(data) == 0 {
		// diff exits with a non-zero status when the files don't match.
		return "", fmt.Errorf("diff error: %v", err)
	}
	res := string(data)
	res = strings.Replace(res, fx, "/x", 1)
	res = strings.Replace(res, fy, "/y", 1)
	return res, nil
}

func WriteDebug(buf *bytes.Buffer, e interface{}) {
	p := debugPrinter{
		buf:     buf,
		ptrseen: make(map[interface{}]int),
		ptrdone: make(map[interface{}]bool),
	}
	v := reflect.ValueOf(e)
	p.collectPtrs(v)
	p.printv(v)
}

func Debug(e interface{}) string {
	buf := new(bytes.Buffer)
	WriteDebug(buf, e)
	return buf.String()
}

func Diff(x, y interface{}) string {
	s, err := diffVal(x, y)
	if err != nil {
		return fmt.Sprintf("format.Diff: %v", err)
	}
	return s
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/dsvensson/go-xmmsclient/xmmsclient"
	"strings"
	"time"
)

func playlistChanges(client *xmmsclient.Client) {
	bcast := client.BroadcastPlaylistChanged()
	for {
		value, err := bcast.Next()
		if err != nil {
			fmt.Println("Error(PlaylistChanged):", err)
			return
		}
		fmt.Println(value)
	}
}

func repeat(client *xmmsclient.Client) {
	for {
		value, err := client.PlaylistListEntries(xmmsclient.ActivePlaylist)
		if err != nil {
			fmt.Println("Error(PlaylistListEntries):", err)
			return
		}
		for position, mid := range value {
			propDict, err := client.MedialibGetInfo(mid)
			if err != nil {
				fmt.Println("Error(GetInfo):", err)
				return
			}

			dict, err := xmmsclient.PropDictToDictDefault(propDict)
			if err != nil {
				fmt.Println("Error(PropDict->Dict):", err)
				return
			}

			fmt.Printf("repeat(): [%2d] %s // %s // %s\n",
				position, dict["artist"], dict["album"], dict["title"])
		}
		time.Sleep(time.Millisecond * 1500)
	}
}

func main() {
	client := xmmsclient.NewClient("hello-from-go")

	clientId, err := client.Dial("localhost:xmms2")
	if err != nil {
		fmt.Println("Error(Dial):", err)
		return
	}

	go repeat(client)
	go playlistChanges(client)

	time.Sleep(time.Millisecond * 5)

	value, err := client.CollectionList(xmmsclient.NamespacePlaylists)
	if err != nil {
		fmt.Println("Error(CollectionList):", err)
		return
	}

	for index, name := range value {
		if !strings.HasPrefix(name, "_") {
			fmt.Printf("  main(): [%2v] %v::%v\n", index, xmmsclient.NamespacePlaylists, name)
		}
	}

	clients, err := client.CourierGetConnectedClients()
	if err != nil {
		fmt.Println("Error(CourierGetConnectedClients):", err)
		return
	}
	fmt.Println("Connected clients:", clients, "self:", clientId)

	coll := xmmsclient.XmmsColl{Type: xmmsclient.CollectionTypeUniverse}
	fetch := xmmsclient.XmmsList{xmmsclient.XmmsString("artist"), xmmsclient.XmmsString("album")}
	group := xmmsclient.XmmsList{xmmsclient.XmmsString("album")}

	matches, err := client.CollectionQueryInfos(coll, 0, 0, fetch, group)
	if err != nil {
		fmt.Println("Error(CollectionQueryInfos):", err)
		return
	}
	fmt.Println("All albums:", matches)

	time.Sleep(time.Second * 3)
	fmt.Println(" close():")
	client.Close()
	fmt.Println(" sleep():")
	time.Sleep(time.Second * 2)
}
<commit_msg>Rename xmmsclient import to reduce noise.<commit_after>package main

import (
	"fmt"
	xc "github.com/dsvensson/go-xmmsclient/xmmsclient"
	"strings"
	"time"
)

func playlistChanges(client *xc.Client) {
	bcast := client.BroadcastPlaylistChanged()
	for {
		value, err := bcast.Next()
		if err != nil {
			fmt.Println("Error(PlaylistChanged):", err)
			return
		}
		fmt.Println(value)
	}
}

func repeat(client *xc.Client) {
	for {
		value, err := client.PlaylistListEntries(xc.ActivePlaylist)
		if err != nil {
			fmt.Println("Error(PlaylistListEntries):", err)
			return
		}
		for position, mid := range value {
			propDict, err := client.MedialibGetInfo(mid)
			if err != nil {
				fmt.Println("Error(GetInfo):", err)
				return
			}

			dict, err := xc.PropDictToDictDefault(propDict)
			if err != nil {
				fmt.Println("Error(PropDict->Dict):", err)
				return
			}

			fmt.Printf("repeat(): [%2d] %s // %s // %s\n",
				position, dict["artist"], dict["album"], dict["title"])
		}
		time.Sleep(time.Millisecond * 1500)
	}
}

func main() {
	client := xc.NewClient("hello-from-go")

	clientId, err := client.Dial("localhost:xmms2")
	if err != nil {
		fmt.Println("Error(Dial):", err)
		return
	}

	go repeat(client)
	go playlistChanges(client)

	time.Sleep(time.Millisecond * 5)

	value, err := client.CollectionList(xc.NamespacePlaylists)
	if err != nil {
		fmt.Println("Error(CollectionList):", err)
		return
	}

	for index, name := range value {
		if !strings.HasPrefix(name, "_") {
			fmt.Printf("  main(): [%2v] %v::%v\n", index, xc.NamespacePlaylists, name)
		}
	}

	clients, err := client.CourierGetConnectedClients()
	if err != nil {
		fmt.Println("Error(CourierGetConnectedClients):", err)
		return
	}
	fmt.Println("Connected clients:", clients, "self:", clientId)

	coll := xc.XmmsColl{Type: xc.CollectionTypeUniverse}
	fetch := xc.XmmsList{xc.XmmsString("artist"), xc.XmmsString("album")}
	group := xc.XmmsList{xc.XmmsString("album")}

	matches, err := client.CollectionQueryInfos(coll, 0, 0, fetch, group)
	if err != nil {
		fmt.Println("Error(CollectionQueryInfos):", err)
		return
	}
	fmt.Println("All albums:", matches)

	time.Sleep(time.Second * 3)
	fmt.Println(" close():")
	client.Close()
	fmt.Println(" sleep():")
	time.Sleep(time.Second * 2)
}
<|endoftext|>


<commit_before>package radosAPI

type apiError struct {
	Code string `json:"Code"`
}

type Entry struct {
	Buckets []struct {
		Bucket     string `json:"bucket"`
		Categories []struct {
			BytesReceived int    `json:"bytes_received"`
			BytesSent     int    `json:"bytes_sent"`
			Category      string `json:"category"`
			Ops           int    `json:"ops"`
			SuccessfulOps int    `json:"successful_ops"`
		} `json:"categories"`
		Epoch int    `json:"epoch"`
		Time  string `json:"time"`
	} `json:"buckets"`
	Owner string `json:"owner"`
}

type Summary struct {
	Categories []struct {
		BytesReceived int    `json:"bytes_received"`
		BytesSent     int    `json:"bytes_sent"`
		Category      string `json:"category"`
		Ops           int    `json:"ops"`
		SuccessfulOps int    `json:"successful_ops"`
	} `json:"categories"`
	Total struct {
		BytesReceived int `json:"bytes_received"`
		BytesSent     int `json:"bytes_sent"`
		Ops           int `json:"ops"`
		SuccessfulOps int `json:"successful_ops"`
	} `json:"total"`
	User string `json:"user"`
}

// Usage represents the response of usage requests
type Usage struct {
	Entries []Entry   `json:"entries"`
	Summary []Summary `json:"summary"`
}

// SubUsers represents the response of subuser requests
type SubUsers []struct {
	ID          string `json:"id"`
	Permissions string `json:"permissions"`
}

// KeysDefinition represents the response of key requests
type KeysDefinition []struct {
	AccessKey string `json:"access_key,omitempty"`
	SecretKey string `json:"secret_key"`
	User      string `json:"user"`
}

// User represents the response of user requests
type User struct {
	Caps        []Capability   `json:"caps"`
	DisplayName string         `json:"display_name"`
	Email       string         `json:"email"`
	Keys        KeysDefinition `json:"keys"`
	MaxBuckets  int            `json:"max_buckets"`
	Subusers    SubUsers       `json:"subusers"`
	Suspended   int            `json:"suspended"`
	SwiftKeys   KeysDefinition `json:"swift_keys"`
	UserID      string         `json:"user_id"`
}

type Stats struct {
	Bucket      string `json:"bucket"`
	BucketQuota struct {
		Enabled    bool `json:"enabled"`
		MaxObjects int  `json:"max_objects"`
		MaxSizeKb  int  `json:"max_size_kb"`
	} `json:"bucket_quota"`
	ID        string `json:"id"`
	IndexPool string `json:"index_pool"`
	Marker    string `json:"marker"`
	MasterVer string `json:"master_ver"`
	MaxMarker string `json:"max_marker"`
	Mtime     string `json:"mtime"`
	Owner     string `json:"owner"`
	Pool      string `json:"pool"`
	Usage     struct {
		RgwMain struct {
			NumObjects   int `json:"num_objects"`
			SizeKb       int `json:"size_kb"`
			SizeKbActual int `json:"size_kb_actual"`
		} `json:"rgw.main"`
	} `json:"usage"`
	Ver string `json:"ver"`
}

type Bucket struct {
	Name  string `json:"name,omitempty"`
	Stats *Stats `json:"stats,omitempty"`
}

// Buckets represents the response of bucket requests
type Buckets []Bucket

// Policy represents the response of policy requests
type Policy struct {
	Acl struct {
		AclGroupMap []struct {
			Acl   int `json:"acl"`
			Group int `json:"group"`
		} `json:"acl_group_map"`
		AclUserMap []struct {
			Acl  int    `json:"acl"`
			User string `json:"user"`
		} `json:"acl_user_map"`
		GrantMap []struct {
			Grant struct {
				Email      string `json:"email"`
				Group      int    `json:"group"`
				ID         string `json:"id"`
				Name       string `json:"name"`
				Permission struct {
					Flags int `json:"flags"`
				} `json:"permission"`
				Type struct {
					Type int `json:"type"`
				} `json:"type"`
			} `json:"grant"`
			ID string `json:"id"`
		} `json:"grant_map"`
	} `json:"acl"`
	Owner struct {
		DisplayName string `json:"display_name"`
		ID          string `json:"id"`
	} `json:"owner"`
}

// Quotas represents the reponse of quotas requests
type Quotas struct {
	BucketQuota struct {
		Enabled    bool `json:"enabled"`
		MaxObjects int  `json:"max_objects"`
		MaxSizeKb  int  `json:"max_size_kb"`
	} `json:"bucket_quota"`
	UserQuota struct {
		Enabled    bool `json:"enabled"`
		MaxObjects int  `json:"max_objects"`
		MaxSizeKb  int  `json:"max_size_kb"`
	} `json:"user_quota"`
}

// Capability represents the reponse of capability requests
type Capability struct {
	Perm string `json:"perm"`
	Type string `json:"type"`
}
<commit_msg>Add the ZoneGroup field to the bucket stats<commit_after>package radosAPI

type apiError struct {
	Code string `json:"Code"`
}

type Entry struct {
	Buckets []struct {
		Bucket     string `json:"bucket"`
		Categories []struct {
			BytesReceived int    `json:"bytes_received"`
			BytesSent     int    `json:"bytes_sent"`
			Category      string `json:"category"`
			Ops           int    `json:"ops"`
			SuccessfulOps int    `json:"successful_ops"`
		} `json:"categories"`
		Epoch int    `json:"epoch"`
		Time  string `json:"time"`
	} `json:"buckets"`
	Owner string `json:"owner"`
}

type Summary struct {
	Categories []struct {
		BytesReceived int    `json:"bytes_received"`
		BytesSent     int    `json:"bytes_sent"`
		Category      string `json:"category"`
		Ops           int    `json:"ops"`
		SuccessfulOps int    `json:"successful_ops"`
	} `json:"categories"`
	Total struct {
		BytesReceived int `json:"bytes_received"`
		BytesSent     int `json:"bytes_sent"`
		Ops           int `json:"ops"`
		SuccessfulOps int `json:"successful_ops"`
	} `json:"total"`
	User string `json:"user"`
}

// Usage represents the response of usage requests
type Usage struct {
	Entries []Entry   `json:"entries"`
	Summary []Summary `json:"summary"`
}

// SubUsers represents the response of subuser requests
type SubUsers []struct {
	ID          string `json:"id"`
	Permissions string `json:"permissions"`
}

// KeysDefinition represents the response of key requests
type KeysDefinition []struct {
	AccessKey string `json:"access_key,omitempty"`
	SecretKey string `json:"secret_key"`
	User      string `json:"user"`
}

// User represents the response of user requests
type User struct {
	Caps        []Capability   `json:"caps"`
	DisplayName string         `json:"display_name"`
	Email       string         `json:"email"`
	Keys        KeysDefinition `json:"keys"`
	MaxBuckets  int            `json:"max_buckets"`
	Subusers    SubUsers       `json:"subusers"`
	Suspended   int            `json:"suspended"`
	SwiftKeys   KeysDefinition `json:"swift_keys"`
	UserID      string         `json:"user_id"`
}

type Stats struct {
	Bucket      string `json:"bucket"`
	BucketQuota struct {
		Enabled    bool `json:"enabled"`
		MaxObjects int  `json:"max_objects"`
		MaxSizeKb  int  `json:"max_size_kb"`
	} `json:"bucket_quota"`
	ID        string `json:"id"`
	IndexPool string `json:"index_pool"`
	Marker    string `json:"marker"`
	MasterVer string `json:"master_ver"`
	MaxMarker string `json:"max_marker"`
	Mtime     string `json:"mtime"`
	Owner     string `json:"owner"`
	Pool      string `json:"pool"`
	Usage     struct {
		RgwMain struct {
			NumObjects   int `json:"num_objects"`
			SizeKb       int `json:"size_kb"`
			SizeKbActual int `json:"size_kb_actual"`
		} `json:"rgw.main"`
	} `json:"usage"`
	Ver string `json:"ver"`
	ZoneGroup string `json:"zonegroup"`
}

type Bucket struct {
	Name  string `json:"name,omitempty"`
	Stats *Stats `json:"stats,omitempty"`
}

// Buckets represents the response of bucket requests
type Buckets []Bucket

// Policy represents the response of policy requests
type Policy struct {
	Acl struct {
		AclGroupMap []struct {
			Acl   int `json:"acl"`
			Group int `json:"group"`
		} `json:"acl_group_map"`
		AclUserMap []struct {
			Acl  int    `json:"acl"`
			User string `json:"user"`
		} `json:"acl_user_map"`
		GrantMap []struct {
			Grant struct {
				Email      string `json:"email"`
				Group      int    `json:"group"`
				ID         string `json:"id"`
				Name       string `json:"name"`
				Permission struct {
					Flags int `json:"flags"`
				} `json:"permission"`
				Type struct {
					Type int `json:"type"`
				} `json:"type"`
			} `json:"grant"`
			ID string `json:"id"`
		} `json:"grant_map"`
	} `json:"acl"`
	Owner struct {
		DisplayName string `json:"display_name"`
		ID          string `json:"id"`
	} `json:"owner"`
}

// Quotas represents the reponse of quotas requests
type Quotas struct {
	BucketQuota struct {
		Enabled    bool `json:"enabled"`
		MaxObjects int  `json:"max_objects"`
		MaxSizeKb  int  `json:"max_size_kb"`
	} `json:"bucket_quota"`
	UserQuota struct {
		Enabled    bool `json:"enabled"`
		MaxObjects int  `json:"max_objects"`
		MaxSizeKb  int  `json:"max_size_kb"`
	} `json:"user_quota"`
}

// Capability represents the reponse of capability requests
type Capability struct {
	Perm string `json:"perm"`
	Type string `json:"type"`
}
<|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 rest

import (
	"io"
	"net/http"
	"net/url"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/watch"
)

//TODO:
// Storage interfaces need to be separated into two groups; those that operate
// on collections and those that operate on individually named items.
// Collection interfaces:
// (Method: Current -> Proposed)
//    GET: Lister -> CollectionGetter
//    WATCH: Watcher -> CollectionWatcher
//    CREATE: Creater -> CollectionCreater
//    DELETE: (n/a) -> CollectionDeleter
//    UPDATE: (n/a) -> CollectionUpdater
//
// Single item interfaces:
// (Method: Current -> Proposed)
//    GET: Getter -> NamedGetter
//    WATCH: (n/a) -> NamedWatcher
//    CREATE: (n/a) -> NamedCreater
//    DELETE: Deleter -> NamedDeleter
//    UPDATE: Update -> NamedUpdater

// Storage is a generic interface for RESTful storage services.
// Resources which are exported to the RESTful API of apiserver need to implement this interface. It is expected
// that objects may implement any of the below interfaces.
type Storage interface {
	// New returns an empty object that can be used with Create and Update after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object
}

// Lister is an object that can retrieve resources that match the provided field and label criteria.
type Lister interface {
	// NewList returns an empty object that can be used with the List call.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	NewList() runtime.Object
	// List selects resources in the storage which match to the selector.
	List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error)
}

// Getter is an object that can retrieve a named RESTful resource.
type Getter interface {
	// Get finds a resource in the storage by name and returns it.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	Get(ctx api.Context, name string) (runtime.Object, error)
}

// GetterWithOptions is an object that retrieve a named RESTful resource and takes
// additional options on the get request. It allows a caller to also receive the
// subpath of the GET request.
type GetterWithOptions interface {
	// Get finds a resource in the storage by name and returns it.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	// The options object passed to it is of the same type returned by the NewGetOptions
	// method.
	Get(ctx api.Context, name string, options runtime.Object) (runtime.Object, error)

	// NewGetOptions returns an empty options object that will be used to pass
	// options to the Get method. It may return a bool and a string, if true, the
	// value of the request path below the object will be included as the named
	// string in the serialization of the runtime object. E.g., returning "path"
	// will convert the trailing request scheme value to "path" in the map[string][]string
	// passed to the convertor.
	NewGetOptions() (runtime.Object, bool, string)
}

// Deleter is an object that can delete a named RESTful resource.
type Deleter interface {
	// Delete finds a resource in the storage and deletes it.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	// Delete *may* return the object that was deleted, or a status object indicating additional
	// information about deletion.
	Delete(ctx api.Context, name string) (runtime.Object, error)
}

// GracefulDeleter knows how to pass deletion options to allow delayed deletion of a
// RESTful object.
type GracefulDeleter interface {
	// Delete finds a resource in the storage and deletes it.
	// If options are provided, the resource will attempt to honor them or return an invalid
	// request error.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	// Delete *may* return the object that was deleted, or a status object indicating additional
	// information about deletion.
	Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error)
}

// GracefulDeleteAdapter adapts the Deleter interface to GracefulDeleter
type GracefulDeleteAdapter struct {
	Deleter
}

// Delete implements RESTGracefulDeleter in terms of Deleter
func (w GracefulDeleteAdapter) Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error) {
	return w.Deleter.Delete(ctx, name)
}

// Creater is an object that can create an instance of a RESTful object.
type Creater interface {
	// New returns an empty object that can be used with Create after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object

	// Create creates a new version of a resource.
	Create(ctx api.Context, obj runtime.Object) (runtime.Object, error)
}

// NamedCreater is an object that can create an instance of a RESTful object using a name parameter.
type NamedCreater interface {
	// New returns an empty object that can be used with Create after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object

	// Create creates a new version of a resource. It expects a name parameter from the path.
	// This is needed for create operations on subresources which include the name of the parent
	// resource in the path.
	Create(ctx api.Context, name string, obj runtime.Object) (runtime.Object, error)
}

// Updater is an object that can update an instance of a RESTful object.
type Updater interface {
	// New returns an empty object that can be used with Update after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object

	// Update finds a resource in the storage and updates it. Some implementations
	// may allow updates creates the object - they should set the created boolean
	// to true.
	Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
}

// CreaterUpdater is a storage object that must support both create and update.
// Go prevents embedded interfaces that implement the same method.
type CreaterUpdater interface {
	Creater
	Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
}

// CreaterUpdater must satisfy the Updater interface.
var _ Updater = CreaterUpdater(nil)

// Patcher is a storage object that supports both get and update.
type Patcher interface {
	Getter
	Updater
}

// Watcher should be implemented by all Storage objects that
// want to offer the ability to watch for changes through the watch api.
type Watcher interface {
	// 'label' selects on labels; 'field' selects on the object's fields. Not all fields
	// are supported; an error should be returned if 'field' tries to select on a field that
	// isn't supported. 'resourceVersion' allows for continuing/starting a watch at a
	// particular version.
	Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
}

// StandardStorage is an interface covering the common verbs. Provided for testing whether a
// resource satisfies the normal storage methods. Use Storage when passing opaque storage objects.
type StandardStorage interface {
	Getter
	Lister
	CreaterUpdater
	GracefulDeleter
	Watcher
}

// Redirector know how to return a remote resource's location.
type Redirector interface {
	// ResourceLocation should return the remote location of the given resource, and an optional transport to use to request it, or an error.
	ResourceLocation(ctx api.Context, id string) (remoteLocation *url.URL, transport http.RoundTripper, err error)
}

// ConnectHandler is a handler for HTTP connection requests. It extends the standard
// http.Handler interface by adding a method that returns an error object if an error
// occurred during the handling of the request.
type ConnectHandler interface {
	http.Handler

	// RequestError returns an error if one occurred during handling of an HTTP request
	RequestError() error
}

// Connecter is a storage object that responds to a connection request
type Connecter interface {
	// Connect returns a ConnectHandler that will handle the request/response for a request
	Connect(ctx api.Context, id string, options runtime.Object) (ConnectHandler, error)

	// NewConnectOptions returns an empty options object that will be used to pass
	// options to the Connect method. If nil, then a nil options object is passed to
	// Connect. It may return a bool and a string. If true, the value of the request
	// path below the object will be included as the named string in the serialization
	// of the runtime object.
	NewConnectOptions() (runtime.Object, bool, string)

	// ConnectMethods returns the list of HTTP methods handled by Connect
	ConnectMethods() []string
}

// ResourceStreamer is an interface implemented by objects that prefer to be streamed from the server
// instead of decoded directly.
type ResourceStreamer interface {
	// InputStream should return an io.ReadCloser if the provided object supports streaming. The desired
	// api version and a accept header (may be empty) are passed to the call. If no error occurs,
	// the caller may return a flag indicating whether the result should be flushed as writes occur
	// and a content type string that indicates the type of the stream.
	// If a null stream is returned, a StatusNoContent response wil be generated.
	InputStream(apiVersion, acceptHeader string) (stream io.ReadCloser, flush bool, mimeType string, err error)
}

// StorageMetadata is an optional interface that callers can implement to provide additional
// information about their Storage objects.
type StorageMetadata interface {
	// ProducesMIMETypes returns a list of the MIME types the specified HTTP verb (GET, POST, DELETE,
	// PATCH) can respond with.
	ProducesMIMETypes(verb string) []string
}

// ConnectRequest is an object passed to admission control for Connect operations
type ConnectRequest struct {
	// Name is the name of the object on which the connect request was made
	Name string

	// Options is the options object passed to the connect request. See the NewConnectOptions method on Connecter
	Options runtime.Object

	// ResourcePath is the path for the resource in the REST server (ie. "pods/proxy")
	ResourcePath string
}

// IsAnAPIObject makes ConnectRequest a runtime.Object
func (*ConnectRequest) IsAnAPIObject() {}
<commit_msg>Connect should be passed a Responder interface<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 rest

import (
	"io"
	"net/http"
	"net/url"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/watch"
)

//TODO:
// Storage interfaces need to be separated into two groups; those that operate
// on collections and those that operate on individually named items.
// Collection interfaces:
// (Method: Current -> Proposed)
//    GET: Lister -> CollectionGetter
//    WATCH: Watcher -> CollectionWatcher
//    CREATE: Creater -> CollectionCreater
//    DELETE: (n/a) -> CollectionDeleter
//    UPDATE: (n/a) -> CollectionUpdater
//
// Single item interfaces:
// (Method: Current -> Proposed)
//    GET: Getter -> NamedGetter
//    WATCH: (n/a) -> NamedWatcher
//    CREATE: (n/a) -> NamedCreater
//    DELETE: Deleter -> NamedDeleter
//    UPDATE: Update -> NamedUpdater

// Storage is a generic interface for RESTful storage services.
// Resources which are exported to the RESTful API of apiserver need to implement this interface. It is expected
// that objects may implement any of the below interfaces.
type Storage interface {
	// New returns an empty object that can be used with Create and Update after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object
}

// Lister is an object that can retrieve resources that match the provided field and label criteria.
type Lister interface {
	// NewList returns an empty object that can be used with the List call.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	NewList() runtime.Object
	// List selects resources in the storage which match to the selector.
	List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error)
}

// Getter is an object that can retrieve a named RESTful resource.
type Getter interface {
	// Get finds a resource in the storage by name and returns it.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	Get(ctx api.Context, name string) (runtime.Object, error)
}

// GetterWithOptions is an object that retrieve a named RESTful resource and takes
// additional options on the get request. It allows a caller to also receive the
// subpath of the GET request.
type GetterWithOptions interface {
	// Get finds a resource in the storage by name and returns it.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	// The options object passed to it is of the same type returned by the NewGetOptions
	// method.
	Get(ctx api.Context, name string, options runtime.Object) (runtime.Object, error)

	// NewGetOptions returns an empty options object that will be used to pass
	// options to the Get method. It may return a bool and a string, if true, the
	// value of the request path below the object will be included as the named
	// string in the serialization of the runtime object. E.g., returning "path"
	// will convert the trailing request scheme value to "path" in the map[string][]string
	// passed to the convertor.
	NewGetOptions() (runtime.Object, bool, string)
}

// Deleter is an object that can delete a named RESTful resource.
type Deleter interface {
	// Delete finds a resource in the storage and deletes it.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	// Delete *may* return the object that was deleted, or a status object indicating additional
	// information about deletion.
	Delete(ctx api.Context, name string) (runtime.Object, error)
}

// GracefulDeleter knows how to pass deletion options to allow delayed deletion of a
// RESTful object.
type GracefulDeleter interface {
	// Delete finds a resource in the storage and deletes it.
	// If options are provided, the resource will attempt to honor them or return an invalid
	// request error.
	// Although it can return an arbitrary error value, IsNotFound(err) is true for the
	// returned error value err when the specified resource is not found.
	// Delete *may* return the object that was deleted, or a status object indicating additional
	// information about deletion.
	Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error)
}

// GracefulDeleteAdapter adapts the Deleter interface to GracefulDeleter
type GracefulDeleteAdapter struct {
	Deleter
}

// Delete implements RESTGracefulDeleter in terms of Deleter
func (w GracefulDeleteAdapter) Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error) {
	return w.Deleter.Delete(ctx, name)
}

// Creater is an object that can create an instance of a RESTful object.
type Creater interface {
	// New returns an empty object that can be used with Create after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object

	// Create creates a new version of a resource.
	Create(ctx api.Context, obj runtime.Object) (runtime.Object, error)
}

// NamedCreater is an object that can create an instance of a RESTful object using a name parameter.
type NamedCreater interface {
	// New returns an empty object that can be used with Create after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object

	// Create creates a new version of a resource. It expects a name parameter from the path.
	// This is needed for create operations on subresources which include the name of the parent
	// resource in the path.
	Create(ctx api.Context, name string, obj runtime.Object) (runtime.Object, error)
}

// Updater is an object that can update an instance of a RESTful object.
type Updater interface {
	// New returns an empty object that can be used with Update after request data has been put into it.
	// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
	New() runtime.Object

	// Update finds a resource in the storage and updates it. Some implementations
	// may allow updates creates the object - they should set the created boolean
	// to true.
	Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
}

// CreaterUpdater is a storage object that must support both create and update.
// Go prevents embedded interfaces that implement the same method.
type CreaterUpdater interface {
	Creater
	Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
}

// CreaterUpdater must satisfy the Updater interface.
var _ Updater = CreaterUpdater(nil)

// Patcher is a storage object that supports both get and update.
type Patcher interface {
	Getter
	Updater
}

// Watcher should be implemented by all Storage objects that
// want to offer the ability to watch for changes through the watch api.
type Watcher interface {
	// 'label' selects on labels; 'field' selects on the object's fields. Not all fields
	// are supported; an error should be returned if 'field' tries to select on a field that
	// isn't supported. 'resourceVersion' allows for continuing/starting a watch at a
	// particular version.
	Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
}

// StandardStorage is an interface covering the common verbs. Provided for testing whether a
// resource satisfies the normal storage methods. Use Storage when passing opaque storage objects.
type StandardStorage interface {
	Getter
	Lister
	CreaterUpdater
	GracefulDeleter
	Watcher
}

// Redirector know how to return a remote resource's location.
type Redirector interface {
	// ResourceLocation should return the remote location of the given resource, and an optional transport to use to request it, or an error.
	ResourceLocation(ctx api.Context, id string) (remoteLocation *url.URL, transport http.RoundTripper, err error)
}

// Responder abstracts the normal response behavior for a REST method and is passed to callers that
// may wish to handle the response directly in some cases, but delegate to the normal error or object
// behavior in other cases.
type Responder interface {
	// Object writes the provided object to the response. Invoking this method multiple times is undefined.
	Object(statusCode int, obj runtime.Object)
	// Error writes the provided error to the response. This method may only be invoked once.
	Error(err error)
}

// Connecter is a storage object that responds to a connection request.
type Connecter interface {
	// Connect returns an http.Handler that will handle the request/response for a given API invocation.
	// The provided responder may be used for common API responses. The responder will write both status
	// code and body, so the ServeHTTP method should exit after invoking the responder. The Handler will
	// be used for a single API request and then discarded. The Responder is guaranteed to write to the
	// same http.ResponseWriter passed to ServeHTTP.
	Connect(ctx api.Context, id string, options runtime.Object, r Responder) (http.Handler, error)

	// NewConnectOptions returns an empty options object that will be used to pass
	// options to the Connect method. If nil, then a nil options object is passed to
	// Connect. It may return a bool and a string. If true, the value of the request
	// path below the object will be included as the named string in the serialization
	// of the runtime object.
	NewConnectOptions() (runtime.Object, bool, string)

	// ConnectMethods returns the list of HTTP methods handled by Connect
	ConnectMethods() []string
}

// ResourceStreamer is an interface implemented by objects that prefer to be streamed from the server
// instead of decoded directly.
type ResourceStreamer interface {
	// InputStream should return an io.ReadCloser if the provided object supports streaming. The desired
	// api version and a accept header (may be empty) are passed to the call. If no error occurs,
	// the caller may return a flag indicating whether the result should be flushed as writes occur
	// and a content type string that indicates the type of the stream.
	// If a null stream is returned, a StatusNoContent response wil be generated.
	InputStream(apiVersion, acceptHeader string) (stream io.ReadCloser, flush bool, mimeType string, err error)
}

// StorageMetadata is an optional interface that callers can implement to provide additional
// information about their Storage objects.
type StorageMetadata interface {
	// ProducesMIMETypes returns a list of the MIME types the specified HTTP verb (GET, POST, DELETE,
	// PATCH) can respond with.
	ProducesMIMETypes(verb string) []string
}

// ConnectRequest is an object passed to admission control for Connect operations
type ConnectRequest struct {
	// Name is the name of the object on which the connect request was made
	Name string

	// Options is the options object passed to the connect request. See the NewConnectOptions method on Connecter
	Options runtime.Object

	// ResourcePath is the path for the resource in the REST server (ie. "pods/proxy")
	ResourcePath string
}

// IsAnAPIObject makes ConnectRequest a runtime.Object
func (*ConnectRequest) IsAnAPIObject() {}
<|endoftext|>


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

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

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

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

package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	fancypath "path"
	"path/filepath"
	"strings"
	"time"

	"github.com/ghodss/yaml"
	"github.com/kubernetes/helm/pkg/common"
)

// DefaultHTTPTimeout is the default HTTP timeout.
var DefaultHTTPTimeout = time.Second * 10

// DefaultHTTPProtocol is the default HTTP Protocol (http, https).
var DefaultHTTPProtocol = "http"

// Client is a DM client.
type Client struct {
	// Timeout on HTTP connections.
	HTTPTimeout time.Duration
	// The protocol. Currently only http and https are supported.
	Protocol string
	// Transport
	Transport http.RoundTripper
	// Debug enables http logging
	Debug bool

	// Base URL for remote service
	baseURL *url.URL
}

// NewClient creates a new DM client. Host name is required.
func NewClient(host string) *Client {
	url, _ := DefaultServerURL(host)

	return &Client{
		HTTPTimeout: DefaultHTTPTimeout,
		baseURL:     url,
		Transport:   http.DefaultTransport,
	}
}

// SetDebug enables debug mode which logs http
func (c *Client) SetDebug(enable bool) *Client {
	c.Debug = enable
	return c
}

// transport wraps client transport if debug is enabled
func (c *Client) transport() http.RoundTripper {
	if c.Debug {
		return NewDebugTransport(c.Transport)
	}
	return c.Transport
}

// SetTransport sets a custom Transport. Defaults to http.DefaultTransport
func (c *Client) SetTransport(tr http.RoundTripper) *Client {
	c.Transport = tr
	return c
}

// SetTimeout sets a timeout for http connections
func (c *Client) SetTimeout(seconds int) *Client {
	c.HTTPTimeout = time.Duration(time.Duration(seconds) * time.Second)
	return c
}

// url constructs the URL.
func (c *Client) url(rawurl string) (string, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return "", err
	}
	return c.baseURL.ResolveReference(u).String(), nil
}

func (c *Client) agent() string {
	return fmt.Sprintf("helm/%s", "0.0.1")
}

// CallService is a low-level function for making an API call.
//
// This calls the service and then unmarshals the returned data into dest.
func (c *Client) CallService(path, method, action string, dest interface{}, reader io.Reader) error {
	u, err := c.url(path)
	if err != nil {
		return err
	}

	resp, err := c.callHTTP(u, method, action, reader)
	if err != nil {
		return err
	}
	if err := json.Unmarshal([]byte(resp), dest); err != nil {
		return fmt.Errorf("Failed to parse JSON response from service: %s", resp)
	}
	return nil
}

// callHTTP is  a low-level primitive for executing HTTP operations.
func (c *Client) callHTTP(path, method, action string, reader io.Reader) (string, error) {
	request, err := http.NewRequest(method, path, reader)

	// TODO: dynamically set version
	request.Header.Set("User-Agent", c.agent())
	request.Header.Add("Content-Type", "application/json")

	client := &http.Client{
		Timeout:   c.HTTPTimeout,
		Transport: c.transport(),
	}

	response, err := client.Do(request)
	if err != nil {
		return "", err
	}

	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}

	s := response.StatusCode
	if s < http.StatusOK || s >= http.StatusMultipleChoices {
		return "", &HTTPError{StatusCode: s, Message: string(body), URL: request.URL}
	}

	return string(body), nil
}

// DefaultServerURL converts a host, host:port, or URL string to the default base server API path
// to use with a Client
func DefaultServerURL(host string) (*url.URL, error) {
	if host == "" {
		return nil, fmt.Errorf("host must be a URL or a host:port pair")
	}
	base := host
	hostURL, err := url.Parse(base)
	if err != nil {
		return nil, err
	}
	if hostURL.Scheme == "" {
		hostURL, err = url.Parse(DefaultHTTPProtocol + "://" + base)
		if err != nil {
			return nil, err
		}
	}
	if len(hostURL.Path) > 0 && !strings.HasSuffix(hostURL.Path, "/") {
		hostURL.Path = hostURL.Path + "/"
	}

	return hostURL, nil
}

// ListDeployments lists the deployments in DM.
func (c *Client) ListDeployments() ([]string, error) {
	var l []string
	if err := c.CallService("deployments", "GET", "list deployments", &l, nil); err != nil {
		return nil, err
	}

	return l, nil
}

// PostChart sends a chart to DM for deploying.
//
// This returns the location for the new chart, typically of the form
// `helm:repo/bucket/name-version.tgz`.
func (c *Client) PostChart(filename, deployname string) (string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return "", err
	}

	u, err := c.url("/v2/charts")
	request, err := http.NewRequest("POST", u, f)
	if err != nil {
		f.Close()
		return "", err
	}

	// There is an argument to be made for using the legacy x-octet-stream for
	// this. But since we control both sides, we should use the standard one.
	// Also, gzip (x-compress) is usually treated as a content encoding. In this
	// case it probably is not, but it makes more sense to follow the standard,
	// even though we don't assume the remote server will strip it off.
	request.Header.Add("Content-Type", "application/x-tar")
	request.Header.Add("Content-Encoding", "gzip")
	request.Header.Add("X-Deployment-Name", deployname)
	request.Header.Add("X-Chart-Name", filepath.Base(filename))
	request.Header.Set("User-Agent", c.agent())

	client := &http.Client{
		Timeout:   c.HTTPTimeout,
		Transport: c.transport(),
	}

	response, err := client.Do(request)
	if err != nil {
		return "", err
	}

	// We only want 201 CREATED. Admittedly, we could accept 200 and 202.
	if response.StatusCode != http.StatusCreated {
		body, err := ioutil.ReadAll(response.Body)
		response.Body.Close()
		if err != nil {
			return "", err
		}
		return "", &HTTPError{StatusCode: response.StatusCode, Message: string(body), URL: request.URL}
	}

	loc := response.Header.Get("Location")
	return loc, nil
}

// HTTPError is an error caused by an unexpected HTTP status code.
//
// The StatusCode will not necessarily be a 4xx or 5xx. Any unexpected code
// may be returned.
type HTTPError struct {
	StatusCode int
	Message    string
	URL        *url.URL
}

// Error implements the error interface.
func (e *HTTPError) Error() string {
	return e.Message
}

// String implmenets the io.Stringer interface.
func (e *HTTPError) String() string {
	return e.Error()
}

// GetDeployment retrieves the supplied deployment
func (c *Client) GetDeployment(name string) (*common.Deployment, error) {
	var deployment *common.Deployment
	if err := c.CallService(fancypath.Join("deployments", name), "GET", "get deployment", &deployment, nil); err != nil {
		return nil, err
	}
	return deployment, nil
}

// DeleteDeployment deletes the supplied deployment
func (c *Client) DeleteDeployment(name string) (*common.Deployment, error) {
	var deployment *common.Deployment
	if err := c.CallService(filepath.Join("deployments", name), "DELETE", "delete deployment", &deployment, nil); err != nil {
		return nil, err
	}
	return deployment, nil
}

// PostDeployment posts a deployment object to the manager service.
func (c *Client) PostDeployment(name string, cfg *common.Configuration) error {
	d, err := yaml.Marshal(cfg)
	if err != nil {
		return err
	}
	// This is a stop-gap until we get this API cleaned up.
	t := common.Template{
		Name:    name,
		Content: string(d),
	}

	data, err := json.Marshal(t)
	if err != nil {
		return err
	}

	var out struct{}

	b := bytes.NewBuffer(data)
	return c.CallService("/deployments", "POST", "post deployment", &out, b)
}
<commit_msg>fix(client): remove unused Protocol from client<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	fancypath "path"
	"path/filepath"
	"strings"
	"time"

	"github.com/ghodss/yaml"
	"github.com/kubernetes/helm/pkg/common"
)

// DefaultHTTPTimeout is the default HTTP timeout.
var DefaultHTTPTimeout = time.Second * 10

// DefaultHTTPProtocol is the default HTTP Protocol (http, https).
var DefaultHTTPProtocol = "http"

// Client is a DM client.
type Client struct {
	// Timeout on HTTP connections.
	HTTPTimeout time.Duration
	// Transport
	Transport http.RoundTripper
	// Debug enables http logging
	Debug bool

	// Base URL for remote service
	baseURL *url.URL
}

// NewClient creates a new DM client. Host name is required.
func NewClient(host string) *Client {
	url, _ := DefaultServerURL(host)

	return &Client{
		HTTPTimeout: DefaultHTTPTimeout,
		baseURL:     url,
		Transport:   http.DefaultTransport,
	}
}

// SetDebug enables debug mode which logs http
func (c *Client) SetDebug(enable bool) *Client {
	c.Debug = enable
	return c
}

// transport wraps client transport if debug is enabled
func (c *Client) transport() http.RoundTripper {
	if c.Debug {
		return NewDebugTransport(c.Transport)
	}
	return c.Transport
}

// SetTransport sets a custom Transport. Defaults to http.DefaultTransport
func (c *Client) SetTransport(tr http.RoundTripper) *Client {
	c.Transport = tr
	return c
}

// SetTimeout sets a timeout for http connections
func (c *Client) SetTimeout(seconds int) *Client {
	c.HTTPTimeout = time.Duration(time.Duration(seconds) * time.Second)
	return c
}

// url constructs the URL.
func (c *Client) url(rawurl string) (string, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return "", err
	}
	return c.baseURL.ResolveReference(u).String(), nil
}

func (c *Client) agent() string {
	return fmt.Sprintf("helm/%s", "0.0.1")
}

// CallService is a low-level function for making an API call.
//
// This calls the service and then unmarshals the returned data into dest.
func (c *Client) CallService(path, method, action string, dest interface{}, reader io.Reader) error {
	u, err := c.url(path)
	if err != nil {
		return err
	}

	resp, err := c.callHTTP(u, method, action, reader)
	if err != nil {
		return err
	}
	if err := json.Unmarshal([]byte(resp), dest); err != nil {
		return fmt.Errorf("Failed to parse JSON response from service: %s", resp)
	}
	return nil
}

// callHTTP is  a low-level primitive for executing HTTP operations.
func (c *Client) callHTTP(path, method, action string, reader io.Reader) (string, error) {
	request, err := http.NewRequest(method, path, reader)

	// TODO: dynamically set version
	request.Header.Set("User-Agent", c.agent())
	request.Header.Add("Content-Type", "application/json")

	client := &http.Client{
		Timeout:   c.HTTPTimeout,
		Transport: c.transport(),
	}

	response, err := client.Do(request)
	if err != nil {
		return "", err
	}

	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}

	s := response.StatusCode
	if s < http.StatusOK || s >= http.StatusMultipleChoices {
		return "", &HTTPError{StatusCode: s, Message: string(body), URL: request.URL}
	}

	return string(body), nil
}

// DefaultServerURL converts a host, host:port, or URL string to the default base server API path
// to use with a Client
func DefaultServerURL(host string) (*url.URL, error) {
	if host == "" {
		return nil, fmt.Errorf("host must be a URL or a host:port pair")
	}
	base := host
	hostURL, err := url.Parse(base)
	if err != nil {
		return nil, err
	}
	if hostURL.Scheme == "" {
		hostURL, err = url.Parse(DefaultHTTPProtocol + "://" + base)
		if err != nil {
			return nil, err
		}
	}
	if len(hostURL.Path) > 0 && !strings.HasSuffix(hostURL.Path, "/") {
		hostURL.Path = hostURL.Path + "/"
	}

	return hostURL, nil
}

// ListDeployments lists the deployments in DM.
func (c *Client) ListDeployments() ([]string, error) {
	var l []string
	if err := c.CallService("deployments", "GET", "list deployments", &l, nil); err != nil {
		return nil, err
	}

	return l, nil
}

// PostChart sends a chart to DM for deploying.
//
// This returns the location for the new chart, typically of the form
// `helm:repo/bucket/name-version.tgz`.
func (c *Client) PostChart(filename, deployname string) (string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return "", err
	}

	u, err := c.url("/v2/charts")
	request, err := http.NewRequest("POST", u, f)
	if err != nil {
		f.Close()
		return "", err
	}

	// There is an argument to be made for using the legacy x-octet-stream for
	// this. But since we control both sides, we should use the standard one.
	// Also, gzip (x-compress) is usually treated as a content encoding. In this
	// case it probably is not, but it makes more sense to follow the standard,
	// even though we don't assume the remote server will strip it off.
	request.Header.Add("Content-Type", "application/x-tar")
	request.Header.Add("Content-Encoding", "gzip")
	request.Header.Add("X-Deployment-Name", deployname)
	request.Header.Add("X-Chart-Name", filepath.Base(filename))
	request.Header.Set("User-Agent", c.agent())

	client := &http.Client{
		Timeout:   c.HTTPTimeout,
		Transport: c.transport(),
	}

	response, err := client.Do(request)
	if err != nil {
		return "", err
	}

	// We only want 201 CREATED. Admittedly, we could accept 200 and 202.
	if response.StatusCode != http.StatusCreated {
		body, err := ioutil.ReadAll(response.Body)
		response.Body.Close()
		if err != nil {
			return "", err
		}
		return "", &HTTPError{StatusCode: response.StatusCode, Message: string(body), URL: request.URL}
	}

	loc := response.Header.Get("Location")
	return loc, nil
}

// HTTPError is an error caused by an unexpected HTTP status code.
//
// The StatusCode will not necessarily be a 4xx or 5xx. Any unexpected code
// may be returned.
type HTTPError struct {
	StatusCode int
	Message    string
	URL        *url.URL
}

// Error implements the error interface.
func (e *HTTPError) Error() string {
	return e.Message
}

// String implmenets the io.Stringer interface.
func (e *HTTPError) String() string {
	return e.Error()
}

// GetDeployment retrieves the supplied deployment
func (c *Client) GetDeployment(name string) (*common.Deployment, error) {
	var deployment *common.Deployment
	if err := c.CallService(fancypath.Join("deployments", name), "GET", "get deployment", &deployment, nil); err != nil {
		return nil, err
	}
	return deployment, nil
}

// DeleteDeployment deletes the supplied deployment
func (c *Client) DeleteDeployment(name string) (*common.Deployment, error) {
	var deployment *common.Deployment
	if err := c.CallService(filepath.Join("deployments", name), "DELETE", "delete deployment", &deployment, nil); err != nil {
		return nil, err
	}
	return deployment, nil
}

// PostDeployment posts a deployment object to the manager service.
func (c *Client) PostDeployment(name string, cfg *common.Configuration) error {
	d, err := yaml.Marshal(cfg)
	if err != nil {
		return err
	}
	// This is a stop-gap until we get this API cleaned up.
	t := common.Template{
		Name:    name,
		Content: string(d),
	}

	data, err := json.Marshal(t)
	if err != nil {
		return err
	}

	var out struct{}

	b := bytes.NewBuffer(data)
	return c.CallService("/deployments", "POST", "post deployment", &out, b)
}
<|endoftext|>


<commit_before>// Copyright 2017-2020 The Usacloud 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 config

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/sacloud/usacloud/pkg/util"

	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/profile"
	"github.com/sacloud/usacloud/pkg/define"
	"github.com/sacloud/usacloud/pkg/validation"
	"github.com/spf13/pflag"
)

// Config CLI全コマンドが利用するフラグ
type Config struct {
	profile.ConfigValue
	// Profile プロファイル名
	Profile string `json:"-"`
	// DefaultOutputType デフォルトアウトプットタイプ
	DefaultOutputType string
	// NoColor ANSIエスケープシーケンスによる色つけを無効化
	NoColor bool
}

// InitConfig 指定のFlagSetにConfigへ値を設定するためのフラグを登録する
func InitConfig(flags *pflag.FlagSet) {
	initCredentialConfig(flags)
	initOutputConfig(flags)
	initDebugConfig(flags)
}

// LoadConfigValue 指定のフラグセットからフラグを読み取り*Flagsを組み立てて返す
func LoadConfigValue(flags *pflag.FlagSet, errW io.Writer) (*Config, error) {
	o := &Config{}
	o.loadConfig(flags, errW)

	return o, util.FlattenErrors(o.Validate(true))
}

func initCredentialConfig(fs *pflag.FlagSet) {
	fs.StringP("profile", "", "default", "the name of saved credentials")
	fs.StringP("token", "", "", "the API token used when calling SAKURA Cloud API")
	fs.StringP("secret", "", "", "the API secret used when calling SAKURA Cloud API")
	fs.StringP("zone", "", "", "target zone name")
	fs.StringSliceP("zones", "", []string{}, "permitted zone names")
}

func initOutputConfig(fs *pflag.FlagSet) {
	fs.BoolP("no-color", "", false, "disable ANSI color output")
}

func initDebugConfig(fs *pflag.FlagSet) {
	fs.BoolP("trace", "", false, "enable trace logs for API calling")
	fs.BoolP("fake", "", false, "enable fake API driver")
	fs.StringP("fake-store", "", "", "path to file store used by the fake API driver")
}

func (o *Config) EnableHTTPTrace() bool {
	if o.TraceMode == "" {
		return false
	}

	// TraceModeが"api"の場合はfalseにする(TraceMode=1などの場合はAPI/HTTP両方が有効になる)
	if strings.ToLower(o.TraceMode) == "api" {
		return false
	}
	return true
}

func (o *Config) EnableAPITrace() bool {
	if o.TraceMode == "" {
		return false
	}

	// TraceModeが"http"の場合はfalseにする(TraceMode=1などの場合はAPI/HTTP両方が有効になる)
	if strings.ToLower(o.TraceMode) == "http" {
		return false
	}
	return true
}

func (o *Config) IsEmpty() bool {
	return o.AccessToken == "" &&
		o.AccessTokenSecret == "" &&
		o.Zone == "" && o.DefaultOutputType == ""
}

func (o *Config) loadConfig(flags *pflag.FlagSet, errW io.Writer) {
	o.loadFromEnv()
	o.loadFromProfile(errW)
	o.loadFromFlags(flags, errW)
	o.fillDefaults()
}

func (o *Config) fillDefaults() {
	if len(o.Zones) == 0 {
		o.Zones = sacloud.SakuraCloudZones
	}
}

func (o *Config) loadFromEnv() {
	o.Profile = stringFromEnv("SAKURACLOUD_PROFILE", "default")
	o.AccessToken = stringFromEnv("SAKURACLOUD_ACCESS_TOKEN", "")
	o.AccessTokenSecret = stringFromEnv("SAKURACLOUD_ACCESS_TOKEN_SECRET", "")
	o.Zone = stringFromEnv("SAKURACLOUD_ZONE", "is1a")
	o.Zones = stringSliceFromEnv("SAKURACLOUD_ZONES", sacloud.SakuraCloudZones)
	o.AcceptLanguage = stringFromEnv("SAKURACLOUD_ACCEPT_LANGUAGE", "")
	o.RetryMax = intFromEnv("SAKURACLOUD_RETRY_MAX", sacloud.APIDefaultRetryMax)
	o.RetryWaitMax = intFromEnv("SAKURACLOUD_RETRY_WAIT_MAX", 64)
	o.RetryWaitMin = intFromEnv("SAKURACLOUD_RETRY_WAIT_MIN", 1)
	o.HTTPRequestTimeout = intFromEnv("SAKURACLOUD_API_REQUEST_TIMEOUT", 300)
	o.HTTPRequestRateLimit = intFromEnv("SAKURACLOUD_API_REQUEST_RATE_LIMIT", 1)
	o.APIRootURL = stringFromEnv("SAKURACLOUD_API_ROOT_URL", sacloud.SakuraCloudAPIRoot)
	o.TraceMode = stringFromEnv("SAKURACLOUD_TRACE", "")
	o.FakeMode = os.Getenv("SAKURACLOUD_FAKE_MODE") != ""
	o.FakeStorePath = stringFromEnv("SAKURACLOUD_FAKE_STORE_PATH", "")
}

func (o *Config) loadFromProfile(errW io.Writer) {
	if o.Profile != "" {
		if err := profile.Load(o.Profile, o); err != nil {
			fmt.Fprintf(errW, "[WARN] loading profile %q is failed: %s", o.Profile, err) // nolint
			return
		}
	}
}

func (o *Config) loadFromFlags(flags *pflag.FlagSet, errW io.Writer) {
	if flags.Changed("token") {
		v, err := flags.GetString("token")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "token", err) // nolint
			return
		}
		o.AccessToken = v
	}
	if flags.Changed("secret") {
		v, err := flags.GetString("secret")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "secret", err) // nolint
			return
		}
		o.AccessTokenSecret = v
	}
	if flags.Changed("zone") {
		v, err := flags.GetString("zone")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "zone", err) // nolint
			return
		}
		o.Zone = v
	}
	if flags.Changed("zones") {
		v, err := flags.GetStringSlice("zones")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "zones", err) // nolint
			return
		}
		o.Zones = v
	}
	if flags.Changed("no-color") {
		v, err := flags.GetBool("no-color")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "no-color", err) // nolint
			return
		}
		o.NoColor = v
	}
	if flags.Changed("trace") {
		v, err := flags.GetBool("trace")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "trace", err) // nolint
			return
		}
		if v {
			o.TraceMode = "all"
		}
	}
	if flags.Changed("fake") {
		v, err := flags.GetBool("fake")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "fake", err) // nolint
			return
		}
		o.FakeMode = v
	}
	if flags.Changed("fake-store") {
		v, err := flags.GetString("fake-store")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "fake-store", err) // nolint
			return
		}
		o.FakeStorePath = v
	}
}

func stringFromEnv(key, defaultValue string) string {
	v := os.Getenv(key)
	if v == "" {
		return defaultValue
	}
	return v
}

func stringSliceFromEnv(key string, defaultValue []string) []string {
	v := os.Getenv(key)
	if v == "" {
		return defaultValue
	}
	values := strings.Split(v, ",")
	for i := range values {
		values[i] = strings.Trim(values[i], " ")
	}
	return values
}

func intFromEnv(key string, defaultValue int) int {
	v := os.Getenv(key)
	if v == "" {
		return defaultValue
	}
	i, err := strconv.ParseInt(v, 10, 64)
	if err != nil {
		return defaultValue
	}
	return int(i)
}

func (o *Config) Validate(skipCred bool) []error {
	var errs []error

	if !skipCred {
		errs = append(errs, validation.Required("token", o.AccessToken)...)
		errs = append(errs, validation.Required("secret", o.AccessTokenSecret)...)
		errs = append(errs, validation.Required("zone", o.Zone)...)
		errs = append(errs, validation.StringInSlice("zone", o.Zone, o.Zones)...)
	}
	errs = append(errs, validation.StringInSlice("default-output-type", o.DefaultOutputType, define.AllowOutputTypes)...)

	return errs
}
<commit_msg>Adjust some codes to libsacloud v2.8.8<commit_after>// Copyright 2017-2020 The Usacloud 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 config

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/sacloud/usacloud/pkg/util"

	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/profile"
	"github.com/sacloud/usacloud/pkg/define"
	"github.com/sacloud/usacloud/pkg/validation"
	"github.com/spf13/pflag"
)

// Config CLI全コマンドが利用するフラグ
type Config struct {
	profile.ConfigValue
	// Profile プロファイル名
	Profile string `json:"-"`
	// DefaultOutputType デフォルトアウトプットタイプ
	DefaultOutputType string
	// NoColor ANSIエスケープシーケンスによる色つけを無効化
	NoColor bool
}

// InitConfig 指定のFlagSetにConfigへ値を設定するためのフラグを登録する
func InitConfig(flags *pflag.FlagSet) {
	initCredentialConfig(flags)
	initOutputConfig(flags)
	initDebugConfig(flags)
}

// LoadConfigValue 指定のフラグセットからフラグを読み取り*Flagsを組み立てて返す
func LoadConfigValue(flags *pflag.FlagSet, errW io.Writer) (*Config, error) {
	o := &Config{}
	o.loadConfig(flags, errW)

	return o, util.FlattenErrors(o.Validate(true))
}

func initCredentialConfig(fs *pflag.FlagSet) {
	fs.StringP("profile", "", "default", "the name of saved credentials")
	fs.StringP("token", "", "", "the API token used when calling SAKURA Cloud API")
	fs.StringP("secret", "", "", "the API secret used when calling SAKURA Cloud API")
	fs.StringP("zone", "", "", "target zone name")
	fs.StringSliceP("zones", "", []string{}, "permitted zone names")
}

func initOutputConfig(fs *pflag.FlagSet) {
	fs.BoolP("no-color", "", false, "disable ANSI color output")
}

func initDebugConfig(fs *pflag.FlagSet) {
	fs.BoolP("trace", "", false, "enable trace logs for API calling")
	fs.BoolP("fake", "", false, "enable fake API driver")
	fs.StringP("fake-store", "", "", "path to file store used by the fake API driver")
}

func (o *Config) IsEmpty() bool {
	return o.AccessToken == "" &&
		o.AccessTokenSecret == "" &&
		o.Zone == "" && o.DefaultOutputType == ""
}

func (o *Config) loadConfig(flags *pflag.FlagSet, errW io.Writer) {
	o.loadFromEnv()
	o.loadFromProfile(errW)
	o.loadFromFlags(flags, errW)
	o.fillDefaults()
}

func (o *Config) fillDefaults() {
	if len(o.Zones) == 0 {
		o.Zones = sacloud.SakuraCloudZones
	}
}

func (o *Config) loadFromEnv() {
	o.Profile = stringFromEnv("SAKURACLOUD_PROFILE", "default")
	o.AccessToken = stringFromEnv("SAKURACLOUD_ACCESS_TOKEN", "")
	o.AccessTokenSecret = stringFromEnv("SAKURACLOUD_ACCESS_TOKEN_SECRET", "")
	o.Zone = stringFromEnv("SAKURACLOUD_ZONE", "is1a")
	o.Zones = stringSliceFromEnv("SAKURACLOUD_ZONES", sacloud.SakuraCloudZones)
	o.AcceptLanguage = stringFromEnv("SAKURACLOUD_ACCEPT_LANGUAGE", "")
	o.RetryMax = intFromEnv("SAKURACLOUD_RETRY_MAX", sacloud.APIDefaultRetryMax)
	o.RetryWaitMax = intFromEnv("SAKURACLOUD_RETRY_WAIT_MAX", 64)
	o.RetryWaitMin = intFromEnv("SAKURACLOUD_RETRY_WAIT_MIN", 1)
	o.HTTPRequestTimeout = intFromEnv("SAKURACLOUD_API_REQUEST_TIMEOUT", 300)
	o.HTTPRequestRateLimit = intFromEnv("SAKURACLOUD_API_REQUEST_RATE_LIMIT", 1)
	o.APIRootURL = stringFromEnv("SAKURACLOUD_API_ROOT_URL", sacloud.SakuraCloudAPIRoot)
	o.TraceMode = stringFromEnv("SAKURACLOUD_TRACE", "")
	o.FakeMode = os.Getenv("SAKURACLOUD_FAKE_MODE") != ""
	o.FakeStorePath = stringFromEnv("SAKURACLOUD_FAKE_STORE_PATH", "")
}

func (o *Config) loadFromProfile(errW io.Writer) {
	if o.Profile != "" {
		if err := profile.Load(o.Profile, o); err != nil {
			fmt.Fprintf(errW, "[WARN] loading profile %q is failed: %s", o.Profile, err) // nolint
			return
		}
	}
}

func (o *Config) loadFromFlags(flags *pflag.FlagSet, errW io.Writer) {
	if flags.Changed("token") {
		v, err := flags.GetString("token")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "token", err) // nolint
			return
		}
		o.AccessToken = v
	}
	if flags.Changed("secret") {
		v, err := flags.GetString("secret")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "secret", err) // nolint
			return
		}
		o.AccessTokenSecret = v
	}
	if flags.Changed("zone") {
		v, err := flags.GetString("zone")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "zone", err) // nolint
			return
		}
		o.Zone = v
	}
	if flags.Changed("zones") {
		v, err := flags.GetStringSlice("zones")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "zones", err) // nolint
			return
		}
		o.Zones = v
	}
	if flags.Changed("no-color") {
		v, err := flags.GetBool("no-color")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "no-color", err) // nolint
			return
		}
		o.NoColor = v
	}
	if flags.Changed("trace") {
		v, err := flags.GetBool("trace")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "trace", err) // nolint
			return
		}
		if v {
			o.TraceMode = "all"
		}
	}
	if flags.Changed("fake") {
		v, err := flags.GetBool("fake")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "fake", err) // nolint
			return
		}
		o.FakeMode = v
	}
	if flags.Changed("fake-store") {
		v, err := flags.GetString("fake-store")
		if err != nil {
			fmt.Fprintf(errW, "[WARN] reading value of %q flag is failed: %s", "fake-store", err) // nolint
			return
		}
		o.FakeStorePath = v
	}
}

func stringFromEnv(key, defaultValue string) string {
	v := os.Getenv(key)
	if v == "" {
		return defaultValue
	}
	return v
}

func stringSliceFromEnv(key string, defaultValue []string) []string {
	v := os.Getenv(key)
	if v == "" {
		return defaultValue
	}
	values := strings.Split(v, ",")
	for i := range values {
		values[i] = strings.Trim(values[i], " ")
	}
	return values
}

func intFromEnv(key string, defaultValue int) int {
	v := os.Getenv(key)
	if v == "" {
		return defaultValue
	}
	i, err := strconv.ParseInt(v, 10, 64)
	if err != nil {
		return defaultValue
	}
	return int(i)
}

func (o *Config) Validate(skipCred bool) []error {
	var errs []error

	if !skipCred {
		errs = append(errs, validation.Required("token", o.AccessToken)...)
		errs = append(errs, validation.Required("secret", o.AccessTokenSecret)...)
		errs = append(errs, validation.Required("zone", o.Zone)...)
		errs = append(errs, validation.StringInSlice("zone", o.Zone, o.Zones)...)
	}
	errs = append(errs, validation.StringInSlice("default-output-type", o.DefaultOutputType, define.AllowOutputTypes)...)

	return errs
}
<|endoftext|>


<commit_before>package image

import (
	"bytes"
	"encoding/hex"
	"strconv"

	"github.com/golang/glog"
	"github.com/pkg/errors"
	. "kubevirt.io/containerized-data-importer/pkg/common"
)

// Size of buffer used to read file headers.
// Note: this is the size of tar's header. If a larger number is used the tar unarchive operation
//   creates the destination file too large, by the difference between this const and 512.
const MaxExpectedHdrSize = 512

// key is file format, eg. "gz" or "tar", value is metadata describing the layout for this hdr
type Headers map[string]Header

var knownHeaders = Headers{
	"gz": Header{
		Format:      "gz",
		magicNumber: []byte{0x1F, 0x8B},
		// TODO: size not in hdr
		SizeOff: 0,
		SizeLen: 0,
	},
	"qcow2": Header{
		Format:      "qcow2",
		magicNumber: []byte{'Q', 'F', 'I', 0xfb},
		mgOffset:    0,
		SizeOff:     24,
		SizeLen:     8,
	},
	"tar": Header{
		Format:      "tar",
		magicNumber: []byte{0x75, 0x73, 0x74, 0x61, 0x72, 0x20},
		mgOffset:    0x101,
		SizeOff:     124,
		SizeLen:     8,
	},
	"xz": Header{
		Format:      "xz",
		magicNumber: []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00},
		// TODO: size not in hdr
		SizeOff: 0,
		SizeLen: 0,
	},
}

type Header struct {
	Format      string
	magicNumber []byte
	mgOffset    int
	SizeOff     int // in bytes
	SizeLen     int // in bytes
}

// simple map copy since := assignment copies the reference to the map, not contents.
func CopyKnownHdrs() Headers {
	m := make(Headers)
	for k, v := range knownHeaders {
		m[k] = v
	}
	return m
}

func (h Header) Match(b []byte) bool {
	return bytes.Equal(b[h.mgOffset:h.mgOffset+len(h.magicNumber)], h.magicNumber)
}

func (h Header) Size(b []byte) (int64, error) {
	if h.SizeLen == 0 { // no size is supported in this format's header
		return 0, nil
	}
	s := hex.EncodeToString(b[h.SizeOff : h.SizeOff+h.SizeLen])
	size, err := strconv.ParseInt(s, 16, 64)
	if err != nil {
		return 0, errors.Wrapf(err, "unable to determine original file size from %+v", s)
	}
	glog.V(Vdebug).Infof("Size: %q size in bytes (at off %d:%d): %d", h.Format, h.SizeOff, h.SizeOff+h.SizeLen, size)
	return size, nil
}
<commit_msg>Reduce tar magic num slice to match all possible tar identifies (#319)<commit_after>package image

import (
	"bytes"
	"encoding/hex"
	"strconv"

	"github.com/golang/glog"
	"github.com/pkg/errors"
	. "kubevirt.io/containerized-data-importer/pkg/common"
)

// Size of buffer used to read file headers.
// Note: this is the size of tar's header. If a larger number is used the tar unarchive operation
//   creates the destination file too large, by the difference between this const and 512.
const MaxExpectedHdrSize = 512

// key is file format, eg. "gz" or "tar", value is metadata describing the layout for this hdr
type Headers map[string]Header

var knownHeaders = Headers{
	"gz": Header{
		Format:      "gz",
		magicNumber: []byte{0x1F, 0x8B},
		// TODO: size not in hdr
		SizeOff: 0,
		SizeLen: 0,
	},
	"qcow2": Header{
		Format:      "qcow2",
		magicNumber: []byte{'Q', 'F', 'I', 0xfb},
		mgOffset:    0,
		SizeOff:     24,
		SizeLen:     8,
	},
	"tar": Header{
		Format:      "tar",
		magicNumber: []byte{0x75, 0x73, 0x74, 0x61, 0x72},
		mgOffset:    0x101,
		SizeOff:     124,
		SizeLen:     8,
	},
	"xz": Header{
		Format:      "xz",
		magicNumber: []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00},
		// TODO: size not in hdr
		SizeOff: 0,
		SizeLen: 0,
	},
}

type Header struct {
	Format      string
	magicNumber []byte
	mgOffset    int
	SizeOff     int // in bytes
	SizeLen     int // in bytes
}

// simple map copy since := assignment copies the reference to the map, not contents.
func CopyKnownHdrs() Headers {
	m := make(Headers)
	for k, v := range knownHeaders {
		m[k] = v
	}
	return m
}

func (h Header) Match(b []byte) bool {
	return bytes.Equal(b[h.mgOffset:h.mgOffset+len(h.magicNumber)], h.magicNumber)
}

func (h Header) Size(b []byte) (int64, error) {
	if h.SizeLen == 0 { // no size is supported in this format's header
		return 0, nil
	}
	s := hex.EncodeToString(b[h.SizeOff : h.SizeOff+h.SizeLen])
	size, err := strconv.ParseInt(s, 16, 64)
	if err != nil {
		return 0, errors.Wrapf(err, "unable to determine original file size from %+v", s)
	}
	glog.V(Vdebug).Infof("Size: %q size in bytes (at off %d:%d): %d", h.Format, h.SizeOff, h.SizeOff+h.SizeLen, size)
	return size, nil
}
<|endoftext|>


<commit_before>package registry

import (
	"strings"
)

// create new tree and initialize root leaf
func newTree() *RepositoryLeaf {
	return &RepositoryLeaf{
		Parent:   nil,
		Path:     "/",
		Name:     "/",
		Images:   make([]*RepositoryImage, 0),
		Children: make([]*RepositoryLeaf, 0),
	}
}

// create new leaf for a tree
func (leaf *RepositoryLeaf) newLeaf(name string) *RepositoryLeaf {
	child := &RepositoryLeaf{
		Parent:   leaf,
		Name:     name,
		Images:   make([]*RepositoryImage, 0),
		Children: make([]*RepositoryLeaf, 0),
	}

	leaf.Children = append(leaf.Children, child)
	child.Path = child.formatPath("") // do not append current name to path

	return child
}

// find leaf by name, beware, if start searching from /
// this method can return unexpected result
func (leaf *RepositoryLeaf) findLeafByName(name string) *RepositoryLeaf {
	if leaf.Name == name {
		return leaf
	}

	for _, child := range leaf.Children {
		if strings.Compare(child.Name, name) == 0 {
			return child
		}

		founded := child.findLeafByName(name)
		if founded != nil {
			return founded
		}
	}

	return nil
}

// get leaf by provided path
func (leaf *RepositoryLeaf) findLeafByPath(path string) *RepositoryLeaf {
	if leaf.Path == path {
		return leaf
	}

	for _, child := range leaf.Children {
		if strings.Compare(child.Path, path) == 0 {
			return child
		}

		founded := child.findLeafByPath(path)
		if founded != nil {
			return founded
		}
	}

	return nil
}

// add new group/image to tree
func (leaf *RepositoryLeaf) addItem(item string) {
	if strings.Contains(item, "/") {
		parts := strings.SplitN(item, "/", 2)
		child := leaf.findLeafByName(parts[0])
		if child == nil {
			child = leaf.newLeaf(parts[0])
		}

		child.addItem(parts[1])

	} else {
		leaf.Images = append(leaf.Images, &RepositoryImage{
			Path:   leaf.formatPath(item),
			Name:   item,
			Parent: leaf,
		})
	}
}

// build path to group/image
//
func (leaf *RepositoryLeaf) formatPath(imageName string) string {
	pathSlice := make([]string, 0)
	if imageName != "" {
		pathSlice = append(pathSlice, imageName)
	}

	p := leaf
	for {
		if p.Name != "/" {
			pathSlice = append(pathSlice, p.Name)
		}
		if p = p.Parent; p == nil {
			break
		}
	}

	// https://github.com/golang/go/wiki/SliceTricks
	for i := len(pathSlice) / 2 - 1; i >= 0; i-- {
		opp := len(pathSlice) - 1 - i
		pathSlice[i], pathSlice[opp] = pathSlice[opp], pathSlice[i]
	}

	return strings.Join(pathSlice, "/")
}
<commit_msg>gofmt<commit_after>package registry

import (
	"strings"
)

// create new tree and initialize root leaf
func newTree() *RepositoryLeaf {
	return &RepositoryLeaf{
		Parent:   nil,
		Path:     "/",
		Name:     "/",
		Images:   make([]*RepositoryImage, 0),
		Children: make([]*RepositoryLeaf, 0),
	}
}

// create new leaf for a tree
func (leaf *RepositoryLeaf) newLeaf(name string) *RepositoryLeaf {
	child := &RepositoryLeaf{
		Parent:   leaf,
		Name:     name,
		Images:   make([]*RepositoryImage, 0),
		Children: make([]*RepositoryLeaf, 0),
	}

	leaf.Children = append(leaf.Children, child)
	child.Path = child.formatPath("") // do not append current name to path

	return child
}

// find leaf by name, beware, if start searching from /
// this method can return unexpected result
func (leaf *RepositoryLeaf) findLeafByName(name string) *RepositoryLeaf {
	if leaf.Name == name {
		return leaf
	}

	for _, child := range leaf.Children {
		if strings.Compare(child.Name, name) == 0 {
			return child
		}

		founded := child.findLeafByName(name)
		if founded != nil {
			return founded
		}
	}

	return nil
}

// get leaf by provided path
func (leaf *RepositoryLeaf) findLeafByPath(path string) *RepositoryLeaf {
	if leaf.Path == path {
		return leaf
	}

	for _, child := range leaf.Children {
		if strings.Compare(child.Path, path) == 0 {
			return child
		}

		founded := child.findLeafByPath(path)
		if founded != nil {
			return founded
		}
	}

	return nil
}

// add new group/image to tree
func (leaf *RepositoryLeaf) addItem(item string) {
	if strings.Contains(item, "/") {
		parts := strings.SplitN(item, "/", 2)
		child := leaf.findLeafByName(parts[0])
		if child == nil {
			child = leaf.newLeaf(parts[0])
		}

		child.addItem(parts[1])

	} else {
		leaf.Images = append(leaf.Images, &RepositoryImage{
			Path:   leaf.formatPath(item),
			Name:   item,
			Parent: leaf,
		})
	}
}

// build path to group/image
//
func (leaf *RepositoryLeaf) formatPath(imageName string) string {
	pathSlice := make([]string, 0)
	if imageName != "" {
		pathSlice = append(pathSlice, imageName)
	}

	p := leaf
	for {
		if p.Name != "/" {
			pathSlice = append(pathSlice, p.Name)
		}
		if p = p.Parent; p == nil {
			break
		}
	}

	// https://github.com/golang/go/wiki/SliceTricks
	for i := len(pathSlice)/2 - 1; i >= 0; i-- {
		opp := len(pathSlice) - 1 - i
		pathSlice[i], pathSlice[opp] = pathSlice[opp], pathSlice[i]
	}

	return strings.Join(pathSlice, "/")
}
<|endoftext|>