<commit_before>package relations

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestTransducer(t *testing.T) {
	source := strings.NewReader(`(<a,>+<b,>)*.<a,>.<b,>.<b,>`)
	tr, _ := NewTransducer(source)

	state1 := tr.root
	assert.Equal(t, 1, state1.index)
	assert.Equal(t, 2, state1.next['a'][0].state.index)
	assert.Equal(t, 1, state1.next['b'][0].state.index)
	assert.Equal(t, 1, len(state1.next['a']))
	assert.Equal(t, 1, len(state1.next['b']))

	state2 := state1.next['a'][0].state
	assert.Equal(t, 2, state2.next['a'][0].state.index)
	assert.Equal(t, 3, state2.next['b'][0].state.index)
	assert.Equal(t, 1, len(state2.next['a']))
	assert.Equal(t, 1, len(state2.next['b']))

	state3 := state2.next['b'][0].state
	assert.Equal(t, 2, state3.next['a'][0].state.index)
	assert.Equal(t, 4, state3.next['b'][0].state.index)
	assert.Equal(t, 1, len(state3.next['a']))
	assert.Equal(t, 1, len(state3.next['b']))

	state4 := state3.next['b'][0].state
	assert.Equal(t, 2, state4.next['a'][0].state.index)
	assert.Equal(t, 1, len(state4.next['a']))
	assert.Equal(t, 1, len(state4.next['b']))
	assert.Equal(t, 1, state4.next['b'][0].state.index)
}

func TestTransducerFinal(t *testing.T) {
	source := strings.NewReader(`(<a,>+<b,>)*.<a,>.<b,>.<b,>`)
	tr, _ := NewTransducer(source)

	a := tr.root
	assert.False(t, a.final)

	b := a.next['a'][0].state
	assert.False(t, b.final)

	c := b.next['b'][0].state
	assert.False(t, c.final)

	d := c.next['b'][0].state
	assert.True(t, d.final)
}

func TestSameInputTape(t *testing.T) {
	source := strings.NewReader(`<a,b>+<a,c>+<a,d>`)
	tr, _ := NewTransducer(source)

	state1 := tr.root
	assert.Equal(t, 1, state1.index)

	assert.Equal(t, 1, len(state1.next))
	assert.Equal(t, 3, len(state1.next['a']))

	next := state1.next['a']
	assert.True(t, next[0].state == next[1].state && next[1].state == next[2].state)
	assert.Equal(t, 2, next[0].state.index)
	assert.True(t, next[0].state.final)
}

func TestMulticharInputTransducer(t *testing.T) {
	source := strings.NewReader(`<abc,xy>+<aca,zz>`)
	tr, _ := NewTransducer(source)

	state1 := tr.root
	assert.Equal(t, 1, state1.index)
	assert.Equal(t, 2, len(state1.next['a']))

	assert.Equal(t, 2, state1.next['a'][0].state.index)
	assert.Equal(t, "xy", state1.next['a'][0].out)

	assert.Equal(t, 3, state1.next['a'][1].state.index)
	assert.Equal(t, "zz", state1.next['a'][1].out)

	state2 := state1.next['a'][0].state
	assert.Equal(t, 0, len(state2.next['a']))
	assert.Equal(t, 0, len(state2.next['c']))
	assert.Equal(t, 4, state2.next['b'][0].state.index)
	assert.Equal(t, "", state2.next['b'][0].out)

	state3 := state1.next['a'][1].state
	assert.Equal(t, 0, len(state3.next['a']))
	assert.Equal(t, 0, len(state3.next['b']))
	assert.Equal(t, 5, state3.next['c'][0].state.index)
	assert.Equal(t, "", state3.next['c'][0].out)

	state4 := state2.next['b'][0].state
	assert.Equal(t, 0, len(state4.next['a']))
	assert.Equal(t, 0, len(state4.next['b']))
	assert.Equal(t, 6, state4.next['c'][0].state.index)
	assert.Equal(t, "", state4.next['c'][0].out)

	state5 := state3.next['c'][0].state
	assert.Equal(t, 0, len(state5.next['b']))
	assert.Equal(t, 0, len(state5.next['c']))
	assert.Equal(t, 6, state5.next['a'][0].state.index)
	assert.Equal(t, "", state5.next['a'][0].out)

	state6 := state5.next['a'][0].state
	assert.True(t, state6.final)
}
<commit_msg>Fix inconsistent transducer test<commit_after>package relations

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestTransducer(t *testing.T) {
	source := strings.NewReader(`(<a,>+<b,>)*.<a,>.<b,>.<b,>`)
	tr, _ := NewTransducer(source)

	state1 := tr.root
	assert.Equal(t, 1, state1.index)
	assert.Equal(t, 2, state1.next['a'][0].state.index)
	assert.Equal(t, 1, state1.next['b'][0].state.index)
	assert.Equal(t, 1, len(state1.next['a']))
	assert.Equal(t, 1, len(state1.next['b']))

	state2 := state1.next['a'][0].state
	assert.Equal(t, 2, state2.next['a'][0].state.index)
	assert.Equal(t, 3, state2.next['b'][0].state.index)
	assert.Equal(t, 1, len(state2.next['a']))
	assert.Equal(t, 1, len(state2.next['b']))

	state3 := state2.next['b'][0].state
	assert.Equal(t, 2, state3.next['a'][0].state.index)
	assert.Equal(t, 4, state3.next['b'][0].state.index)
	assert.Equal(t, 1, len(state3.next['a']))
	assert.Equal(t, 1, len(state3.next['b']))

	state4 := state3.next['b'][0].state
	assert.Equal(t, 2, state4.next['a'][0].state.index)
	assert.Equal(t, 1, len(state4.next['a']))
	assert.Equal(t, 1, len(state4.next['b']))
	assert.Equal(t, 1, state4.next['b'][0].state.index)
}

func TestTransducerFinal(t *testing.T) {
	source := strings.NewReader(`(<a,>+<b,>)*.<a,>.<b,>.<b,>`)
	tr, _ := NewTransducer(source)

	a := tr.root
	assert.False(t, a.final)

	b := a.next['a'][0].state
	assert.False(t, b.final)

	c := b.next['b'][0].state
	assert.False(t, c.final)

	d := c.next['b'][0].state
	assert.True(t, d.final)
}

func TestSameInputTape(t *testing.T) {
	source := strings.NewReader(`<a,b>+<a,c>+<a,d>`)
	tr, _ := NewTransducer(source)

	state1 := tr.root
	assert.Equal(t, 1, state1.index)

	assert.Equal(t, 1, len(state1.next))
	assert.Equal(t, 3, len(state1.next['a']))

	next := state1.next['a']
	assert.True(t, next[0].state == next[1].state && next[1].state == next[2].state)
	assert.Equal(t, 2, next[0].state.index)
	assert.True(t, next[0].state.final)
}

func TestMulticharInputTransducer(t *testing.T) {
	source := strings.NewReader(`<abc,xy>+<aca,zz>`)
	tr, _ := NewTransducer(source)

	state1 := tr.root
	assert.Equal(t, 1, state1.index)
	assert.Equal(t, 2, len(state1.next['a']))
}
<|endoftext|>


<commit_before>package main

import (
	"container/ring"
	"fmt"
)

type Color string

var colors = [...]Color{"white", "blue", "red", "yellow", "orange", "green"}
var edgesForFace = map[Color][]Color{
	"white":  {"red", "green", "orange", "blue"},
	"red":    {"blue", "yellow", "green", "white"},
	"blue":   {"white", "orange", "yellow", "red"},
	"yellow": {"green", "red", "blue", "orange"},
	"orange": {"yellow", "blue", "white", "green"},
	"green":  {"orange", "white", "red", "yellow"},
}

var edgePos = [...]int{0, 1, 2, 4, 3, 2, 4, 5, 6, 6, 7, 0}

type Face [8]Color

type Edge [12]*Color

type Cube struct {
	faceMap map[Color]*Face
	edgeMap map[Color]Edge
}

func New() (*Cube, error) {
	newFaceMap := make(map[Color]*Face)
	newEdgeMap := make(map[Color]Edge)
	for _, color := range colors {
		newFaceMap[color] = &Face{color, color, color, color, color, color, color, color}
	}
	i := 0
	for _, faceColor := range colors {
		var newEdge Edge
		for _, edgeColor := range edgesForFace[faceColor] {
			newEdge[i] = &newFaceMap[edgeColor][edgePos[i]]
			newEdge[i+1] = &newFaceMap[edgeColor][edgePos[i+1]]
			newEdge[i+2] = &newFaceMap[edgeColor][edgePos[i+2]]
			i += 3
		}
		newEdgeMap[faceColor] = newEdge
	}
	return &Cube{newFaceMap, newEdgeMap}, nil
}

type ThreeDTransformer struct {
	faceRing ring.Ring
	edgeRing ring.Ring
}

func main() {
	cube1 := new(Cube)
	face1 := &Face{"red", "red", "red", "red", "red", "red", "red", "red"}
	faceMap1 := make(map[Color]*Face)
	faceMap1["red"] = face1
	cube1.faceMap = faceMap1
	edge1 := Edge{&face1[0], &face1[1], &face1[2], &face1[3], &face1[4], &face1[5],
		&face1[6], &face1[7], &face1[0], &face1[1], &face1[2], &face1[3]}
	edgeMap1 := make(map[Color]Edge)
	edgeMap1["red"] = edge1
	cube1.edgeMap = edgeMap1
	*cube1.edgeMap["red"][0] = "blue"
	*cube1.edgeMap["red"][1] = "green"
	fmt.Println(cube1.faceMap["red"][0])
	fmt.Println(cube1.faceMap["red"][1])
	fmt.Println(cube1.faceMap["red"][2])
	fmt.Println(*cube1.edgeMap["red"][2])
}

<commit_msg>Show that NewCube works.<commit_after>package main

import (
	"container/ring"
	"fmt"
)

type Color string

var colors = [...]Color{"white", "blue", "red", "yellow", "orange", "green"}
var edgesForFace = map[Color][]Color{
	"white":  {"red", "green", "orange", "blue"},
	"red":    {"blue", "yellow", "green", "white"},
	"blue":   {"white", "orange", "yellow", "red"},
	"yellow": {"green", "red", "blue", "orange"},
	"orange": {"yellow", "blue", "white", "green"},
	"green":  {"orange", "white", "red", "yellow"},
}

var edgePos = [...]int{0, 1, 2, 4, 3, 2, 4, 5, 6, 6, 7, 0}

type Face [8]Color

type Edge [12]*Color

type Cube struct {
	faceMap map[Color]*Face
	edgeMap map[Color]Edge
}

func NewCube() (*Cube, error) {
	newFaceMap := make(map[Color]*Face)
	newEdgeMap := make(map[Color]Edge)
	for _, color := range colors {
		newFaceMap[color] = &Face{color, color, color, color, color, color, color, color}
	}
	i := 0
	for _, faceColor := range colors {
		var newEdge Edge
		for _, edgeColor := range edgesForFace[faceColor] {
		        //fmt.Println(faceColor)
		        //fmt.Println(i)
			newEdge[i] = &newFaceMap[edgeColor][edgePos[i]]
			newEdge[i+1] = &newFaceMap[edgeColor][edgePos[i+1]]
			newEdge[i+2] = &newFaceMap[edgeColor][edgePos[i+2]]
			i += 3
			if i == 12 {
			    i = 0
			}
		}
		newEdgeMap[faceColor] = newEdge
	}
	return &Cube{newFaceMap, newEdgeMap}, nil
}

type ThreeDTransformer struct {
	faceRing ring.Ring
	edgeRing ring.Ring
}

func main() {
	cube1,_ := NewCube()

	//fmt.Println(cube1)
	fmt.Println(cube1.faceMap["red"][1])
	fmt.Println(cube1.faceMap["red"][2])
	fmt.Println(*cube1.edgeMap["red"][2])
	fmt.Println(*cube1.edgeMap["red"][3])
	fmt.Println(*cube1.edgeMap["red"][8])
	fmt.Println(*cube1.edgeMap["red"][11])
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"net/url"

	"golang.org/x/crypto/scrypt"
)

// Session stores information related to identifying a user to Keybase.io.
type Session struct {
	CSRFToken     string
	SessionCookie string
}

// User stores information related to a Keybase.io user.
type User struct {
	Name string
	Salt string

	Identity *Session
}

