<commit_before>package codecs

import "github.com/pions/webrtc/pkg/rtp"

// OpusPayloader payloads Opus packets
type OpusPayloader struct{}

// Payload fragments an Opus packet across one or more byte arrays
func (p *OpusPayloader) Payload(mtu int, payload []byte) [][]byte {
	return [][]byte{payload}
}

// OpusPacket represents the VP8 header that is stored in the payload of an RTP Packet
type OpusPacket struct {
	Payload []byte
}

// Unmarshal parses the passed byte slice and stores the result in the OpusPacket this method is called upon
func (p *OpusPacket) Unmarshal(packet *rtp.Packet) ([]byte, error) {
	p.Payload = packet.Payload
	return p.Payload, nil
}
<commit_msg>RTP packetization should copy payload<commit_after>package codecs

import "github.com/pions/webrtc/pkg/rtp"

// OpusPayloader payloads Opus packets
type OpusPayloader struct{}

// Payload fragments an Opus packet across one or more byte arrays
func (p *OpusPayloader) Payload(mtu int, payload []byte) [][]byte {
	out := make([]byte, len(payload))
	copy(out, payload)
	return [][]byte{out}
}

// OpusPacket represents the VP8 header that is stored in the payload of an RTP Packet
type OpusPacket struct {
	Payload []byte
}

// Unmarshal parses the passed byte slice and stores the result in the OpusPacket this method is called upon
func (p *OpusPacket) Unmarshal(packet *rtp.Packet) ([]byte, error) {
	p.Payload = packet.Payload
	return p.Payload, nil
}
<|endoftext|>


<commit_before>// Package bookmarkable manages private bookmarks using Gist as the
// storage mechanism.
package bookmarkable

import (
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"io/ioutil"
	"strings"
	"time"
)

// DB is the front end storage model.
type db struct {
	config         *config
	configFileName *string
	bookmarks      []*Bookmark
	storage        *gistStore
	filename       string
}

// New creates and returns a DB from a config file.
func New(configFileName *string, dbDir string) (*db, error) {
	db := &db{
		configFileName: configFileName,
		bookmarks:      make([]*Bookmark, 0),
	}

	c, err := parseConfig(*db.configFileName)

	if err != nil {
		return nil, err
	}

	db.config = c
	db.filename = dbDir + "/bookmarkable.json"
	db.storage = newGistStore(db.config.ID, &db.config.Token)

	return db, nil
}

// Sync updates local bookmarks with the remote copy.
//
// This does not merge bookmarks so anything you have managed to store
// locally will be overwritten.
func (db *db) Sync() error {
	var err error
	if err = db.storage.init(); err != nil {
		return err
	}

	// write the gist id to the config file if we don't already have it
	if db.config.ID == nil {
		db.config.ID = db.storage.gist.ID
		if err = db.writeConfig(); err != nil {
			return err
		}
	}

	return db.writeBookmarks()
}

func (db *db) writeConfig() error {
	var b []byte
	var err error

	if b, err = json.MarshalIndent(db.config, "", "  "); err != nil {
		return err
	}

	if err = ioutil.WriteFile(*db.configFileName, b, 0644); err != nil {
		return err
	}

	return nil
}

func (db *db) writeBookmarks() error {
	d1 := []byte(*db.storage.content)
	return ioutil.WriteFile(db.filename, d1, 0644)
}

// Search returns Bookmarks structs that match the given phrase.
func (db *db) Search(phrase string) []*Bookmark {
	var results []*Bookmark

	ary, err := db.GetBookmarks()

	if err != nil {
		panic(err)
	}

	for _, b := range ary {
		if b.matches(phrase) {
			results = append(results, b)
		}
	}

	return results
}

// Add adds a new Bookmark to the collection, and updates storage.
func (db *db) Add(url string, tags []string) error {
	p, err := newPage(&url)

	if err != nil {
		return err
	}

	b := Bookmark{
		Title:     *p.title,
		URL:       *p.url,
		Tags:      tags,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}

	bookmarks, err := db.GetBookmarks()
	if err != nil {
		return err
	}

	db.bookmarks = append(bookmarks, &b)

	var bytes []byte

	if bytes, err = json.MarshalIndent(db.bookmarks, "", "  "); err != nil {
		return err
	}

	content := string(bytes)
	db.storage.content = &content

	if err := db.storage.update(); err != nil {
		return err
	}

	return db.writeBookmarks()
}

// GetBookmarks returns all locally stored Bookmark structs.
func (db *db) GetBookmarks() ([]*Bookmark, error) {
	if len(db.bookmarks) == 0 {
		bytes, err := ioutil.ReadFile(db.filename)

		if err != nil {
			return nil, err
		}

		if err := json.Unmarshal(bytes, &db.bookmarks); err != nil {
			return nil, err
		}
	}

	return db.bookmarks, nil
}

// Bookmark represents a single Bookmark
type Bookmark struct {
	Title     string    `json:"title"`
	URL       string    `json:"url"`
	Tags      []string  `json:"tags"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

func (b *Bookmark) matches(phrase string) bool {
	phrase = strings.ToLower(phrase)

	if strings.Contains(strings.ToLower(b.Title), phrase) {
		return true
	}

	for _, tag := range b.Tags {
		if strings.Contains(tag, phrase) {
			return true
		}
	}

	return false
}

type page struct {
	url   *string
	title *string
}

func (p *page) String() string {
	return fmt.Sprintf("url:%s : title:%v", *p.url, *p.title)
}

func newPage(url *string) (*page, error) {
	p := &page{
		url: url,
	}

	doc, err := goquery.NewDocument(*p.url)
	if err != nil {
		return nil, err
	}

	title := strings.TrimSpace(doc.Find("head title").Text())
	p.title = &title

	return p, nil
}
<commit_msg>golint<commit_after>// Package bookmarkable manages private bookmarks using Gist as the
// storage mechanism.
package bookmarkable

import (
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"io/ioutil"
	"strings"
	"time"
)

// DB is the front end storage model.
type DB struct {
	config         *config
	configFileName *string
	bookmarks      []*Bookmark
	storage        *gistStore
	filename       string
}

// New creates and returns a DB from a config file.
func New(configFileName *string, dbDir string) (*DB, error) {
	db := &DB{
		configFileName: configFileName,
		bookmarks:      make([]*Bookmark, 0),
	}

	c, err := parseConfig(*db.configFileName)

	if err != nil {
		return nil, err
	}

	db.config = c
	db.filename = dbDir + "/bookmarkable.json"
	db.storage = newGistStore(db.config.ID, &db.config.Token)

	return db, nil
}

// Sync updates local bookmarks with the remote copy.
//
// This does not merge bookmarks so anything you have managed to store
// locally will be overwritten.
func (db *DB) Sync() error {
	var err error
	if err = db.storage.init(); err != nil {
		return err
	}

	// write the gist id to the config file if we don't already have it
	if db.config.ID == nil {
		db.config.ID = db.storage.gist.ID
		if err = db.writeConfig(); err != nil {
			return err
		}
	}

	return db.writeBookmarks()
}

func (db *DB) writeConfig() error {
	var b []byte
	var err error

	if b, err = json.MarshalIndent(db.config, "", "  "); err != nil {
		return err
	}

	if err = ioutil.WriteFile(*db.configFileName, b, 0644); err != nil {
		return err
	}

	return nil
}

func (db *DB) writeBookmarks() error {
	d1 := []byte(*db.storage.content)
	return ioutil.WriteFile(db.filename, d1, 0644)
}

// Search returns Bookmarks structs that match the given phrase.
func (db *DB) Search(phrase string) []*Bookmark {
	var results []*Bookmark

	ary, err := db.GetBookmarks()

	if err != nil {
		panic(err)
	}

	for _, b := range ary {
		if b.matches(phrase) {
			results = append(results, b)
		}
	}

	return results
}

// Add adds a new Bookmark to the collection, and updates storage.
func (db *DB) Add(url string, tags []string) error {
	p, err := newPage(&url)

	if err != nil {
		return err
	}

	b := Bookmark{
		Title:     *p.title,
		URL:       *p.url,
		Tags:      tags,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}

	bookmarks, err := db.GetBookmarks()
	if err != nil {
		return err
	}

	db.bookmarks = append(bookmarks, &b)

	var bytes []byte

	if bytes, err = json.MarshalIndent(db.bookmarks, "", "  "); err != nil {
		return err
	}

	content := string(bytes)
	db.storage.content = &content

	if err := db.storage.update(); err != nil {
		return err
	}

	return db.writeBookmarks()
}

// GetBookmarks returns all locally stored Bookmark structs.
func (db *DB) GetBookmarks() ([]*Bookmark, error) {
	if len(db.bookmarks) == 0 {
		bytes, err := ioutil.ReadFile(db.filename)

		if err != nil {
			return nil, err
		}

		if err := json.Unmarshal(bytes, &db.bookmarks); err != nil {
			return nil, err
		}
	}

	return db.bookmarks, nil
}

// Bookmark represents a single Bookmark
type Bookmark struct {
	Title     string    `json:"title"`
	URL       string    `json:"url"`
	Tags      []string  `json:"tags"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

func (b *Bookmark) matches(phrase string) bool {
	phrase = strings.ToLower(phrase)

	if strings.Contains(strings.ToLower(b.Title), phrase) {
		return true
	}

	for _, tag := range b.Tags {
		if strings.Contains(tag, phrase) {
			return true
		}
	}

	return false
}

type page struct {
	url   *string
	title *string
}

func (p *page) String() string {
	return fmt.Sprintf("url:%s : title:%v", *p.url, *p.title)
}

func newPage(url *string) (*page, error) {
	p := &page{
		url: url,
	}

	doc, err := goquery.NewDocument(*p.url)
	if err != nil {
		return nil, err
	}

	title := strings.TrimSpace(doc.Find("head title").Text())
	p.title = &title

	return p, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"hash/crc32"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

// A Steam game in a library. May or may not be installed.
type Game struct {
	// Official Steam id.
	Id string
	// Warning, may contain Unicode characters.
	Name string
	// Tags, including user-created category and Steam's "Favorite" tag.
	Tags []string
	// Path for the grid image.
	ImagePath string
	// Raw bytes of the encoded image (usually jpg).
	ImageBytes []byte
	// Description of where the image was found (backup, official, search).
	ImageSource string
}

// Pattern of game declarations in the public profile. It's actually JSON
// inside Javascript, but this way is easier to extract.
const profileGamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`

// Fetches the list of games from the public user profile. This is better than
// looking locally because the profiles give the full game name, which can be
// used for image searches later on.
func addGamesFromProfile(user User, games map[string]*Game) (err error) {
	profile, err := GetProfile(user)
	if err != nil {
		return
	}

	// Fetch game list from public profile.
	pattern := regexp.MustCompile(profileGamePattern)
	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		gameId := groups[1]
		gameName := groups[2]
		tags := []string{""}
		imagePath := ""
		games[gameId] = &Game{gameId, gameName, tags, imagePath, nil, ""}
	}

	return
}

// Loads the categories list. This finds the categories for the games loaded
// from the profile and sometimes find new games, although without names.
func addUnknownGames(user User, games map[string]*Game) {
	// Fetch game categories from local file.
	sharedConfFile := filepath.Join(user.Dir, "7", "remote", "sharedconfig.vdf")
	if _, err := os.Stat(sharedConfFile); err != nil {
		// No categories file found, skipping this part.
		return
	}
	sharedConfBytes, err := ioutil.ReadFile(sharedConfFile)
	if err != nil {
		return
	}

	sharedConf := string(sharedConfBytes)
	// VDF pattern: "steamid" { "tags { "0" "category" } }
	gamePattern := regexp.MustCompile(`"([0-9]+)"\s*{[^}]+?"tags"\s*{([^}]+?)}`)
	tagsPattern := regexp.MustCompile(`"[0-9]+"\s*"(.+?)"`)
	for _, gameGroups := range gamePattern.FindAllStringSubmatch(sharedConf, -1) {
		gameId := gameGroups[1]
		tagsText := gameGroups[2]

		for _, tagGroups := range tagsPattern.FindAllStringSubmatch(tagsText, -1) {
			tag := tagGroups[1]

			game, ok := games[gameId]
			if ok {
				game.Tags = append(game.Tags, tag)
			} else {
				// If for some reason it wasn't included in the profile, create a new
				// entry for it now. Unfortunately we don't have a name.
				gameName := ""
				games[gameId] = &Game{gameId, gameName, []string{tag}, "", nil, ""}
			}
		}
	}
}

// Adds non-Steam games that have been registered locally.
// This information is in the file config/shortcuts.vdf, in binary format.
// It contains the non-Steam games with names, target (exe location) and
// tags/categories. To create a grid image we must compute the Steam ID, which
// is just crc32(target + label) + "02000000", using IEEE standard polynomials.
func addNonSteamGames(user User, games map[string]*Game) {
	shortcutsVdf := filepath.Join(user.Dir, "config", "shortcuts.vdf")
	if _, err := os.Stat(shortcutsVdf); err != nil {
		return
	}
	shortcutBytes, err := ioutil.ReadFile(shortcutsVdf)
	if err != nil {
		return
	}

	// The actual binary format is known, but using regexes is way easier than
	// parsing the entire file. If I run into any problems I'll replace this.
	gamePattern := regexp.MustCompile("(?i)appname\x00(.+?)\x00\x01exe\x00(.+?)\x00\x01.+?\x00tags\x00(.*?)\x08\x08")
	tagsPattern := regexp.MustCompile("\\d\x00(.+?)\x00")
	for _, gameGroups := range gamePattern.FindAllSubmatch(shortcutBytes, -1) {
		gameName := gameGroups[1]
		target := gameGroups[2]
		uniqueName := bytes.Join([][]byte{target, gameName}, []byte(""))
		// Does IEEE CRC32 of target concatenated with gameName, then convert
		// to 64bit Steam ID. No idea why Steam chose this operation.
		top := uint64(crc32.ChecksumIEEE(uniqueName)) | 0x80000000
		gameId := strconv.FormatUint(top<<32|0x02000000, 10)
		game := Game{gameId, string(gameName), []string{}, "", nil, ""}
		games[gameId] = &game

		tagsText := gameGroups[3]
		for _, tagGroups := range tagsPattern.FindAllSubmatch(tagsText, -1) {
			tag := tagGroups[1]
			game.Tags = append(game.Tags, string(tag))
		}
	}
}

// Returns all games from a given user, using both the public profile and local
// files to gather the data. Returns a map of game by ID.
func GetGames(user User) map[string]*Game {
	games := make(map[string]*Game, 0)

	addGamesFromProfile(user, games)
	addUnknownGames(user, games)
	addNonSteamGames(user, games)

	imageExtensions := []string{
		" (original).jpg",
		" (original).png",
		".jpg",
		".jpeg",
		".png",
		".gif",
	}

	// Load existing and backup images.
	for _, game := range games {
		gridDir := filepath.Join(user.Dir, "config", "grid")
		for _, extension := range imageExtensions {
			imagePath := filepath.Join(gridDir, game.Id+extension)
			imageBytes, err := ioutil.ReadFile(imagePath)
			if err == nil {
				game.ImagePath = imagePath
				game.ImageBytes = imageBytes
				if strings.HasPrefix(" (original)", extension) {
					game.ImageSource = "backup"
				} else {
					game.ImageSource = "existing"
				}
				break
			}
		}
		if game.ImageBytes == nil {
			game.ImagePath = filepath.Join(gridDir, game.Id+".jpg")
		}
	}

	return games
}
<commit_msg>Store final path and correctly detect backups<commit_after>package main

import (
	"bytes"
	"hash/crc32"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

// A Steam game in a library. May or may not be installed.
type Game struct {
	// Official Steam id.
	Id string
	// Warning, may contain Unicode characters.
	Name string
	// Tags, including user-created category and Steam's "Favorite" tag.
	Tags []string
	// Path for the grid image.
	ImagePath string
	// Raw bytes of the encoded image (usually jpg).
	ImageBytes []byte
	// Description of where the image was found (backup, official, search).
	ImageSource string
}

// Pattern of game declarations in the public profile. It's actually JSON
// inside Javascript, but this way is easier to extract.
const profileGamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`

// Fetches the list of games from the public user profile. This is better than
// looking locally because the profiles give the full game name, which can be
// used for image searches later on.
func addGamesFromProfile(user User, games map[string]*Game) (err error) {
	profile, err := GetProfile(user)
	if err != nil {
		return
	}

	// Fetch game list from public profile.
	pattern := regexp.MustCompile(profileGamePattern)
	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		gameId := groups[1]
		gameName := groups[2]
		tags := []string{""}
		imagePath := ""
		games[gameId] = &Game{gameId, gameName, tags, imagePath, nil, ""}
	}

	return
}

