<commit_before>package grandRepositorySky

//IMPORT parts ----------------------------------------------------------
import (
	"bytes"
	"fmt"
	"github.com/tgermain/grandRepositorySky/dht"
	"math/big"
)

//Const parts -----------------------------------------------------------
const HUGESTINT = 9223372036854775807
const SPACESIZE = 160

//Objects parts ---------------------------------------------------------
type DHTnode struct {
	id       string
	fingers  []*fingerEntry //Successor is fingers[0].tmp
	ip, port string
}

type fingerEntry struct {
	idKey  string
	idResp string
	tmp    *DHTnode
}

//Method parts ----------------------------------------------------------

func (currentNode *DHTnode) AddToRing(newNode DHTnode) {
	//furthers comments assume that he current currentNode is named x
	switch {
	case bytes.Compare([]byte(currentNode.id), []byte(currentNode.fingers[0].tmp.id)) == 0:
		{
			//init case : currentNode looping on itself
			// fmt.Println("Init case : 2 node")

			newNode.fingers[0].tmp = currentNode.fingers[0].tmp
			currentNode.fingers[0].tmp = &newNode
			//TODO : initialize both fingers tables
		}
	case dht.Between(currentNode.id, currentNode.fingers[0].tmp.id, newNode.id):
		// (currentNode.id < newNode.id) && (newNode.id < currentNode.fingers[0].tmp.id)
		{
			//case of x->(x+2) and we want to add (x+1) node
			// fmt.Println("add in the middle")
			newNode.fingers[0].tmp = currentNode.fingers[0].tmp
			currentNode.fingers[0].tmp = &newNode
		}
	case dht.Between(currentNode.fingers[0].tmp.id, newNode.id, currentNode.id):
		// (currentNode.fingers[0].tmp.id < currentNode.id) && (currentNode.id < newNode.id)
		{
			//case of X -> 0 and we want to add (x+1) node
			// fmt.Println("add at the end")
			newNode.fingers[0].tmp = currentNode.fingers[0].tmp
			currentNode.fingers[0].tmp = &newNode
		}
	default:
		{
			// fmt.Println("Go to the next")
			currentNode.fingers[0].tmp.AddToRing(newNode)
		}
	}
}

func (currentNode *DHTnode) Lookup(idToSearch string) *DHTnode {
	if dht.Between(currentNode.id, currentNode.fingers[0].tmp.id, idToSearch) {
		// fmt.Printf("We are seeking for %s\n", idToSearch)
		return currentNode
	} else {
		// fmt.Println("go to the next one")
		//TODO use the fingers table here
		return currentNode.findClosestNode(idToSearch).Lookup(idToSearch)
	}
}

func (currentNode *DHTnode) findClosestNode(idToSearch string) *DHTnode {
	minDistance := big.NewInt(HUGESTINT)
	bestFinger := currentNode.fingers[0].tmp

	for _, v := range currentNode.fingers {
		//if a member of finger table brought closer than the actual one, we udate the value of minDistance and of the chosen finger
		currentDistance := dht.Distance([]byte(v.id), []byte(idToSearch), SPACESIZE)

		// x.cmp(y)
		// -1 if x <  y
		//  0 if x == y
		// +1 if x >  y

		if minDistance.Cmp(currentDistance) == 1 {
			minDistance = currentDistance
			bestFinger = v
		}
	}
	fmt.Printf("From [%s] We have found the bes way to go to [%s] : we go throught node [%s]\n", currentNode.id, idToSearch, bestFinger.id)
	return bestFinger
}

func (node *DHTnode) PrintRing() {
	fmt.Printf("%s\n", node.id)
	node.fingers[0].tmp.printRingRec(node.id)
}

func (node *DHTnode) printRingRec(origId string) {
	fmt.Printf("%s\n", node.id)
	if bytes.Compare([]byte(node.fingers[0].tmp.id), []byte(origId)) != 0 {

		node.fingers[0].tmp.printRingRec(origId)
	}
}

func (node *DHTnode) TestCalcFingers(k, m int) {
	fingersId, _ := dht.CalcFinger([]byte(node.id), k, m)
	node.Lookup(fingersId).PrintNodeInfo()
}

func (node *DHTnode) PrintNodeInfo() {
	fmt.Println("---------------------------------")
	fmt.Println("Node info")
	fmt.Println("---------------------------------")
	fmt.Printf("  Id		Ip						Port\n")
	fmt.Printf("  %s		%s 		%s\n", node.id, node.ip, node.port)
	fmt.Println()
	fmt.Println("  Fingers table :")
	fmt.Println("  ---------------------------------")
	fmt.Println("  Index	idkey					idNode ")
	for i, v := range node.fingers {
		fmt.Printf("  %d 		%s					%s\n", i, v.idKey, v.idResp)
	}
	fmt.Println("---------------------------------")

}

//other functions parts --------------------------------------------------------
func MakeDHTNode(NewId *string, NewIp, NewPort string) DHTnode {
	if NewId == nil {
		tempId := dht.GenerateNodeId()
		NewId = &tempId
	}
	daNode := DHTnode{
		id:      *NewId,
		fingers: make([]*fingerEntry, 1),
		ip:      NewIp,
		port:    NewPort,
	}
	// initialization of fingers table is done while adding the node to the ring
	// The fingers table of the first node of a ring is initialized when a second node is added to the ring

	//Initialize the finger table with each finger pointing to the node frehly created itself
	return daNode
}
<commit_msg>adding a check of nil value in finger table<commit_after>package grandRepositorySky

//IMPORT parts ----------------------------------------------------------
import (
	"bytes"
	"fmt"
	"github.com/tgermain/grandRepositorySky/dht"
	"math/big"
)

//Const parts -----------------------------------------------------------
const HUGESTINT = 9223372036854775807
const SPACESIZE = 160

//Objects parts ---------------------------------------------------------
type DHTnode struct {
	id       string
	fingers  []*fingerEntry //Successor is fingers[0].tmp
	ip, port string
}

type fingerEntry struct {
	idKey  string
	idResp string
	tmp    *DHTnode
}

//Method parts ----------------------------------------------------------

func (currentNode *DHTnode) AddToRing(newNode DHTnode) {
	//furthers comments assume that he current currentNode is named x
	switch {
	case bytes.Compare([]byte(currentNode.id), []byte(currentNode.fingers[0].tmp.id)) == 0:
		{
			//init case : currentNode looping on itself
			// fmt.Println("Init case : 2 node")

			newNode.fingers[0].tmp = currentNode.fingers[0].tmp
			currentNode.fingers[0].tmp = &newNode
			//TODO : initialize both fingers tables
		}
	case dht.Between(currentNode.id, currentNode.fingers[0].tmp.id, newNode.id):
		// (currentNode.id < newNode.id) && (newNode.id < currentNode.fingers[0].tmp.id)
		{
			//case of x->(x+2) and we want to add (x+1) node
			// fmt.Println("add in the middle")
			newNode.fingers[0].tmp = currentNode.fingers[0].tmp
			currentNode.fingers[0].tmp = &newNode
		}
	case dht.Between(currentNode.fingers[0].tmp.id, newNode.id, currentNode.id):
		// (currentNode.fingers[0].tmp.id < currentNode.id) && (currentNode.id < newNode.id)
		{
			//case of X -> 0 and we want to add (x+1) node
			// fmt.Println("add at the end")
			newNode.fingers[0].tmp = currentNode.fingers[0].tmp
			currentNode.fingers[0].tmp = &newNode
		}
	default:
		{
			// fmt.Println("Go to the next")
			currentNode.fingers[0].tmp.AddToRing(newNode)
		}
	}
}

func (currentNode *DHTnode) Lookup(idToSearch string) *DHTnode {
	if dht.Between(currentNode.id, currentNode.fingers[0].tmp.id, idToSearch) {
		// fmt.Printf("We are seeking for %s\n", idToSearch)
		return currentNode
	} else {
		// fmt.Println("go to the next one")
		//TODO use the fingers table here
		return currentNode.findClosestNode(idToSearch).Lookup(idToSearch)
	}
}

func (currentNode *DHTnode) findClosestNode(idToSearch string) *DHTnode {
	minDistance := big.NewInt(HUGESTINT)
	bestFinger := currentNode.fingers[0].tmp

	for _, v := range currentNode.fingers {
		if v != nil {
			//if a member of finger table brought closer than the actual one, we udate the value of minDistance and of the chosen finger
			currentDistance := dht.Distance([]byte(v.idResp), []byte(idToSearch), SPACESIZE)

			// x.cmp(y)
			// -1 if x <  y
			//  0 if x == y
			// +1 if x >  y

			if minDistance.Cmp(currentDistance) == 1 {
				minDistance = currentDistance
				bestFinger = v.tmp
			}
		}
	}
	fmt.Printf("From [%s] We have found the bes way to go to [%s] : we go throught node [%s]\n", currentNode.id, idToSearch, bestFinger.id)
	return bestFinger
}

func (node *DHTnode) PrintRing() {
	fmt.Printf("%s\n", node.id)
	node.fingers[0].tmp.printRingRec(node.id)
}

func (node *DHTnode) printRingRec(origId string) {
	fmt.Printf("%s\n", node.id)
	if bytes.Compare([]byte(node.fingers[0].tmp.id), []byte(origId)) != 0 {

		node.fingers[0].tmp.printRingRec(origId)
	}
}

func (node *DHTnode) TestCalcFingers(k, m int) {
	fingersId, _ := dht.CalcFinger([]byte(node.id), k, m)
	node.Lookup(fingersId).PrintNodeInfo()
}

func (node *DHTnode) PrintNodeInfo() {
	fmt.Println("---------------------------------")
	fmt.Println("Node info")
	fmt.Println("---------------------------------")
	fmt.Printf("  Id		Ip						Port\n")
	fmt.Printf("  %s		%s 		%s\n", node.id, node.ip, node.port)
	fmt.Println()
	fmt.Println("  Fingers table :")
	fmt.Println("  ---------------------------------")
	fmt.Println("  Index	idkey					idNode ")
	for i, v := range node.fingers {
		if v != nil {
			fmt.Printf("  %d 		%s					%s\n", i, v.idKey, v.idResp)
		}
	}
	fmt.Println("---------------------------------")

}

//other functions parts --------------------------------------------------------
func MakeDHTNode(NewId *string, NewIp, NewPort string) DHTnode {
	if NewId == nil {
		tempId := dht.GenerateNodeId()
		NewId = &tempId
	}
	daNode := DHTnode{
		id:      *NewId,
		fingers: make([]*fingerEntry, 1),
		ip:      NewIp,
		port:    NewPort,
	}
	// initialization of fingers table is done while adding the node to the ring
	// The fingers table of the first node of a ring is initialized when a second node is added to the ring

	//Initialize the finger table with each finger pointing to the node frehly created itself
	return daNode
}
<|endoftext|>


<commit_before>package network_test