// The URL used to get a user's salt.
const GetSaltURL string = "https://keybase.io/_/api/1.0/getsalt.json"

// The URL used to log into Keybase.io.
const LoginURL string = "https://keybase.io/_/api/1.0/login.json"

// Performs an HTTP GET operation against a selected URL with specified
// parameters. The function will return the response's body and any cookies
// received since those are the values that Keybase's API rely on.
func get(URL string, params url.Values) ([]byte, []*http.Cookie, error) {

	getURL, err := url.Parse(GetSaltURL)
	if err != nil {
		return nil, nil, err
	}

	getURL.RawQuery = params.Encode()

	client := &http.Client{}
	request, err := http.NewRequest("GET", getURL.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	resp, err := client.Do(request)
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, nil, err
	}

	return body, resp.Cookies(), nil
}

// Performs an HTTP POST operation against a selected URL with the specified
// JSON values. The function will return the response's body and any cookies
// received since those are the values that Keybase's API rely on.
func post(URL string, params map[string]string) ([]byte, []*http.Cookie, error) {

	jsonValues, err := json.Marshal(params)
	if err != nil {
		return nil, nil, err
	}

	client := &http.Client{}
	request, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonValues))
	if err != nil {
		return nil, nil, err
	}

	request.Header.Add("Content-Type", "application/json")

	resp, err := client.Do(request)
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, nil, err
	}

	return body, resp.Cookies(), nil
}

// Takes the body returned from Keybase.io's getsalt API call and parses into
// retrieves the desired data from the returned JSON data.
func parseSalt(body []byte) (string, string, string, error) {
	var saltParams map[string]interface{}
	err := json.Unmarshal(body, &saltParams)
	if err != nil {
		return "", "", "", err
	}

	salt := saltParams["salt"].(string)
	csrfToken := saltParams["csrf_token"].(string)
	loginSession := saltParams["login_session"].(string)

	return salt, csrfToken, loginSession, nil
}

func (user *User) getSalt() (string, error) {
	params := url.Values{}
	params.Add("email_or_username", user.Name)

	body, _, err := get(GetSaltURL, params)
	if err != nil {
		return "", err
	}

	salt, csrfToken, loginSession, err := parseSalt(body)
	if err != nil {
		return "", err
	}

	user.Salt = salt
	user.Identity.CSRFToken = csrfToken

	return loginSession, nil
}

// Hash's a user's password use Scrypt.
func hashPassphrase(salt string, passphrase string) ([]byte, error) {
	decodedSalt, err := hex.DecodeString(salt)
	if err != nil {
		return nil, err
	}

	hash, err := scrypt.Key([]byte(passphrase), decodedSalt, int(math.Pow(2, 15)), 8, 1, 224)
	if err != nil {
		return nil, err
	}

	pwh := hash[192:224]

	return pwh, nil
}

// Creates an HMAC from the user's hashed password at the current login session.
func getHMAC(pwh []byte, loginSession string) ([]byte, error) {
	b64Session, err := base64.StdEncoding.DecodeString(loginSession)
	if err != nil {
		return nil, err
	}

	hmacPWH := hmac.New(sha512.New, pwh)
	hmacPWH.Write(b64Session)

	return hmacPWH.Sum(nil), nil
}

// Login creates a session for a user.
func (user *User) Login(passphrase string) error {
	loginSession, err := user.getSalt()
	if err != nil {
		return err
	}

	pwh, err := hashPassphrase(user.Salt, passphrase)
	if err != nil {
		return err
	}

	hmacPWH, err := getHMAC(pwh, loginSession)
	if err != nil {
		return nil
	}

	loginValues := map[string]string{"email_or_username": user.Name,
		"hmac_pwh":      hex.EncodeToString(hmacPWH),
		"login_session": loginSession}

	body, cookies, err := post(LoginURL, loginValues)
	if err != nil {
		return err
	}

	for _, cookie := range cookies {
		if cookie.Name == "session" {
			user.Identity.SessionCookie = cookie.Value
		}
	}

	fmt.Println("Login Body:", string(body))

	return nil
}

func main() {
	user := flag.String("user", "", "User name or e-mail address.")
	passphrase := flag.String("passphrase", "", "Passphrase.")

	flag.Parse()

	session := Session{}
	me := User{Name: *user, Identity: &session}

	err := me.Login(*passphrase)
	if err != nil {
		panic(err)
	}

	// salt, csrfToken, loginSession, err := GetSalt(*user)
	// if err != nil {
	// 	panic(err)
	// }

	//	Login(*user, salt, loginSession, *passphrase)

	fmt.Println("Returned GetSalt values for user", *user, ".")
	fmt.Println("salt:", me.Salt)
	fmt.Println("csrfToken:", me.Identity.CSRFToken)
	// fmt.Println("loginSession:", loginSession)
}
<commit_msg>Begun working on parsing data returned from login.<commit_after>package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"reflect"

	"golang.org/x/crypto/scrypt"
)

// Session stores information related to identifying a user to Keybase.io.
type Session struct {
	CSRFToken     string
	SessionCookie string
}

// User stores information related to a Keybase.io user.
type User struct {
	Name      string
	Salt      string
	PublicKey []string

	Identity *Session
}

// The URL used to get a user's salt.
const GetSaltURL string = "https://keybase.io/_/api/1.0/getsalt.json"

// The URL used to log into Keybase.io.
const LoginURL string = "https://keybase.io/_/api/1.0/login.json"

// NewUser creates a new user with a given name. The name should be a Keybase.io
// user's username or e-mail address.
func NewUser(name string) *User {
	session := Session{}
	user := User{Name: name, Identity: &session}

	return &user
}

// Performs an HTTP GET operation against a selected URL with specified
// parameters. The function will return the response's body and any cookies
// received since those are the values that Keybase's API rely on.
func get(URL string, params url.Values) ([]byte, []*http.Cookie, error) {

	getURL, err := url.Parse(GetSaltURL)
	if err != nil {
		return nil, nil, err
	}

	getURL.RawQuery = params.Encode()

	client := &http.Client{}
	request, err := http.NewRequest("GET", getURL.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	resp, err := client.Do(request)
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, nil, err
	}

	return body, resp.Cookies(), nil
}

// Performs an HTTP POST operation against a selected URL with the specified
// JSON values. The function will return the response's body and any cookies
// received since those are the values that Keybase's API rely on.
func post(URL string, params map[string]string) ([]byte, []*http.Cookie, error) {

	jsonValues, err := json.Marshal(params)
	if err != nil {
		return nil, nil, err
	}

	client := &http.Client{}
	request, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonValues))
	if err != nil {
		return nil, nil, err
	}

	request.Header.Add("Content-Type", "application/json")

	resp, err := client.Do(request)
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, nil, err
	}

	return body, resp.Cookies(), nil
}

// Takes the body returned from Keybase.io's getsalt API call and parses into
// retrieves the desired data from the returned JSON data.
func parseSalt(body []byte) (string, string, error) {
	var saltParams map[string]interface{}
	err := json.Unmarshal(body, &saltParams)
	if err != nil {
		return "", "", err
	}

	salt := saltParams["salt"].(string)
	loginSession := saltParams["login_session"].(string)

	return salt, loginSession, nil
}

func (user *User) getSalt() (string, error) {
	params := url.Values{}
	params.Add("email_or_username", user.Name)

	body, _, err := get(GetSaltURL, params)
	if err != nil {
		return "", err
	}

	salt, loginSession, err := parseSalt(body)
	if err != nil {
		return "", err
	}

	user.Salt = salt

	return loginSession, nil
}

// Hash's a user's password use Scrypt.
func hashPassphrase(salt string, passphrase string) ([]byte, error) {
	decodedSalt, err := hex.DecodeString(salt)
	if err != nil {
		return nil, err
	}

	hash, err := scrypt.Key([]byte(passphrase), decodedSalt, int(math.Pow(2, 15)), 8, 1, 224)
	if err != nil {
		return nil, err
	}

	pwh := hash[192:224]

	return pwh, nil
}

// Creates an HMAC from the user's hashed password at the current login session.
func getHMAC(pwh []byte, loginSession string) ([]byte, error) {
	b64Session, err := base64.StdEncoding.DecodeString(loginSession)
	if err != nil {
		return nil, err
	}

	hmacPWH := hmac.New(sha512.New, pwh)
	hmacPWH.Write(b64Session)

	return hmacPWH.Sum(nil), nil
}

func (user *User) verifyCSRFToken(csrfToken string) error {
	fmt.Println("Stored CSRF Token:", user.Identity.CSRFToken)
	fmt.Println("Received CSRF Token:", csrfToken)

	if user.Identity.CSRFToken != csrfToken {
		return errors.New("keybase: csrf token mismatch")
	}

	fmt.Println("CSRF tokens match.")
	return nil
}

// func NewUserFromObject(userObject map[string]interface{}) (*User, error) {
// 	var basics map[string]interface{}
// 	err := json.Unmarshal()
// 	basics = userObject["basics"]
// 	user := NewUser(basics["username"])
//
// 	fmt.Println("User name is:", user.Name)
//
// 	return &user
// }

func (user *User) parseLogin(body []byte) error {
	var loginParams map[string]interface{}
	err := json.Unmarshal(body, &loginParams)
	if err != nil {
		return err
	}

	user.Identity.CSRFToken = loginParams["csrf_token"].(string)
	fmt.Println("CSRF Token:", user.Identity.CSRFToken)
	// TODO: Obtain and safe the CSRF token given by the login response.

	me := loginParams["me"].(map[string]interface{})
	fmt.Println("Me Type:", reflect.TypeOf(me), me)
	fmt.Println("First Me:", reflect.TypeOf(me["id"]), me["id"])

	basics := me["basics"].(map[string]interface{})
	fmt.Println("Basics Type:", reflect.TypeOf(basics), basics)
	fmt.Println("Basics Name:", reflect.TypeOf(basics["username"]), basics["username"])

	// meUser, err := NewUserFromObject(me)
	// if err != nil {
	// 	return err
	// }

	// csrfToken := loginParams["csrf_token"].(string)
	// err = user.verifyCSRFToken(csrfToken)
	// if err != nil {
	// 	return err
	// }

	return nil

}

// Login creates a session for a user.
func (user *User) Login(passphrase string) error {
	loginSession, err := user.getSalt()
	if err != nil {
		return err
	}

	pwh, err := hashPassphrase(user.Salt, passphrase)
	if err != nil {
		return err
	}

	hmacPWH, err := getHMAC(pwh, loginSession)
	if err != nil {
		return nil
	}

	loginValues := map[string]string{"email_or_username": user.Name,
		"hmac_pwh":      hex.EncodeToString(hmacPWH),
		"login_session": loginSession}

	body, cookies, err := post(LoginURL, loginValues)
	if err != nil {
		return err
	}

	// fmt.Println("LOGIN BODY:", string(body))

	err = user.parseLogin(body)
	if err != nil {
		return err
	}

	for _, cookie := range cookies {
		if cookie.Name == "session" {
			user.Identity.SessionCookie = cookie.Value
		}
	}

	// fmt.Println("Login Body:", string(body))

	return nil
}

func main() {
	user := flag.String("user", "", "User name or e-mail address.")
	passphrase := flag.String("passphrase", "", "Passphrase.")

	flag.Parse()

	me := NewUser(*user)

	err := me.Login(*passphrase)
	if err != nil {
		panic(err)
	}

	// salt, csrfToken, loginSession, err := GetSalt(*user)
	// if err != nil {
	// 	panic(err)
	// }

	//	Login(*user, salt, loginSession, *passphrase)

	fmt.Println("Returned GetSalt values for user", *user, ".")
	fmt.Println("salt:", me.Salt)
	fmt.Println("csrfToken:", me.Identity.CSRFToken)
	// fmt.Println("loginSession:", loginSession)
}
<|endoftext|>


<commit_before>// Package keyring provides a uniform API over a range of desktop credential storage engines
//
// See project homepage at https://github.com/99designs/keyring for more background
package keyring

import (
	"errors"
	"log"
)

// All currently supported secure storage backends
const (
	InvalidBackend       BackendType = "invalid"
	SecretServiceBackend BackendType = "secret-service"
	KeychainBackend      BackendType = "keychain"
	KWalletBackend       BackendType = "kwallet"
	WinCredBackend       BackendType = "wincred"
	FileBackend          BackendType = "file"
)

type BackendType string

var supportedBackends = map[BackendType]opener{}