// Loads the categories list. This finds the categories for the games loaded
// from the profile and sometimes find new games, although without names.
func addUnknownGames(user User, games map[string]*Game) {
	// Fetch game categories from local file.
	sharedConfFile := filepath.Join(user.Dir, "7", "remote", "sharedconfig.vdf")
	if _, err := os.Stat(sharedConfFile); err != nil {
		// No categories file found, skipping this part.
		return
	}
	sharedConfBytes, err := ioutil.ReadFile(sharedConfFile)
	if err != nil {
		return
	}

	sharedConf := string(sharedConfBytes)
	// VDF pattern: "steamid" { "tags { "0" "category" } }
	gamePattern := regexp.MustCompile(`"([0-9]+)"\s*{[^}]+?"tags"\s*{([^}]+?)}`)
	tagsPattern := regexp.MustCompile(`"[0-9]+"\s*"(.+?)"`)
	for _, gameGroups := range gamePattern.FindAllStringSubmatch(sharedConf, -1) {
		gameId := gameGroups[1]
		tagsText := gameGroups[2]

		for _, tagGroups := range tagsPattern.FindAllStringSubmatch(tagsText, -1) {
			tag := tagGroups[1]

			game, ok := games[gameId]
			if ok {
				game.Tags = append(game.Tags, tag)
			} else {
				// If for some reason it wasn't included in the profile, create a new
				// entry for it now. Unfortunately we don't have a name.
				gameName := ""
				games[gameId] = &Game{gameId, gameName, []string{tag}, "", nil, ""}
			}
		}
	}
}

// Adds non-Steam games that have been registered locally.
// This information is in the file config/shortcuts.vdf, in binary format.
// It contains the non-Steam games with names, target (exe location) and
// tags/categories. To create a grid image we must compute the Steam ID, which
// is just crc32(target + label) + "02000000", using IEEE standard polynomials.
func addNonSteamGames(user User, games map[string]*Game) {
	shortcutsVdf := filepath.Join(user.Dir, "config", "shortcuts.vdf")
	if _, err := os.Stat(shortcutsVdf); err != nil {
		return
	}
	shortcutBytes, err := ioutil.ReadFile(shortcutsVdf)
	if err != nil {
		return
	}

	// The actual binary format is known, but using regexes is way easier than
	// parsing the entire file. If I run into any problems I'll replace this.
	gamePattern := regexp.MustCompile("(?i)appname\x00(.+?)\x00\x01exe\x00(.+?)\x00\x01.+?\x00tags\x00(.*?)\x08\x08")
	tagsPattern := regexp.MustCompile("\\d\x00(.+?)\x00")
	for _, gameGroups := range gamePattern.FindAllSubmatch(shortcutBytes, -1) {
		gameName := gameGroups[1]
		target := gameGroups[2]
		uniqueName := bytes.Join([][]byte{target, gameName}, []byte(""))
		// Does IEEE CRC32 of target concatenated with gameName, then convert
		// to 64bit Steam ID. No idea why Steam chose this operation.
		top := uint64(crc32.ChecksumIEEE(uniqueName)) | 0x80000000
		gameId := strconv.FormatUint(top<<32|0x02000000, 10)
		game := Game{gameId, string(gameName), []string{}, "", nil, ""}
		games[gameId] = &game

		tagsText := gameGroups[3]
		for _, tagGroups := range tagsPattern.FindAllSubmatch(tagsText, -1) {
			tag := tagGroups[1]
			game.Tags = append(game.Tags, string(tag))
		}
	}
}

// Returns all games from a given user, using both the public profile and local
// files to gather the data. Returns a map of game by ID.
func GetGames(user User) map[string]*Game {
	games := make(map[string]*Game, 0)

	addGamesFromProfile(user, games)
	addUnknownGames(user, games)
	addNonSteamGames(user, games)

	suffixes := []string{
		" (original)..jpg", // Mistakes were made, own up to them.
		" (original)..png",
		" (original).jpg",
		" (original).png",
		".jpg",
		".jpeg",
		".png",
		".gif",
	}

	// Load existing and backup images.
	for _, game := range games {
		gridDir := filepath.Join(user.Dir, "config", "grid")
		for _, suffix := range suffixes {
			imagePath := filepath.Join(gridDir, game.Id+suffix)
			imageBytes, err := ioutil.ReadFile(imagePath)
			if err == nil {
				game.ImagePath = filepath.Join(gridDir, game.Id+filepath.Ext(game.ImagePath))
				game.ImageBytes = imageBytes
				if strings.HasPrefix(suffix, " (original)") {
					game.ImageSource = "backup"
				} else {
					game.ImageSource = "manual customization"
				}
				break
			}
		}
		if game.ImageBytes == nil {
			game.ImagePath = filepath.Join(gridDir, game.Id+".jpg")
		}
	}

	return games
}
<|endoftext|>


<commit_before>// Copyright 2016 Mesosphere, Inc.
//
// 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 collector

// This file contains all work to be done in response to 'go generate':

//go:generate go run ../schema/generator.go -infile ../schema/metrics.avsc -outfile metrics_schema/schema.go
<commit_msg>(maint) remove unused collector/generator.go<commit_after><|endoftext|>


<commit_before>package command

import (
	"errors"

	"github.com/codegangsta/cli"
	"github.com/coreos/go-etcd/etcd"
)

// NewRemoveCommand returns the CLI command for "rm".
func NewRemoveCommand() cli.Command {
	return cli.Command{
		Name:  "rm",
		Usage: "remove a key",
		Flags: []cli.Flag{
			cli.BoolFlag{"dir", "removes the key if it is an empty directory or a key-value pair"},
			cli.BoolFlag{"recursive", "removes the key and all child keys(if it is a directory)"},
		},
		Action: func(c *cli.Context) {
			handleKey(c, removeCommandFunc)
		},
	}
}

// removeCommandFunc executes the "rm" command.
func removeCommandFunc(c *cli.Context, client *etcd.Client) (*etcd.Response, error) {
	if len(c.Args()) == 0 {
		return nil, errors.New("Key required")
	}
	key := c.Args()[0]
	recursive := c.Bool("recursive")
	dir := c.Bool("dir")

	if recursive || !dir {
		return client.Delete(key, recursive)
	}

	return client.DeleteDir(key)
}
<commit_msg>feat(rm_command.go) support comapreAndDelete<commit_after>package command

import (
	"errors"

	"github.com/codegangsta/cli"
	"github.com/coreos/go-etcd/etcd"
)

// NewRemoveCommand returns the CLI command for "rm".
func NewRemoveCommand() cli.Command {
	return cli.Command{
		Name:  "rm",
		Usage: "remove a key",
		Flags: []cli.Flag{
			cli.BoolFlag{"dir", "removes the key if it is an empty directory or a key-value pair"},
			cli.BoolFlag{"recursive", "removes the key and all child keys(if it is a directory)"},
			cli.StringFlag{"with-value", "", "previous value"},
			cli.IntFlag{"with-index", 0, "previous index"},
		},
		Action: func(c *cli.Context) {
			handleKey(c, removeCommandFunc)
		},
	}
}