import (
	"encoding/json"
	"fmt"
	"github.com/APTrust/exchange/models"
	"github.com/APTrust/exchange/network"
	"github.com/stretchr/testify/assert"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestNewPharosClient(t *testing.T) {

}

func TestInstitutionGet(t *testing.T) {
	testServer := httptest.NewServer(http.HandlerFunc(institutionGetHander))
	defer testServer.Close()

	client, err := network.NewPharosClient(testServer.URL, "v1", "user", "key")
	if err != nil {
		t.Error(err)
		return
	}

	response := client.InstitutionGet("college.edu")

	respData, _ := response.RawResponseData()
	fmt.Println(string(respData))
	assert.Nil(t, response.Error)
}

// HTTP test server handler functions

func institutionGetHander(w http.ResponseWriter, r *http.Request) {

	// ---------------------------------------------------
	// TODO: Look into https://github.com/icrowley/fake
	// for generating test data.
	// ---------------------------------------------------

	inst := models.Institution{}
	instJson, _ := json.Marshal(inst)
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintln(w, string(instJson))
}

// func institutionListHander(w http.ResponseWriter, r *http.Request) {
// 	w.Header().Set("Content-Type", "application/json")
// 	fmt.Fprintln(w, `{"fake twitter json string"}`)
// }
<commit_msg>Starting PharosClient tests<commit_after>package network_test

import (
	"encoding/json"
	"fmt"
//	"github.com/APTrust/exchange/models"
	"github.com/APTrust/exchange/network"
	"github.com/APTrust/exchange/testdata"
	"github.com/stretchr/testify/assert"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestNewPharosClient(t *testing.T) {
	_, err := network.NewPharosClient("http://example.com", "v1", "user", "key")
	if err != nil {
		t.Error(err)
	}
}

func TestInstitutionGet(t *testing.T) {
	testServer := httptest.NewServer(http.HandlerFunc(institutionGetHander))
	defer testServer.Close()

	client, err := network.NewPharosClient(testServer.URL, "v1", "user", "key")
	if err != nil {
		t.Error(err)
		return
	}

	response := client.InstitutionGet("college.edu")
	assert.Nil(t, response.Error)
	assert.EqualValues(t, "Institution", response.ObjectType())
	if response.Institution() == nil {
		t.Errorf("Institution should not be nil")
	}
	assert.NotEqual(t, "", len(response.Institution().Identifier))
}

// HTTP test server handler functions

func institutionGetHander(w http.ResponseWriter, r *http.Request) {
	inst := testdata.MakeInstitution()
	instJson, _ := json.Marshal(inst)
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintln(w, string(instJson))
}

// func institutionListHander(w http.ResponseWriter, r *http.Request) {
// 	w.Header().Set("Content-Type", "application/json")
// 	fmt.Fprintln(w, `{"fake twitter json string"}`)
// }
<|endoftext|>


<commit_before>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package directory provides features for currencies, currency rates,
// conversion of prices to a specified currency format, countries and regions.
package directory
<commit_msg>directory: Add todo https://github.com/mledoze/countries<commit_after>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package directory provides features for currencies, currency rates,
// conversion of prices to a specified currency format, countries and regions.
//
// @todo think about: https://github.com/mledoze/countries
package directory
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package model

import (
	"fmt"
	"strings"

	"github.com/golang/glog"
	"k8s.io/kops/nodeup/pkg/distros"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
)

// LogrotateBuilder installs logrotate.d and configures log rotation for kubernetes logs
type LogrotateBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &LogrotateBuilder{}

func (b *LogrotateBuilder) Build(c *fi.ModelBuilderContext) error {
	if b.Distribution == distros.DistributionContainerOS {
		glog.Infof("Detected ContainerOS; won't install logrotate")
		return nil
	} else if b.Distribution == distros.DistributionCoreOS {
		glog.Infof("Detected CoreOS; won't install logrotate")
	} else {
		c.AddTask(&nodetasks.Package{Name: "logrotate"})
	}

	k8sVersion, err := util.ParseKubernetesVersion(b.Cluster.Spec.KubernetesVersion)
	if err != nil || k8sVersion == nil {
		return fmt.Errorf("unable to parse KubernetesVersion %q", b.Cluster.Spec.KubernetesVersion)
	}

	if k8sVersion.Major == 1 && k8sVersion.Minor < 6 {
		// In version 1.6, we move log rotation to docker, but prior to that we need a logrotate rule
		b.addLogRotate(c, "docker-containers", "/var/lib/docker/containers/*/*-json.log", logRotateOptions{MaxSize: "10M"})
	}

	b.addLogRotate(c, "docker", "/var/log/docker.log", logRotateOptions{})
	b.addLogRotate(c, "kube-addons", "/var/log/kube-addons.log", logRotateOptions{})
	b.addLogRotate(c, "kube-apiserver", "/var/log/kube-apiserver.log", logRotateOptions{})
	b.addLogRotate(c, "kube-controller-manager", "/var/log/kube-controller-manager.log", logRotateOptions{})
	b.addLogRotate(c, "kube-proxy", "/var/log/kube-proxy.log", logRotateOptions{})
	b.addLogRotate(c, "kube-scheduler", "/var/log/kube-scheduler.log", logRotateOptions{})
	b.addLogRotate(c, "kubelet", "/var/log/kubelet.log", logRotateOptions{})

	if err := b.addLogrotateService(c); err != nil {
		return err
	}

	// Add timer to run hourly.
	{
		unit := &systemd.Manifest{}
		unit.Set("Unit", "Description", "Hourly Log Rotation")
		unit.Set("Timer", "OnCalendar", "hourly")

		service := &nodetasks.Service{
			Name:       "logrotate.timer", // Override (by name) any existing timer
			Definition: s(unit.Render()),
		}

		service.InitDefaults()

		c.AddTask(service)
	}

	return nil
}

// addLogrotateService creates a logrotate systemd task to act as target for the timer, if one is needed
func (b *LogrotateBuilder) addLogrotateService(c *fi.ModelBuilderContext) error {
	switch b.Distribution {
	case distros.DistributionCoreOS:
	case distros.DistributionContainerOS:
		// logrotate service already exists
		return nil
	}

	manifest := &systemd.Manifest{}
	manifest.Set("Unit", "Description", "Rotate and Compress System Logs")
	manifest.Set("Service", "ExecStart", "/usr/sbin/logrotate /etc/logrotate.conf")

	service := &nodetasks.Service{
		Name:       "logrotate.service",
		Definition: s(manifest.Render()),
	}
	service.InitDefaults()
	c.AddTask(service)

	return nil
}

type logRotateOptions struct {
	MaxSize string
}

func (b *LogrotateBuilder) addLogRotate(c *fi.ModelBuilderContext, name, path string, options logRotateOptions) {
	if options.MaxSize == "" {
		options.MaxSize = "100M"
	}

	lines := []string{
		path + "{",
		"  rotate 5",
		"  copytruncate",
		"  missingok",
		"  notifempty",
		"  delaycompress",
		"  maxsize " + options.MaxSize,
		"  daily",
		"  create 0644 root root",
		"}",
	}

	contents := strings.Join(lines, "\n")

	t := &nodetasks.File{
		Path:     "/etc/logrotate.d/" + name,
		Contents: fi.NewStringResource(contents),
		Type:     nodetasks.FileType_File,
		Mode:     s("0644"),
	}
	c.AddTask(t)
}
<commit_msg>Fix CoreOS logrotate service failure.<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package model

import (
	"fmt"
	"strings"

	"github.com/golang/glog"
	"k8s.io/kops/nodeup/pkg/distros"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
)

// LogrotateBuilder installs logrotate.d and configures log rotation for kubernetes logs
type LogrotateBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &LogrotateBuilder{}

func (b *LogrotateBuilder) Build(c *fi.ModelBuilderContext) error {
	if b.Distribution == distros.DistributionContainerOS {
		glog.Infof("Detected ContainerOS; won't install logrotate")
		return nil
	} else if b.Distribution == distros.DistributionCoreOS {
		glog.Infof("Detected CoreOS; won't install logrotate")
	} else {
		c.AddTask(&nodetasks.Package{Name: "logrotate"})
	}

	k8sVersion, err := util.ParseKubernetesVersion(b.Cluster.Spec.KubernetesVersion)
	if err != nil || k8sVersion == nil {
		return fmt.Errorf("unable to parse KubernetesVersion %q", b.Cluster.Spec.KubernetesVersion)
	}

	if k8sVersion.Major == 1 && k8sVersion.Minor < 6 {
		// In version 1.6, we move log rotation to docker, but prior to that we need a logrotate rule
		b.addLogRotate(c, "docker-containers", "/var/lib/docker/containers/*/*-json.log", logRotateOptions{MaxSize: "10M"})
	}

	b.addLogRotate(c, "docker", "/var/log/docker.log", logRotateOptions{})
	b.addLogRotate(c, "kube-addons", "/var/log/kube-addons.log", logRotateOptions{})
	b.addLogRotate(c, "kube-apiserver", "/var/log/kube-apiserver.log", logRotateOptions{})
	b.addLogRotate(c, "kube-controller-manager", "/var/log/kube-controller-manager.log", logRotateOptions{})
	b.addLogRotate(c, "kube-proxy", "/var/log/kube-proxy.log", logRotateOptions{})
	b.addLogRotate(c, "kube-scheduler", "/var/log/kube-scheduler.log", logRotateOptions{})
	b.addLogRotate(c, "kubelet", "/var/log/kubelet.log", logRotateOptions{})

	if err := b.addLogrotateService(c); err != nil {
		return err
	}

	// Add timer to run hourly.
	{
		unit := &systemd.Manifest{}
		unit.Set("Unit", "Description", "Hourly Log Rotation")
		unit.Set("Timer", "OnCalendar", "hourly")

		service := &nodetasks.Service{
			Name:       "logrotate.timer", // Override (by name) any existing timer
			Definition: s(unit.Render()),
		}

		service.InitDefaults()

		c.AddTask(service)
	}

	return nil
}

// addLogrotateService creates a logrotate systemd task to act as target for the timer, if one is needed
func (b *LogrotateBuilder) addLogrotateService(c *fi.ModelBuilderContext) error {
	switch b.Distribution {
	case distros.DistributionCoreOS, distros.DistributionContainerOS:
		// logrotate service already exists
		return nil
	}

	manifest := &systemd.Manifest{}
	manifest.Set("Unit", "Description", "Rotate and Compress System Logs")
	manifest.Set("Service", "ExecStart", "/usr/sbin/logrotate /etc/logrotate.conf")

	service := &nodetasks.Service{
		Name:       "logrotate.service",
		Definition: s(manifest.Render()),
	}
	service.InitDefaults()
	c.AddTask(service)

	return nil
}

type logRotateOptions struct {
	MaxSize string
}

func (b *LogrotateBuilder) addLogRotate(c *fi.ModelBuilderContext, name, path string, options logRotateOptions) {
	if options.MaxSize == "" {
		options.MaxSize = "100M"
	}

	lines := []string{
		path + "{",
		"  rotate 5",
		"  copytruncate",
		"  missingok",
		"  notifempty",
		"  delaycompress",
		"  maxsize " + options.MaxSize,
		"  daily",
		"  create 0644 root root",
		"}",
	}

	contents := strings.Join(lines, "\n")

	t := &nodetasks.File{
		Path:     "/etc/logrotate.d/" + name,
		Contents: fi.NewStringResource(contents),
		Type:     nodetasks.FileType_File,
		Mode:     s("0644"),
	}
	c.AddTask(t)
}
<|endoftext|>


<commit_before>// +build darwin

package client

import (
	"fmt"
	"os"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	"github.com/keybase/go-kext"
)

func KeybaseFuseStatus(bundleVersion string) keybase1.FuseStatus {
	st := keybase1.FuseStatus{
		BundleVersion: bundleVersion,
		InstallStatus: keybase1.InstallStatus_UNKNOWN,
		InstallAction: keybase1.InstallAction_UNKNOWN,
	}

	var kextInfo *kext.Info

	// Check osxfuse 3.x
	path3 := "/Library/Filesystems/osxfuse.fs"
	if _, err := os.Stat(path3); err == nil {
		st.Path = path3
		kextID3 := "com.github.osxfuse.filesystems.osxfuse"
		infov3, errv3 := kext.LoadInfo(kextID3)
		if errv3 != nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: errv3.Error()}
			return st
		}
		if infov3 == nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: fmt.Sprintf("Fuse (3) installed (%s) but kext was not loaded (%s)", st.Path, kextID3)}
			return st
		}

		// Installed (v3)
		st.KextID = kextID3
		kextInfo = infov3
	}

	// Check osxfuse 2.x
	path2 := "/Library/Filesystems/osxfusefs.fs"
	if _, err := os.Stat(path2); err == nil {

		// Make sure Fuse2 isn't still lingering around
		if st.KextID != "" {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: "Fuse 2 and 3 both exist"}
			return st
		}

		st.Path = path2
		kextID2 := "com.github.osxfuse.filesystems.osxfusefs"
		infov2, errv2 := kext.LoadInfo(kextID2)
		if errv2 != nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: errv2.Error()}
			return st
		}
		if infov2 == nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: fmt.Sprintf("Fuse (2) installed (%s) but kext was not loaded (%s)", st.Path, kextID2)}
			return st
		}
		// Installed (v2)
		st.KextID = kextID2
		kextInfo = infov2
	}

	// If neither is found, we have no install
	if st.KextID == "" || kextInfo == nil {
		st.InstallStatus = keybase1.InstallStatus_NOT_INSTALLED
		st.InstallAction = keybase1.InstallAction_INSTALL
		return st
	}

	st.Version = kextInfo.Version
	st.KextStarted = kextInfo.Started

	installStatus, installAction, status := installStatus(st.Version, st.BundleVersion, "")
	st.InstallStatus = installStatus
	st.InstallAction = installAction
	st.Status = status

	return st
}
<commit_msg>Fix comment<commit_after>// +build darwin