// AvailableBackends provides a slice of all available backend keys on the current OS
func AvailableBackends() []BackendType {
	b := []BackendType{}
	for k := range supportedBackends {
		if k != FileBackend {
			b = append(b, k)
		}
	}
	// make sure FileBackend is last
	return append(b, FileBackend)
}

type opener func(cfg Config) (Keyring, error)

// Open will open a specific keyring backend
func Open(cfg Config) (Keyring, error) {
	if cfg.AllowedBackends == nil {
		cfg.AllowedBackends = AvailableBackends()
	}
	debugf("Considering backends: %v", cfg.AllowedBackends)
	for _, backend := range cfg.AllowedBackends {
		if opener, ok := supportedBackends[backend]; ok {
			openBackend, err := opener(cfg)
			if err != nil {
				debugf("Failed backend %s: %s", backend, err)
				continue
			}
			return openBackend, nil
		}
	}
	return nil, ErrNoAvailImpl
}

// Item is a thing stored on the keyring
type Item struct {
	Key         string
	Data        []byte
	Label       string
	Description string

	// Backend specific config
	KeychainNotTrustApplication bool
	KeychainNotSynchronizable   bool
}

// Keyring provides the uniform interface over the underlying backends
type Keyring interface {
	// Returns an Item matching the key or ErrKeyNotFound
	Get(key string) (Item, error)
	// Stores an Item on the keyring
	Set(item Item) error
	// Removes the item with matching key
	Remove(key string) error
	// Provides a slice of all keys stored on the keyring
	Keys() ([]string, error)
}

// ErrNoAvailImpl is returned by Open when a backend cannot be found
var ErrNoAvailImpl = errors.New("Specified keyring backend not available")

// ErrKeyNotFound is returned by Keyring Get when the item is not on the keyring
var ErrKeyNotFound = errors.New("The specified item could not be found in the keyring.")

var (
	// Whether to print debugging output
	Debug bool
)

func debugf(pattern string, args ...interface{}) {
	if Debug {
		log.Printf("[keyring] "+pattern, args...)
	}
}
<commit_msg>map InvalidBackend to (default) empty string<commit_after>// Package keyring provides a uniform API over a range of desktop credential storage engines
//
// See project homepage at https://github.com/99designs/keyring for more background
package keyring

import (
	"errors"
	"log"
)

// All currently supported secure storage backends
const (
	InvalidBackend       BackendType = ""
	SecretServiceBackend BackendType = "secret-service"
	KeychainBackend      BackendType = "keychain"
	KWalletBackend       BackendType = "kwallet"
	WinCredBackend       BackendType = "wincred"
	FileBackend          BackendType = "file"
)

type BackendType string

var supportedBackends = map[BackendType]opener{}

// AvailableBackends provides a slice of all available backend keys on the current OS
func AvailableBackends() []BackendType {
	b := []BackendType{}
	for k := range supportedBackends {
		if k != FileBackend {
			b = append(b, k)
		}
	}
	// make sure FileBackend is last
	return append(b, FileBackend)
}

type opener func(cfg Config) (Keyring, error)

// Open will open a specific keyring backend
func Open(cfg Config) (Keyring, error) {
	if cfg.AllowedBackends == nil {
		cfg.AllowedBackends = AvailableBackends()
	}
	debugf("Considering backends: %v", cfg.AllowedBackends)
	for _, backend := range cfg.AllowedBackends {
		if opener, ok := supportedBackends[backend]; ok {
			openBackend, err := opener(cfg)
			if err != nil {
				debugf("Failed backend %s: %s", backend, err)
				continue
			}
			return openBackend, nil
		}
	}
	return nil, ErrNoAvailImpl
}

// Item is a thing stored on the keyring
type Item struct {
	Key         string
	Data        []byte
	Label       string
	Description string

	// Backend specific config
	KeychainNotTrustApplication bool
	KeychainNotSynchronizable   bool
}

// Keyring provides the uniform interface over the underlying backends
type Keyring interface {
	// Returns an Item matching the key or ErrKeyNotFound
	Get(key string) (Item, error)
	// Stores an Item on the keyring
	Set(item Item) error
	// Removes the item with matching key
	Remove(key string) error
	// Provides a slice of all keys stored on the keyring
	Keys() ([]string, error)
}

// ErrNoAvailImpl is returned by Open when a backend cannot be found
var ErrNoAvailImpl = errors.New("Specified keyring backend not available")

// ErrKeyNotFound is returned by Keyring Get when the item is not on the keyring
var ErrKeyNotFound = errors.New("The specified item could not be found in the keyring.")

var (
	// Whether to print debugging output
	Debug bool
)

func debugf(pattern string, args ...interface{}) {
	if Debug {
		log.Printf("[keyring] "+pattern, args...)
	}
}
<|endoftext|>


<commit_before>package kickbox

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

type Client struct {
	apiKey string
	http   http.Client
}

func NewClient(apiKey string) Client {
	client := Client{
		apiKey: apiKey,
		http:   http.Client{},
	}

	// Set the default timeout to 3 seconds
	client.SetTimeout(time.Second * 3)
	return client
}

// Configure the request timeout value (includes connecting, waiting for a response, and reading the response)
func (c Client) SetTimeout(time time.Duration) {
	c.http.Timeout = time
}

// Verify the given email address using Kickbox.io
func (c Client) Verify(address string) (*Result, error) {
	return c.verify(KickboxResultBuilder{}, c.url(address))
}

// Build the API endpoint given the email address and API key
func (c Client) url(address string) string {
	return fmt.Sprintf("https://api.kickbox.io/v2/verify?email=%s&apikey=%s", url.QueryEscape(address), url.QueryEscape(c.apiKey))
}

// Request and read the response of the HTTP request, returning a new Result struct
func (c Client) verify(rb ResultBuilder, url string) (*Result, error) {
	// Send our API request
	response, err := c.http.Get(url)
	if err != nil {
		return nil, err
	}

	// Did we get a HTTP 200?
	if response.StatusCode != 200 {
		msg := fmt.Sprintf("Kickbox API returned HTTP %d", response.Status)
		return nil, errors.New(msg)
	}

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

	// Build our Result struct
	result, err := rb.NewResult(body)
	if err != nil {
		return nil, err
	}

	return result, nil
}
<commit_msg>Return a pointer to a Client<commit_after>package kickbox

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"time"
)

type Client struct {
	apiKey string
	http   http.Client
}

func NewClient(apiKey string) *Client {
	client := Client{
		apiKey: apiKey,
		http:   http.Client{},
	}

	// Set the default timeout to 3 seconds
	client.SetTimeout(time.Second * 3)
	return *client
}

// Configure the request timeout value (includes connecting, waiting for a response, and reading the response)
func (c Client) SetTimeout(time time.Duration) {
	c.http.Timeout = time
}

// Verify the given email address using Kickbox.io
func (c Client) Verify(address string) (*Result, error) {
	return c.verify(KickboxResultBuilder{}, c.url(address))
}

// Build the API endpoint given the email address and API key
func (c Client) url(address string) string {
	return fmt.Sprintf("https://api.kickbox.io/v2/verify?email=%s&apikey=%s", url.QueryEscape(address), url.QueryEscape(c.apiKey))
}

// Request and read the response of the HTTP request, returning a new Result struct
func (c Client) verify(rb ResultBuilder, url string) (*Result, error) {
	// Send our API request
	response, err := c.http.Get(url)
	if err != nil {
		return nil, err
	}

	// Did we get a HTTP 200?
	if response.StatusCode != 200 {
		msg := fmt.Sprintf("Kickbox API returned HTTP %d", response.Status)
		return nil, errors.New(msg)
	}

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

	// Build our Result struct
	result, err := rb.NewResult(body)
	if err != nil {
		return nil, err
	}

	return result, nil
}
<|endoftext|>


<commit_before>package infrastructure_test

import (
	"os"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	. "github.com/cloudfoundry/bosh-agent/infrastructure"
	boshsettings "github.com/cloudfoundry/bosh-agent/settings"
	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	fakesys "github.com/cloudfoundry/bosh-utils/system/fakes"
)

var _ = Describe("FileMetadataService", func() {
	var (
		fs              *fakesys.FakeFileSystem
		metadataService MetadataService
	)

	BeforeEach(func() {
		fs = fakesys.NewFakeFileSystem()
		logger := boshlog.NewLogger(boshlog.LevelNone)
		metadataService = NewFileMetadataService(
			"fake-metadata-file-path",
			"fake-userdata-file-path",
			"fake-settings-file-path",
			fs,
			logger,
		)
	})

	Describe("GetInstanceID", func() {
		Context("when metadata service file exists", func() {
			BeforeEach(func() {
				metadataContents := `{"instance-id":"fake-instance-id"}`
				fs.WriteFileString("fake-metadata-file-path", metadataContents)
			})

			It("returns instance id", func() {
				instanceID, err := metadataService.GetInstanceID()
				Expect(err).NotTo(HaveOccurred())
				Expect(instanceID).To(Equal("fake-instance-id"))
			})
		})

		Context("when metadata service file does not exist", func() {
			It("returns an error", func() {
				_, err := metadataService.GetInstanceID()
				Expect(err).To(HaveOccurred())
			})
		})

		Context("when metadata service file has invalid format", func() {
			BeforeEach(func() {
				fs.WriteFileString("fake-metadata-file-path", "bad-json")
			})

			It("returns an error", func() {
				_, err := metadataService.GetInstanceID()
				Expect(err).To(HaveOccurred())
			})
		})
	})

	Describe("GetServerName", func() {
		Context("when userdata file exists", func() {
			BeforeEach(func() {
				userDataContents := `{"server":{"name":"fake-server-name"}}`
				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns server name", func() {
				serverName, err := metadataService.GetServerName()
				Expect(err).NotTo(HaveOccurred())
				Expect(serverName).To(Equal("fake-server-name"))
			})
		})

		Context("when userdata file does not exist", func() {
			It("returns an error", func() {
				serverName, err := metadataService.GetServerName()
				Expect(err).To(HaveOccurred())
				Expect(serverName).To(BeEmpty())
			})
		})
	})

	Describe("GetNetworks", func() {
		It("returns the network settings", func() {
			userDataContents := `
				{
					"networks": {
						"network_1": {"type": "manual", "ip": "1.2.3.4", "netmask": "2.3.4.5", "gateway": "3.4.5.6", "default": ["dns"], "dns": ["8.8.8.8"], "mac": "fake-mac-address-1"},
						"network_2": {"type": "dynamic", "default": ["dns"], "dns": ["8.8.8.8"], "mac": "fake-mac-address-2"}
					}
				}`
			fs.WriteFileString("fake-userdata-file-path", userDataContents)

			networks, err := metadataService.GetNetworks()
			Expect(err).ToNot(HaveOccurred())
			Expect(networks).To(Equal(boshsettings.Networks{
				"network_1": boshsettings.Network{
					Type:    "manual",
					IP:      "1.2.3.4",
					Netmask: "2.3.4.5",
					Gateway: "3.4.5.6",
					Default: []string{"dns"},
					DNS:     []string{"8.8.8.8"},
					Mac:     "fake-mac-address-1",
				},
				"network_2": boshsettings.Network{
					Type:    "dynamic",
					Default: []string{"dns"},
					DNS:     []string{"8.8.8.8"},
					Mac:     "fake-mac-address-2",
				},
			}))
		})

		It("returns a nil Networks if the settings are missing (from an old CPI version)", func() {
			userDataContents := `{}`
			fs.WriteFileString("fake-userdata-file-path", userDataContents)

			networks, err := metadataService.GetNetworks()
			Expect(err).ToNot(HaveOccurred())
			Expect(networks).To(BeNil())
		})

		It("raises an error if we can't read the file", func() {
			networks, err := metadataService.GetNetworks()
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("Reading user data:"))
			be, ok := err.(bosherr.ComplexError)
			Expect(ok).To(BeTrue())
			be, ok = be.Cause.(bosherr.ComplexError)
			Expect(ok).To(BeTrue())
			pe, ok := be.Cause.(*os.PathError)
			Expect(ok).To(BeTrue())
			Expect(os.IsNotExist(pe)).To(BeTrue())
			Expect(networks).To(BeNil())
		})
	})

	Describe("GetRegistryEndpoint", func() {
		Context("when metadata service file exists", func() {
			BeforeEach(func() {
				userDataContents := `{"registry":{"endpoint":"fake-registry-endpoint"}}`
				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns registry endpoint", func() {
				registryEndpoint, err := metadataService.GetRegistryEndpoint()
				Expect(err).NotTo(HaveOccurred())
				Expect(registryEndpoint).To(Equal("fake-registry-endpoint"))
			})
		})

		Context("when metadata service file does not exist", func() {
			It("returns registry endpoint pointing to a settings file", func() {
				registryEndpoint, err := metadataService.GetRegistryEndpoint()
				Expect(err).NotTo(HaveOccurred())
				Expect(registryEndpoint).To(Equal("fake-settings-file-path"))
			})
		})
	})

	Describe("GetSettings", func() {
		Context("when metadata service file exists", func() {
			BeforeEach(func() {
				userDataContents := `
				{
					"registry":{"endpoint":"fake-registry-endpoint"},
					"settings":{
						"agent_id":"Agent-Foo",
						"mbus": "Agent-Mbus"
					}
				}`

				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns settings", func() {
				settings, err := metadataService.GetSettings()
				Expect(err).NotTo(HaveOccurred())
				Expect(settings.AgentID).To(Equal("Agent-Foo"))
			})

			Context("when metadata settings does NOT contain agentID", func() {
				BeforeEach(func() {
					userDataContents := `
					{
						"registry":{"endpoint":"fake-registry-endpoint"},
						"settings":{
							"mbus": "Agent-Mbus"
						}
					}`

					fs.WriteFileString("fake-userdata-file-path", userDataContents)
				})

				It("returns error", func() {
					_, err := metadataService.GetSettings()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(Equal("Metadata does not provide settings"))
				})
			})

		})

		Context("when metadata service file does not exist", func() {
			BeforeEach(func() {
				fs.RemoveAll("fake-settings-file-path")
			})

			It("returns error", func() {
				_, err := metadataService.GetSettings()
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(Equal("Reading user data: Not found: open fake-userdata-file-path: no such file or directory"))
			})
		})

		Context("when we have incorrect metadata in file", func() {
			BeforeEach(func() {
				userDataContents := `
					{
						"INCORRECT JSON": ,
						"registry":{"endpoint":"fake-registry-endpoint"},
						"settings":{
							"mbus": "Agent-Mbus"
					}`

				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns error", func() {
				_, err := metadataService.GetSettings()
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(Equal("Unmarshalling user data: invalid character ',' looking for beginning of value"))
			})
		})
	})

	Describe("IsAvailable", func() {
		Context("when file does not exist", func() {
			It("returns false", func() {
				Expect(metadataService.IsAvailable()).To(BeFalse())
			})
		})

		Context("when file exists", func() {
			BeforeEach(func() {
				fs.WriteFileString("fake-settings-file-path", ``)
			})

			It("returns true", func() {
				Expect(metadataService.IsAvailable()).To(BeTrue())
			})
		})
	})
})
<commit_msg>Fix windows integration test<commit_after>package infrastructure_test