// removeCommandFunc executes the "rm" command.
func removeCommandFunc(c *cli.Context, client *etcd.Client) (*etcd.Response, error) {
	if len(c.Args()) == 0 {
		return nil, errors.New("Key required")
	}
	key := c.Args()[0]
	recursive := c.Bool("recursive")
	dir := c.Bool("dir")

	// TODO: distinguish with flag is not set and empty flag
	// the cli pkg need to provide this feature
	prevValue := c.String("with-value")
	prevIndex := uint64(c.Int("with-index"))

	if prevValue != "" || prevIndex != 0 {
		return client.CompareAndDelete(key, prevValue, prevIndex)
	}

	if recursive || !dir {
		return client.Delete(key, recursive)
	}

	return client.DeleteDir(key)
}
<|endoftext|>


<commit_before>package streamlog

import (
	"io"
	"log"
	"os"

	"github.com/joefitzgerald/standardlog"
)

// OutputStream represents standard output streams
type OutputStream int

// The standard output streams
const (
	Out OutputStream = iota
	Err
)

// StreamLogger allows logging to stderr and stdout streams
type StreamLogger interface {
	Flags() int
	Prefix() string
	Print(s OutputStream, v ...interface{})
	Printf(s OutputStream, format string, v ...interface{})
	Println(s OutputStream, v ...interface{})
	PrintErr(v ...interface{})
	PrintfErr(format string, v ...interface{})
	PrintlnErr(v ...interface{})
	PrintOut(v ...interface{})
	PrintfOut(format string, v ...interface{})
	PrintlnOut(v ...interface{})
	SetFlags(flag int)
	SetPrefix(prefix string)
}

// NewWithWriters creates a new StdOutErrStreamLogger. The out and err variables set the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func NewWithWriters(out io.Writer, err io.Writer, prefix string, flag int) *StdOutErrStreamLogger {
	outLogger := log.New(os.Stdout, prefix, log.LstdFlags)
	errLogger := log.New(os.Stderr, prefix, log.LstdFlags)
	return &StdOutErrStreamLogger{out: outLogger, err: errLogger, prefix: prefix, flag: flag}
}

// NewWithLoggers creates a new StdOutErrStreamLogger. The out and err variables
// set the destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func NewWithLoggers(out standardlog.Logger, err standardlog.Logger, prefix string, flag int) *StdOutErrStreamLogger {
	return &StdOutErrStreamLogger{out: out, err: err, prefix: prefix, flag: flag}
}

// StdOutErrStreamLogger is an OutErrLogger using stderr and stdout
type StdOutErrStreamLogger struct {
	out    standardlog.Logger // Logger for OutputStream.Out
	err    standardlog.Logger // Logger for OutputStream.Err
	prefix string             // prefix to write at beginning of each line
	flag   int                // properties
}

// New creates a new StdOutErrStreamLogger that writes to os.Stdout and
// os.Stderr.
func (l *StdOutErrStreamLogger) New() *StdOutErrStreamLogger {
	return NewWithWriters(os.Stdout, os.Stderr, "", log.LstdFlags)
}
<commit_msg>Implementing Interface Functions - Don't export outErrLogger - New... funcs return StreamLogger, not implementation<commit_after>package streamlog

import (
	"io"
	"log"
	"os"
	"sync"

	"github.com/joefitzgerald/standardlog"
)

// OutputStream represents standard output streams
type OutputStream int

// The standard output streams
const (
	Out OutputStream = iota
	Err
)

// StreamLogger allows logging to stderr and stdout streams
type StreamLogger interface {
	Flags() int
	Prefix() string
	Print(s OutputStream, v ...interface{})
	Printf(s OutputStream, format string, v ...interface{})
	Println(s OutputStream, v ...interface{})
	PrintErr(v ...interface{})
	PrintfErr(format string, v ...interface{})
	PrintlnErr(v ...interface{})
	PrintOut(v ...interface{})
	PrintfOut(format string, v ...interface{})
	PrintlnOut(v ...interface{})
	SetFlags(flag int)
	SetPrefix(prefix string)
}

// New creates a new StreamLogger that writes to os.Stdout and os.Stderr.
func New() StreamLogger {
	return NewWithWriters(os.Stdout, os.Stderr, "", log.LstdFlags)
}

// NewWithWriters creates a new StdOutErrStreamLogger. The out and err variables set the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func NewWithWriters(out io.Writer, err io.Writer, prefix string, flag int) StreamLogger {
	outLogger := log.New(os.Stdout, prefix, log.LstdFlags)
	errLogger := log.New(os.Stderr, prefix, log.LstdFlags)
	return &outErrStreamLogger{out: outLogger, err: errLogger, prefix: prefix, flag: flag}
}

// NewWithLoggers creates a new StdOutErrStreamLogger. The out and err variables
// set the destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func NewWithLoggers(out standardlog.Logger, err standardlog.Logger, prefix string, flag int) StreamLogger {
	return &outErrStreamLogger{out: out, err: err, prefix: prefix, flag: flag}
}

// StdOutErrStreamLogger is an OutErrLogger using stderr and stdout
type outErrStreamLogger struct {
	mu     sync.Mutex         // ensures atomic writes; protects the following fields
	out    standardlog.Logger // Logger for OutputStream.Out
	err    standardlog.Logger // Logger for OutputStream.Err
	prefix string             // prefix to write at beginning of each line
	flag   int                // properties
}

// Flags returns the output flags for the logger.
func (l *outErrStreamLogger) Flags() int {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.flag
}

// Prefix returns the output prefix for the logger.
func (l *outErrStreamLogger) Prefix() string {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.prefix
}

// SetPrefix sets the output prefix for the logger.
func (l *outErrStreamLogger) SetPrefix(prefix string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.prefix = prefix
	l.out.SetPrefix(prefix)
	l.err.SetPrefix(prefix)
}

// SetFlags sets the output flags for the logger.
func (l *outErrStreamLogger) SetFlags(flag int) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.flag = flag
	l.out.SetFlags(flag)
	l.err.SetFlags(flag)
}

// Printf calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Printf.
func (l *outErrStreamLogger) Printf(s OutputStream, format string, v ...interface{}) {
	switch s {
	case Out:
		l.out.Printf(format, v)
	case Err:
		l.err.Printf(format, v)
	}
}

// Print calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Print.
func (l *outErrStreamLogger) Print(s OutputStream, v ...interface{}) {
	switch s {
	case Out:
		l.out.Print(v)
	case Err:
		l.err.Print(v)
	}
}

// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Println.
func (l *outErrStreamLogger) Println(s OutputStream, v ...interface{}) {
	switch s {
	case Out:
		l.out.Println(v)
	case Err:
		l.err.Println(v)
	}
}

// Printf calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Printf.
func (l *outErrStreamLogger) PrintfErr(format string, v ...interface{}) {
	l.err.Printf(format, v)
}

// Print calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Print.
func (l *outErrStreamLogger) PrintErr(v ...interface{}) {
	l.err.Print(v)
}

// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Println.
func (l *outErrStreamLogger) PrintlnErr(v ...interface{}) {
	l.err.Println(v)
}

// Printf calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Printf.
func (l *outErrStreamLogger) PrintfOut(format string, v ...interface{}) {
	l.out.Printf(format, v)
}

// Print calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Print.
func (l *outErrStreamLogger) PrintOut(v ...interface{}) {
	l.out.Print(v)
}

// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of fmt.Println.
func (l *outErrStreamLogger) PrintlnOut(v ...interface{}) {
	l.out.Println(v)
}
<|endoftext|>


<commit_before>package http

import (
	"encoding/json"
	"fmt"
	"github.com/getlantern/flashlight/client"
	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/flashlight/util"
	"github.com/getlantern/golog"
	"github.com/getlantern/whitelist"
	"github.com/skratchdot/open-golang/open"
	"net/http"
	"reflect"
	"time"

	"github.com/getlantern/tarfs"
)

const (
	UiUrl = "http://%s"
	UiDir = "src/github.com/getlantern/ui/app"
)

var (
	log = golog.LoggerFor("http")
)

type JsonResponse struct {
	Error     string   `json:"Error, omitempty"`
	Whitelist []string `json:"Whitelist, omitempty"`
	Original  []string `json:"Original, omitempty"`
}

type WhitelistHandler struct {
	http.HandlerFunc
	whitelist *whitelist.Whitelist
	wlChan    chan *whitelist.Config
}

func sendJsonResponse(w http.ResponseWriter, response *JsonResponse, indent bool) {

	enc := json.NewEncoder(w)
	err := enc.Encode(response)
	if err != nil {
		log.Fatalf("error sending json response %v", err)
	}
}

func setResponseHeaders(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
	w.Header().Set("Access-Control-Allow-Credentials", "True")
	w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")

}

func (wlh WhitelistHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var response JsonResponse

	setResponseHeaders(w)

	switch r.Method {
	case "OPTIONS":
		// return if it's a preflight OPTIONS request
		// this is mainly for testing the UI when it's running on
		// a separate port
		return
	case "POST":
		// update whitelist
		decoder := json.NewDecoder(r.Body)
		var entries []string
		err := decoder.Decode(&entries)
		if err != nil {
			log.Error(err)
			response.Error = fmt.Sprintf("Error decoding whitelist: %s", err.Error())
		} else {
			wl := wlh.whitelist.UpdateEntries(entries)
			copy := wlh.whitelist.Copy()
			log.Debug("Propagating whitelist changes..")
			wlh.wlChan <- copy
			response.Whitelist = wl
		}
	case "GET":
		response.Whitelist = wlh.whitelist.GetEntries()
	default:
		log.Debugf("Received %s", response.Error)
		response.Error = "Invalid whitelist HTTP request"
		response.Whitelist = nil
	}
	sendJsonResponse(w, &response, false)
}

func servePacFile(w http.ResponseWriter, r *http.Request) {
	pacFile := whitelist.GetPacFile()
	http.ServeFile(w, r, pacFile)
}

func ListenAndServe(cfg *client.ClientConfig, cfgChan chan *config.Config, wlChan chan *whitelist.Config) {

	wlh := &WhitelistHandler{
		whitelist: whitelist.New(cfg.Whitelist),
		wlChan:    wlChan,
	}

	r := http.NewServeMux()
	r.Handle("/whitelist", wlh)

	// poll for config updates to the whitelist
	// with this immediately see flashlight.yaml
	// changes in the UI
	go func() {
		for {
			newCfg := <-cfgChan
			clientCfg := newCfg.Client
			if !reflect.DeepEqual(wlh.whitelist.GetConfig(), clientCfg.Whitelist) {
				log.Debugf("Whitelist changed in flashlight.yaml..")
				wlh.whitelist = whitelist.New(newCfg.Client.Whitelist)
				wlh.whitelist.RefreshEntries()
			}
		}
	}()
	r.HandleFunc("/proxy_on.pac", servePacFile)

	UiDirExists, err := util.DirExists(UiDir)
	if err != nil {
		log.Debugf("UI Directory does not exist %s", err)
	}

	if UiDirExists {
		// UI directory found--serve assets directly from it
		log.Debugf("Serving UI assets from directory %s", UiDir)
		r.Handle("/", http.FileServer(http.Dir(UiDir)))
	} else {
		start := time.Now()
		fs, err := tarfs.New(Data, "../ui/app")
		if err != nil {
			panic(err)
		}
		delta := time.Now().Sub(start)
		log.Debugf("tarfs startup time: %v", delta)
		r.Handle("/", http.FileServer(fs))
	}

	httpServer := &http.Server{
		Addr:    cfg.UiAddr,
		Handler: r,
	}

	log.Debugf("Starting UI HTTP server at %s", cfg.UiAddr)
	uiAddr := fmt.Sprintf(UiUrl, cfg.UiAddr)

	if cfg.OpenUi {
		err = open.Run(uiAddr)
		if err != nil {
			log.Errorf("Could not open UI! %s", err)
		}
	}

	err = httpServer.ListenAndServe()
	if err != nil {
		log.Errorf("Could not start HTTP server! %s", err)
	}
}
<commit_msg>dont update pac file on subsequent GET requests<commit_after>package http