package client

import (
	"fmt"
	"os"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	"github.com/keybase/go-kext"
)

func KeybaseFuseStatus(bundleVersion string) keybase1.FuseStatus {
	st := keybase1.FuseStatus{
		BundleVersion: bundleVersion,
		InstallStatus: keybase1.InstallStatus_UNKNOWN,
		InstallAction: keybase1.InstallAction_UNKNOWN,
	}

	var kextInfo *kext.Info

	// Check osxfuse 3.x
	path3 := "/Library/Filesystems/osxfuse.fs"
	if _, err := os.Stat(path3); err == nil {
		st.Path = path3
		kextID3 := "com.github.osxfuse.filesystems.osxfuse"
		infov3, errv3 := kext.LoadInfo(kextID3)
		if errv3 != nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: errv3.Error()}
			return st
		}
		if infov3 == nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: fmt.Sprintf("Fuse (3) installed (%s) but kext was not loaded (%s)", st.Path, kextID3)}
			return st
		}

		// Installed (v3)
		st.KextID = kextID3
		kextInfo = infov3
	}

	// Check osxfuse 2.x
	path2 := "/Library/Filesystems/osxfusefs.fs"
	if _, err := os.Stat(path2); err == nil {

		// If Fuse3 exists (above), and we also have Fuse2 then we have a borked
		// install.
		if st.KextID != "" {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: "Fuse 2 and 3 both exist"}
			return st
		}

		st.Path = path2
		kextID2 := "com.github.osxfuse.filesystems.osxfusefs"
		infov2, errv2 := kext.LoadInfo(kextID2)
		if errv2 != nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: errv2.Error()}
			return st
		}
		if infov2 == nil {
			st.InstallStatus = keybase1.InstallStatus_ERROR
			st.InstallAction = keybase1.InstallAction_NONE
			st.Status = keybase1.Status{Code: libkb.SCGeneric, Name: "INSTALL_ERROR", Desc: fmt.Sprintf("Fuse (2) installed (%s) but kext was not loaded (%s)", st.Path, kextID2)}
			return st
		}
		// Installed (v2)
		st.KextID = kextID2
		kextInfo = infov2
	}

	// If neither is found, we have no install
	if st.KextID == "" || kextInfo == nil {
		st.InstallStatus = keybase1.InstallStatus_NOT_INSTALLED
		st.InstallAction = keybase1.InstallAction_INSTALL
		return st
	}

	st.Version = kextInfo.Version
	st.KextStarted = kextInfo.Started

	installStatus, installAction, status := installStatus(st.Version, st.BundleVersion, "")
	st.InstallStatus = installStatus
	st.InstallAction = installAction
	st.Status = status

	return st
}
<|endoftext|>


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

// +build !go1.6

package gcimporter

import (
	"go/types"
	"unsafe"
)

func setName(pkg *types.Package, name string) {
	(*types_Package)(unsafe.Pointer(pkg)).name = name
}

// The underlying type of types_Package is identical to
// the underlying type of types.Package. We use it with
// package unsafe to set the name field since 1.5 does
// not have the Package.SetName method.
// TestSetName verifies that the layout with respect to
// the name field is correct.
type types_Package struct {
	path     string
	name     string
	scope    *types.Scope
	complete bool
	imports  []*types.Package
	fake     bool
}
<commit_msg>go/gcimporter15: fix build for go1.4<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build go1.5,!go1.6

package gcimporter

import (
	"go/types"
	"unsafe"
)

func setName(pkg *types.Package, name string) {
	(*types_Package)(unsafe.Pointer(pkg)).name = name
}

// The underlying type of types_Package is identical to
// the underlying type of types.Package. We use it with
// package unsafe to set the name field since 1.5 does
// not have the Package.SetName method.
// TestSetName verifies that the layout with respect to
// the name field is correct.
type types_Package struct {
	path     string
	name     string
	scope    *types.Scope
	complete bool
	imports  []*types.Package
	fake     bool
}
<|endoftext|>


<commit_before>// Copyright 2020 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bzltestutil

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

// TestWrapperAbnormalExit is used by Wrap to indicate the child
// process exitted without an exit code (for example being killed by a signal).
// We use 6, in line with Bazel's RUN_FAILURE.
const TestWrapperAbnormalExit = 6

func ShouldWrap() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP: %q", wrapEnv)
		}
		return wrap
	}
	_, ok := os.LookupEnv("XML_OUTPUT_FILE")
	return ok
}

// shouldAddTestV indicates if the test wrapper should prepend a -test.v flag to
// the test args. This is required to get information about passing tests from
// test2json for complete XML reports.
func shouldAddTestV() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP_TESTV"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP_TESTV: %q", wrapEnv)
		}
		return wrap
	}
	return false
}

func Wrap(pkg string) error {
	var jsonBuffer bytes.Buffer
	jsonConverter := NewConverter(&jsonBuffer, pkg, Timestamp)
	pipeRead, pipeWrite := io.Pipe()

	args := os.Args[1:]
	if shouldAddTestV() {
		args = append([]string{"-test.v"}, args...)
	}
	exePath := os.Args[0]
	if !filepath.IsAbs(exePath) && strings.ContainsRune(exePath, filepath.Separator) && testExecDir != "" {
		exePath = filepath.Join(testExecDir, exePath)
	}
	cmd := exec.Command(exePath, args...)
	cmd.Env = append(os.Environ(), "GO_TEST_WRAP=0")
	cmd.Stderr = io.MultiWriter(os.Stderr, pipeWrite)
	cmd.Stdout = io.MultiWriter(os.Stdout, pipeWrite)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		_, err := io.Copy(jsonConverter, pipeRead)
		if err != nil {
			panic(err)
		}
		wg.Done()
	}()
	err := cmd.Run()
	pipeWrite.Close()
	wg.Wait()
	jsonConverter.Close()
	if out, ok := os.LookupEnv("XML_OUTPUT_FILE"); ok {
		werr := writeReport(jsonBuffer, pkg, out)
		if werr != nil {
			if err != nil {
				return fmt.Errorf("error while generating testreport: %s, (error wrapping test execution: %s)", werr, err)
			}
			return fmt.Errorf("error while generating testreport: %s", werr)
		}
	}
	return err
}

func writeReport(jsonBuffer bytes.Buffer, pkg string, path string) error {
	xml, cerr := json2xml(&jsonBuffer, pkg)
	if cerr != nil {
		return fmt.Errorf("error converting test output to xml: %s", cerr)
	}
	if err := ioutil.WriteFile(path, xml, 0664); err != nil {
		return fmt.Errorf("error writing test xml: %s", err)
	}
	return nil
}
<commit_msg>synchronize when writing to the JSON converter (#3311)<commit_after>// Copyright 2020 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bzltestutil

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

// TestWrapperAbnormalExit is used by Wrap to indicate the child
// process exitted without an exit code (for example being killed by a signal).
// We use 6, in line with Bazel's RUN_FAILURE.
const TestWrapperAbnormalExit = 6

func ShouldWrap() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP: %q", wrapEnv)
		}
		return wrap
	}
	_, ok := os.LookupEnv("XML_OUTPUT_FILE")
	return ok
}

// shouldAddTestV indicates if the test wrapper should prepend a -test.v flag to
// the test args. This is required to get information about passing tests from
// test2json for complete XML reports.
func shouldAddTestV() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP_TESTV"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP_TESTV: %q", wrapEnv)
		}
		return wrap
	}
	return false
}

// streamMerger intelligently merges an input stdout and stderr stream and dumps
// the output to the writer `inner`. Additional synchronization is applied to
// ensure that one line at a time is written to the inner writer.
type streamMerger struct {
	OutW, ErrW *io.PipeWriter
	mutex sync.Mutex
	inner io.Writer
	wg sync.WaitGroup
	outR, errR *bufio.Reader
}

func NewStreamMerger(w io.Writer) *streamMerger {
	outR, outW := io.Pipe()
	errR, errW := io.Pipe()
	return &streamMerger{
		inner: w,
		OutW: outW,
		ErrW: errW,
		outR: bufio.NewReader(outR),
		errR: bufio.NewReader(errR),
	}
}

func (m *streamMerger) Start() {
	m.wg.Add(2)
	process := func(r *bufio.Reader) {
		for {
			s, err := r.ReadString('\n')
			if len(s) > 0 {
				m.mutex.Lock()
				io.WriteString(m.inner, s)
				m.mutex.Unlock()
			}
			if err == io.EOF {
				break
			}
		}
		m.wg.Done()
	}
	go process(m.outR)
	go process(m.errR)
}

func (m *streamMerger) Wait() {
	m.wg.Wait()
}

func Wrap(pkg string) error {
	var jsonBuffer bytes.Buffer
	jsonConverter := NewConverter(&jsonBuffer, pkg, Timestamp)
	streamMerger := NewStreamMerger(jsonConverter)

	args := os.Args[1:]
	if shouldAddTestV() {
		args = append([]string{"-test.v"}, args...)
	}
	exePath := os.Args[0]
	if !filepath.IsAbs(exePath) && strings.ContainsRune(exePath, filepath.Separator) && testExecDir != "" {
		exePath = filepath.Join(testExecDir, exePath)
	}
	cmd := exec.Command(exePath, args...)
	cmd.Env = append(os.Environ(), "GO_TEST_WRAP=0")
	cmd.Stderr = io.MultiWriter(os.Stderr, streamMerger.ErrW)
	cmd.Stdout = io.MultiWriter(os.Stdout, streamMerger.OutW)
	streamMerger.Start()
	err := cmd.Run()
	streamMerger.ErrW.Close()
	streamMerger.OutW.Close()
	streamMerger.Wait()
	jsonConverter.Close()
	if out, ok := os.LookupEnv("XML_OUTPUT_FILE"); ok {
		werr := writeReport(jsonBuffer, pkg, out)
		if werr != nil {
			if err != nil {
				return fmt.Errorf("error while generating testreport: %s, (error wrapping test execution: %s)", werr, err)
			}
			return fmt.Errorf("error while generating testreport: %s", werr)
		}
	}
	return err
}