import (
	"os"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	. "github.com/cloudfoundry/bosh-agent/infrastructure"
	boshsettings "github.com/cloudfoundry/bosh-agent/settings"
	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	fakesys "github.com/cloudfoundry/bosh-utils/system/fakes"
)

var _ = Describe("FileMetadataService", func() {
	var (
		fs              *fakesys.FakeFileSystem
		metadataService MetadataService
	)

	BeforeEach(func() {
		fs = fakesys.NewFakeFileSystem()
		logger := boshlog.NewLogger(boshlog.LevelNone)
		metadataService = NewFileMetadataService(
			"fake-metadata-file-path",
			"fake-userdata-file-path",
			"fake-settings-file-path",
			fs,
			logger,
		)
	})

	Describe("GetInstanceID", func() {
		Context("when metadata service file exists", func() {
			BeforeEach(func() {
				metadataContents := `{"instance-id":"fake-instance-id"}`
				fs.WriteFileString("fake-metadata-file-path", metadataContents)
			})

			It("returns instance id", func() {
				instanceID, err := metadataService.GetInstanceID()
				Expect(err).NotTo(HaveOccurred())
				Expect(instanceID).To(Equal("fake-instance-id"))
			})
		})

		Context("when metadata service file does not exist", func() {
			It("returns an error", func() {
				_, err := metadataService.GetInstanceID()
				Expect(err).To(HaveOccurred())
			})
		})

		Context("when metadata service file has invalid format", func() {
			BeforeEach(func() {
				fs.WriteFileString("fake-metadata-file-path", "bad-json")
			})

			It("returns an error", func() {
				_, err := metadataService.GetInstanceID()
				Expect(err).To(HaveOccurred())
			})
		})
	})

	Describe("GetServerName", func() {
		Context("when userdata file exists", func() {
			BeforeEach(func() {
				userDataContents := `{"server":{"name":"fake-server-name"}}`
				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns server name", func() {
				serverName, err := metadataService.GetServerName()
				Expect(err).NotTo(HaveOccurred())
				Expect(serverName).To(Equal("fake-server-name"))
			})
		})

		Context("when userdata file does not exist", func() {
			It("returns an error", func() {
				serverName, err := metadataService.GetServerName()
				Expect(err).To(HaveOccurred())
				Expect(serverName).To(BeEmpty())
			})
		})
	})

	Describe("GetNetworks", func() {
		It("returns the network settings", func() {
			userDataContents := `
				{
					"networks": {
						"network_1": {"type": "manual", "ip": "1.2.3.4", "netmask": "2.3.4.5", "gateway": "3.4.5.6", "default": ["dns"], "dns": ["8.8.8.8"], "mac": "fake-mac-address-1"},
						"network_2": {"type": "dynamic", "default": ["dns"], "dns": ["8.8.8.8"], "mac": "fake-mac-address-2"}
					}
				}`
			fs.WriteFileString("fake-userdata-file-path", userDataContents)

			networks, err := metadataService.GetNetworks()
			Expect(err).ToNot(HaveOccurred())
			Expect(networks).To(Equal(boshsettings.Networks{
				"network_1": boshsettings.Network{
					Type:    "manual",
					IP:      "1.2.3.4",
					Netmask: "2.3.4.5",
					Gateway: "3.4.5.6",
					Default: []string{"dns"},
					DNS:     []string{"8.8.8.8"},
					Mac:     "fake-mac-address-1",
				},
				"network_2": boshsettings.Network{
					Type:    "dynamic",
					Default: []string{"dns"},
					DNS:     []string{"8.8.8.8"},
					Mac:     "fake-mac-address-2",
				},
			}))
		})

		It("returns a nil Networks if the settings are missing (from an old CPI version)", func() {
			userDataContents := `{}`
			fs.WriteFileString("fake-userdata-file-path", userDataContents)

			networks, err := metadataService.GetNetworks()
			Expect(err).ToNot(HaveOccurred())
			Expect(networks).To(BeNil())
		})

		It("raises an error if we can't read the file", func() {
			networks, err := metadataService.GetNetworks()
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("Reading user data:"))
			be, ok := err.(bosherr.ComplexError)
			Expect(ok).To(BeTrue())
			be, ok = be.Cause.(bosherr.ComplexError)
			Expect(ok).To(BeTrue())
			pe, ok := be.Cause.(*os.PathError)
			Expect(ok).To(BeTrue())
			Expect(os.IsNotExist(pe)).To(BeTrue())
			Expect(networks).To(BeNil())
		})
	})

	Describe("GetRegistryEndpoint", func() {
		Context("when metadata service file exists", func() {
			BeforeEach(func() {
				userDataContents := `{"registry":{"endpoint":"fake-registry-endpoint"}}`
				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns registry endpoint", func() {
				registryEndpoint, err := metadataService.GetRegistryEndpoint()
				Expect(err).NotTo(HaveOccurred())
				Expect(registryEndpoint).To(Equal("fake-registry-endpoint"))
			})
		})

		Context("when metadata service file does not exist", func() {
			It("returns registry endpoint pointing to a settings file", func() {
				registryEndpoint, err := metadataService.GetRegistryEndpoint()
				Expect(err).NotTo(HaveOccurred())
				Expect(registryEndpoint).To(Equal("fake-settings-file-path"))
			})
		})
	})

	Describe("GetSettings", func() {
		Context("when metadata service file exists", func() {
			BeforeEach(func() {
				userDataContents := `
				{
					"registry":{"endpoint":"fake-registry-endpoint"},
					"settings":{
						"agent_id":"Agent-Foo",
						"mbus": "Agent-Mbus"
					}
				}`

				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns settings", func() {
				settings, err := metadataService.GetSettings()
				Expect(err).NotTo(HaveOccurred())
				Expect(settings.AgentID).To(Equal("Agent-Foo"))
			})

			Context("when metadata settings does NOT contain agentID", func() {
				BeforeEach(func() {
					userDataContents := `
					{
						"registry":{"endpoint":"fake-registry-endpoint"},
						"settings":{
							"mbus": "Agent-Mbus"
						}
					}`

					fs.WriteFileString("fake-userdata-file-path", userDataContents)
				})

				It("returns error", func() {
					_, err := metadataService.GetSettings()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(Equal("Metadata does not provide settings"))
				})
			})
		})

		Context("when metadata service file does not exist", func() {
			BeforeEach(func() {
				fs.RemoveAll("fake-settings-file-path")
			})

			It("returns error", func() {
				_, err := metadataService.GetSettings()
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("Reading user data: Not found: open fake-userdata-file-path"))
			})
		})

		Context("when we have incorrect metadata in file", func() {
			BeforeEach(func() {
				userDataContents := `
					{
						"INCORRECT JSON": ,
						"registry":{"endpoint":"fake-registry-endpoint"},
						"settings":{
							"mbus": "Agent-Mbus"
					}`

				fs.WriteFileString("fake-userdata-file-path", userDataContents)
			})

			It("returns error", func() {
				_, err := metadataService.GetSettings()
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(Equal("Unmarshalling user data: invalid character ',' looking for beginning of value"))
			})
		})
	})

	Describe("IsAvailable", func() {
		Context("when file does not exist", func() {
			It("returns false", func() {
				Expect(metadataService.IsAvailable()).To(BeFalse())
			})
		})

		Context("when file exists", func() {
			BeforeEach(func() {
				fs.WriteFileString("fake-settings-file-path", ``)
			})

			It("returns true", func() {
				Expect(metadataService.IsAvailable()).To(BeTrue())
			})
		})
	})
})
<|endoftext|>


<commit_before>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
#include "lmdbgo.h"
*/
import "C"

import (
	"log"
	"math"
	"runtime"
	"unsafe"
)

// This flags are used exclusively for Txn.OpenDBI and Txn.OpenRoot.  The
// Create flag must always be supplied when opening a non-root DBI for the
// first time.
//
// BUG(bmatsuo):
// MDB_INTEGERKEY and MDB_INTEGERDUP aren't usable. I'm not sure they would be
// faster with the cgo bridge.  They need to be tested and benchmarked.
const (
	// Flags for Txn.OpenDBI.

	ReverseKey = C.MDB_REVERSEKEY // Use reverse string keys.
	DupSort    = C.MDB_DUPSORT    // Use sorted duplicates.
	DupFixed   = C.MDB_DUPFIXED   // Duplicate items have a fixed size (DupSort).
	ReverseDup = C.MDB_REVERSEDUP // Reverse duplicate values (DupSort).
	Create     = C.MDB_CREATE     // Create DB if not already existing.
)

// Txn is a database transaction in an environment.
//
// WARNING: A writable Txn is not threadsafe and may only be used in the
// goroutine that created it.
//
// See MDB_txn.
type Txn struct {
	// If RawRead is true []byte values retrieved from Get() calls on the Txn
	// and its cursors will point directly into the memory-mapped structure.
	// Such slices will be readonly and must only be referenced wthin the
	// transaction's lifetime.
	RawRead  bool
	managed  bool
	readonly bool
	env      *Env
	_txn     *C.MDB_txn
	errLogf  func(format string, v ...interface{})
}

// beginTxn does not lock the OS thread which is a prerequisite for creating a
// write transaction.
func beginTxn(env *Env, parent *Txn, flags uint) (*Txn, error) {
	txn := &Txn{
		readonly: (flags&Readonly != 0),
		env:      env,
	}
	var ptxn *C.MDB_txn
	if parent == nil {
		ptxn = nil
	} else {
		ptxn = parent._txn
	}
	ret := C.mdb_txn_begin(env._env, ptxn, C.uint(flags), &txn._txn)
	if ret != success {
		return nil, operrno("mdb_txn_begin", ret)
	}
	return txn, nil
}