import (
	"encoding/json"
	"fmt"
	"github.com/getlantern/flashlight/client"
	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/flashlight/util"
	"github.com/getlantern/golog"
	"github.com/getlantern/whitelist"
	"github.com/skratchdot/open-golang/open"
	"net/http"
	"reflect"
	"time"

	"github.com/getlantern/tarfs"
)

const (
	UiUrl = "http://%s"
	UiDir = "src/github.com/getlantern/ui/app"
)

var (
	log = golog.LoggerFor("http")
)

type JsonResponse struct {
	Error     string   `json:"Error, omitempty"`
	Whitelist []string `json:"Whitelist, omitempty"`
	Original  []string `json:"Original, omitempty"`
}

type WhitelistHandler struct {
	http.HandlerFunc
	whitelist *whitelist.Whitelist
	wlChan    chan *whitelist.Config
}

func sendJsonResponse(w http.ResponseWriter, response *JsonResponse, indent bool) {

	enc := json.NewEncoder(w)
	err := enc.Encode(response)
	if err != nil {
		log.Errorf("error sending json response %v", err)
	}
}

func setResponseHeaders(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
	w.Header().Set("Access-Control-Allow-Credentials", "True")
	w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")

}

func (wlh WhitelistHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var response JsonResponse

	setResponseHeaders(w)

	switch r.Method {
	case "OPTIONS":
		// return if it's a preflight OPTIONS request
		// this is mainly for testing the UI when it's running on
		// a separate port
		return
	case "POST":
		// update whitelist
		decoder := json.NewDecoder(r.Body)
		var entries []string
		err := decoder.Decode(&entries)
		if err != nil {
			log.Error(err)
			response.Error = fmt.Sprintf("Error decoding whitelist: %s", err.Error())
		} else {
			wl := wlh.whitelist.UpdateEntries(entries)
			copy := wlh.whitelist.Copy()
			log.Debug("Propagating whitelist changes..")
			wlh.wlChan <- copy
			response.Whitelist = wl
		}
	case "GET":
		response.Whitelist = wlh.whitelist.GetEntries()
	default:
		log.Debugf("Received %s", response.Error)
		response.Error = "Invalid whitelist HTTP request"
		response.Whitelist = nil
	}
	sendJsonResponse(w, &response, false)
}

func servePacFile(w http.ResponseWriter, r *http.Request) {
	pacFile := whitelist.GetPacFile()
	http.ServeFile(w, r, pacFile)
}

func ListenAndServe(cfg *client.ClientConfig, cfgChan chan *config.Config, wlChan chan *whitelist.Config) {

	wlh := &WhitelistHandler{
		whitelist: whitelist.New(cfg.Whitelist),
		wlChan:    wlChan,
	}

	r := http.NewServeMux()
	r.Handle("/whitelist", wlh)

	// poll for config updates to the whitelist
	// with this immediately see flashlight.yaml
	// changes in the UI
	go func() {
		for {
			newCfg := <-cfgChan
			clientCfg := newCfg.Client
			if !reflect.DeepEqual(wlh.whitelist.GetConfig(), clientCfg.Whitelist) {
				log.Debugf("Whitelist changed in flashlight.yaml..")
				wlh.whitelist = whitelist.New(newCfg.Client.Whitelist)
				wlh.whitelist.RefreshEntries()
			}
		}
	}()
	r.HandleFunc("/proxy_on.pac", servePacFile)

	UiDirExists, err := util.DirExists(UiDir)
	if err != nil {
		log.Debugf("UI Directory does not exist %s", err)
	}

	if UiDirExists {
		// UI directory found--serve assets directly from it
		log.Debugf("Serving UI assets from directory %s", UiDir)
		r.Handle("/", http.FileServer(http.Dir(UiDir)))
	} else {
		start := time.Now()
		fs, err := tarfs.New(Data, "../ui/app")
		if err != nil {
			panic(err)
		}
		delta := time.Now().Sub(start)
		log.Debugf("tarfs startup time: %v", delta)
		r.Handle("/", http.FileServer(fs))
	}

	httpServer := &http.Server{
		Addr:    cfg.UiAddr,
		Handler: r,
	}

	log.Debugf("Starting UI HTTP server at %s", cfg.UiAddr)
	uiAddr := fmt.Sprintf(UiUrl, cfg.UiAddr)

	if cfg.OpenUi {
		err = open.Run(uiAddr)
		if err != nil {
			log.Errorf("Could not open UI! %s", err)
		}
	}

	err = httpServer.ListenAndServe()
	if err != nil {
		log.Errorf("Could not start HTTP server! %s", err)
	}
}
<|endoftext|>


<commit_before>package horizon

import (
	"errors"
	"fmt"

	"github.com/stellar/horizon/db2"
	"github.com/stellar/horizon/db2/history"
	"github.com/stellar/horizon/render/hal"
	"github.com/stellar/horizon/render/sse"
	"github.com/stellar/horizon/resource"
)

// PaymentsIndexAction returns a paged slice of payments based upon the provided
// filters
type PaymentsIndexAction struct {
	Action
	LedgerFilter      int32
	AccountFilter     string
	TransactionFilter string
	PagingParams      db2.PageQuery
	Records           []history.Operation
	Ledgers           history.LedgerCache
	Page              hal.Page
}

// JSON is a method for actions.JSON
func (action *PaymentsIndexAction) JSON() {
	action.Do(
		action.EnsureHistoryFreshness,
		action.loadParams,
		action.ValidateCursorWithinHistory,
		action.loadRecords,
		action.loadLedgers,
		action.loadPage,
	)
	action.Do(func() {
		hal.Render(action.W, action.Page)
	})
}

// SSE is a method for actions.SSE
func (action *PaymentsIndexAction) SSE(stream sse.Stream) {
	action.Setup(
		action.EnsureHistoryFreshness,
		action.loadParams,
		action.ValidateCursorWithinHistory,
	)
	action.Do(
		action.loadRecords,
		func() {
			stream.SetLimit(int(action.PagingParams.Limit))
			records := action.Records[stream.SentCount():]

			for _, record := range records {
				ledger, found := action.Ledgers.Records[record.LedgerSequence()]
				if !found {
					msg := fmt.Sprintf("could not find ledger data for sequence %d", record.LedgerSequence())
					stream.Err(errors.New(msg))
					return
				}

				res, err := resource.NewOperation(action.Ctx, record, ledger)

				if err != nil {
					stream.Err(err)
					return
				}

				stream.Send(sse.Event{
					ID:   res.PagingToken(),
					Data: res,
				})
			}
		})
}

func (action *PaymentsIndexAction) loadParams() {
	action.ValidateCursorAsDefault()
	action.AccountFilter = action.GetString("account_id")
	action.LedgerFilter = action.GetInt32("ledger_id")
	action.TransactionFilter = action.GetString("tx_id")
	action.PagingParams = action.GetPageQuery()
}

func (action *PaymentsIndexAction) loadRecords() {
	q := action.HistoryQ()
	ops := q.Operations().OnlyPayments()

	switch {
	case action.AccountFilter != "":
		ops.ForAccount(action.AccountFilter)
	case action.LedgerFilter > 0:
		ops.ForLedger(action.LedgerFilter)
	case action.TransactionFilter != "":
		ops.ForTransaction(action.TransactionFilter)
	}

	action.Err = ops.Page(action.PagingParams).Select(&action.Records)
}

// loadLedgers populates the ledger cache for this action
func (action *PaymentsIndexAction) loadLedgers() {
	for _, op := range action.Records {
		action.Ledgers.Queue(op.LedgerSequence())
	}

	action.Err = action.Ledgers.Load(action.HistoryQ())
}

func (action *PaymentsIndexAction) loadPage() {
	for _, record := range action.Records {
		var res hal.Pageable

		ledger, found := action.Ledgers.Records[record.LedgerSequence()]
		if !found {
			msg := fmt.Sprintf("could not find ledger data for sequence %d", record.LedgerSequence())
			action.Err = errors.New(msg)
			return
		}

		res, action.Err = resource.NewOperation(action.Ctx, record, ledger)
		if action.Err != nil {
			return
		}
		action.Page.Add(res)
	}

	action.Page.BaseURL = action.BaseURL()
	action.Page.BasePath = action.Path()
	action.Page.Limit = action.PagingParams.Limit
	action.Page.Cursor = action.PagingParams.Cursor
	action.Page.Order = action.PagingParams.Order
	action.Page.PopulateLinks()
}
<commit_msg>Fix missing loadLedgers call in steaming payments endpoint<commit_after>package horizon

import (
	"errors"
	"fmt"

	"github.com/stellar/horizon/db2"
	"github.com/stellar/horizon/db2/history"
	"github.com/stellar/horizon/render/hal"
	"github.com/stellar/horizon/render/sse"
	"github.com/stellar/horizon/resource"
)

// PaymentsIndexAction returns a paged slice of payments based upon the provided
// filters
type PaymentsIndexAction struct {
	Action
	LedgerFilter      int32
	AccountFilter     string
	TransactionFilter string
	PagingParams      db2.PageQuery
	Records           []history.Operation
	Ledgers           history.LedgerCache
	Page              hal.Page
}

// JSON is a method for actions.JSON
func (action *PaymentsIndexAction) JSON() {
	action.Do(
		action.EnsureHistoryFreshness,
		action.loadParams,
		action.ValidateCursorWithinHistory,
		action.loadRecords,
		action.loadLedgers,
		action.loadPage,
	)
	action.Do(func() {
		hal.Render(action.W, action.Page)
	})
}

// SSE is a method for actions.SSE
func (action *PaymentsIndexAction) SSE(stream sse.Stream) {
	action.Setup(
		action.EnsureHistoryFreshness,
		action.loadParams,
		action.ValidateCursorWithinHistory,
	)
	action.Do(
		action.loadRecords,
		action.loadLedgers,
		func() {
			stream.SetLimit(int(action.PagingParams.Limit))
			records := action.Records[stream.SentCount():]

			for _, record := range records {
				ledger, found := action.Ledgers.Records[record.LedgerSequence()]
				if !found {
					msg := fmt.Sprintf("could not find ledger data for sequence %d", record.LedgerSequence())
					stream.Err(errors.New(msg))
					return
				}

				res, err := resource.NewOperation(action.Ctx, record, ledger)

				if err != nil {
					stream.Err(err)
					return
				}

				stream.Send(sse.Event{
					ID:   res.PagingToken(),
					Data: res,
				})
			}
		})
}

func (action *PaymentsIndexAction) loadParams() {
	action.ValidateCursorAsDefault()
	action.AccountFilter = action.GetString("account_id")
	action.LedgerFilter = action.GetInt32("ledger_id")
	action.TransactionFilter = action.GetString("tx_id")
	action.PagingParams = action.GetPageQuery()
}

func (action *PaymentsIndexAction) loadRecords() {
	q := action.HistoryQ()
	ops := q.Operations().OnlyPayments()

	switch {
	case action.AccountFilter != "":
		ops.ForAccount(action.AccountFilter)
	case action.LedgerFilter > 0:
		ops.ForLedger(action.LedgerFilter)
	case action.TransactionFilter != "":
		ops.ForTransaction(action.TransactionFilter)
	}

	action.Err = ops.Page(action.PagingParams).Select(&action.Records)
}

// loadLedgers populates the ledger cache for this action
func (action *PaymentsIndexAction) loadLedgers() {
	for _, op := range action.Records {
		action.Ledgers.Queue(op.LedgerSequence())
	}

	action.Err = action.Ledgers.Load(action.HistoryQ())
}