func writeReport(jsonBuffer bytes.Buffer, pkg string, path string) error {
	xml, cerr := json2xml(&jsonBuffer, pkg)
	if cerr != nil {
		return fmt.Errorf("error converting test output to xml: %s", cerr)
	}
	if err := ioutil.WriteFile(path, xml, 0664); err != nil {
		return fmt.Errorf("error writing test xml: %s", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
)

const (
	width      = 600
	height     = 300
	cells      = 100
	xyrange    = 30.0
	xyscale    = width / 2 / xyrange
	multiplier = 0.4
	zscale     = height * multiplier
	angle      = math.Pi / 6
)

var (
	sin30 = math.Sin(angle)
	cos30 = math.Cos(angle)
)

type Point struct {
	X, Y, Z float64
}

func (p *Point) Isom() (float64, float64) {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return sx, sy
}

func NewPoint(i, j int, f func(float64, float64) float64) (*Point, error) {
	x := xyrange * (float64(i)/cells - 0.5)
	y := xyrange * (float64(j)/cells - 0.5)
	z := f(x, y)
	if math.IsNaN(z) || math.IsInf(z, +1) || math.IsInf(z, -1) {
		return nil, fmt.Errorf("error: function returned non real number")
	}
	return &Point{x, y, z}, nil
}

type Isometric struct {
	Sx, Sy float64
}

func NewIsometric(p Point) *Isometric {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return &Isometric{Sx: sx, Sy: sy}
}

type IsometricPolygon struct {
	A, B, C, D Isometric
	Color      string
}

func (p *IsometricPolygon) String() string {
	return fmt.Sprintf("<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
		"style='stroke:green; fill:%s; stroke-width:0.7'/>\n",
		p.A.Sx, p.A.Sy, p.B.Sx, p.B.Sy, p.C.Sx, p.C.Sy, p.D.Sx, p.D.Sy, p.Color)
}

func main() {
	fmt.Printf("<svg xmlns='http://www.w3.org/2000/svg' "+
		"width='%d' height='%d'>\n", width, height)

	// points := make([]Point, 0, cells*cells)
	// var min, max float64

	for i := 0; i < cells; i++ {
		for j := 0; j < cells; j++ {
			_, aErr := NewPoint(i+1, j, f1)
			_, bErr := NewPoint(i, j, f1)
			_, cErr := NewPoint(i, j+1, f1)
			_, dErr := NewPoint(i+1, j+1, f1)

			if aErr != nil || bErr != nil || cErr != nil || dErr != nil {
				continue
			}

			fmt.Printf("%v %v %v %v\n", aErr, bErr, cErr, dErr)

			// color := htcmap.AsStr((bz+dz)/2, -0.13, +0.13)

		}
	}
	fmt.Println("</svg>")
}

func f1(x, y float64) float64 {
	r := math.Hypot(x, y)
	return math.Sin(r) / r
}

func f2(x, y float64) float64 {
	return x * math.Exp(-x*x-y*y)
}
<commit_msg>Added getting min and max func results. This is necessary  for  polygon coloring.<commit_after>package main

import (
	"fmt"
	"math"
)

const (
	width      = 600
	height     = 300
	cells      = 100
	xyrange    = 30.0
	xyscale    = width / 2 / xyrange
	multiplier = 0.4
	zscale     = height * multiplier
	angle      = math.Pi / 6
)

var (
	sin30 = math.Sin(angle)
	cos30 = math.Cos(angle)
)

// Point represents dot on three dimensional system of coordinates
type Point struct {
	X, Y, Z float64
}

func (p *Point) Isom() (float64, float64) {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return sx, sy
}

// NewPoint transform given cells i and j to coordinates and executes given
// function of two variables using created coordinates. If successful, a pointer
// to new Point returned or error in case when function returns non-real value.
func NewPoint(i, j int, f func(float64, float64) float64) (*Point, error) {
	// Transforming cell indexes to coordinates.
	x := xyrange * (float64(i)/cells - 0.5)
	y := xyrange * (float64(j)/cells - 0.5)
	z := f(x, y)
	if math.IsNaN(z) || math.IsInf(z, +1) || math.IsInf(z, -1) {
		return nil, fmt.Errorf("error: function returned non real number")
	}
	return &Point{x, y, z}, nil
}

type Isometric struct {
	Sx, Sy float64
}

func NewIsometric(p Point) *Isometric {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return &Isometric{Sx: sx, Sy: sy}
}

type IsometricPolygon struct {
	A, B, C, D Isometric
	Color      string
}

func (p *IsometricPolygon) String() string {
	return fmt.Sprintf("<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
		"style='stroke:green; fill:%s; stroke-width:0.7'/>\n",
		p.A.Sx, p.A.Sy, p.B.Sx, p.B.Sy, p.C.Sx, p.C.Sy, p.D.Sx, p.D.Sy, p.Color)
}

func main() {
	// fmt.Printf("<svg xmlns='http://www.w3.org/2000/svg' "+
	// 	"width='%d' height='%d'>\n", width, height)

	cellPoints := make([][4]*Point, 0, cells*cells)
	var min, max float64

	for i := 0; i < cells; i++ {
		for j := 0; j < cells; j++ {
			// TODO: Rework ugly solution and find better names.
			var coords [4]*Point
			var aErr, bErr, cErr, dErr error
			coords[0], aErr = NewPoint(i+1, j, f1)
			coords[1], bErr = NewPoint(i, j, f1)
			coords[2], cErr = NewPoint(i, j+1, f1)
			coords[3], dErr = NewPoint(i+1, j+1, f1)

			// Skipping cell with non real points.
			if aErr != nil || bErr != nil || cErr != nil || dErr != nil {
				continue
			}
			for _, p := range coords {
				min = math.Min(min, p.Z)
				max = math.Max(max, p.Z)
			}
			cellPoints = append(cellPoints, coords)
			// fmt.Printf("%v %v %v %v\n", aErr, bErr, cErr, dErr)

			// color := htcmap.AsStr((bz+dz)/2, -0.13, +0.13)

		}

	}
	fmt.Printf("Min: %g, Max: %g\n", min, max)
	// fmt.Println("</svg>")
}

func f1(x, y float64) float64 {
	r := math.Hypot(x, y)
	return math.Sin(r) / r
}

func f2(x, y float64) float64 {
	return x * math.Exp(-x*x-y*y)
}
<|endoftext|>


<commit_before>package handlers

import (
	"encoding/json"
	"github.com/vivowares/eywa/Godeps/_workspace/src/github.com/zenazn/goji/web"
	"github.com/vivowares/eywa/models"
	. "github.com/vivowares/eywa/presenters"
	. "github.com/vivowares/eywa/utils"
	"net/http"
	"time"
	"bytes"
)

func CreateChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch := &models.Channel{}
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(ch)
	if err != nil {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
		return
	}

	err = ch.Create()
	if err != nil {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
	} else {
		Render.JSON(w, http.StatusCreated, NewChannelBrief(ch))
	}
}

func UpdateChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)
	if !found {
		w.WriteHeader(http.StatusNotFound)
	} else {
		fields := ch.Fields
		ch.Fields = nil
		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(ch)
		if err != nil {
			Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
			return
		}
		if ch.Fields == nil {
			ch.Fields = fields
		}
		err = ch.Update()
		if err != nil {
			Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
		} else {
			w.WriteHeader(http.StatusOK)
		}
	}
}

func ListChannels(c web.C, w http.ResponseWriter, r *http.Request) {
	chs := models.Channels()

	cs := []*ChannelBrief{}
	for _, ch := range chs {
		cs = append(cs, NewChannelBrief(ch))
	}

	Render.JSON(w, http.StatusOK, cs)
}

func GetChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)

	if !found {
		w.WriteHeader(http.StatusNotFound)
	} else {
		Render.JSON(w, http.StatusOK, NewChannelDetail(ch))
	}
}

func GetChannelTagStats(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findCachedChannel(c, "id")
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel not found"})
		return
	}

	q := &models.StatsQuery{Channel: ch}
	err := q.Parse(QueryToMap(r.URL.Query()))
	if err != nil {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
	} else {
		stats, err := q.QueryES()
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
		} else {
			Render.JSON(w, http.StatusOK, stats)
		}
	}
}

func GetChannelIndexStats(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findCachedChannel(c, "id")
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel not found"})
		return
	}
	stats, found := models.FetchCachedChannelIndexStatsById(ch.Id)
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel stats not found"})
	} else {
		Render.JSON(w, http.StatusOK, stats)
	}
}

func GetChannelRequestTemplate(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel not found"})
		return
	}

	query := QueryToMap(r.URL.Query())

	if len(query) != 0 {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": "invalid query"})
		return
	}

	tmplName, tmpl, err := FetchRequestTemplateByChannel(ch)
	if err != nil {
		Render.JSON(w, http.StatusInternalServerError, err.Error())
		return
	}

	w.Header().Set("Content-Type", "text/plain; charset=\"UTF-8\"")
	http.ServeContent(w, r, tmplName, time.Now(), bytes.NewReader([]byte(tmpl)))
}

func DeleteChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)
	if !found {
		w.WriteHeader(http.StatusNotFound)
	} else {
		err := ch.Delete()
		if err != nil {
			Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
		} else {
			if r.URL.Query().Get("with_indices") == "true" {
				err = ch.DeleteIndices()
			}
			if err != nil {
				Render.JSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
			} else {
				w.WriteHeader(http.StatusOK)
			}
		}
	}
}
<commit_msg>Render Text<commit_after>package handlers

import (
	"encoding/json"
	"github.com/vivowares/eywa/Godeps/_workspace/src/github.com/zenazn/goji/web"
	"github.com/vivowares/eywa/models"
	. "github.com/vivowares/eywa/presenters"
	. "github.com/vivowares/eywa/utils"
	"net/http"
)

func CreateChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch := &models.Channel{}
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(ch)
	if err != nil {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
		return
	}

	err = ch.Create()
	if err != nil {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
	} else {
		Render.JSON(w, http.StatusCreated, NewChannelBrief(ch))
	}
}

func UpdateChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)
	if !found {
		w.WriteHeader(http.StatusNotFound)
	} else {
		fields := ch.Fields
		ch.Fields = nil
		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(ch)
		if err != nil {
			Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
			return
		}
		if ch.Fields == nil {
			ch.Fields = fields
		}
		err = ch.Update()
		if err != nil {
			Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
		} else {
			w.WriteHeader(http.StatusOK)
		}
	}
}

func ListChannels(c web.C, w http.ResponseWriter, r *http.Request) {
	chs := models.Channels()

	cs := []*ChannelBrief{}
	for _, ch := range chs {
		cs = append(cs, NewChannelBrief(ch))
	}

	Render.JSON(w, http.StatusOK, cs)
}

func GetChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)

	if !found {
		w.WriteHeader(http.StatusNotFound)
	} else {
		Render.JSON(w, http.StatusOK, NewChannelDetail(ch))
	}
}

func GetChannelTagStats(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findCachedChannel(c, "id")
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel not found"})
		return
	}

	q := &models.StatsQuery{Channel: ch}
	err := q.Parse(QueryToMap(r.URL.Query()))
	if err != nil {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
	} else {
		stats, err := q.QueryES()
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
		} else {
			Render.JSON(w, http.StatusOK, stats)
		}
	}
}

func GetChannelIndexStats(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findCachedChannel(c, "id")
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel not found"})
		return
	}
	stats, found := models.FetchCachedChannelIndexStatsById(ch.Id)
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel stats not found"})
	} else {
		Render.JSON(w, http.StatusOK, stats)
	}
}

func GetChannelRequestTemplate(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)
	if !found {
		Render.JSON(w, http.StatusNotFound, map[string]string{"error": "channel not found"})
		return
	}

	query := QueryToMap(r.URL.Query())

	if len(query) != 0 {
		Render.JSON(w, http.StatusBadRequest, map[string]string{"error": "invalid query"})
		return
	}

	_, tmpl, err := FetchRequestTemplateByChannel(ch)
	if err != nil {
		Render.JSON(w, http.StatusInternalServerError, err.Error())
	} else {
		Render.Text(w, http.StatusOK, tmpl)
	}
}

func DeleteChannel(c web.C, w http.ResponseWriter, r *http.Request) {
	ch, found := findChannel(c)
	if !found {
		w.WriteHeader(http.StatusNotFound)
	} else {
		err := ch.Delete()
		if err != nil {
			Render.JSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
		} else {
			if r.URL.Query().Get("with_indices") == "true" {
				err = ch.DeleteIndices()
			}
			if err != nil {
				Render.JSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
			} else {
				w.WriteHeader(http.StatusOK)
			}
		}
	}
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	neturl "net/url"
	"strings"

	"github.com/cloudfoundry/cli/cf/api/resources"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/errors"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/net"
)

var orgRoleToPathMap = map[string]string{
	models.ORG_USER:        "users",
	models.ORG_MANAGER:     "managers",
	models.BILLING_MANAGER: "billing_managers",
	models.ORG_AUDITOR:     "auditors",
}

var spaceRoleToPathMap = map[string]string{
	models.SPACE_MANAGER:   "managers",
	models.SPACE_DEVELOPER: "developers",
	models.SPACE_AUDITOR:   "auditors",
}