// Commit persists all transaction operations to the database and clears the
// finalizer on txn.  A Txn cannot be used again after Commit is called.
//
// See mdb_txn_commit.
func (txn *Txn) Commit() error {
	if txn.managed {
		panic("managed transaction cannot be comitted directly")
	}
	if txn != nil {
		runtime.SetFinalizer(txn, nil)
	}
	return txn.commit()
}

func (txn *Txn) commit() error {
	ret := C.mdb_txn_commit(txn._txn)
	txn._txn = nil
	return operrno("mdb_txn_commit", ret)
}

// Abort discards pending writes in the transaction and clears the finalizer on
// txn.  A Txn cannot be used again after Abort is called.
//
// See mdb_txn_abort.
func (txn *Txn) Abort() {
	if txn.managed {
		panic("managed transaction cannot be aborted directly")
	}
	if txn != nil {
		runtime.SetFinalizer(txn, nil)
	}
	txn.abort()
}

func (txn *Txn) abort() {
	if txn._txn == nil {
		return
	}
	C.mdb_txn_abort(txn._txn)
	// The transaction handle is always freed.
	txn._txn = nil
}

// Reset aborts the transaction clears internal state so the transaction may be
// reused by calling Renew.  If txn is not going to be reused txn.Abort() must
// be called to release its slot in the lock table and free its memory.  Reset
// panics if txn is managed by Update, View, etc.
//
// See mdb_txn_reset.
func (txn *Txn) Reset() {
	if txn.managed {
		panic("managed transaction cannot be reset directly")
	}
	txn.reset()
}

func (txn *Txn) reset() {
	C.mdb_txn_reset(txn._txn)
}

// Renew reuses a transaction that was previously reset by calling txn.Reset().
// Renew panics if txn is managed by Update, View, etc.
//
// See mdb_txn_renew.
func (txn *Txn) Renew() error {
	if txn.managed {
		panic("managed transaction cannot be renewed directly")
	}
	return txn.renew()
}

func (txn *Txn) renew() error {
	ret := C.mdb_txn_renew(txn._txn)
	return operrno("mdb_txn_renew", ret)
}

// OpenDBI opens a named database in the environment.  An error is returned if
// name is empty.  The DBI returned by OpenDBI can be used in other
// transactions but not before Txn has terminated.
//
// OpenDBI can only be called after env.SetMaxDBs() has been called to set the
// maximum number of named databases.
//
// The C API uses null terminated strings for database names.  A consequence is
// that names cannot contain null bytes themselves. OpenDBI does not check for
// null bytes in the name argument.
//
// See mdb_dbi_open.
func (txn *Txn) OpenDBI(name string, flags uint) (DBI, error) {
	cname := C.CString(name)
	dbi, err := txn.openDBI(cname, flags)
	C.free(unsafe.Pointer(cname))
	return dbi, err
}

// CreateDBI is a shorthand for OpenDBI that passed the flag lmdb.Create.
func (txn *Txn) CreateDBI(name string) (DBI, error) {
	return txn.OpenDBI(name, Create)
}

// Flags returns the database flags for handle dbi.
func (txn *Txn) Flags(dbi DBI) (uint, error) {
	var cflags C.uint
	ret := C.mdb_dbi_flags(txn._txn, C.MDB_dbi(dbi), (*C.uint)(&cflags))
	return uint(cflags), operrno("mdb_dbi_flags", ret)
}

// OpenRoot opens the root database.  OpenRoot behaves similarly to OpenDBI but
// does not require env.SetMaxDBs() to be called beforehand.  And, OpenRoot can
// be called without flags in a View transaction.
func (txn *Txn) OpenRoot(flags uint) (DBI, error) {
	return txn.openDBI(nil, flags)
}

func (txn *Txn) openDBI(cname *C.char, flags uint) (DBI, error) {
	var dbi C.MDB_dbi
	ret := C.mdb_dbi_open(txn._txn, cname, C.uint(flags), &dbi)
	if ret != success {
		return DBI(math.NaN()), operrno("mdb_dbi_open", ret)
	}
	return DBI(dbi), nil
}

// Stat returns a Stat describing the database dbi.
//
// See mdb_stat.
func (txn *Txn) Stat(dbi DBI) (*Stat, error) {
	var _stat C.MDB_stat
	ret := C.mdb_stat(txn._txn, C.MDB_dbi(dbi), &_stat)
	if ret != success {
		return nil, operrno("mdb_stat", ret)
	}
	stat := Stat{PSize: uint(_stat.ms_psize),
		Depth:         uint(_stat.ms_depth),
		BranchPages:   uint64(_stat.ms_branch_pages),
		LeafPages:     uint64(_stat.ms_leaf_pages),
		OverflowPages: uint64(_stat.ms_overflow_pages),
		Entries:       uint64(_stat.ms_entries)}
	return &stat, nil
}

// Drop empties the database if del is false.  Drop deletes and closes the
// database if del is true.
//
// See mdb_drop.
func (txn *Txn) Drop(dbi DBI, del bool) error {
	ret := C.mdb_drop(txn._txn, C.MDB_dbi(dbi), cbool(del))
	return operrno("mdb_drop", ret)
}

// Sub executes fn in a subtransaction.  Sub commits the subtransaction iff a
// nil error is returned by fn and otherwise aborts it.  Sub returns any error
// it encounters.
//
// Sub may only be called on an Update (a Txn created without the Readonly
// flag).  Calling Sub on a View transaction will return an error.
//
// Any call to Abort, Commit, Renew, or Reset on a Txn created by Sub will
// panic.
func (txn *Txn) Sub(fn TxnOp) error {
	// As of 0.9.14 Readonly is the only Txn flag and readonly subtransactions
	// don't make sense.
	return txn.subFlag(0, fn)
}

func (txn *Txn) subFlag(flags uint, fn TxnOp) error {
	sub, err := beginTxn(txn.env, txn, flags)
	if err != nil {
		return err
	}
	sub.managed = true
	defer sub.abort()
	err = fn(sub)
	if err != nil {
		return err
	}
	return sub.commit()
}

func (txn *Txn) bytes(val *mdbVal) []byte {
	if txn.RawRead {
		return val.Bytes()
	}
	return val.BytesCopy()
}

// Get retrieves items from database dbi.  If txn.RawRead is true the slice
// returned by Get references a readonly section of memory that must not be
// accessed after txn has terminated.
//
// See mdb_get.
func (txn *Txn) Get(dbi DBI, key []byte) ([]byte, error) {
	kdata, kn := valBytes(key)
	val := new(mdbVal)
	ret := C.lmdbgo_mdb_get(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		(*C.MDB_val)(val),
	)
	err := operrno("mdb_get", ret)
	if err != nil {
		return nil, err
	}
	return txn.bytes(val), nil
}

// Put stores an item in database dbi.
//
// See mdb_put.
func (txn *Txn) Put(dbi DBI, key []byte, val []byte, flags uint) error {
	kdata, kn := valBytes(key)
	vdata, vn := valBytes(val)
	ret := C.lmdbgo_mdb_put2(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		vdata, C.size_t(vn),
		C.uint(flags),
	)
	return operrno("mdb_put", ret)
}

// PutReserve returns a []byte of length n that can be written to, potentially
// avoiding a memcopy.  The returned byte slice is only valid in txn's thread,
// before it has terminated.
func (txn *Txn) PutReserve(dbi DBI, key []byte, n int, flags uint) ([]byte, error) {
	kdata, kn := valBytes(key)
	val := &mdbVal{mv_size: C.size_t(n)}
	ret := C.lmdbgo_mdb_put1(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		(*C.MDB_val)(val),
		C.uint(flags|C.MDB_RESERVE),
	)
	err := operrno("mdb_put", ret)
	if err != nil {
		return nil, err
	}
	return val.Bytes(), nil
}

// Del deletes an item from database dbi.  Del ignores val unless dbi has the
// DupSort flag.
//
// See mdb_del.
func (txn *Txn) Del(dbi DBI, key, val []byte) error {
	kdata, kn := valBytes(key)
	vdata, vn := valBytes(val)
	ret := C.lmdbgo_mdb_del(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		vdata, C.size_t(vn),
	)
	return operrno("mdb_del", ret)
}

// OpenCursor allocates and initializes a Cursor to database dbi.
//
// See mdb_cursor_open.
func (txn *Txn) OpenCursor(dbi DBI) (*Cursor, error) {
	cur, err := openCursor(txn, dbi)
	if cur != nil && txn.readonly {
		runtime.SetFinalizer(cur, (*Cursor).close)
	}
	return cur, err
}

func (txn *Txn) errf(format string, v ...interface{}) {
	if txn.errLogf != nil {
		txn.errLogf(format, v...)
		return
	}
	log.Printf(format, v...)
}

// TxnOp is an operation applied to a managed transaction.  The Txn passed to a
// TxnOp is managed and the operation must not call Commit, Abort, Renew, or
// Reset on it.
//
// IMPORTANT:
// TxnOps that write to the database (those passed to Update or BeginUpdate)
// must not use the Txn in another goroutine (passing it directly or otherwise
// through closure).  Doing so has undefined results.
type TxnOp func(txn *Txn) error
<commit_msg>lmdb: remove unnecessary check for nil *Txn<commit_after>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
#include "lmdbgo.h"
*/
import "C"

import (
	"log"
	"math"
	"runtime"
	"unsafe"
)

// This flags are used exclusively for Txn.OpenDBI and Txn.OpenRoot.  The
// Create flag must always be supplied when opening a non-root DBI for the
// first time.
//
// BUG(bmatsuo):
// MDB_INTEGERKEY and MDB_INTEGERDUP aren't usable. I'm not sure they would be
// faster with the cgo bridge.  They need to be tested and benchmarked.
const (
	// Flags for Txn.OpenDBI.

	ReverseKey = C.MDB_REVERSEKEY // Use reverse string keys.
	DupSort    = C.MDB_DUPSORT    // Use sorted duplicates.
	DupFixed   = C.MDB_DUPFIXED   // Duplicate items have a fixed size (DupSort).
	ReverseDup = C.MDB_REVERSEDUP // Reverse duplicate values (DupSort).
	Create     = C.MDB_CREATE     // Create DB if not already existing.
)

// Txn is a database transaction in an environment.
//
// WARNING: A writable Txn is not threadsafe and may only be used in the
// goroutine that created it.
//
// See MDB_txn.
type Txn struct {
	// If RawRead is true []byte values retrieved from Get() calls on the Txn
	// and its cursors will point directly into the memory-mapped structure.
	// Such slices will be readonly and must only be referenced wthin the
	// transaction's lifetime.
	RawRead  bool
	managed  bool
	readonly bool
	env      *Env
	_txn     *C.MDB_txn
	errLogf  func(format string, v ...interface{})
}

// beginTxn does not lock the OS thread which is a prerequisite for creating a
// write transaction.
func beginTxn(env *Env, parent *Txn, flags uint) (*Txn, error) {
	txn := &Txn{
		readonly: (flags&Readonly != 0),
		env:      env,
	}
	var ptxn *C.MDB_txn
	if parent == nil {
		ptxn = nil
	} else {
		ptxn = parent._txn
	}
	ret := C.mdb_txn_begin(env._env, ptxn, C.uint(flags), &txn._txn)
	if ret != success {
		return nil, operrno("mdb_txn_begin", ret)
	}
	return txn, nil
}

// Commit persists all transaction operations to the database and clears the
// finalizer on txn.  A Txn cannot be used again after Commit is called.
//
// See mdb_txn_commit.
func (txn *Txn) Commit() error {
	if txn.managed {
		panic("managed transaction cannot be comitted directly")
	}
	runtime.SetFinalizer(txn, nil)
	return txn.commit()
}

func (txn *Txn) commit() error {
	ret := C.mdb_txn_commit(txn._txn)
	txn._txn = nil
	return operrno("mdb_txn_commit", ret)
}

// Abort discards pending writes in the transaction and clears the finalizer on
// txn.  A Txn cannot be used again after Abort is called.
//
// See mdb_txn_abort.
func (txn *Txn) Abort() {
	if txn.managed {
		panic("managed transaction cannot be aborted directly")
	}
	runtime.SetFinalizer(txn, nil)
	txn.abort()
}