func (action *PaymentsIndexAction) loadPage() {
	for _, record := range action.Records {
		var res hal.Pageable

		ledger, found := action.Ledgers.Records[record.LedgerSequence()]
		if !found {
			msg := fmt.Sprintf("could not find ledger data for sequence %d", record.LedgerSequence())
			action.Err = errors.New(msg)
			return
		}

		res, action.Err = resource.NewOperation(action.Ctx, record, ledger)
		if action.Err != nil {
			return
		}
		action.Page.Add(res)
	}

	action.Page.BaseURL = action.BaseURL()
	action.Page.BasePath = action.Path()
	action.Page.Limit = action.PagingParams.Limit
	action.Page.Cursor = action.PagingParams.Cursor
	action.Page.Order = action.PagingParams.Order
	action.Page.PopulateLinks()
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 framework

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/golang/glog"

	"istio.io/istio/tests/e2e/util"
)

const (
	yamlSuffix         = ".yaml"
	istioInstallDir    = "install/kubernetes"
	istioAddonsDir     = "install/kubernetes/addons"
	nonAuthInstallFile = "istio.yaml"
	authInstallFile    = "istio-auth.yaml"
)

var (
	namespace    = flag.String("namespace", "", "Namespace to use for testing (empty to create/delete temporary one)")
	mixerHub     = flag.String("mixer_hub", "", "Mixer hub, if different from istio.Version")
	mixerTag     = flag.String("mixer_tag", "", "Mixer tag, if different from istio.Version")
	pilotHub     = flag.String("pilot_hub", "", "pilot hub, if different from istio.Version")
	pilotTag     = flag.String("pilot_tag", "", "pilot tag, if different from istio.Version")
	caHub        = flag.String("ca_hub", "", "Ca hub")
	caTag        = flag.String("ca_tag", "", "Ca tag")
	authEnable   = flag.Bool("auth_enable", false, "Enable auth")
	rbacfile     = flag.String("rbac_path", "", "Rbac yaml file")
	localCluster = flag.Bool("use_local_cluster", false, "Whether the cluster is local or not")

	addons = []string{
		"prometheus",
	}
)

// KubeInfo gathers information for kubectl
type KubeInfo struct {
	Namespace string

	TmpDir  string
	yamlDir string

	Ingress string

	localCluster     bool
	namespaceCreated bool

	// Istioctl installation
	Istioctl *Istioctl
	// App Manager
	AppManager *AppManager
}

// newKubeInfo create a new KubeInfo by given temp dir and runID
func newKubeInfo(tmpDir, runID string) (*KubeInfo, error) {
	if *namespace == "" {
		*namespace = runID
	}
	yamlDir := filepath.Join(tmpDir, "yaml")
	i, err := NewIstioctl(yamlDir, *namespace, *namespace, *pilotHub, *pilotTag)
	if err != nil {
		return nil, err
	}
	a := NewAppManager(tmpDir, *namespace, i)

	return &KubeInfo{
		Namespace:        *namespace,
		namespaceCreated: false,
		TmpDir:           tmpDir,
		yamlDir:          yamlDir,
		localCluster:     *localCluster,
		Istioctl:         i,
		AppManager:       a,
	}, nil
}

// Setup set up Kubernetes prerequest for tests
func (k *KubeInfo) Setup() error {
	glog.Info("Setting up kubeInfo")
	var err error
	if err = os.Mkdir(k.yamlDir, os.ModeDir|os.ModePerm); err != nil {
		return err
	}

	if err = util.CreateNamespace(k.Namespace); err != nil {
		glog.Error("Failed to create namespace.")
		return err
	}
	k.namespaceCreated = true

	if err = k.deployIstio(); err != nil {
		glog.Error("Failed to deploy Istio.")
		return err
	}

	if err = k.deployAddons(); err != nil {
		glog.Error("Failed to deploy istio addons")
		return err
	}

	var in string
	if k.localCluster {
		in, err = util.GetIngressPod(k.Namespace)
	} else {
		in, err = util.GetIngress(k.Namespace)
	}
	if err != nil {
		return err
	}
	k.Ingress = in
	return nil
}

// Teardown clean up everything created by setup
func (k *KubeInfo) Teardown() error {
	glog.Info("Cleaning up kubeInfo")
	var err error
	if k.namespaceCreated {
		if err = util.DeleteNamespace(k.Namespace); err != nil {
			glog.Errorf("Failed to delete namespace %s", k.Namespace)
			return err
		}

		// confirm the namespace is deleted as it will cause future creation to fail
		maxAttempts := 15
		namespaceDeleted := false
		totalWait := 0
		for attempts := 1; attempts <= maxAttempts; attempts++ {
			namespaceDeleted, err = util.NamespaceDeleted(k.Namespace)
			if namespaceDeleted {
				break
			}
			totalWait += attempts
			time.Sleep(time.Duration(attempts) * time.Second)
		}

		if !namespaceDeleted {
			glog.Errorf("Failed to delete namespace %s after %v seconds", k.Namespace, totalWait)
			return err
		}
		k.namespaceCreated = false
		glog.Infof("Namespace %s deletion status: %v", k.Namespace, namespaceDeleted)
	}
	return err
}

func (k *KubeInfo) deployAddons() error {
	for _, addon := range addons {
		yamlFile := util.GetResourcePath(filepath.Join(istioAddonsDir, fmt.Sprintf("%s.yaml", addon)))
		if err := util.KubeApply(k.Namespace, yamlFile); err != nil {
			glog.Errorf("Kubectl apply %s failed", yamlFile)
			return err
		}
	}
	return nil
}

func (k *KubeInfo) deployIstio() error {
	istioYaml := nonAuthInstallFile
	if *authEnable {
		istioYaml = authInstallFile
	}
	baseIstioYaml := util.GetResourcePath(filepath.Join(istioInstallDir, istioYaml))
	testIstioYaml := filepath.Join(k.TmpDir, "yaml", istioYaml)

	if *rbacfile != "" {
		baseRbacYaml := util.GetResourcePath(*rbacfile)
		testRbacYaml := filepath.Join(k.TmpDir, "yaml", filepath.Base(*rbacfile))
		if err := k.generateRbac(baseRbacYaml, testRbacYaml); err != nil {
			glog.Errorf("Generating rbac yaml failed")
		}
		if err := util.KubeApply(k.Namespace, testRbacYaml); err != nil {
			glog.Errorf("Rbac deployment failed")
			return err
		}
	}

	if err := k.generateIstio(baseIstioYaml, testIstioYaml); err != nil {
		glog.Errorf("Generating yaml %s failed", testIstioYaml)
		return err
	}
	if err := util.KubeApply(k.Namespace, testIstioYaml); err != nil {
		glog.Errorf("Istio core %s deployment failed", testIstioYaml)
		return err
	}

	return nil
}

func (k *KubeInfo) generateRbac(src, dst string) error {
	content, err := ioutil.ReadFile(src)
	if err != nil {
		glog.Errorf("Cannot read original yaml file %s", src)
		return err
	}
	namespace := []byte(fmt.Sprintf("namespace: %s", k.Namespace))
	r := regexp.MustCompile("namespace: default")
	content = r.ReplaceAllLiteral(content, namespace)
	err = ioutil.WriteFile(dst, content, 0600)
	if err != nil {
		glog.Errorf("Cannot write into generate rbac file %s", dst)
	}
	return err
}

func (k *KubeInfo) generateIstio(src, dst string) error {
	content, err := ioutil.ReadFile(src)
	if err != nil {
		glog.Errorf("Cannot read original yaml file %s", src)
		return err
	}

	if *mixerHub != "" && *mixerTag != "" {
		content = updateIstioYaml("mixer", *mixerHub, *mixerTag, content)
	}
	if *pilotHub != "" && *pilotTag != "" {
		content = updateIstioYaml("pilot", *pilotHub, *pilotTag, content)
		//Need to be updated when the string "proxy_debug" is changed
		content = updateIstioYaml("proxy_debug", *pilotHub, *pilotTag, content)
	}
	if *caHub != "" && *caTag != "" {
		//Need to be updated when the string "istio-ca" is changed
		content = updateIstioYaml("istio-ca", *caHub, *caTag, content)
	}
	if *localCluster {
		content = []byte(strings.Replace(string(content), "LoadBalancer", "NodePort", 1))
	}

	err = ioutil.WriteFile(dst, content, 0600)
	if err != nil {
		glog.Errorf("Cannot write into generated yaml file %s", dst)
	}
	return err
}

func updateIstioYaml(module, hub, tag string, content []byte) []byte {
	image := []byte(fmt.Sprintf("image: %s/%s:%s", hub, module, tag))
	r := regexp.MustCompile(fmt.Sprintf("image: .*(\\/%s):.*", module))
	return r.ReplaceAllLiteral(content, image)
}
<commit_msg>enable zipkin (#684)<commit_after>// Copyright 2017 Istio 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 framework

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/golang/glog"

	"istio.io/istio/tests/e2e/util"
)

const (
	yamlSuffix         = ".yaml"
	istioInstallDir    = "install/kubernetes"
	istioAddonsDir     = "install/kubernetes/addons"
	nonAuthInstallFile = "istio.yaml"
	authInstallFile    = "istio-auth.yaml"
)

var (
	namespace    = flag.String("namespace", "", "Namespace to use for testing (empty to create/delete temporary one)")
	mixerHub     = flag.String("mixer_hub", "", "Mixer hub, if different from istio.Version")
	mixerTag     = flag.String("mixer_tag", "", "Mixer tag, if different from istio.Version")
	pilotHub     = flag.String("pilot_hub", "", "pilot hub, if different from istio.Version")
	pilotTag     = flag.String("pilot_tag", "", "pilot tag, if different from istio.Version")
	caHub        = flag.String("ca_hub", "", "Ca hub")
	caTag        = flag.String("ca_tag", "", "Ca tag")
	authEnable   = flag.Bool("auth_enable", false, "Enable auth")
	rbacfile     = flag.String("rbac_path", "", "Rbac yaml file")
	localCluster = flag.Bool("use_local_cluster", false, "Whether the cluster is local or not")

	addons = []string{
		"prometheus",
		"zipkin",
	}
)

// KubeInfo gathers information for kubectl
type KubeInfo struct {
	Namespace string

	TmpDir  string
	yamlDir string

	Ingress string

	localCluster     bool
	namespaceCreated bool

	// Istioctl installation
	Istioctl *Istioctl
	// App Manager
	AppManager *AppManager
}

// newKubeInfo create a new KubeInfo by given temp dir and runID
func newKubeInfo(tmpDir, runID string) (*KubeInfo, error) {
	if *namespace == "" {
		*namespace = runID
	}
	yamlDir := filepath.Join(tmpDir, "yaml")
	i, err := NewIstioctl(yamlDir, *namespace, *namespace, *pilotHub, *pilotTag)
	if err != nil {
		return nil, err
	}
	a := NewAppManager(tmpDir, *namespace, i)

	return &KubeInfo{
		Namespace:        *namespace,
		namespaceCreated: false,
		TmpDir:           tmpDir,
		yamlDir:          yamlDir,
		localCluster:     *localCluster,
		Istioctl:         i,
		AppManager:       a,
	}, nil
}

// Setup set up Kubernetes prerequest for tests
func (k *KubeInfo) Setup() error {
	glog.Info("Setting up kubeInfo")
	var err error
	if err = os.Mkdir(k.yamlDir, os.ModeDir|os.ModePerm); err != nil {
		return err
	}

	if err = util.CreateNamespace(k.Namespace); err != nil {
		glog.Error("Failed to create namespace.")
		return err
	}
	k.namespaceCreated = true

	if err = k.deployIstio(); err != nil {
		glog.Error("Failed to deploy Istio.")
		return err
	}

	if err = k.deployAddons(); err != nil {
		glog.Error("Failed to deploy istio addons")
		return err
	}

	var in string
	if k.localCluster {
		in, err = util.GetIngressPod(k.Namespace)
	} else {
		in, err = util.GetIngress(k.Namespace)
	}
	if err != nil {
		return err
	}
	k.Ingress = in
	return nil
}