type UserRepository interface {
	FindByUsername(username string) (user models.UserFields, apiErr error)
	ListUsersInOrgForRole(orgGuid string, role string) ([]models.UserFields, error)
	ListUsersInOrgForRoleWithNoUAA(orgGuid string, role string) ([]models.UserFields, error)
	ListUsersInSpaceForRole(spaceGuid string, role string) ([]models.UserFields, error)
	ListUsersInSpaceForRoleWithNoUAA(spaceGuid string, role string) ([]models.UserFields, error)
	Create(username, password string) (apiErr error)
	Delete(userGuid string) (apiErr error)
	SetOrgRole(userGuid, orgGuid, role string) (apiErr error)
	SetOrgRoleByUsername(username, orgGuid, role string) (apiErr error)
	UnsetOrgRole(userGuid, orgGuid, role string) (apiErr error)
	SetSpaceRole(userGuid, spaceGuid, orgGuid, role string) (apiErr error)
	UnsetSpaceRole(userGuid, spaceGuid, role string) (apiErr error)
}

type CloudControllerUserRepository struct {
	config     core_config.Reader
	uaaGateway net.Gateway
	ccGateway  net.Gateway
}

func NewCloudControllerUserRepository(config core_config.Reader, uaaGateway net.Gateway, ccGateway net.Gateway) (repo CloudControllerUserRepository) {
	repo.config = config
	repo.uaaGateway = uaaGateway
	repo.ccGateway = ccGateway
	return
}

func (repo CloudControllerUserRepository) FindByUsername(username string) (models.UserFields, error) {
	uaaEndpoint, apiErr := repo.getAuthEndpoint()
	var user models.UserFields
	if apiErr != nil {
		return user, apiErr
	}

	usernameFilter := neturl.QueryEscape(fmt.Sprintf(`userName Eq "%s"`, username))
	path := fmt.Sprintf("%s/Users?attributes=id,userName&filter=%s", uaaEndpoint, usernameFilter)
	users, apiErr := repo.updateOrFindUsersWithUAAPath([]models.UserFields{}, path)

	if apiErr != nil {
		errType, ok := apiErr.(errors.HttpError)
		if ok {
			if errType.StatusCode() == 403 {
				return user, errors.NewAccessDeniedError()
			}
		}
		return user, apiErr
	} else if len(users) == 0 {
		return user, errors.NewModelNotFoundError("User", username)
	}

	return users[0], apiErr
}