func (txn *Txn) abort() {
	if txn._txn == nil {
		return
	}
	C.mdb_txn_abort(txn._txn)
	// The transaction handle is always freed.
	txn._txn = nil
}

// Reset aborts the transaction clears internal state so the transaction may be
// reused by calling Renew.  If txn is not going to be reused txn.Abort() must
// be called to release its slot in the lock table and free its memory.  Reset
// panics if txn is managed by Update, View, etc.
//
// See mdb_txn_reset.
func (txn *Txn) Reset() {
	if txn.managed {
		panic("managed transaction cannot be reset directly")
	}
	txn.reset()
}

func (txn *Txn) reset() {
	C.mdb_txn_reset(txn._txn)
}

// Renew reuses a transaction that was previously reset by calling txn.Reset().
// Renew panics if txn is managed by Update, View, etc.
//
// See mdb_txn_renew.
func (txn *Txn) Renew() error {
	if txn.managed {
		panic("managed transaction cannot be renewed directly")
	}
	return txn.renew()
}

func (txn *Txn) renew() error {
	ret := C.mdb_txn_renew(txn._txn)
	return operrno("mdb_txn_renew", ret)
}

// OpenDBI opens a named database in the environment.  An error is returned if
// name is empty.  The DBI returned by OpenDBI can be used in other
// transactions but not before Txn has terminated.
//
// OpenDBI can only be called after env.SetMaxDBs() has been called to set the
// maximum number of named databases.
//
// The C API uses null terminated strings for database names.  A consequence is
// that names cannot contain null bytes themselves. OpenDBI does not check for
// null bytes in the name argument.
//
// See mdb_dbi_open.
func (txn *Txn) OpenDBI(name string, flags uint) (DBI, error) {
	cname := C.CString(name)
	dbi, err := txn.openDBI(cname, flags)
	C.free(unsafe.Pointer(cname))
	return dbi, err
}

// CreateDBI is a shorthand for OpenDBI that passed the flag lmdb.Create.
func (txn *Txn) CreateDBI(name string) (DBI, error) {
	return txn.OpenDBI(name, Create)
}

// Flags returns the database flags for handle dbi.
func (txn *Txn) Flags(dbi DBI) (uint, error) {
	var cflags C.uint
	ret := C.mdb_dbi_flags(txn._txn, C.MDB_dbi(dbi), (*C.uint)(&cflags))
	return uint(cflags), operrno("mdb_dbi_flags", ret)
}

// OpenRoot opens the root database.  OpenRoot behaves similarly to OpenDBI but
// does not require env.SetMaxDBs() to be called beforehand.  And, OpenRoot can
// be called without flags in a View transaction.
func (txn *Txn) OpenRoot(flags uint) (DBI, error) {
	return txn.openDBI(nil, flags)
}

func (txn *Txn) openDBI(cname *C.char, flags uint) (DBI, error) {
	var dbi C.MDB_dbi
	ret := C.mdb_dbi_open(txn._txn, cname, C.uint(flags), &dbi)
	if ret != success {
		return DBI(math.NaN()), operrno("mdb_dbi_open", ret)
	}
	return DBI(dbi), nil
}

// Stat returns a Stat describing the database dbi.
//
// See mdb_stat.
func (txn *Txn) Stat(dbi DBI) (*Stat, error) {
	var _stat C.MDB_stat
	ret := C.mdb_stat(txn._txn, C.MDB_dbi(dbi), &_stat)
	if ret != success {
		return nil, operrno("mdb_stat", ret)
	}
	stat := Stat{PSize: uint(_stat.ms_psize),
		Depth:         uint(_stat.ms_depth),
		BranchPages:   uint64(_stat.ms_branch_pages),
		LeafPages:     uint64(_stat.ms_leaf_pages),
		OverflowPages: uint64(_stat.ms_overflow_pages),
		Entries:       uint64(_stat.ms_entries)}
	return &stat, nil
}

// Drop empties the database if del is false.  Drop deletes and closes the
// database if del is true.
//
// See mdb_drop.
func (txn *Txn) Drop(dbi DBI, del bool) error {
	ret := C.mdb_drop(txn._txn, C.MDB_dbi(dbi), cbool(del))
	return operrno("mdb_drop", ret)
}

// Sub executes fn in a subtransaction.  Sub commits the subtransaction iff a
// nil error is returned by fn and otherwise aborts it.  Sub returns any error
// it encounters.
//
// Sub may only be called on an Update (a Txn created without the Readonly
// flag).  Calling Sub on a View transaction will return an error.
//
// Any call to Abort, Commit, Renew, or Reset on a Txn created by Sub will
// panic.
func (txn *Txn) Sub(fn TxnOp) error {
	// As of 0.9.14 Readonly is the only Txn flag and readonly subtransactions
	// don't make sense.
	return txn.subFlag(0, fn)
}

func (txn *Txn) subFlag(flags uint, fn TxnOp) error {
	sub, err := beginTxn(txn.env, txn, flags)
	if err != nil {
		return err
	}
	sub.managed = true
	defer sub.abort()
	err = fn(sub)
	if err != nil {
		return err
	}
	return sub.commit()
}

func (txn *Txn) bytes(val *mdbVal) []byte {
	if txn.RawRead {
		return val.Bytes()
	}
	return val.BytesCopy()
}

// Get retrieves items from database dbi.  If txn.RawRead is true the slice
// returned by Get references a readonly section of memory that must not be
// accessed after txn has terminated.
//
// See mdb_get.
func (txn *Txn) Get(dbi DBI, key []byte) ([]byte, error) {
	kdata, kn := valBytes(key)
	val := new(mdbVal)
	ret := C.lmdbgo_mdb_get(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		(*C.MDB_val)(val),
	)
	err := operrno("mdb_get", ret)
	if err != nil {
		return nil, err
	}
	return txn.bytes(val), nil
}

// Put stores an item in database dbi.
//
// See mdb_put.
func (txn *Txn) Put(dbi DBI, key []byte, val []byte, flags uint) error {
	kdata, kn := valBytes(key)
	vdata, vn := valBytes(val)
	ret := C.lmdbgo_mdb_put2(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		vdata, C.size_t(vn),
		C.uint(flags),
	)
	return operrno("mdb_put", ret)
}

// PutReserve returns a []byte of length n that can be written to, potentially
// avoiding a memcopy.  The returned byte slice is only valid in txn's thread,
// before it has terminated.
func (txn *Txn) PutReserve(dbi DBI, key []byte, n int, flags uint) ([]byte, error) {
	kdata, kn := valBytes(key)
	val := &mdbVal{mv_size: C.size_t(n)}
	ret := C.lmdbgo_mdb_put1(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		(*C.MDB_val)(val),
		C.uint(flags|C.MDB_RESERVE),
	)
	err := operrno("mdb_put", ret)
	if err != nil {
		return nil, err
	}
	return val.Bytes(), nil
}

// Del deletes an item from database dbi.  Del ignores val unless dbi has the
// DupSort flag.
//
// See mdb_del.
func (txn *Txn) Del(dbi DBI, key, val []byte) error {
	kdata, kn := valBytes(key)
	vdata, vn := valBytes(val)
	ret := C.lmdbgo_mdb_del(
		txn._txn, C.MDB_dbi(dbi),
		kdata, C.size_t(kn),
		vdata, C.size_t(vn),
	)
	return operrno("mdb_del", ret)
}

// OpenCursor allocates and initializes a Cursor to database dbi.
//
// See mdb_cursor_open.
func (txn *Txn) OpenCursor(dbi DBI) (*Cursor, error) {
	cur, err := openCursor(txn, dbi)
	if cur != nil && txn.readonly {
		runtime.SetFinalizer(cur, (*Cursor).close)
	}
	return cur, err
}

func (txn *Txn) errf(format string, v ...interface{}) {
	if txn.errLogf != nil {
		txn.errLogf(format, v...)
		return
	}
	log.Printf(format, v...)
}

// TxnOp is an operation applied to a managed transaction.  The Txn passed to a
// TxnOp is managed and the operation must not call Commit, Abort, Renew, or
// Reset on it.
//
// IMPORTANT:
// TxnOps that write to the database (those passed to Update or BeginUpdate)
// must not use the Txn in another goroutine (passing it directly or otherwise
// through closure).  Doing so has undefined results.
type TxnOp func(txn *Txn) error
<|endoftext|>


<commit_before>package consumer

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/aws/aws-sdk-go/service/kinesis/kinesisiface"
)

// listShards pulls a list of shard IDs from the kinesis api
func listShards(ksis kinesisiface.KinesisAPI, streamName string) ([]*kinesis.Shard, error) {
	var ss []*kinesis.Shard
	var listShardsInput = &kinesis.ListShardsInput{
		StreamName: aws.String(streamName),
	}

	for {
		resp, err := ksis.ListShards(listShardsInput)
		if err != nil {
			return nil, fmt.Errorf("ListShards error: %v", err)
		}
		ss = append(ss, resp.Shards...)

		if resp.NextToken == nil {
			return ss, nil
		}

		listShardsInput = &kinesis.ListShardsInput{
			NextToken:  resp.NextToken,
			StreamName: aws.String(streamName),
		}
	}
}
<commit_msg>Don't send StreamName when calling ListShards with NextToken. (#110)<commit_after>package consumer

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/aws/aws-sdk-go/service/kinesis/kinesisiface"
)

// listShards pulls a list of shard IDs from the kinesis api
func listShards(ksis kinesisiface.KinesisAPI, streamName string) ([]*kinesis.Shard, error) {
	var ss []*kinesis.Shard
	var listShardsInput = &kinesis.ListShardsInput{
		StreamName: aws.String(streamName),
	}

	for {
		resp, err := ksis.ListShards(listShardsInput)
		if err != nil {
			return nil, fmt.Errorf("ListShards error: %v", err)
		}
		ss = append(ss, resp.Shards...)

		if resp.NextToken == nil {
			return ss, nil
		}

		listShardsInput = &kinesis.ListShardsInput{
			NextToken: resp.NextToken,
		}
	}
}
<|endoftext|>


<commit_before>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"reflect"
	"unsafe"
)

// Multi is a wrapper for a contiguous page of sorted, fixed-length values
// passed to Cursor.PutMulti or retrieved using Cursor.Get with the
// GetMultiple/NextMultiple flag.
//
// Multi values are only useful in databases opened with DupSort|DupFixed.
type Multi struct {
	page   []byte
	stride int
}

// WrapMulti converts a page of contiguous values with stride size into a
// Multi.  WrapMulti panics if len(page) is not a multiple of stride.
//
//		_, val, _ := cursor.Get(nil, nil, lmdb.FirstDup)
//		_, page, _ := cursor.Get(nil, nil, lmdb.GetMultiple)
//		multi := lmdb.WrapMulti(page, len(val))
//
// See mdb_cursor_get and MDB_GET_MULTIPLE.
func WrapMulti(page []byte, stride int) *Multi {
	if len(page)%stride != 0 {
		panic("incongruent arguments")
	}
	return &Multi{page: page, stride: stride}
}

// Vals returns a slice containing the values in m.  The returned slice has
// length m.Len() and each item has length m.Stride().
func (m *Multi) Vals() [][]byte {
	n := m.Len()
	ps := make([][]byte, n)
	for i := 0; i < n; i++ {
		ps[i] = m.Val(i)
	}
	return ps
}

// Val returns the value at index i.  Val panics if i is out of range.
func (m *Multi) Val(i int) []byte {
	off := i * m.stride
	return m.page[off : off+m.stride]
}

// Len returns the number of values in the Multi.
func (m *Multi) Len() int {
	return len(m.page) / m.stride
}

// Stride returns the length of an individual value in the m.
func (m *Multi) Stride() int {
	return m.stride
}

// Size returns the total size of the Multi data and is equal to
//
//		m.Len()*m.Stride()
//
func (m *Multi) Size() int {
	return len(m.page)
}

// Page returns the Multi page data as a raw slice of bytes with length
// m.Size().
func (m *Multi) Page() []byte {
	return m.page[:len(m.page):len(m.page)]
}

func (m *Multi) val() *multiVal {
	return &multiVal{
		mdbVal{
			mv_size: C.size_t(m.stride),
			mv_data: unsafe.Pointer(&m.page[0]),
		},
		mdbVal{
			mv_size: C.size_t(len(m.page) / m.stride),
		},
	}
}