// Teardown clean up everything created by setup
func (k *KubeInfo) Teardown() error {
	glog.Info("Cleaning up kubeInfo")
	var err error
	if k.namespaceCreated {
		if err = util.DeleteNamespace(k.Namespace); err != nil {
			glog.Errorf("Failed to delete namespace %s", k.Namespace)
			return err
		}

		// confirm the namespace is deleted as it will cause future creation to fail
		maxAttempts := 15
		namespaceDeleted := false
		totalWait := 0
		for attempts := 1; attempts <= maxAttempts; attempts++ {
			namespaceDeleted, err = util.NamespaceDeleted(k.Namespace)
			if namespaceDeleted {
				break
			}
			totalWait += attempts
			time.Sleep(time.Duration(attempts) * time.Second)
		}

		if !namespaceDeleted {
			glog.Errorf("Failed to delete namespace %s after %v seconds", k.Namespace, totalWait)
			return err
		}
		k.namespaceCreated = false
		glog.Infof("Namespace %s deletion status: %v", k.Namespace, namespaceDeleted)
	}
	return err
}

func (k *KubeInfo) deployAddons() error {
	for _, addon := range addons {
		yamlFile := util.GetResourcePath(filepath.Join(istioAddonsDir, fmt.Sprintf("%s.yaml", addon)))
		if err := util.KubeApply(k.Namespace, yamlFile); err != nil {
			glog.Errorf("Kubectl apply %s failed", yamlFile)
			return err
		}
	}
	return nil
}

func (k *KubeInfo) deployIstio() error {
	istioYaml := nonAuthInstallFile
	if *authEnable {
		istioYaml = authInstallFile
	}
	baseIstioYaml := util.GetResourcePath(filepath.Join(istioInstallDir, istioYaml))
	testIstioYaml := filepath.Join(k.TmpDir, "yaml", istioYaml)

	if *rbacfile != "" {
		baseRbacYaml := util.GetResourcePath(*rbacfile)
		testRbacYaml := filepath.Join(k.TmpDir, "yaml", filepath.Base(*rbacfile))
		if err := k.generateRbac(baseRbacYaml, testRbacYaml); err != nil {
			glog.Errorf("Generating rbac yaml failed")
		}
		if err := util.KubeApply(k.Namespace, testRbacYaml); err != nil {
			glog.Errorf("Rbac deployment failed")
			return err
		}
	}

	if err := k.generateIstio(baseIstioYaml, testIstioYaml); err != nil {
		glog.Errorf("Generating yaml %s failed", testIstioYaml)
		return err
	}
	if err := util.KubeApply(k.Namespace, testIstioYaml); err != nil {
		glog.Errorf("Istio core %s deployment failed", testIstioYaml)
		return err
	}

	return nil
}

func (k *KubeInfo) generateRbac(src, dst string) error {
	content, err := ioutil.ReadFile(src)
	if err != nil {
		glog.Errorf("Cannot read original yaml file %s", src)
		return err
	}
	namespace := []byte(fmt.Sprintf("namespace: %s", k.Namespace))
	r := regexp.MustCompile("namespace: default")
	content = r.ReplaceAllLiteral(content, namespace)
	err = ioutil.WriteFile(dst, content, 0600)
	if err != nil {
		glog.Errorf("Cannot write into generate rbac file %s", dst)
	}
	return err
}

func (k *KubeInfo) generateIstio(src, dst string) error {
	content, err := ioutil.ReadFile(src)
	if err != nil {
		glog.Errorf("Cannot read original yaml file %s", src)
		return err
	}

	if *mixerHub != "" && *mixerTag != "" {
		content = updateIstioYaml("mixer", *mixerHub, *mixerTag, content)
	}
	if *pilotHub != "" && *pilotTag != "" {
		content = updateIstioYaml("pilot", *pilotHub, *pilotTag, content)
		//Need to be updated when the string "proxy_debug" is changed
		content = updateIstioYaml("proxy_debug", *pilotHub, *pilotTag, content)
	}
	if *caHub != "" && *caTag != "" {
		//Need to be updated when the string "istio-ca" is changed
		content = updateIstioYaml("istio-ca", *caHub, *caTag, content)
	}
	if *localCluster {
		content = []byte(strings.Replace(string(content), "LoadBalancer", "NodePort", 1))
	}

	err = ioutil.WriteFile(dst, content, 0600)
	if err != nil {
		glog.Errorf("Cannot write into generated yaml file %s", dst)
	}
	return err
}

func updateIstioYaml(module, hub, tag string, content []byte) []byte {
	image := []byte(fmt.Sprintf("image: %s/%s:%s", hub, module, tag))
	r := regexp.MustCompile(fmt.Sprintf("image: .*(\\/%s):.*", module))
	return r.ReplaceAllLiteral(content, image)
}
<|endoftext|>


<commit_before>package templating

import (
	"html/template"
	"io"
	"log"
	"os"
)

var templates *template.Template
var currentTemplateRenderer TemplateRenderer

type TemplateRenderer interface {
	RenderTemplate(wr io.Writer, ctx TemplateContext) error
}

type TemplateContext interface {
	// Add an error that should be displayed
	// to the user
	AddError(err error)

	// Add a notice/message that should be
	// displayed to the user
	AddNotice(notice string)

	// Name of the (main) template that is being
	// rendered (not header or footer templates).
	Name() string
}

// Bring your own TemplateRenderer,
// e.g. for testing
func SetTemplateRenderer(tr TemplateRenderer) {
	currentTemplateRenderer = tr
}

func initTemplateRenderer() {
	if os.Getenv("environment") == "production" {
		currentTemplateRenderer = &cachingTemplateRenderer{templates}
		return
	}

	log.Println("Using reloading template renderer")

	currentTemplateRenderer = &reloadingTemplateRenderer{}
}

func RenderTemplate(wr io.Writer, ctx TemplateContext) error {
	if currentTemplateRenderer == nil {
		initTemplateRenderer()
	}

	return currentTemplateRenderer.RenderTemplate(wr, ctx)
}

type cachingTemplateRenderer struct {
	templates *template.Template
}

func (r cachingTemplateRenderer) RenderTemplate(wr io.Writer, ctx TemplateContext) error {
	if r.templates == nil {
		var err error
		r.templates, err = template.ParseGlob("./templates/*.html")

		if err != nil {
			return err
		}
	}

	return renderWithLayout(r.templates, wr, ctx.Name(), ctx)
}

type reloadingTemplateRenderer struct{}

func (r reloadingTemplateRenderer) RenderTemplate(wr io.Writer, ctx TemplateContext) error {
	templates, err := template.ParseGlob("./templates/*.html")

	templates.Funcs(funcMap)

	if err != nil {
		return err
	}

	return renderWithLayout(templates, wr, ctx.Name(), ctx)
}