func (repo CloudControllerUserRepository) ListUsersInOrgForRole(orgGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPath(fmt.Sprintf("/v2/organizations/%s/%s", orgGuid, orgRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) ListUsersInOrgForRoleWithNoUAA(orgGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPathWithNoUAA(fmt.Sprintf("/v2/organizations/%s/%s", orgGuid, orgRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) ListUsersInSpaceForRole(spaceGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPath(fmt.Sprintf("/v2/spaces/%s/%s", spaceGuid, spaceRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) ListUsersInSpaceForRoleWithNoUAA(spaceGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPathWithNoUAA(fmt.Sprintf("/v2/spaces/%s/%s", spaceGuid, spaceRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) listUsersWithPathWithNoUAA(path string) (users []models.UserFields, apiErr error) {
	apiErr = repo.ccGateway.ListPaginatedResources(
		repo.config.ApiEndpoint(),
		path,
		resources.UserResource{},
		func(resource interface{}) bool {
			user := resource.(resources.UserResource).ToFields()
			users = append(users, user)
			return true
		})
	if apiErr != nil {
		return
	}

	return
}

func (repo CloudControllerUserRepository) listUsersWithPath(path string) (users []models.UserFields, apiErr error) {
	guidFilters := []string{}

	apiErr = repo.ccGateway.ListPaginatedResources(
		repo.config.ApiEndpoint(),
		path,
		resources.UserResource{},
		func(resource interface{}) bool {
			user := resource.(resources.UserResource).ToFields()
			users = append(users, user)
			guidFilters = append(guidFilters, fmt.Sprintf(`Id eq "%s"`, user.Guid))
			return true
		})
	if apiErr != nil {
		return
	}

	if len(guidFilters) == 0 {
		return
	}

	uaaEndpoint, apiErr := repo.getAuthEndpoint()
	if apiErr != nil {
		return
	}

	filter := strings.Join(guidFilters, " or ")
	usersURL := fmt.Sprintf("%s/Users?attributes=id,userName&filter=%s", uaaEndpoint, neturl.QueryEscape(filter))
	users, apiErr = repo.updateOrFindUsersWithUAAPath(users, usersURL)
	return
}

func (repo CloudControllerUserRepository) updateOrFindUsersWithUAAPath(ccUsers []models.UserFields, path string) (updatedUsers []models.UserFields, apiErr error) {
	uaaResponse := new(resources.UAAUserResources)
	apiErr = repo.uaaGateway.GetResource(path, uaaResponse)
	if apiErr != nil {
		return
	}

	for _, uaaResource := range uaaResponse.Resources {
		var ccUserFields models.UserFields

		for _, u := range ccUsers {
			if u.Guid == uaaResource.Id {
				ccUserFields = u
				break
			}
		}

		updatedUsers = append(updatedUsers, models.UserFields{
			Guid:     uaaResource.Id,
			Username: uaaResource.Username,
			IsAdmin:  ccUserFields.IsAdmin,
		})
	}
	return
}

func (repo CloudControllerUserRepository) Create(username, password string) (err error) {
	uaaEndpoint, err := repo.getAuthEndpoint()
	if err != nil {
		return
	}

	path := "/Users"
	body, err := json.Marshal(resources.NewUAAUserResource(username, password))

	if err != nil {
		return
	}

	createUserResponse := &resources.UAAUserFields{}
	err = repo.uaaGateway.CreateResource(uaaEndpoint, path, bytes.NewReader(body), createUserResponse)
	switch httpErr := err.(type) {
	case nil:
	case errors.HttpError:
		if httpErr.StatusCode() == http.StatusConflict {
			err = errors.NewModelAlreadyExistsError("user", username)
			return
		}
		return
	default:
		return
	}

	path = "/v2/users"
	body, err = json.Marshal(resources.Metadata{
		Guid: createUserResponse.Id,
	})

	if err != nil {
		return
	}

	return repo.ccGateway.CreateResource(repo.config.ApiEndpoint(), path, bytes.NewReader(body))
}

func (repo CloudControllerUserRepository) Delete(userGuid string) (apiErr error) {
	path := fmt.Sprintf("/v2/users/%s", userGuid)

	apiErr = repo.ccGateway.DeleteResource(repo.config.ApiEndpoint(), path)

	if httpErr, ok := apiErr.(errors.HttpError); ok && httpErr.ErrorCode() != errors.USER_NOT_FOUND {
		return
	}
	uaaEndpoint, apiErr := repo.getAuthEndpoint()
	if apiErr != nil {
		return
	}

	path = fmt.Sprintf("/Users/%s", userGuid)
	return repo.uaaGateway.DeleteResource(uaaEndpoint, path)
}

func (repo CloudControllerUserRepository) SetOrgRole(userGuid string, orgGuid string, role string) (apiErr error) {
	apiErr = repo.setOrUnsetOrgRole("PUT", userGuid, orgGuid, role)
	if apiErr != nil {
		return
	}
	return repo.addOrgUserRole(userGuid, orgGuid)
}

func (repo CloudControllerUserRepository) SetOrgRoleByUsername(username string, orgGuid string, role string) (apiErr error) {
	rolePath, found := orgRoleToPathMap[role]

	if !found {
		apiErr = errors.NewWithFmt(T("Invalid Role {{.Role}}",
			map[string]interface{}{"Role": role}))
		return
	}

	path := fmt.Sprintf("%s/v2/organizations/%s/%s", repo.config.ApiEndpoint(), orgGuid, rolePath)
	request, _ := repo.ccGateway.NewRequest("PUT", path, repo.config.AccessToken(), strings.NewReader(`{"username": "`+username+`"}`))

	_, apiErr = repo.ccGateway.PerformRequest(request)
	if apiErr != nil {
		return
	}
	apiErr = repo.assocUserWithOrgByUsername(username, orgGuid)
	return
}

func (repo CloudControllerUserRepository) UnsetOrgRole(userGuid, orgGuid, role string) (apiErr error) {
	return repo.setOrUnsetOrgRole("DELETE", userGuid, orgGuid, role)
}

func (repo CloudControllerUserRepository) setOrUnsetOrgRole(verb, userGuid, orgGuid, role string) (apiErr error) {
	rolePath, found := orgRoleToPathMap[role]

	if !found {
		apiErr = errors.NewWithFmt(T("Invalid Role {{.Role}}",
			map[string]interface{}{"Role": role}))
		return
	}

	path := fmt.Sprintf("%s/v2/organizations/%s/%s/%s", repo.config.ApiEndpoint(), orgGuid, rolePath, userGuid)
	request, apiErr := repo.ccGateway.NewRequest(verb, path, repo.config.AccessToken(), nil)
	if apiErr != nil {
		return
	}

	_, apiErr = repo.ccGateway.PerformRequest(request)
	if apiErr != nil {
		return
	}
	return
}

func (repo CloudControllerUserRepository) SetSpaceRole(userGuid, spaceGuid, orgGuid, role string) (apiErr error) {
	rolePath, apiErr := repo.checkSpaceRole(userGuid, spaceGuid, role)
	if apiErr != nil {
		return
	}

	apiErr = repo.addOrgUserRole(userGuid, orgGuid)
	if apiErr != nil {
		return
	}

	return repo.ccGateway.UpdateResource(repo.config.ApiEndpoint(), rolePath, nil)
}

func (repo CloudControllerUserRepository) UnsetSpaceRole(userGuid, spaceGuid, role string) (apiErr error) {
	rolePath, apiErr := repo.checkSpaceRole(userGuid, spaceGuid, role)
	if apiErr != nil {
		return
	}
	return repo.ccGateway.DeleteResource(repo.config.ApiEndpoint(), rolePath)
}

func (repo CloudControllerUserRepository) checkSpaceRole(userGuid, spaceGuid, role string) (string, error) {
	var apiErr error

	rolePath, found := spaceRoleToPathMap[role]

	if !found {
		apiErr = errors.NewWithFmt(T("Invalid Role {{.Role}}",
			map[string]interface{}{"Role": role}))
	}

	apiPath := fmt.Sprintf("/v2/spaces/%s/%s/%s", spaceGuid, rolePath, userGuid)
	return apiPath, apiErr
}

func (repo CloudControllerUserRepository) assocUserWithOrgByUsername(username, orgGuid string) (apiErr error) {
	path := fmt.Sprintf("/v2/organizations/%s/users", orgGuid)
	return repo.ccGateway.UpdateResource(repo.config.ApiEndpoint(), path, strings.NewReader(`{"username": "`+username+`"}`))
}

func (repo CloudControllerUserRepository) addOrgUserRole(userGuid, orgGuid string) (apiErr error) {
	path := fmt.Sprintf("/v2/organizations/%s/users/%s", orgGuid, userGuid)
	return repo.ccGateway.UpdateResource(repo.config.ApiEndpoint(), path, nil)
}

func (repo CloudControllerUserRepository) getAuthEndpoint() (string, error) {
	uaaEndpoint := repo.config.UaaEndpoint()
	if uaaEndpoint == "" {
		return "", errors.New(T("UAA endpoint missing from config file"))
	}
	return uaaEndpoint, nil
}
<commit_msg>Refactor users.go<commit_after>package api

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	neturl "net/url"
	"strings"

	"github.com/cloudfoundry/cli/cf/api/resources"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/errors"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/net"
)

var orgRoleToPathMap = map[string]string{
	models.ORG_USER:        "users",
	models.ORG_MANAGER:     "managers",
	models.BILLING_MANAGER: "billing_managers",
	models.ORG_AUDITOR:     "auditors",
}

var spaceRoleToPathMap = map[string]string{
	models.SPACE_MANAGER:   "managers",
	models.SPACE_DEVELOPER: "developers",
	models.SPACE_AUDITOR:   "auditors",
}

type UserRepository interface {
	FindByUsername(username string) (user models.UserFields, apiErr error)
	ListUsersInOrgForRole(orgGuid string, role string) ([]models.UserFields, error)
	ListUsersInOrgForRoleWithNoUAA(orgGuid string, role string) ([]models.UserFields, error)
	ListUsersInSpaceForRole(spaceGuid string, role string) ([]models.UserFields, error)
	ListUsersInSpaceForRoleWithNoUAA(spaceGuid string, role string) ([]models.UserFields, error)
	Create(username, password string) (apiErr error)
	Delete(userGuid string) (apiErr error)
	SetOrgRole(userGuid, orgGuid, role string) (apiErr error)
	SetOrgRoleByUsername(username, orgGuid, role string) (apiErr error)
	UnsetOrgRole(userGuid, orgGuid, role string) (apiErr error)
	SetSpaceRole(userGuid, spaceGuid, orgGuid, role string) (apiErr error)
	UnsetSpaceRole(userGuid, spaceGuid, role string) (apiErr error)
}

type CloudControllerUserRepository struct {
	config     core_config.Reader
	uaaGateway net.Gateway
	ccGateway  net.Gateway
}

func NewCloudControllerUserRepository(config core_config.Reader, uaaGateway net.Gateway, ccGateway net.Gateway) (repo CloudControllerUserRepository) {
	repo.config = config
	repo.uaaGateway = uaaGateway
	repo.ccGateway = ccGateway
	return
}

func (repo CloudControllerUserRepository) FindByUsername(username string) (models.UserFields, error) {
	uaaEndpoint, apiErr := repo.getAuthEndpoint()
	var user models.UserFields
	if apiErr != nil {
		return user, apiErr
	}

	usernameFilter := neturl.QueryEscape(fmt.Sprintf(`userName Eq "%s"`, username))
	path := fmt.Sprintf("%s/Users?attributes=id,userName&filter=%s", uaaEndpoint, usernameFilter)
	users, apiErr := repo.updateOrFindUsersWithUAAPath([]models.UserFields{}, path)

	if apiErr != nil {
		errType, ok := apiErr.(errors.HttpError)
		if ok {
			if errType.StatusCode() == 403 {
				return user, errors.NewAccessDeniedError()
			}
		}
		return user, apiErr
	} else if len(users) == 0 {
		return user, errors.NewModelNotFoundError("User", username)
	}

	return users[0], apiErr
}

func (repo CloudControllerUserRepository) ListUsersInOrgForRole(orgGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPath(fmt.Sprintf("/v2/organizations/%s/%s", orgGuid, orgRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) ListUsersInOrgForRoleWithNoUAA(orgGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPathWithNoUAA(fmt.Sprintf("/v2/organizations/%s/%s", orgGuid, orgRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) ListUsersInSpaceForRole(spaceGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPath(fmt.Sprintf("/v2/spaces/%s/%s", spaceGuid, spaceRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) ListUsersInSpaceForRoleWithNoUAA(spaceGuid string, roleName string) (users []models.UserFields, apiErr error) {
	return repo.listUsersWithPathWithNoUAA(fmt.Sprintf("/v2/spaces/%s/%s", spaceGuid, spaceRoleToPathMap[roleName]))
}

func (repo CloudControllerUserRepository) listUsersWithPathWithNoUAA(path string) (users []models.UserFields, apiErr error) {
	apiErr = repo.ccGateway.ListPaginatedResources(
		repo.config.ApiEndpoint(),
		path,
		resources.UserResource{},
		func(resource interface{}) bool {
			user := resource.(resources.UserResource).ToFields()
			users = append(users, user)
			return true
		})
	if apiErr != nil {
		return
	}

	return
}

func (repo CloudControllerUserRepository) listUsersWithPath(path string) (users []models.UserFields, apiErr error) {
	guidFilters := []string{}

	apiErr = repo.ccGateway.ListPaginatedResources(
		repo.config.ApiEndpoint(),
		path,
		resources.UserResource{},
		func(resource interface{}) bool {
			user := resource.(resources.UserResource).ToFields()
			users = append(users, user)
			guidFilters = append(guidFilters, fmt.Sprintf(`Id eq "%s"`, user.Guid))
			return true
		})
	if apiErr != nil {
		return
	}

	if len(guidFilters) == 0 {
		return
	}

	uaaEndpoint, apiErr := repo.getAuthEndpoint()
	if apiErr != nil {
		return
	}

	filter := strings.Join(guidFilters, " or ")
	usersURL := fmt.Sprintf("%s/Users?attributes=id,userName&filter=%s", uaaEndpoint, neturl.QueryEscape(filter))
	users, apiErr = repo.updateOrFindUsersWithUAAPath(users, usersURL)
	return
}

func (repo CloudControllerUserRepository) updateOrFindUsersWithUAAPath(ccUsers []models.UserFields, path string) (updatedUsers []models.UserFields, apiErr error) {
	uaaResponse := new(resources.UAAUserResources)
	apiErr = repo.uaaGateway.GetResource(path, uaaResponse)
	if apiErr != nil {
		return
	}

	for _, uaaResource := range uaaResponse.Resources {
		var ccUserFields models.UserFields

		for _, u := range ccUsers {
			if u.Guid == uaaResource.Id {
				ccUserFields = u
				break
			}
		}

		updatedUsers = append(updatedUsers, models.UserFields{
			Guid:     uaaResource.Id,
			Username: uaaResource.Username,
			IsAdmin:  ccUserFields.IsAdmin,
		})
	}
	return
}

func (repo CloudControllerUserRepository) Create(username, password string) (err error) {
	uaaEndpoint, err := repo.getAuthEndpoint()
	if err != nil {
		return
	}

	path := "/Users"
	body, err := json.Marshal(resources.NewUAAUserResource(username, password))

	if err != nil {
		return
	}

	createUserResponse := &resources.UAAUserFields{}
	err = repo.uaaGateway.CreateResource(uaaEndpoint, path, bytes.NewReader(body), createUserResponse)
	switch httpErr := err.(type) {
	case nil:
	case errors.HttpError:
		if httpErr.StatusCode() == http.StatusConflict {
			err = errors.NewModelAlreadyExistsError("user", username)
			return
		}
		return
	default:
		return
	}

	path = "/v2/users"
	body, err = json.Marshal(resources.Metadata{
		Guid: createUserResponse.Id,
	})

	if err != nil {
		return
	}

	return repo.ccGateway.CreateResource(repo.config.ApiEndpoint(), path, bytes.NewReader(body))
}

func (repo CloudControllerUserRepository) Delete(userGuid string) (apiErr error) {
	path := fmt.Sprintf("/v2/users/%s", userGuid)

	apiErr = repo.ccGateway.DeleteResource(repo.config.ApiEndpoint(), path)

	if httpErr, ok := apiErr.(errors.HttpError); ok && httpErr.ErrorCode() != errors.USER_NOT_FOUND {
		return
	}
	uaaEndpoint, apiErr := repo.getAuthEndpoint()
	if apiErr != nil {
		return
	}

	path = fmt.Sprintf("/Users/%s", userGuid)
	return repo.uaaGateway.DeleteResource(uaaEndpoint, path)
}

func (repo CloudControllerUserRepository) SetOrgRole(userGuid string, orgGuid string, role string) (err error) {
	path, err := userGuidPath(repo.config.ApiEndpoint(), userGuid, orgGuid, role)
	if err != nil {
		return
	}
	err = repo.callApi("PUT", path, nil)
	if err != nil {
		return
	}
	return repo.assocUserWithOrgByUserGuid(userGuid, orgGuid)
}

func (repo CloudControllerUserRepository) UnsetOrgRole(userGuid, orgGuid, role string) (err error) {
	path, err := userGuidPath(repo.config.ApiEndpoint(), userGuid, orgGuid, role)
	if err != nil {
		return
	}
	return repo.callApi("DELETE", path, nil)
}

func (repo CloudControllerUserRepository) SetOrgRoleByUsername(username string, orgGuid string, role string) (err error) {
	path, err := orgRolesPath(repo.config.ApiEndpoint(), username, orgGuid, role)
	if err != nil {
		return
	}
	err = repo.callApi("PUT", path, usernamePayload(username))
	if err != nil {
		return
	}
	return repo.assocUserWithOrgByUsername(username, orgGuid)
}

func (repo CloudControllerUserRepository) callApi(verb, path string, body io.ReadSeeker) (err error) {
	request, err := repo.ccGateway.NewRequest(verb, path, repo.config.AccessToken(), body)
	if err != nil {
		return
	}
	_, err = repo.ccGateway.PerformRequest(request)
	if err != nil {
		return
	}
	return
}

func userGuidPath(apiEndpoint, userGuid, orgGuid, role string) (string, error) {
	rolePath, err := rolePath(role)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("%s/v2/organizations/%s/%s/%s", apiEndpoint, orgGuid, rolePath, userGuid), nil
}

func orgRolesPath(apiEndpoint, username, orgGuid, role string) (string, error) {
	rolePath, err := rolePath(role)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("%s/v2/organizations/%s/%s", apiEndpoint, orgGuid, rolePath), nil
}

func (repo CloudControllerUserRepository) SetSpaceRole(userGuid, spaceGuid, orgGuid, role string) (apiErr error) {
	rolePath, apiErr := repo.checkSpaceRole(userGuid, spaceGuid, role)
	if apiErr != nil {
		return
	}

	apiErr = repo.assocUserWithOrgByUserGuid(userGuid, orgGuid)
	if apiErr != nil {
		return
	}

	return repo.ccGateway.UpdateResource(repo.config.ApiEndpoint(), rolePath, nil)
}

func (repo CloudControllerUserRepository) UnsetSpaceRole(userGuid, spaceGuid, role string) (apiErr error) {
	rolePath, apiErr := repo.checkSpaceRole(userGuid, spaceGuid, role)
	if apiErr != nil {
		return
	}
	return repo.ccGateway.DeleteResource(repo.config.ApiEndpoint(), rolePath)
}

func (repo CloudControllerUserRepository) checkSpaceRole(userGuid, spaceGuid, role string) (string, error) {
	var apiErr error

	rolePath, found := spaceRoleToPathMap[role]

	if !found {
		apiErr = errors.NewWithFmt(T("Invalid Role {{.Role}}",
			map[string]interface{}{"Role": role}))
	}

	apiPath := fmt.Sprintf("/v2/spaces/%s/%s/%s", spaceGuid, rolePath, userGuid)
	return apiPath, apiErr
}

func (repo CloudControllerUserRepository) assocUserWithOrgByUsername(username, orgGuid string) (apiErr error) {
	path := fmt.Sprintf("/v2/organizations/%s/users", orgGuid)
	return repo.ccGateway.UpdateResource(repo.config.ApiEndpoint(), path, usernamePayload(username))
}

func (repo CloudControllerUserRepository) assocUserWithOrgByUserGuid(userGuid, orgGuid string) (apiErr error) {
	path := fmt.Sprintf("/v2/organizations/%s/users/%s", orgGuid, userGuid)
	return repo.ccGateway.UpdateResource(repo.config.ApiEndpoint(), path, nil)
}

func (repo CloudControllerUserRepository) getAuthEndpoint() (string, error) {
	uaaEndpoint := repo.config.UaaEndpoint()
	if uaaEndpoint == "" {
		return "", errors.New(T("UAA endpoint missing from config file"))
	}
	return uaaEndpoint, nil
}

func rolePath(role string) (string, error) {
	path, found := orgRoleToPathMap[role]

	if !found {
		return "", errors.NewWithFmt(T("Invalid Role {{.Role}}",
			map[string]interface{}{"Role": role}))
	}
	return path, nil
}

func usernamePayload(username string) *strings.Reader {
	return strings.NewReader(`{"username": "` + username + `"}`)
}
<|endoftext|>


<commit_before>package channeldb

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"github.com/boltdb/bolt"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
	"github.com/roasbeef/btcd/wire"
)

const (
	dbName = "channel.db"
)

var (
	// Big endian is the preferred byte order, due to cursor scans over integer
	// keys iterating in order.
	byteOrder = binary.BigEndian
)

var bufPool = &sync.Pool{
	New: func() interface{} { return new(bytes.Buffer) },
}

// DB is the primary datastore for the LND daemon. The database stores
// information related to nodes, routing data, open/closed channels, fee
// schedules, and reputation data.
type DB struct {
	store *bolt.DB

	netParams *chaincfg.Params
}

// Open opens an existing channeldb created under the passed namespace with
// sensitive data encrypted by the passed EncryptorDecryptor implementation.
// TODO(roasbeef): versioning?
func Open(dbPath string, netParams *chaincfg.Params) (*DB, error) {
	path := filepath.Join(dbPath, dbName)

	if !fileExists(path) {
		if err := createChannelDB(dbPath); err != nil {
			return nil, err
		}
	}

	bdb, err := bolt.Open(path, 0600, nil)
	if err != nil {
		return nil, err
	}

	return &DB{store: bdb, netParams: netParams}, nil
}

// Wipe completely deletes all saved state within all used buckets within the
// database. The deletion is done in a single transaction, therefore this
// operation is fully atomic.
func (d *DB) Wipe() error {
	return d.store.Update(func(tx *bolt.Tx) error {
		err := tx.DeleteBucket(openChannelBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		err = tx.DeleteBucket(closedChannelBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		err = tx.DeleteBucket(invoiceBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		return nil
	})
}

// Close terminates the underlying database handle manually.
func (d *DB) Close() error {
	return d.store.Close()
}

// createChannelDB creates and initializes a fresh version of channeldb. In
// the case that the target path has not yet been created or doesn't yet exist,
// then the path is created. Additionally, all required top-level buckets used
// within the database are created.
func createChannelDB(dbPath string) error {
	if !fileExists(dbPath) {
		if err := os.MkdirAll(dbPath, 0700); err != nil {
			return err
		}
	}

	path := filepath.Join(dbPath, dbName)
	bdb, err := bolt.Open(path, 0600, nil)
	if err != nil {
		return err
	}

	err = bdb.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucket(openChannelBucket); err != nil {
			return err
		}

		if _, err := tx.CreateBucket(closedChannelBucket); err != nil {
			return err
		}

		if _, err := tx.CreateBucket(invoiceBucket); err != nil {
			return err
		}

		if _, err := tx.CreateBucket(nodeInfoBucket); err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return fmt.Errorf("unable to create new channeldb")
	}

	return bdb.Close()
}

// fileExists returns true if the file exists, and false otherwise.
func fileExists(path string) bool {
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}

	return true
}

// FetchOpenChannel returns all stored currently active/open channels
// associated with the target nodeID. In the case that no active channels are
// known to have been created with this node, then a zero-length slice is
// returned.
func (d *DB) FetchOpenChannels(nodeID *btcec.PublicKey) ([]*OpenChannel, error) {
	var channels []*OpenChannel
	err := d.store.View(func(tx *bolt.Tx) error {
		// Get the bucket dedicated to storing the meta-data for open
		// channels.
		openChanBucket := tx.Bucket(openChannelBucket)
		if openChanBucket == nil {
			return nil
		}

		// Within this top level bucket, fetch the bucket dedicated to storing
		// open channel data specific to the remote node.
		pub := nodeID.SerializeCompressed()
		nodeChanBucket := openChanBucket.Bucket(pub)
		if nodeChanBucket == nil {
			return nil
		}

		// Finally, we both of the necessary buckets retrieved, fetch
		// all the active channels related to this node.
		nodeChannels, err := d.fetchNodeChannels(openChanBucket,
			nodeChanBucket)
		if err != nil {
			return err
		}

		channels = nodeChannels
		return nil
	})

	return channels, err
}

// fetchNodeChannels retrieves all active channels from the target
// nodeChanBucket. This function is typically used to fetch all the active
// channels related to a particualr node.
func (d *DB) fetchNodeChannels(openChanBucket,
	nodeChanBucket *bolt.Bucket) ([]*OpenChannel, error) {

	var channels []*OpenChannel

	// Once we have the node's channel bucket, iterate through each
	// item in the inner chan ID bucket. This bucket acts as an
	// index for all channels we currently have open with this node.
	nodeChanIDBucket := nodeChanBucket.Bucket(chanIDBucket[:])
	if nodeChanIDBucket == nil {
		return nil, nil
	}
	err := nodeChanIDBucket.ForEach(func(k, v []byte) error {
		if k == nil {
			return nil
		}

		outBytes := bytes.NewReader(k)
		chanID := &wire.OutPoint{}
		if err := readOutpoint(outBytes, chanID); err != nil {
			return err
		}

		oChannel, err := fetchOpenChannel(openChanBucket,
			nodeChanBucket, chanID)
		if err != nil {
			return err
		}
		oChannel.Db = d

		channels = append(channels, oChannel)
		return nil
	})
	if err != nil {
		return nil, err
	}

	return channels, nil
}

// FetchAllChannels attempts to retrieve all open channels currently stored
// within the database. If no active channels exist within the network, then
// ErrNoActiveChannels is returned.
func (d *DB) FetchAllChannels() ([]*OpenChannel, error) {
	var channels []*OpenChannel

	err := d.store.View(func(tx *bolt.Tx) error {
		// Get the bucket dedicated to storing the meta-data for open
		// channels.
		openChanBucket := tx.Bucket(openChannelBucket)
		if openChanBucket == nil {
			return ErrNoActiveChannels
		}

		// Next, fetch the bucket dedicated to storing meta-data
		// related to all nodes. All keys within this bucket are the
		// serialized public keys of all our direct counterparties.
		nodeMetaBucket := tx.Bucket(nodeInfoBucket)
		if nodeMetaBucket == nil {
			return fmt.Errorf("node bucket not created")
		}

		// Finally for each node public key in the bucket, fetch all
		// the channels related to this particualr ndoe.
		return nodeMetaBucket.ForEach(func(k, v []byte) error {
			nodeChanBucket := openChanBucket.Bucket(k)
			if nodeChanBucket == nil {
				return nil
			}

			nodeChannels, err := d.fetchNodeChannels(openChanBucket,
				nodeChanBucket)
			if err != nil {
				return err
			}

			channels = append(channels, nodeChannels...)
			return nil
		})
	})

	return channels, err
}
<commit_msg>channeldb: ensure the nodeInfoBucket is deleted within .Wipe()<commit_after>package channeldb

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"github.com/boltdb/bolt"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
	"github.com/roasbeef/btcd/wire"
)

const (
	dbName = "channel.db"
)

var (
	// Big endian is the preferred byte order, due to cursor scans over integer
	// keys iterating in order.
	byteOrder = binary.BigEndian
)

var bufPool = &sync.Pool{
	New: func() interface{} { return new(bytes.Buffer) },
}

// DB is the primary datastore for the LND daemon. The database stores
// information related to nodes, routing data, open/closed channels, fee
// schedules, and reputation data.
type DB struct {
	store *bolt.DB

	netParams *chaincfg.Params
}

// Open opens an existing channeldb created under the passed namespace with
// sensitive data encrypted by the passed EncryptorDecryptor implementation.
// TODO(roasbeef): versioning?
func Open(dbPath string, netParams *chaincfg.Params) (*DB, error) {
	path := filepath.Join(dbPath, dbName)

	if !fileExists(path) {
		if err := createChannelDB(dbPath); err != nil {
			return nil, err
		}
	}

	bdb, err := bolt.Open(path, 0600, nil)
	if err != nil {
		return nil, err
	}

	return &DB{store: bdb, netParams: netParams}, nil
}

// Wipe completely deletes all saved state within all used buckets within the
// database. The deletion is done in a single transaction, therefore this
// operation is fully atomic.
func (d *DB) Wipe() error {
	return d.store.Update(func(tx *bolt.Tx) error {
		err := tx.DeleteBucket(openChannelBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		err = tx.DeleteBucket(closedChannelBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		err = tx.DeleteBucket(invoiceBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		err = tx.DeleteBucket(nodeInfoBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		return nil
	})
}

// Close terminates the underlying database handle manually.
func (d *DB) Close() error {
	return d.store.Close()
}

// createChannelDB creates and initializes a fresh version of channeldb. In
// the case that the target path has not yet been created or doesn't yet exist,
// then the path is created. Additionally, all required top-level buckets used
// within the database are created.
func createChannelDB(dbPath string) error {
	if !fileExists(dbPath) {
		if err := os.MkdirAll(dbPath, 0700); err != nil {
			return err
		}
	}

	path := filepath.Join(dbPath, dbName)
	bdb, err := bolt.Open(path, 0600, nil)
	if err != nil {
		return err
	}

	err = bdb.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucket(openChannelBucket); err != nil {
			return err
		}

		if _, err := tx.CreateBucket(closedChannelBucket); err != nil {
			return err
		}

		if _, err := tx.CreateBucket(invoiceBucket); err != nil {
			return err
		}

		if _, err := tx.CreateBucket(nodeInfoBucket); err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return fmt.Errorf("unable to create new channeldb")
	}

	return bdb.Close()
}

// fileExists returns true if the file exists, and false otherwise.
func fileExists(path string) bool {
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}

	return true
}

// FetchOpenChannel returns all stored currently active/open channels
// associated with the target nodeID. In the case that no active channels are
// known to have been created with this node, then a zero-length slice is
// returned.
func (d *DB) FetchOpenChannels(nodeID *btcec.PublicKey) ([]*OpenChannel, error) {
	var channels []*OpenChannel
	err := d.store.View(func(tx *bolt.Tx) error {
		// Get the bucket dedicated to storing the meta-data for open
		// channels.
		openChanBucket := tx.Bucket(openChannelBucket)
		if openChanBucket == nil {
			return nil
		}

		// Within this top level bucket, fetch the bucket dedicated to storing
		// open channel data specific to the remote node.
		pub := nodeID.SerializeCompressed()
		nodeChanBucket := openChanBucket.Bucket(pub)
		if nodeChanBucket == nil {
			return nil
		}

		// Finally, we both of the necessary buckets retrieved, fetch
		// all the active channels related to this node.
		nodeChannels, err := d.fetchNodeChannels(openChanBucket,
			nodeChanBucket)
		if err != nil {
			return err
		}

		channels = nodeChannels
		return nil
	})

	return channels, err
}

// fetchNodeChannels retrieves all active channels from the target
// nodeChanBucket. This function is typically used to fetch all the active
// channels related to a particualr node.
func (d *DB) fetchNodeChannels(openChanBucket,
	nodeChanBucket *bolt.Bucket) ([]*OpenChannel, error) {

	var channels []*OpenChannel

	// Once we have the node's channel bucket, iterate through each
	// item in the inner chan ID bucket. This bucket acts as an
	// index for all channels we currently have open with this node.
	nodeChanIDBucket := nodeChanBucket.Bucket(chanIDBucket[:])
	if nodeChanIDBucket == nil {
		return nil, nil
	}
	err := nodeChanIDBucket.ForEach(func(k, v []byte) error {
		if k == nil {
			return nil
		}

		outBytes := bytes.NewReader(k)
		chanID := &wire.OutPoint{}
		if err := readOutpoint(outBytes, chanID); err != nil {
			return err
		}

		oChannel, err := fetchOpenChannel(openChanBucket,
			nodeChanBucket, chanID)
		if err != nil {
			return err
		}
		oChannel.Db = d

		channels = append(channels, oChannel)
		return nil
	})
	if err != nil {
		return nil, err
	}

	return channels, nil
}

// FetchAllChannels attempts to retrieve all open channels currently stored
// within the database. If no active channels exist within the network, then
// ErrNoActiveChannels is returned.
func (d *DB) FetchAllChannels() ([]*OpenChannel, error) {
	var channels []*OpenChannel

	err := d.store.View(func(tx *bolt.Tx) error {
		// Get the bucket dedicated to storing the meta-data for open
		// channels.
		openChanBucket := tx.Bucket(openChannelBucket)
		if openChanBucket == nil {
			return ErrNoActiveChannels
		}

		// Next, fetch the bucket dedicated to storing meta-data
		// related to all nodes. All keys within this bucket are the
		// serialized public keys of all our direct counterparties.
		nodeMetaBucket := tx.Bucket(nodeInfoBucket)
		if nodeMetaBucket == nil {
			return fmt.Errorf("node bucket not created")
		}

		// Finally for each node public key in the bucket, fetch all
		// the channels related to this particualr ndoe.
		return nodeMetaBucket.ForEach(func(k, v []byte) error {
			nodeChanBucket := openChanBucket.Bucket(k)
			if nodeChanBucket == nil {
				return nil
			}

			nodeChannels, err := d.fetchNodeChannels(openChanBucket,
				nodeChanBucket)
			if err != nil {
				return err
			}

			channels = append(channels, nodeChannels...)
			return nil
		})
	})

	return channels, err
}
<|endoftext|>


<commit_before>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package merge

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/open-policy-agent/opa/util"
)

func BenchmarkInterfaceMaps(b *testing.B) {

	for _, size := range []int{100, 1000, 10000} {

		b.Run(fmt.Sprintf("store size %v", size), func(b *testing.B) {
			aRaw := "{"
			for i := 0; i < size; i++ {
				if i != 0 {
					aRaw += ","
				}
				aRaw += fmt.Sprintf(`"%v":{"a":{"b":"c","d":"e"}}`, i)
			}
			aRaw += "}"

			aVals := map[string]interface{}{}
			if err := util.UnmarshalJSON([]byte(aRaw), &aVals); err != nil {
				panic(err)
			}
			for i := 0; i < b.N; i++ {
				bRaw := fmt.Sprintf(`{"a%v":{"b":"c","d":"e"}}`, i)
				bVals := map[string]interface{}{}
				if err := util.UnmarshalJSON([]byte(bRaw), &bVals); err != nil {
					panic(err)
				}

				b.StartTimer()
				_, ok := InterfaceMaps(aVals, bVals)
				b.StopTimer()

				if !ok {
					b.Fatal("merging interfaces failed")
				}
			}
		})

	}
}

func TestMergeDocs(t *testing.T) {

	tests := []struct {
		a  string
		b  string
		c  string
		ok bool
	}{
		{`{"x": 1, "y": 2}`, `{"z": 3}`, `{"x": 1, "y": 2, "z": 3}`, true},
		{`{"x": {"y": 2}}`, `{"z": 3, "x": {"q": 4}}`, `{"x": {"y": 2, "q": 4}, "z": 3}`, true},
		{`{"x": 1}`, `{"x": 1}`, "", false},
		{`{"x": {"y": [{"z": 2}]}}`, `{"x": {"y": [{"z": 3}]}}`, "", false},
	}

	for _, tc := range tests {
		a := map[string]interface{}{}
		if err := util.UnmarshalJSON([]byte(tc.a), &a); err != nil {
			panic(err)
		}
		aInitial := map[string]interface{}{}
		if err := util.UnmarshalJSON([]byte(tc.a), &aInitial); err != nil {
			panic(err)
		}

		b := map[string]interface{}{}
		if err := util.UnmarshalJSON([]byte(tc.b), &b); err != nil {
			panic(err)
		}

		if len(tc.c) == 0 {

			c, ok := InterfaceMaps(a, b)
			if ok {
				t.Errorf("Expected merge(%v,%v) == false but got: %v", a, b, c)
			}

			if !reflect.DeepEqual(a, aInitial) {
				t.Errorf("Expected conflicting merge to not mutate a (%v) but got a: %v", aInitial, a)
			}

		} else {

			expected := map[string]interface{}{}
			if err := util.UnmarshalJSON([]byte(tc.c), &expected); err != nil {
				panic(err)
			}

			c, ok := InterfaceMaps(a, b)
			if !ok || !reflect.DeepEqual(c, expected) {
				t.Errorf("Expected merge(%v, %v) == %v but got: %v (ok: %v)", a, b, expected, c, ok)
			}

			if reflect.DeepEqual(a, aInitial) || !reflect.DeepEqual(a, c) {
				t.Errorf("Expected merge to mutate a (%v) but got %v", aInitial, a)
			}

		}
	}
}
<commit_msg>internal/merge: remove InterfaceMaps benchmark (#3990)<commit_after>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package merge

import (
	"reflect"
	"testing"

	"github.com/open-policy-agent/opa/util"
)

func TestMergeDocs(t *testing.T) {

	tests := []struct {
		a  string
		b  string
		c  string
		ok bool
	}{
		{`{"x": 1, "y": 2}`, `{"z": 3}`, `{"x": 1, "y": 2, "z": 3}`, true},
		{`{"x": {"y": 2}}`, `{"z": 3, "x": {"q": 4}}`, `{"x": {"y": 2, "q": 4}, "z": 3}`, true},
		{`{"x": 1}`, `{"x": 1}`, "", false},
		{`{"x": {"y": [{"z": 2}]}}`, `{"x": {"y": [{"z": 3}]}}`, "", false},
	}

	for _, tc := range tests {
		a := map[string]interface{}{}
		if err := util.UnmarshalJSON([]byte(tc.a), &a); err != nil {
			panic(err)
		}
		aInitial := map[string]interface{}{}
		if err := util.UnmarshalJSON([]byte(tc.a), &aInitial); err != nil {
			panic(err)
		}

		b := map[string]interface{}{}
		if err := util.UnmarshalJSON([]byte(tc.b), &b); err != nil {
			panic(err)
		}

		if len(tc.c) == 0 {

			c, ok := InterfaceMaps(a, b)
			if ok {
				t.Errorf("Expected merge(%v,%v) == false but got: %v", a, b, c)
			}

			if !reflect.DeepEqual(a, aInitial) {
				t.Errorf("Expected conflicting merge to not mutate a (%v) but got a: %v", aInitial, a)
			}

		} else {

			expected := map[string]interface{}{}
			if err := util.UnmarshalJSON([]byte(tc.c), &expected); err != nil {
				panic(err)
			}

			c, ok := InterfaceMaps(a, b)
			if !ok || !reflect.DeepEqual(c, expected) {
				t.Errorf("Expected merge(%v, %v) == %v but got: %v (ok: %v)", a, b, expected, c, ok)
			}

			if reflect.DeepEqual(a, aInitial) || !reflect.DeepEqual(a, c) {
				t.Errorf("Expected merge to mutate a (%v) but got %v", aInitial, a)
			}

		}
	}
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"io/ioutil"
	"os/exec"
	"runtime"
	"text/template"

	"github.com/ninjasphere/go-ninja/config"
)

var src = `<?xml version="1.0" standalone="no"?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
	<name replace-wildcards="yes">{{.Serial}}</name>
	{{if .Paired}}
		{{if .Master}}
	<service>
		<type>_ninja-homecloud-rest._tcp</type>
		<port>{{.RestPort}}</port>
		<txt-record>ninja.sphere.user_id={{.User}}</txt-record>
		<txt-record>ninja.sphere.node_id={{.Serial}}</txt-record>
		<txt-record>ninja.sphere.site_id={{.Site}}</txt-record>
		<txt-record>ninja.sphere.site_updated={{.SiteUpdated}}</txt-record>
		<txt-record>ninja.sphere.master=true</txt-record>
	</service>
		{{end}}
	<service>
		<type>_ninja-homecloud-mqtt._tcp</type>
		<port>1883</port>
		<txt-record>ninja.sphere.user_id={{.User}}</txt-record>
		<txt-record>ninja.sphere.node_id={{.Serial}}</txt-record>
		<txt-record>ninja.sphere.master={{.Master}}</txt-record>
		<txt-record>ninja.sphere.master_node_id={{.MasterNode}}</txt-record>
		<txt-record>ninja.sphere.site_id={{.Site}}</txt-record>
		<txt-record>ninja.sphere.site_updated={{.SiteUpdated}}</txt-record>
	</service>
	{{else}}
	<service>
		<type>_ninja-setup-assistant-rest._tcp</type>
		<port>8888</port>
		<txt-record>ninja.sphere.node_id={{.Serial}}</txt-record>
	</service>
	{{end}}
</service-group>`

func UpdateSphereAvahiService(isPaired, isMaster bool) error {

	tmpl, err := template.New("avahi").Parse(src)

	if err != nil {
		return err
	}

	serviceDefinition := new(bytes.Buffer)

	err = tmpl.Execute(serviceDefinition, map[string]interface{}{
		"Serial":      config.Serial(),
		"Master":      isMaster,
		"Paired":      isPaired,
		"User":        config.String("", "userId"),
		"Site":        config.String("", "siteId"),
		"MasterNode":  config.String("", "masterNodeId"),
		"SiteUpdated": config.Int(0, "siteUpdated"),
		"RestPort":    config.MustInt("homecloud.rest.port"),
	})

	if err != nil {
		return err
	}

	log.Debugf("Saving service definition", serviceDefinition.String())

	if runtime.GOOS != "linux" {
		log.Warningf("Avahi service definition is not being saved, as platform != linux")
		return nil
	}

	err = ioutil.WriteFile("/data/etc/avahi/services/ninjasphere.service", []byte(serviceDefinition.String()), 0644)

	// HACK: Remove this if it doesn't fix Chris's problem
	exec.Command("service", "avahi-daemon", "restart").Output()

	return err
}
<commit_msg>Skip avahi when services directory doesn't exist<commit_after>package client

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"text/template"

	"github.com/ninjasphere/go-ninja/config"
)

var src = `<?xml version="1.0" standalone="no"?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
	<name replace-wildcards="yes">{{.Serial}}</name>
	{{if .Paired}}
		{{if .Master}}
	<service>
		<type>_ninja-homecloud-rest._tcp</type>
		<port>{{.RestPort}}</port>
		<txt-record>ninja.sphere.user_id={{.User}}</txt-record>
		<txt-record>ninja.sphere.node_id={{.Serial}}</txt-record>
		<txt-record>ninja.sphere.site_id={{.Site}}</txt-record>
		<txt-record>ninja.sphere.site_updated={{.SiteUpdated}}</txt-record>
		<txt-record>ninja.sphere.master=true</txt-record>
	</service>
		{{end}}
	<service>
		<type>_ninja-homecloud-mqtt._tcp</type>
		<port>1883</port>
		<txt-record>ninja.sphere.user_id={{.User}}</txt-record>
		<txt-record>ninja.sphere.node_id={{.Serial}}</txt-record>
		<txt-record>ninja.sphere.master={{.Master}}</txt-record>
		<txt-record>ninja.sphere.master_node_id={{.MasterNode}}</txt-record>
		<txt-record>ninja.sphere.site_id={{.Site}}</txt-record>
		<txt-record>ninja.sphere.site_updated={{.SiteUpdated}}</txt-record>
	</service>
	{{else}}
	<service>
		<type>_ninja-setup-assistant-rest._tcp</type>
		<port>8888</port>
		<txt-record>ninja.sphere.node_id={{.Serial}}</txt-record>
	</service>
	{{end}}
</service-group>`

func UpdateSphereAvahiService(isPaired, isMaster bool) error {

	tmpl, err := template.New("avahi").Parse(src)

	if err != nil {
		return err
	}

	serviceDefinition := new(bytes.Buffer)

	err = tmpl.Execute(serviceDefinition, map[string]interface{}{
		"Serial":      config.Serial(),
		"Master":      isMaster,
		"Paired":      isPaired,
		"User":        config.String("", "userId"),
		"Site":        config.String("", "siteId"),
		"MasterNode":  config.String("", "masterNodeId"),
		"SiteUpdated": config.Int(0, "siteUpdated"),
		"RestPort":    config.MustInt("homecloud.rest.port"),
	})

	if err != nil {
		return err
	}

	log.Debugf("Saving service definition", serviceDefinition.String())

	if runtime.GOOS != "linux" {
		log.Warningf("Avahi service definition is not being saved, as platform != linux")
		return nil
	}

	if _, err := os.Stat("/data/etc/avahi/services"); err != nil {
		log.Warningf("Avahi service definition is not being saved, as /data/etc/avahi/services does not exist")
		return nil
	}

	err = ioutil.WriteFile("/data/etc/avahi/services/ninjasphere.service", []byte(serviceDefinition.String()), 0644)

	// HACK: Remove this if it doesn't fix Chris's problem
	exec.Command("service", "avahi-daemon", "restart").Output()

	return err
}
<|endoftext|>