// multiVal is a type to hold a page of values retrieved from a database
// created with DupSort|DupFixed.
//
// See mdb_cursor_get and MDB_GET_MULTIPLE.
type multiVal [2]mdbVal

// val converts a Multi into a pointer to mdbVal.  This effectively creates a
// C-style array of the Multi data.
//
// See mdb_cursor_put and MDB_MULTIPLE.
func (val *multiVal) val() *mdbVal {
	return &val[0]
}

// MDB_val
type mdbVal C.MDB_val

func valBytes(b []byte) (unsafe.Pointer, int) {
	if len(b) == 0 {
		return nil, 0
	}
	return unsafe.Pointer(&b[0]), len(b)
}

// wrapVal creates an mdbVal that points to p's data. the mdbVal's data must
// not be freed manually and C references must not survive the garbage
// collection of p.
func wrapVal(p []byte) *mdbVal {
	if len(p) == 0 {
		return new(mdbVal)
	}
	return &mdbVal{
		mv_size: C.size_t(len(p)),
		mv_data: unsafe.Pointer(&p[0]),
	}
}

// BytesCopy returns a slice copied from the region pointed to by val.
func (val *mdbVal) BytesCopy() []byte {
	return C.GoBytes(val.mv_data, C.int(val.mv_size))
}

// Bytes creates a slice referencing the region referenced by val.
func (val *mdbVal) Bytes() []byte {
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(val.mv_data)),
		Len:  int(val.mv_size),
		Cap:  int(val.mv_size),
	}
	return *(*[]byte)(unsafe.Pointer(&hdr))
}

// If val is nil, an empty string is returned.
func (val *mdbVal) String() string {
	return C.GoStringN((*C.char)(val.mv_data), C.int(val.mv_size))
}
<commit_msg>lmdb: remove unused internal type multiVal<commit_after>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"reflect"
	"unsafe"
)

// Multi is a wrapper for a contiguous page of sorted, fixed-length values
// passed to Cursor.PutMulti or retrieved using Cursor.Get with the
// GetMultiple/NextMultiple flag.
//
// Multi values are only useful in databases opened with DupSort|DupFixed.
type Multi struct {
	page   []byte
	stride int
}

// WrapMulti converts a page of contiguous values with stride size into a
// Multi.  WrapMulti panics if len(page) is not a multiple of stride.
//
//		_, val, _ := cursor.Get(nil, nil, lmdb.FirstDup)
//		_, page, _ := cursor.Get(nil, nil, lmdb.GetMultiple)
//		multi := lmdb.WrapMulti(page, len(val))
//
// See mdb_cursor_get and MDB_GET_MULTIPLE.
func WrapMulti(page []byte, stride int) *Multi {
	if len(page)%stride != 0 {
		panic("incongruent arguments")
	}
	return &Multi{page: page, stride: stride}
}

// Vals returns a slice containing the values in m.  The returned slice has
// length m.Len() and each item has length m.Stride().
func (m *Multi) Vals() [][]byte {
	n := m.Len()
	ps := make([][]byte, n)
	for i := 0; i < n; i++ {
		ps[i] = m.Val(i)
	}
	return ps
}

// Val returns the value at index i.  Val panics if i is out of range.
func (m *Multi) Val(i int) []byte {
	off := i * m.stride
	return m.page[off : off+m.stride]
}

// Len returns the number of values in the Multi.
func (m *Multi) Len() int {
	return len(m.page) / m.stride
}

// Stride returns the length of an individual value in the m.
func (m *Multi) Stride() int {
	return m.stride
}

// Size returns the total size of the Multi data and is equal to
//
//		m.Len()*m.Stride()
//
func (m *Multi) Size() int {
	return len(m.page)
}

// Page returns the Multi page data as a raw slice of bytes with length
// m.Size().
func (m *Multi) Page() []byte {
	return m.page[:len(m.page):len(m.page)]
}

// MDB_val
type mdbVal C.MDB_val

func valBytes(b []byte) (unsafe.Pointer, int) {
	if len(b) == 0 {
		return nil, 0
	}
	return unsafe.Pointer(&b[0]), len(b)
}

// wrapVal creates an mdbVal that points to p's data. the mdbVal's data must
// not be freed manually and C references must not survive the garbage
// collection of p.
func wrapVal(p []byte) *mdbVal {
	if len(p) == 0 {
		return new(mdbVal)
	}
	return &mdbVal{
		mv_size: C.size_t(len(p)),
		mv_data: unsafe.Pointer(&p[0]),
	}
}

// BytesCopy returns a slice copied from the region pointed to by val.
func (val *mdbVal) BytesCopy() []byte {
	return C.GoBytes(val.mv_data, C.int(val.mv_size))
}

// Bytes creates a slice referencing the region referenced by val.
func (val *mdbVal) Bytes() []byte {
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(val.mv_data)),
		Len:  int(val.mv_size),
		Cap:  int(val.mv_size),
	}
	return *(*[]byte)(unsafe.Pointer(&hdr))
}

// If val is nil, an empty string is returned.
func (val *mdbVal) String() string {
	return C.GoStringN((*C.char)(val.mv_data), C.int(val.mv_size))
}
<|endoftext|>


<commit_before>// Copyright 2016-2019 Granitic. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be found in the LICENSE file at the root of this project.

package logging

import (
	"context"
	"github.com/graniticio/granitic/v2/test"
	"testing"
)

func TestThresholdDetection(t *testing.T) {

	g := new(globalLogSource)

	lal := new(GraniticLogger)
	lal.global = g

	g.level = All
	lal.localLogThreshhold = All

	test.ExpectBool(t, lal.IsLevelEnabled(Debug), true)

	g.level = Error
	test.ExpectBool(t, lal.IsLevelEnabled(Debug), false)

	lal.localLogThreshhold = Debug

	test.ExpectBool(t, lal.IsLevelEnabled(Debug), true)

	g.level = Trace
	test.ExpectBool(t, lal.IsLevelEnabled(Trace), false)

	lal.localLogThreshhold = All
	test.ExpectBool(t, lal.IsLevelEnabled(Trace), true)

}

func TestNilLogging(t *testing.T) {

	var l Logger
	l = new(NullLogger)

	if l.IsLevelEnabled(Trace) {
		t.FailNow()
	}

	ctx := context.Background()

	l.LogDebugf("")
	l.LogAtLevelf(Trace, "TRACE", "")
	l.LogAtLevelfCtx(ctx, Trace, "TRACE", "")
	l.LogDebugfCtx(ctx, "")
	l.LogErrorf("")
	l.LogErrorfCtx(ctx, "")
	l.LogErrorfCtxWithTrace(ctx, "")
	l.LogErrorfWithTrace("")
	l.LogErrorfWithTrace("")
	l.LogFatalf("")
	l.LogFatalfCtx(ctx, "")
	l.LogInfof("")
	l.LogInfofCtx(ctx, "")
	l.LogTracef("")
	l.LogTracefCtx(ctx, "")
	l.LogWarnf("")
	l.LogWarnfCtx(ctx, "")

}
<commit_msg>Logging tests<commit_after>// Copyright 2016-2019 Granitic. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be found in the LICENSE file at the root of this project.

package logging

import (
	"context"
	"github.com/graniticio/granitic/v2/test"
	"testing"
)

func TestStdoutLoggerCanBeBuilt(t *testing.T) {

	l := NewStdoutLogger(Trace)

	l.LogTracef("MESSAGE")

	l = NewStdoutLogger(Trace, "PREFIX")

	l.LogTracef("MESSAGE")

}

func TestThresholdDetection(t *testing.T) {

	g := new(globalLogSource)

	lal := new(GraniticLogger)
	lal.global = g

	g.level = All
	lal.localLogThreshhold = All

	test.ExpectBool(t, lal.IsLevelEnabled(Debug), true)

	g.level = Error
	test.ExpectBool(t, lal.IsLevelEnabled(Debug), false)

	lal.localLogThreshhold = Debug

	test.ExpectBool(t, lal.IsLevelEnabled(Debug), true)

	g.level = Trace
	test.ExpectBool(t, lal.IsLevelEnabled(Trace), false)

	lal.localLogThreshhold = All
	test.ExpectBool(t, lal.IsLevelEnabled(Trace), true)

}

func TestNilLogging(t *testing.T) {

	var l Logger
	l = new(NullLogger)

	if l.IsLevelEnabled(Trace) {
		t.FailNow()
	}

	ctx := context.Background()

	l.LogDebugf("")
	l.LogAtLevelf(Trace, "TRACE", "")
	l.LogAtLevelfCtx(ctx, Trace, "TRACE", "")
	l.LogDebugfCtx(ctx, "")
	l.LogErrorf("")
	l.LogErrorfCtx(ctx, "")
	l.LogErrorfCtxWithTrace(ctx, "")
	l.LogErrorfWithTrace("")
	l.LogErrorfWithTrace("")
	l.LogFatalf("")
	l.LogFatalfCtx(ctx, "")
	l.LogInfof("")
	l.LogInfofCtx(ctx, "")
	l.LogTracef("")
	l.LogTracefCtx(ctx, "")
	l.LogWarnf("")
	l.LogWarnfCtx(ctx, "")

}
<|endoftext|>


<commit_before>package goStrongswanVici

import (
	"fmt"
)

type Connection struct {
	ConnConf map[string]IKEConf `json:"connections"`
}

type IKEConf struct {
	LocalAddrs  []string               `json:"local_addrs"`
	RemoteAddrs []string               `json:"remote_addrs,omitempty"`
	Proposals   []string               `json:"proposals,omitempty"`
	Version     string                 `json:"version"` //1 for ikev1, 0 for ikev1 & ikev2
	Encap       string                 `json:"encap"`   //yes,no
	KeyingTries string                 `json:"keyingtries"`
	RekeyTime   string                 `json:"rekey_time"`
	DPDDelay    string                 `json:"dpd_delay,omitempty"`
	LocalAuth   AuthConf               `json:"local"`
	RemoteAuth  AuthConf               `json:"remote"`
	Pools       []string               `json:"pools,omitempty"`
	Children    map[string]ChildSAConf `json:"children"`
}

type AuthConf struct {
	ID         string `json:"id"`
	Round      string `json:"round,omitempty"`
	AuthMethod string `json:"auth"` // (psk|pubkey)
	EAP_ID     string `json:"eap_id,omitempty"`
}

type ChildSAConf struct {
	Local_ts      []string `json:"local_ts"`
	Remote_ts     []string `json:"remote_ts"`
	ESPProposals  []string `json:"esp_proposals,omitempty"` //aes128-sha1_modp1024
	StartAction   string   `json:"start_action"`            //none,trap,start
	CloseAction   string   `json:"close_action"`
	ReqID         string   `json:"reqid"`
	RekeyTime     string   `json:"rekey_time"`
	ReplayWindow  string   `json:"replay_window,omitempty"`
	Mode          string   `json:"mode"`
	InstallPolicy string   `json:"policies"`
	UpDown        string   `json:"updown,omitempty"`
	Priority      string   `json:"priority,omitempty"`
	MarkIn        string   `json:"mark_in,omitempty"`
	MarkOut       string   `json:"mark_out,omitempty"`
}

func (c *ClientConn) LoadConn(conn *map[string]IKEConf) error {
	requestMap := &map[string]interface{}{}

	err := ConvertToGeneral(conn, requestMap)

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

	msg, err := c.Request("load-conn", *requestMap)

	if msg["success"] != "yes" {
		return fmt.Errorf("unsuccessful LoadConn: %v", msg["errmsg"])
	}

	return nil
}
<commit_msg>- add dead peer detection support<commit_after>package goStrongswanVici

import (
	"fmt"
)

type Connection struct {
	ConnConf map[string]IKEConf `json:"connections"`
}

type IKEConf struct {
	LocalAddrs  []string               `json:"local_addrs"`
	RemoteAddrs []string               `json:"remote_addrs,omitempty"`
	Proposals   []string               `json:"proposals,omitempty"`
	Version     string                 `json:"version"` //1 for ikev1, 0 for ikev1 & ikev2
	Encap       string                 `json:"encap"`   //yes,no
	KeyingTries string                 `json:"keyingtries"`
	RekeyTime   string                 `json:"rekey_time"`
	DPDDelay    string                 `json:"dpd_delay,omitempty"`
	LocalAuth   AuthConf               `json:"local"`
	RemoteAuth  AuthConf               `json:"remote"`
	Pools       []string               `json:"pools,omitempty"`
	Children    map[string]ChildSAConf `json:"children"`
}