func renderWithLayout(t *template.Template, wr io.Writer, name string, data interface{}) error {
	for _, templateName := range []string{"header.html", name, "footer.html"} {
		err := t.ExecuteTemplate(wr, templateName, data)

		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Remove unfinished/experimental code<commit_after>package templating

import (
	"html/template"
	"io"
	"log"
	"os"
)

var templates *template.Template
var currentTemplateRenderer TemplateRenderer

type TemplateRenderer interface {
	RenderTemplate(wr io.Writer, ctx TemplateContext) error
}

type TemplateContext interface {
	// Add an error that should be displayed
	// to the user
	AddError(err error)

	// Add a notice/message that should be
	// displayed to the user
	AddNotice(notice string)

	// Name of the (main) template that is being
	// rendered (not header or footer templates).
	Name() string
}

// Bring your own TemplateRenderer,
// e.g. for testing
func SetTemplateRenderer(tr TemplateRenderer) {
	currentTemplateRenderer = tr
}

func initTemplateRenderer() {
	if os.Getenv("environment") == "production" {
		currentTemplateRenderer = &cachingTemplateRenderer{templates}
		return
	}

	log.Println("Using reloading template renderer")

	currentTemplateRenderer = &reloadingTemplateRenderer{}
}

func RenderTemplate(wr io.Writer, ctx TemplateContext) error {
	if currentTemplateRenderer == nil {
		initTemplateRenderer()
	}

	return currentTemplateRenderer.RenderTemplate(wr, ctx)
}

type cachingTemplateRenderer struct {
	templates *template.Template
}

func (r cachingTemplateRenderer) RenderTemplate(wr io.Writer, ctx TemplateContext) error {
	if r.templates == nil {
		var err error
		r.templates, err = template.ParseGlob("./templates/*.html")

		if err != nil {
			return err
		}
	}

	return renderWithLayout(r.templates, wr, ctx.Name(), ctx)
}

type reloadingTemplateRenderer struct{}

func (r reloadingTemplateRenderer) RenderTemplate(wr io.Writer, ctx TemplateContext) error {
	templates, err := template.ParseGlob("./templates/*.html")

	if err != nil {
		return err
	}

	return renderWithLayout(templates, wr, ctx.Name(), ctx)
}

func renderWithLayout(t *template.Template, wr io.Writer, name string, data interface{}) error {
	for _, templateName := range []string{"header.html", name, "footer.html"} {
		err := t.ExecuteTemplate(wr, templateName, data)

		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"time"

	"github.com/coreos/etcd/pkg/flags"
	"github.com/privacylab/talek/common"
	"github.com/privacylab/talek/libtalek"
	"github.com/privacylab/talek/server"
	"github.com/spf13/pflag"
)

// Talekutil is used to generate configuration files for structuring a talek
// deployment.  In particular, creating a set of configuration files for the
// clients and various trust domains.
func main() {

	outputClient := pflag.Bool("client", false, "Create configuration for a talek client.")
	outputReplica := pflag.Bool("replica", false, "Create configuration for a talek server.")
	outputTD := pflag.Bool("trustdomain", false, "Create raw trustdomain configuration.")
	outputCommon := pflag.Bool("common", false, "Create common config template.")
	name := pflag.String("name", "talek", "Server Name.")
	address := pflag.String("address", "localhost:9000", "Server Address.")
	infile := pflag.String("infile", "", "Begin with configuration from file.")
	outfile := pflag.String("outfile", "talek.json", "Save configuration to file.")
	private := pflag.Bool("private", false, "Include private key configuration.")
	trustdomains := pflag.String("trustdomains", "talek.json", "Comma separated list of trust domains.")
	ferr := flags.SetPflagsFromEnv(common.EnvPrefix, pflag.CommandLine)
	if ferr != nil {
		fmt.Printf("Error reading environment variables, %v\n", ferr)
		return
	}
	pflag.Parse()

	if *outputCommon {
		common := common.Config{
			NumBuckets:         1024,
			BucketDepth:        4,
			DataSize:           1024,
			BloomFalsePositive: .05,
			WriteInterval:      time.Second,
			ReadInterval:       time.Second,
			MaxLoadFactor:      0.95,
		}
		commonDat, err := json.MarshalIndent(common, "", "  ")
		if err != nil {
			fmt.Printf("Could not serialize common config: %v\n", err)
			return
		}
		ioutil.WriteFile(*outfile, commonDat, 0640)

		return
	}

	if !*outputReplica && !*outputTD && !*outputClient {
		fmt.Println("Talekutil needs a mode: --client, --replica, or --trustdomain.")
		return
	} else if (*outputReplica && *outputTD) || (*outputClient && *outputReplica) || (*outputClient && *outputTD) {
		fmt.Println("Mode must be one of --replica or --trustdomain or --client.")
		return
	}

	if *outputClient {
		clientUtil(*infile, *outfile, *trustdomains)
		return
	}

	var sc = server.Config{
		ReadBatch:     8,
		WriteInterval: time.Second,
		ReadInterval:  time.Second,
	}
	var tdc common.TrustDomainConfig
	var err error

	if len(*infile) > 0 {
		dat, readerr := ioutil.ReadFile(*infile)
		if readerr != nil {
			fmt.Printf("Could not read input file: %v\n", readerr)
			return
		}
		err = json.Unmarshal(dat, &tdc)
		if err != nil {
			fmt.Printf("Could not parse input file: %v\n", err)
			return
		}
		err = json.Unmarshal(dat, &sc)
		if err != nil {
			fmt.Printf("Could not parse input file: %v\n", err)
			return
		}
	} else {
		tdc = *common.NewTrustDomainConfig(*name, *address, true, false)
	}
	if sc.TrustDomain != nil {
		tdc = *sc.TrustDomain
	}
	tdc.Name = *name
	tdc.Address = *address
	tdc.IsValid = true

	var tdb []byte
	if *private {
		tdp := tdc.Private()
		if bytes.Compare(tdp.PrivateKey[:], make([]byte, 32)) == 0 {
			fmt.Printf("Imported configuration did not include key.\n")
			return
		}
		tdb, err = json.MarshalIndent(tdp, "", "  ")
		if err != nil {
			fmt.Printf("Failed to export config: %v\n", err)
			return
		}
	} else {
		tdb, err = json.MarshalIndent(tdc, "", "  ")
		if err != nil {
			fmt.Printf("Failed to export config: %v\n", err)
			return
		}
	}
	if *outputTD {
		err = ioutil.WriteFile(*outfile, tdb, 0640)
		if err != nil {
			fmt.Printf("Failed to write file: %v\n", err)
			return
		}
	} else if *outputReplica {
		// We write a custom version of the replica config that is still able to be
		// unmarshaled. In particular, the code below uses the serialized version of
		// the trust domain from above, which may have it's private key stripped
		// (which can't easily be directly specified), and with the pointer to the
		// common config removed.

		// first encode
		servraw, err := json.Marshal(sc)
		if err != nil {
			fmt.Printf("Cannot flatten replica: %v\n", err)
			return
		}
		// reload both replica config and trustdomain config as JSON messages
		var servstruct map[string]interface{}
		err = json.Unmarshal(servraw, &servstruct)
		if err != nil {
			fmt.Printf("Failed to unmarshal replica: %v\n", err)
			return
		}
		delete(servstruct, "CommonConfig")
		delete(servstruct, "TrustDomain")
		var tdstruct map[string]interface{}
		err = json.Unmarshal(tdb, &tdstruct)
		if err != nil {
			fmt.Printf("Failed to unmarshal trust domain: %v\n", err)
			return
		}
		servstruct["TrustDomain"] = tdstruct

		servraw, err = json.MarshalIndent(servstruct, "", "  ")
		if err != nil {
			fmt.Printf("Could not flatten combined replica config: %v\n", err)
			return
		}
		err = ioutil.WriteFile(*outfile, servraw, 0640)
		if err != nil {
			fmt.Printf("Failed to write file: %v\n", err)
			return
		}
	}
}

// update/create client configuration with an explicit set of server trust domains.
func clientUtil(infile string, outfile string, trustfiles string) {
	domainPaths := strings.Split(trustfiles, ",")
	trustDomains := make([]*common.TrustDomainConfig, len(domainPaths))
	for i, path := range domainPaths {
		tdString, err := ioutil.ReadFile(path)
		if err != nil {
			log.Printf("Could not read %s!\n", path)
			return
		}
		trustDomains[i] = new(common.TrustDomainConfig)
		if err := json.Unmarshal(tdString, trustDomains[i]); err != nil {
			log.Printf("Could not parse %s: %v\n", path, err)
			return
		}
	}

	clientconf := libtalek.ClientConfig{
		ReadInterval:  time.Second,
		WriteInterval: time.Second,
	}
	if len(infile) > 0 {
		dat, readerr := ioutil.ReadFile(infile)
		if readerr != nil {
			fmt.Printf("Could not read input file: %v\n", readerr)
			return
		}
		if err := json.Unmarshal(dat, &clientconf); err != nil {
			fmt.Printf("Could not parse input file: %v\n", err)
			return
		}
	}

	clientconf.TrustDomains = trustDomains
	bytes, err := json.MarshalIndent(clientconf, "", "  ")
	if err != nil {
		fmt.Printf("Failed to export config: %v\n", err)
		return
	}
	err = ioutil.WriteFile(outfile, bytes, 0644)
	if err != nil {
		fmt.Printf("Failed to write %s: %v\n", outfile, err)
		return
	}
}
<commit_msg>fix vet error<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"time"

	"github.com/coreos/etcd/pkg/flags"
	"github.com/privacylab/talek/common"
	"github.com/privacylab/talek/libtalek"
	"github.com/privacylab/talek/server"
	"github.com/spf13/pflag"
)

// Talekutil is used to generate configuration files for structuring a talek
// deployment.  In particular, creating a set of configuration files for the
// clients and various trust domains.
func main() {

	outputClient := pflag.Bool("client", false, "Create configuration for a talek client.")
	outputReplica := pflag.Bool("replica", false, "Create configuration for a talek server.")
	outputTD := pflag.Bool("trustdomain", false, "Create raw trustdomain configuration.")
	outputCommon := pflag.Bool("common", false, "Create common config template.")
	name := pflag.String("name", "talek", "Server Name.")
	address := pflag.String("address", "localhost:9000", "Server Address.")
	infile := pflag.String("infile", "", "Begin with configuration from file.")
	outfile := pflag.String("outfile", "talek.json", "Save configuration to file.")
	private := pflag.Bool("private", false, "Include private key configuration.")
	trustdomains := pflag.String("trustdomains", "talek.json", "Comma separated list of trust domains.")
	ferr := flags.SetPflagsFromEnv(common.EnvPrefix, pflag.CommandLine)
	if ferr != nil {
		fmt.Printf("Error reading environment variables, %v\n", ferr)
		return
	}
	pflag.Parse()

	if *outputCommon {
		com := common.Config{
			NumBuckets:         1024,
			BucketDepth:        4,
			DataSize:           1024,
			BloomFalsePositive: .05,
			WriteInterval:      time.Second,
			ReadInterval:       time.Second,
			MaxLoadFactor:      0.95,
		}
		commonDat, err := json.MarshalIndent(com, "", "  ")
		if err != nil {
			fmt.Printf("Could not serialize common config: %v\n", err)
			return
		}
		ioutil.WriteFile(*outfile, commonDat, 0640)

		return
	}

	if !*outputReplica && !*outputTD && !*outputClient {
		fmt.Println("Talekutil needs a mode: --client, --replica, or --trustdomain.")
		return
	} else if (*outputReplica && *outputTD) || (*outputClient && *outputReplica) || (*outputClient && *outputTD) {
		fmt.Println("Mode must be one of --replica or --trustdomain or --client.")
		return
	}

	if *outputClient {
		clientUtil(*infile, *outfile, *trustdomains)
		return
	}

	var sc = server.Config{
		ReadBatch:     8,
		WriteInterval: time.Second,
		ReadInterval:  time.Second,
	}
	var tdc common.TrustDomainConfig
	var err error

	if len(*infile) > 0 {
		dat, readerr := ioutil.ReadFile(*infile)
		if readerr != nil {
			fmt.Printf("Could not read input file: %v\n", readerr)
			return
		}
		err = json.Unmarshal(dat, &tdc)
		if err != nil {
			fmt.Printf("Could not parse input file: %v\n", err)
			return
		}
		err = json.Unmarshal(dat, &sc)
		if err != nil {
			fmt.Printf("Could not parse input file: %v\n", err)
			return
		}
	} else {
		tdc = *common.NewTrustDomainConfig(*name, *address, true, false)
	}
	if sc.TrustDomain != nil {
		tdc = *sc.TrustDomain
	}
	tdc.Name = *name
	tdc.Address = *address
	tdc.IsValid = true

	var tdb []byte
	if *private {
		tdp := tdc.Private()
		if bytes.Compare(tdp.PrivateKey[:], make([]byte, 32)) == 0 {
			fmt.Printf("Imported configuration did not include key.\n")
			return
		}
		tdb, err = json.MarshalIndent(tdp, "", "  ")
		if err != nil {
			fmt.Printf("Failed to export config: %v\n", err)
			return
		}
	} else {
		tdb, err = json.MarshalIndent(tdc, "", "  ")
		if err != nil {
			fmt.Printf("Failed to export config: %v\n", err)
			return
		}
	}
	if *outputTD {
		err = ioutil.WriteFile(*outfile, tdb, 0640)
		if err != nil {
			fmt.Printf("Failed to write file: %v\n", err)
			return
		}
	} else if *outputReplica {
		// We write a custom version of the replica config that is still able to be
		// unmarshaled. In particular, the code below uses the serialized version of
		// the trust domain from above, which may have it's private key stripped
		// (which can't easily be directly specified), and with the pointer to the
		// common config removed.

		// first encode
		servraw, err := json.Marshal(sc)
		if err != nil {
			fmt.Printf("Cannot flatten replica: %v\n", err)
			return
		}
		// reload both replica config and trustdomain config as JSON messages
		var servstruct map[string]interface{}
		err = json.Unmarshal(servraw, &servstruct)
		if err != nil {
			fmt.Printf("Failed to unmarshal replica: %v\n", err)
			return
		}
		delete(servstruct, "CommonConfig")
		delete(servstruct, "TrustDomain")
		var tdstruct map[string]interface{}
		err = json.Unmarshal(tdb, &tdstruct)
		if err != nil {
			fmt.Printf("Failed to unmarshal trust domain: %v\n", err)
			return
		}
		servstruct["TrustDomain"] = tdstruct

		servraw, err = json.MarshalIndent(servstruct, "", "  ")
		if err != nil {
			fmt.Printf("Could not flatten combined replica config: %v\n", err)
			return
		}
		err = ioutil.WriteFile(*outfile, servraw, 0640)
		if err != nil {
			fmt.Printf("Failed to write file: %v\n", err)
			return
		}
	}
}

// update/create client configuration with an explicit set of server trust domains.
func clientUtil(infile string, outfile string, trustfiles string) {
	domainPaths := strings.Split(trustfiles, ",")
	trustDomains := make([]*common.TrustDomainConfig, len(domainPaths))
	for i, path := range domainPaths {
		tdString, err := ioutil.ReadFile(path)
		if err != nil {
			log.Printf("Could not read %s!\n", path)
			return
		}
		trustDomains[i] = new(common.TrustDomainConfig)
		if err := json.Unmarshal(tdString, trustDomains[i]); err != nil {
			log.Printf("Could not parse %s: %v\n", path, err)
			return
		}
	}

	clientconf := libtalek.ClientConfig{
		ReadInterval:  time.Second,
		WriteInterval: time.Second,
	}
	if len(infile) > 0 {
		dat, readerr := ioutil.ReadFile(infile)
		if readerr != nil {
			fmt.Printf("Could not read input file: %v\n", readerr)
			return
		}
		if err := json.Unmarshal(dat, &clientconf); err != nil {
			fmt.Printf("Could not parse input file: %v\n", err)
			return
		}
	}

	clientconf.TrustDomains = trustDomains
	bytes, err := json.MarshalIndent(clientconf, "", "  ")
	if err != nil {
		fmt.Printf("Failed to export config: %v\n", err)
		return
	}
	err = ioutil.WriteFile(outfile, bytes, 0644)
	if err != nil {
		fmt.Printf("Failed to write %s: %v\n", outfile, err)
		return
	}
}
<|endoftext|>


<commit_before>package filelist_test

import (
	"../filelist"
	"log"
)

func main() {
	log.Fatalf("filelist_test.go not implemented")
}
<commit_msg>Initial Sketch<commit_after>package filelist_test

import (
	"../filelist"
	"log"
)

func main() {
	log.Fatalf("filelist_test.go not implemented")
	rootDir := "../filelist"
	dirContents, err := filelist.GetDirectoryListing(rootDir)
	if err != nil {
		log.Fatalf("GetDirectoryListing() threw err %v\n", err)
	}
	log.Printf("dirContents: %v\n", dirContents)
}
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 proc

import (
	"errors"

	"github.com/zenoss/glog"

	"bufio"
	"fmt"
	"io/ioutil"
	"os/exec"
	"strings"
)

var ErrMountPointNotFound = errors.New("mount point not found")

var procNFSFSServersFile = "servers"
var procNFSFSVolumesFile = "volumes"
var procFindmntCommand = "/bin/findmnt --raw --noheading -o MAJ:MIN,FSTYPE,SOURCE,TARGET,OPTIONS %s"

// NFSVolumeInfo is merged from mountinfo and volumes
type NFSMountInfo struct {
	// from findmnt
	MountInfo

	// from /proc/fs/nfsfs/volumes
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// MountInfo is retrieved from mountinfo
type MountInfo struct {
	DeviceID   string // device id: 0:137
	FSType     string // filesystem type: btrfs, nfs4, ext4
	RemotePath string // path to the server: 10.87.209.168:/serviced_var
	LocalPath  string // path on the client: /tmp/serviced/var
	ServerIP   string // server ip address: 10.87.209.168
}

// ProcNFSFSServer is a parsed representation of /proc/fs/nfsfs/servers information.
type ProcNFSFSServer struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	Hostname string // hostname of server: 10.87.209.168
}

// ProcNFSFSVolume is a parsed representation of /proc/fs/nfsfs/volumes information.
type ProcNFSFSVolume struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	DeviceID string // device id: 0:137
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// GetProcNFSFSServers gets a map to the /proc/fs/nfsfs/servers
func GetProcNFSFSServers() (map[string]ProcNFSFSServer, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSServersFile))
	if err != nil {
		return nil, err
	}

	servers := make(map[string]ProcNFSFSServer)
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 5:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSServer{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			Hostname: fields[4],
		}
		key := fmt.Sprintf("%s:%s:%s", svr.Version, svr.ServerID, svr.Port)
		servers[key] = svr
	}
	glog.V(4).Infof("nfsfs servers: %+v", servers)
	return servers, nil
}

// GetProcNFSFSVolumes gets a map to the /proc/fs/nfsfs/volumes
func GetProcNFSFSVolumes() ([]ProcNFSFSVolume, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSVolumesFile))
	if err != nil {
		return nil, err
	}

	var volumes []ProcNFSFSVolume
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 6:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 6 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSVolume{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			DeviceID: fields[3],
			FSID:     fields[4],
			FSCache:  fields[5],
		}
		volumes = append(volumes, svr)
	}
	glog.V(4).Infof("nfsfs volumes: %+v", volumes)
	return volumes, nil
}

// GetProcNFSFSVolume gets the ProcNFSFSVolume of a deviceid from /proc/fs/nfsfs/volumes
func GetProcNFSFSVolume(deviceid string) (*ProcNFSFSVolume, error) {
	volumes, err := GetProcNFSFSVolumes()
	if err != nil {
		return nil, err
	}

	for idx := range volumes {
		glog.V(4).Infof("volume: %+v", volumes[idx])
		if deviceid == volumes[idx].DeviceID {
			return &volumes[idx], nil
		}
	}

	return nil, fmt.Errorf("unable to find volume for deviceid %s", deviceid)
}

// GetMountInfo gets the mount info of the mountpoint
func GetMountInfo(mountpoint string) (*MountInfo, error) {
	command := []string{"bash", "-c", fmt.Sprintf(procFindmntCommand, mountpoint)}

	thecmd := exec.Command(command[0], command[1:]...)
	glog.V(1).Infof("command: %+v", command)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		return nil, err
	}

	// [root@jrivera-tb1 ~]# /bin/findmnt --raw --noheading -o MAJ:MIN,FSTYPE,SOURCE,TARGET,OPTIONS /tmp/serviced/var
	// 0:329 nfs4 10.87.209.168:/serviced_var /tmp/serviced/var rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=10.87.209.168,local_lock=none,addr=10.87.209.168
	line := strings.TrimSpace(string(output))

	glog.V(4).Infof("line: %s", line)

	fields := strings.Fields(line)
	switch len(fields) {
	case 5:
		break
	case 0:
		return nil, ErrMountPointNotFound
	default:
		glog.Infof("command: %+v", command)
		return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
	}

	// parse options
	options := map[string]string{}
	optionParts := strings.Split(fields[4], ",")
	for _, option := range optionParts {
		pairs := strings.Split(option, "=")
		if len(pairs) == 2 {
			glog.V(4).Infof("option: %s  k:%s  v:%s", option, pairs[0], pairs[1])
			options[pairs[0]] = pairs[1]
		}
	}

	// return mount info
	info := MountInfo{
		DeviceID:   fields[0],
		FSType:     fields[1],
		RemotePath: fields[2],
		LocalPath:  fields[3],
		ServerIP:   options["addr"],
	}
	glog.V(4).Infof("mount info: %+v", info)
	return &info, nil
}

// GetNFSVolumeInfo gets the NFSMountInfo of the mountpoint
func GetNFSVolumeInfo(mountpoint string) (*NFSMountInfo, error) {
	minfo, err := GetMountInfo(mountpoint)
	if err != nil {
		return nil, err
	}

	if !strings.HasPrefix(minfo.FSType, "nfs") {
		return nil, fmt.Errorf("%s is not nfs; uses %s", minfo.LocalPath, minfo.FSType)
	}

	volume, err := GetProcNFSFSVolume(minfo.DeviceID)
	if err != nil {
		return nil, err
	}

	info := NFSMountInfo{
		MountInfo: *minfo,

		Version:  volume.Version,
		ServerID: volume.ServerID,
		Port:     volume.Port,
		FSID:     volume.FSID,
		FSCache:  volume.FSCache,
	}

	return &info, nil
}
<commit_msg>fixes CC-742: return ErrMountPointNotFound for findmnt command errors<commit_after>// Copyright 2014 The Serviced 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 proc

import (
	"errors"

	"github.com/zenoss/glog"

	"bufio"
	"fmt"
	"io/ioutil"
	"os/exec"
	"strings"
)

var ErrMountPointNotFound = errors.New("mount point not found")

var procNFSFSServersFile = "servers"
var procNFSFSVolumesFile = "volumes"
var procFindmntCommand = "/bin/findmnt --raw --noheading -o MAJ:MIN,FSTYPE,SOURCE,TARGET,OPTIONS %s"

// NFSVolumeInfo is merged from mountinfo and volumes
type NFSMountInfo struct {
	// from findmnt
	MountInfo

	// from /proc/fs/nfsfs/volumes
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// MountInfo is retrieved from mountinfo
type MountInfo struct {
	DeviceID   string // device id: 0:137
	FSType     string // filesystem type: btrfs, nfs4, ext4
	RemotePath string // path to the server: 10.87.209.168:/serviced_var
	LocalPath  string // path on the client: /tmp/serviced/var
	ServerIP   string // server ip address: 10.87.209.168
}

// ProcNFSFSServer is a parsed representation of /proc/fs/nfsfs/servers information.
type ProcNFSFSServer struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	Hostname string // hostname of server: 10.87.209.168
}

// ProcNFSFSVolume is a parsed representation of /proc/fs/nfsfs/volumes information.
type ProcNFSFSVolume struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	DeviceID string // device id: 0:137
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// GetProcNFSFSServers gets a map to the /proc/fs/nfsfs/servers
func GetProcNFSFSServers() (map[string]ProcNFSFSServer, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSServersFile))
	if err != nil {
		return nil, err
	}

	servers := make(map[string]ProcNFSFSServer)
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 5:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSServer{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			Hostname: fields[4],
		}
		key := fmt.Sprintf("%s:%s:%s", svr.Version, svr.ServerID, svr.Port)
		servers[key] = svr
	}
	glog.V(4).Infof("nfsfs servers: %+v", servers)
	return servers, nil
}

// GetProcNFSFSVolumes gets a map to the /proc/fs/nfsfs/volumes
func GetProcNFSFSVolumes() ([]ProcNFSFSVolume, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSVolumesFile))
	if err != nil {
		return nil, err
	}

	var volumes []ProcNFSFSVolume
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 6:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 6 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSVolume{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			DeviceID: fields[3],
			FSID:     fields[4],
			FSCache:  fields[5],
		}
		volumes = append(volumes, svr)
	}
	glog.V(4).Infof("nfsfs volumes: %+v", volumes)
	return volumes, nil
}

// GetProcNFSFSVolume gets the ProcNFSFSVolume of a deviceid from /proc/fs/nfsfs/volumes
func GetProcNFSFSVolume(deviceid string) (*ProcNFSFSVolume, error) {
	volumes, err := GetProcNFSFSVolumes()
	if err != nil {
		return nil, err
	}

	for idx := range volumes {
		glog.V(4).Infof("volume: %+v", volumes[idx])
		if deviceid == volumes[idx].DeviceID {
			return &volumes[idx], nil
		}
	}

	return nil, fmt.Errorf("unable to find volume for deviceid %s", deviceid)
}

// GetMountInfo gets the mount info of the mountpoint
func GetMountInfo(mountpoint string) (*MountInfo, error) {
	command := []string{"bash", "-c", fmt.Sprintf(procFindmntCommand, mountpoint)}

	thecmd := exec.Command(command[0], command[1:]...)
	glog.V(1).Infof("command: %+v", command)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		glog.Warningf("could not find mountpoint:%s with command:%+v  output:%s (%s)", mountpoint, command, string(output), err)
		return nil, ErrMountPointNotFound
	}

	// [root@jrivera-tb1 ~]# /bin/findmnt --raw --noheading -o MAJ:MIN,FSTYPE,SOURCE,TARGET,OPTIONS /tmp/serviced/var
	// 0:329 nfs4 10.87.209.168:/serviced_var /tmp/serviced/var rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=10.87.209.168,local_lock=none,addr=10.87.209.168
	line := strings.TrimSpace(string(output))

	glog.V(4).Infof("line: %s", line)

	fields := strings.Fields(line)
	switch len(fields) {
	case 5:
		break
	case 0:
		return nil, ErrMountPointNotFound
	default:
		glog.Infof("command: %+v", command)
		return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
	}

	// parse options
	options := map[string]string{}
	optionParts := strings.Split(fields[4], ",")
	for _, option := range optionParts {
		pairs := strings.Split(option, "=")
		if len(pairs) == 2 {
			glog.V(4).Infof("option: %s  k:%s  v:%s", option, pairs[0], pairs[1])
			options[pairs[0]] = pairs[1]
		}
	}

	// return mount info
	info := MountInfo{
		DeviceID:   fields[0],
		FSType:     fields[1],
		RemotePath: fields[2],
		LocalPath:  fields[3],
		ServerIP:   options["addr"],
	}
	glog.V(4).Infof("mount info: %+v", info)
	return &info, nil
}

// GetNFSVolumeInfo gets the NFSMountInfo of the mountpoint
func GetNFSVolumeInfo(mountpoint string) (*NFSMountInfo, error) {
	minfo, err := GetMountInfo(mountpoint)
	if err != nil {
		return nil, err
	}

	if !strings.HasPrefix(minfo.FSType, "nfs") {
		return nil, fmt.Errorf("%s is not nfs; uses %s", minfo.LocalPath, minfo.FSType)
	}

	volume, err := GetProcNFSFSVolume(minfo.DeviceID)
	if err != nil {
		return nil, err
	}

	info := NFSMountInfo{
		MountInfo: *minfo,

		Version:  volume.Version,
		ServerID: volume.ServerID,
		Port:     volume.Port,
		FSID:     volume.FSID,
		FSCache:  volume.FSCache,
	}

	return &info, nil
}
<|endoftext|>