type AuthConf struct {
	ID         string `json:"id"`
	Round      string `json:"round,omitempty"`
	AuthMethod string `json:"auth"` // (psk|pubkey)
	EAP_ID     string `json:"eap_id,omitempty"`
}

type ChildSAConf struct {
	Local_ts      []string `json:"local_ts"`
	Remote_ts     []string `json:"remote_ts"`
	ESPProposals  []string `json:"esp_proposals,omitempty"` //aes128-sha1_modp1024
	StartAction   string   `json:"start_action"`            //none,trap,start
	CloseAction   string   `json:"close_action"`
	ReqID         string   `json:"reqid,omitempty"`
	RekeyTime     string   `json:"rekey_time"`
	ReplayWindow  string   `json:"replay_window,omitempty"`
	Mode          string   `json:"mode"`
	InstallPolicy string   `json:"policies"`
	UpDown        string   `json:"updown,omitempty"`
	Priority      string   `json:"priority,omitempty"`
	MarkIn        string   `json:"mark_in,omitempty"`
	MarkOut       string   `json:"mark_out,omitempty"`
	DpdAction     string   `json:"dpd_action,omitempty"`
}

func (c *ClientConn) LoadConn(conn *map[string]IKEConf) error {
	requestMap := &map[string]interface{}{}

	err := ConvertToGeneral(conn, requestMap)

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

	msg, err := c.Request("load-conn", *requestMap)

	if msg["success"] != "yes" {
		return fmt.Errorf("unsuccessful LoadConn: %v", msg["errmsg"])
	}

	return nil
}
<|endoftext|>


<commit_before>package cluster

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"time"

	dqlite "github.com/canonical/go-dqlite"
	client "github.com/canonical/go-dqlite/client"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/node"
	"github.com/pkg/errors"
)

// ListDatabaseNodes returns a list of database node names.
func ListDatabaseNodes(database *db.Node) ([]string, error) {
	nodes := []db.RaftNode{}
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		nodes, err = tx.GetRaftNodes()
		return err
	})
	if err != nil {
		return nil, errors.Wrapf(err, "Failed to list database nodes")
	}
	addresses := make([]string, 0)
	for _, node := range nodes {
		if node.Role != db.RaftVoter {
			continue
		}
		addresses = append(addresses, node.Address)
	}
	return addresses, nil
}

// Recover attempts data recovery on the cluster database.
func Recover(database *db.Node) error {
	// Figure out if we actually act as dqlite node.
	var info *db.RaftNode
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		info, err = node.DetermineRaftNode(tx)
		return err
	})
	if err != nil {
		return errors.Wrap(err, "Failed to determine node role")
	}

	// If we're not a database node, return an error.
	if info == nil {
		return fmt.Errorf("This LXD instance has no database role")
	}

	// If this is a standalone node not exposed to the network, return an
	// error.
	if info.Address == "" {
		return fmt.Errorf("This LXD instance is not clustered")
	}

	dir := filepath.Join(database.Dir(), "global")
	server, err := dqlite.New(
		uint64(info.ID),
		info.Address,
		dir,
	)
	if err != nil {
		return errors.Wrap(err, "Failed to create dqlite server")
	}

	cluster := []dqlite.NodeInfo{
		{ID: uint64(info.ID), Address: info.Address},
	}

	err = server.Recover(cluster)
	if err != nil {
		return errors.Wrap(err, "Failed to recover database state")
	}

	// Update the list of raft nodes.
	err = database.Transaction(func(tx *db.NodeTx) error {
		nodes := []db.RaftNode{
			{
				NodeInfo: client.NodeInfo{
					ID:      info.ID,
					Address: info.Address,
				},
				Name: info.Name,
			},
		}

		return tx.ReplaceRaftNodes(nodes)
	})
	if err != nil {
		return errors.Wrap(err, "Failed to update database nodes")
	}

	return nil
}

// updateLocalAddress updates the cluster.https_address for this node.
func updateLocalAddress(database *db.Node, address string) error {
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		config, err := node.ConfigLoad(tx)
		if err != nil {
			return err
		}

		newConfig := map[string]interface{}{"cluster.https_address": address}
		_, err = config.Patch(newConfig)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return errors.Wrapf(err, "Failed to update node configuration")
	}

	return nil
}

// Reconfigure replaces the entire cluster configuration.
// Addresses and node roles may be updated. Node IDs are read-only.
func Reconfigure(database *db.Node, raftNodes []db.RaftNode) error {
	var info *db.RaftNode
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		info, err = node.DetermineRaftNode(tx)

		return err
	})
	if err != nil || info == nil {
		return errors.Wrap(err, "Failed to determine node role")
	}

	localAddress := info.Address
	nodes := []client.NodeInfo{}

	for _, raftNode := range raftNodes {
		nodes = append(nodes, raftNode.NodeInfo)

		// Get the new address for this node.
		if raftNode.ID == info.ID {
			localAddress = raftNode.Address
		}
	}

	// Update cluster.https_address if changed.
	if localAddress != info.Address {
		err := updateLocalAddress(database, localAddress)
		if err != nil {
			return err
		}
	}

	dir := filepath.Join(database.Dir(), "global")
	// Replace cluster configuration in dqlite.
	err = dqlite.ReconfigureMembershipExt(dir, nodes)
	if err != nil {
		return errors.Wrap(err, "Failed to recover database state")
	}

	// Replace cluster configuration in local raft_nodes database.
	err = database.Transaction(func(tx *db.NodeTx) error {
		return tx.ReplaceRaftNodes(raftNodes)
	})
	if err != nil {
		return err
	}

	// Create patch file for global nodes database.
	content := ""
	for _, node := range nodes {
		content += fmt.Sprintf("UPDATE nodes SET address = %q WHERE id = %d;\n", node.Address, node.ID)
	}

	if len(content) > 0 {
		filePath := filepath.Join(database.Dir(), "patch.global.sql")
		file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			return err
		}
		defer file.Close()

		_, err = file.Write([]byte(content))
		if err != nil {
			return err
		}
	}

	return nil
}

// RemoveRaftNode removes a raft node from the raft configuration.
func RemoveRaftNode(gateway *Gateway, address string) error {
	nodes, err := gateway.currentRaftNodes()
	if err != nil {
		return errors.Wrap(err, "Failed to get current raft nodes")
	}
	var id uint64
	for _, node := range nodes {
		if node.Address == address {
			id = node.ID
			break
		}
	}
	if id == 0 {
		return fmt.Errorf("No raft node with address %q", address)
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	client, err := client.FindLeader(
		ctx, gateway.NodeStore(),
		client.WithDialFunc(gateway.raftDial()),
		client.WithLogFunc(DqliteLog),
	)
	if err != nil {
		return errors.Wrap(err, "Failed to connect to cluster leader")
	}
	defer client.Close()
	err = client.Remove(ctx, id)
	if err != nil {
		return errors.Wrap(err, "Failed to remove node")
	}
	return nil
}
<commit_msg>lxd/cluster/recover: Preallocate nodes in Reconfigure<commit_after>package cluster

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"time"

	dqlite "github.com/canonical/go-dqlite"
	client "github.com/canonical/go-dqlite/client"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/node"
	"github.com/pkg/errors"
)

// ListDatabaseNodes returns a list of database node names.
func ListDatabaseNodes(database *db.Node) ([]string, error) {
	nodes := []db.RaftNode{}
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		nodes, err = tx.GetRaftNodes()
		return err
	})
	if err != nil {
		return nil, errors.Wrapf(err, "Failed to list database nodes")
	}
	addresses := make([]string, 0)
	for _, node := range nodes {
		if node.Role != db.RaftVoter {
			continue
		}
		addresses = append(addresses, node.Address)
	}
	return addresses, nil
}

// Recover attempts data recovery on the cluster database.
func Recover(database *db.Node) error {
	// Figure out if we actually act as dqlite node.
	var info *db.RaftNode
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		info, err = node.DetermineRaftNode(tx)
		return err
	})
	if err != nil {
		return errors.Wrap(err, "Failed to determine node role")
	}

	// If we're not a database node, return an error.
	if info == nil {
		return fmt.Errorf("This LXD instance has no database role")
	}

	// If this is a standalone node not exposed to the network, return an
	// error.
	if info.Address == "" {
		return fmt.Errorf("This LXD instance is not clustered")
	}

	dir := filepath.Join(database.Dir(), "global")
	server, err := dqlite.New(
		uint64(info.ID),
		info.Address,
		dir,
	)
	if err != nil {
		return errors.Wrap(err, "Failed to create dqlite server")
	}

	cluster := []dqlite.NodeInfo{
		{ID: uint64(info.ID), Address: info.Address},
	}

	err = server.Recover(cluster)
	if err != nil {
		return errors.Wrap(err, "Failed to recover database state")
	}

	// Update the list of raft nodes.
	err = database.Transaction(func(tx *db.NodeTx) error {
		nodes := []db.RaftNode{
			{
				NodeInfo: client.NodeInfo{
					ID:      info.ID,
					Address: info.Address,
				},
				Name: info.Name,
			},
		}

		return tx.ReplaceRaftNodes(nodes)
	})
	if err != nil {
		return errors.Wrap(err, "Failed to update database nodes")
	}

	return nil
}

// updateLocalAddress updates the cluster.https_address for this node.
func updateLocalAddress(database *db.Node, address string) error {
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		config, err := node.ConfigLoad(tx)
		if err != nil {
			return err
		}

		newConfig := map[string]interface{}{"cluster.https_address": address}
		_, err = config.Patch(newConfig)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return errors.Wrapf(err, "Failed to update node configuration")
	}

	return nil
}

// Reconfigure replaces the entire cluster configuration.
// Addresses and node roles may be updated. Node IDs are read-only.
func Reconfigure(database *db.Node, raftNodes []db.RaftNode) error {
	var info *db.RaftNode
	err := database.Transaction(func(tx *db.NodeTx) error {
		var err error
		info, err = node.DetermineRaftNode(tx)

		return err
	})
	if err != nil || info == nil {
		return errors.Wrap(err, "Failed to determine node role")
	}

	localAddress := info.Address

	nodes := make([]client.NodeInfo, 0, len(raftNodes))
	for _, raftNode := range raftNodes {
		nodes = append(nodes, raftNode.NodeInfo)

		// Get the new address for this node.
		if raftNode.ID == info.ID {
			localAddress = raftNode.Address
		}
	}

	// Update cluster.https_address if changed.
	if localAddress != info.Address {
		err := updateLocalAddress(database, localAddress)
		if err != nil {
			return err
		}
	}

	dir := filepath.Join(database.Dir(), "global")
	// Replace cluster configuration in dqlite.
	err = dqlite.ReconfigureMembershipExt(dir, nodes)
	if err != nil {
		return errors.Wrap(err, "Failed to recover database state")
	}

	// Replace cluster configuration in local raft_nodes database.
	err = database.Transaction(func(tx *db.NodeTx) error {
		return tx.ReplaceRaftNodes(raftNodes)
	})
	if err != nil {
		return err
	}

	// Create patch file for global nodes database.
	content := ""
	for _, node := range nodes {
		content += fmt.Sprintf("UPDATE nodes SET address = %q WHERE id = %d;\n", node.Address, node.ID)
	}

	if len(content) > 0 {
		filePath := filepath.Join(database.Dir(), "patch.global.sql")
		file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			return err
		}
		defer file.Close()

		_, err = file.Write([]byte(content))
		if err != nil {
			return err
		}
	}

	return nil
}

// RemoveRaftNode removes a raft node from the raft configuration.
func RemoveRaftNode(gateway *Gateway, address string) error {
	nodes, err := gateway.currentRaftNodes()
	if err != nil {
		return errors.Wrap(err, "Failed to get current raft nodes")
	}
	var id uint64
	for _, node := range nodes {
		if node.Address == address {
			id = node.ID
			break
		}
	}
	if id == 0 {
		return fmt.Errorf("No raft node with address %q", address)
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	client, err := client.FindLeader(
		ctx, gateway.NodeStore(),
		client.WithDialFunc(gateway.raftDial()),
		client.WithLogFunc(DqliteLog),
	)
	if err != nil {
		return errors.Wrap(err, "Failed to connect to cluster leader")
	}
	defer client.Close()
	err = client.Remove(ctx, id)
	if err != nil {
		return errors.Wrap(err, "Failed to remove node")
	}
	return nil
}
<|endoftext|>