<commit_before>package main

import (
	"flag"
	"fmt"
	tc "github.com/ametheus/go-termcolours"
	"image"
	"image/color"
	_ "image/jpeg"
	_ "image/png"
	"log"
	"os"
)

var (
	image_file = flag.String("image_file", "", "The image file to display")
)

const BLOCK = "\xe2\x96\x80"

func init() {
	flag.Parse()
}

func main() {
	reader, err := os.Open(*image_file)
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()

	m, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}
	bounds := m.Bounds()

	fmt.Printf("Image is %s by %s pixels wide\n", tc.Green(fmt.Sprintf("%d", bounds.Max.X)), tc.Green(fmt.Sprintf("%d", bounds.Max.Y)))

	var c0, c1 color.Color
	for y := bounds.Min.Y; y < bounds.Max.Y; y += 2 {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			c0 = m.At(x, y)
			c1 = color.Black
			if (y + 1) < bounds.Max.Y {
				c1 = m.At(x, y+1)
			}

			fmt.Print(tc.Background24(c1, tc.Foreground24(c0, BLOCK)))
		}
		fmt.Print("\n")
	}
}
<commit_msg>Add 256-colour mode, with simple dithering<commit_after>package main

import (
	"flag"
	"fmt"
	tc "github.com/ametheus/go-termcolours"
	"image"
	"image/color"
	_ "image/jpeg"
	_ "image/png"
	"log"
	"os"
)

var (
	image_file = flag.String("image_file", "", "The image file to display")
	use_24bit  = flag.Bool("use_24bit", true, "Use 24-bit colours")
)

const BLOCK = "\xe2\x96\x80"

func init() {
	flag.Parse()
}

func main() {
	reader, err := os.Open(*image_file)
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()

	m, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}
	bounds := m.Bounds()

	fmt.Printf("Image is %s by %s pixels wide\n", tc.Green(fmt.Sprintf("%d", bounds.Max.X)), tc.Green(fmt.Sprintf("%d", bounds.Max.Y)))

	if *use_24bit {
		Write24(m, bounds)
	} else {
		Write8(m, bounds)
	}
}

func Write24(i image.Image, bounds image.Rectangle) {
	var c0, c1 color.Color
	for y := bounds.Min.Y; y < bounds.Max.Y; y += 2 {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			c0 = i.At(x, y)
			c1 = color.Black
			if (y + 1) < bounds.Max.Y {
				c1 = i.At(x, y+1)
			}

			fmt.Print(tc.Background24(c1, tc.Foreground24(c0, BLOCK)))
		}
		fmt.Print("\n")
	}
}

func cdiff(before color.Color, after tc.C256) (r, g, b int32) {
	r0, g0, b0, _ := before.RGBA()
	r1, g1, b1, _ := after.RGBA()

	r = int32(r1) - int32(r0)
	g = int32(g1) - int32(g0)
	b = int32(b1) - int32(b0)
	return
}

func pos(a, b int32) uint32 {
	a += b
	if a < 0 {
		return 0
	}
	return uint32(a)
}

func iadd(i image.Image, x, y int, dR, dG, dB int32, multiplier float64) {
	col := i.At(x, y)

	r, g, b, _ := col.RGBA()
	r = pos(int32(r), int32(float64(dR)*multiplier))
	g = pos(int32(g), int32(float64(dG)*multiplier))
	b = pos(int32(b), int32(float64(dB)*multiplier))

	cnew := color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0}
	i.(*image.RGBA).Set(x, y, cnew)
}

func iget(i image.Image, bounds image.Rectangle, x, y int) tc.C256 {
	col := i.At(x, y)
	aft := tc.Convert256(col)

	dr, dg, db := cdiff(col, aft)

	if (x + 1) < bounds.Max.X {
		iadd(i, x+1, y, dr, db, dg, 7.0/16.0)
		if (y + 1) < bounds.Max.Y {
			iadd(i, x+1, y+1, dr, db, dg, 1.0/16.0)
		}
	}
	if (y + 1) < bounds.Max.Y {
		iadd(i, x, y+1, dr, db, dg, 5.0/16.0)
		if (x - 1) >= bounds.Min.X {
			iadd(i, x-1, y+1, dr, db, dg, 3.0/16.0)
		}
	}

	return aft
}

func Write8(i image.Image, bounds image.Rectangle) {
	var c0, c1 tc.C256
	for y := bounds.Min.Y; y < bounds.Max.Y; y += 2 {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			c0 = iget(i, bounds, x, y)
			c1 = 232
			if (y + 1) < bounds.Max.Y {
				c1 = iget(i, bounds, x, y+1)
			}

			fmt.Print(tc.Background8(c1, tc.Foreground24(c0, BLOCK)))
		}
		fmt.Print("\n")
	}
}
<|endoftext|>


<commit_before>package controller

import (
	"testing"
	"github.com/mageddo/go-logging"
	"bk-api/test"
	"bk-api/service"
	"bk-api/entity"
	"github.com/stretchr/testify/assert"
)

func TestGetV1_0ListBookmarksNoOffsetError(t *testing.T){

	test.BuildDatabase()

	nowOffsetMsg := `{"code":400,"message":"Please pass a valid offset and quantity"}
`
	resp, c, err := test.NewReq("GET", BOOKMARK_V1)

	assert.Nil(t, err)
	assert.Equal(t, 400, c)

	assert.Equal(t, nowOffsetMsg, resp)

}

func TestGetV1_0ListBookmarks(t *testing.T){

	ctx := logging.NewContext()
	test.BuildDatabase()

	expectedBookmarks := "[{\"id\":1,\"name\":\"X\",\"visibility\":1,\"html\":\"\",\"length\":3}]"

	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X2", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X3", entity.PRIVATE))

	resp, c, err := test.NewReq("GET", BOOKMARK_V1 + "?from=0&quantity=1")

	assert.Nil(t, err)
	assert.Equal(t, 200, c)

	resp = regex.ReplaceAllString(resp, "")

	assert.Equal(t, len(expectedBookmarks), len(resp))
	assert.Equal(t, expectedBookmarks, resp)

}

func TestGetV1_0ListBookmarksValidateFromSuccess(t *testing.T){

	ctx := logging.NewContext()
	test.BuildDatabase()

	expectedBookmarks := "[{\"id\":2,\"name\":\"X2\",\"visibility\":1,\"html\":\"\",\"length\":3},{\"id\":3,\"name\":\"X3\",\"visibility\":0,\"html\":\"\",\"length\":3}]"

	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X2", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X3", entity.PRIVATE))

	resp, c, err := test.NewReq("GET", BOOKMARK_V1 + "?from=1&quantity=2")

	assert.Nil(t, err)
	assert.Equal(t, 200, c)

	resp = regex.ReplaceAllString(resp, "")

	assert.Equal(t, len(expectedBookmarks), len(resp))
	assert.Equal(t, expectedBookmarks, resp)

}

<commit_msg>MG-402 creating search test<commit_after>package controller

import (
	"testing"
	"github.com/mageddo/go-logging"
	"bk-api/test"
	"bk-api/service"
	"bk-api/entity"
	"github.com/stretchr/testify/assert"
)

func TestGetV1_0ListBookmarksNoOffsetError(t *testing.T){

	test.BuildDatabase()

	nowOffsetMsg := `{"code":400,"message":"Please pass a valid offset and quantity"}
`
	resp, c, err := test.NewReq("GET", BOOKMARK_V1)

	assert.Nil(t, err)
	assert.Equal(t, 400, c)

	assert.Equal(t, nowOffsetMsg, resp)

}

func TestGetV1_0ListBookmarks(t *testing.T){

	ctx := logging.NewContext()
	test.BuildDatabase()

	expectedBookmarks := "[{\"id\":1,\"name\":\"X\",\"visibility\":1,\"html\":\"\",\"length\":3}]"

	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X2", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X3", entity.PRIVATE))

	resp, c, err := test.NewReq("GET", BOOKMARK_V1 + "?from=0&quantity=1")

	assert.Nil(t, err)
	assert.Equal(t, 200, c)

	resp = regex.ReplaceAllString(resp, "")

	assert.Equal(t, len(expectedBookmarks), len(resp))
	assert.Equal(t, expectedBookmarks, resp)

}

func TestGetV1_0ListBookmarksValidateFromSuccess(t *testing.T){

	ctx := logging.NewContext()
	test.BuildDatabase()

	expectedBookmarks := "[{\"id\":2,\"name\":\"X2\",\"visibility\":1,\"html\":\"\",\"length\":3},{\"id\":3,\"name\":\"X3\",\"visibility\":0,\"html\":\"\",\"length\":3}]"

	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X2", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("X3", entity.PRIVATE))

	resp, c, err := test.NewReq("GET", BOOKMARK_V1 + "?from=1&quantity=2")

	assert.Nil(t, err)
	assert.Equal(t, 200, c)

	resp = regex.ReplaceAllString(resp, "")

	assert.Equal(t, len(expectedBookmarks), len(resp))
	assert.Equal(t, expectedBookmarks, resp)

}

func TestGetV1_0ListBookmarksSearchSuccess(t *testing.T){

	ctx := logging.NewContext()
	test.BuildDatabase()

	expectedBookmarks := `[{"id":2,"name":"Android 7.0 was released","html":"","length":2},{"id":3,"name":"Separate your software release by major, minor and patch","html":"","length":2}]`

	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("Google is the most popular search engine site", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("Android 7.0 was released", entity.PUBLIC))
	service.NewBookmarkService(ctx).SaveBookmark(entity.NewBookmarkWithNameAndVisibility("Separate your software release by major, minor and patch", entity.PRIVATE))

	resp, c, err := test.NewReq("GET", BOOKMARK_V1 + "?from=0&quantity=3&query=release")

	assert.Nil(t, err)
	assert.Equal(t, 200, c)

	resp = regex.ReplaceAllString(resp, "")

	assert.Equal(t, len(expectedBookmarks), len(resp))
	assert.Equal(t, expectedBookmarks, resp)

}

<|endoftext|>


<commit_before>package pipelines_test

import (
	"github.com/concourse/testflight/gitserver"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Configuring a resource in a pipeline config", func() {
	var gitServer *gitserver.Server

	BeforeEach(func() {
		gitServer = gitserver.Start(client)

		configurePipeline(
			"-c", "fixtures/config_params.yml",
			"-v", "git-server="+gitServer.URI(),
		)

		taskFileContents := `---
platform: linux
image_resource:
  type: docker-image
  source: {repository: busybox}
run:
  path: sh
  args: ["-c", "printenv SOURCE_PARAM"]
params:
  SOURCE_PARAM: file_source
`
		gitServer.WriteFile("some-repo/task.yml", taskFileContents)
		gitServer.CommitResourceWithFile("task.yml")
	})

	AfterEach(func() {
		gitServer.Stop()
	})

	Context("when specifying file in task config", func() {
		It("executes the file with params specified in file", func() {
			watch := flyWatch("file-test")
			Expect(watch).To(gbytes.Say("file_source"))
		})

		It("executes the file with params from config", func() {
			watch := flyWatch("file-config-params-test")
			Expect(watch).To(gbytes.Say("config_params_source"))
		})

		It("executes the file with job params", func() {
			watch := flyWatch("file-params-test")
			Expect(watch).To(gbytes.Say("job_params_source"))
		})

		It("executes the file with job params, overlaying the config params", func() {
			watch := flyWatch("everything-params-test")
			Expect(watch).To(gbytes.Say("job_params_source"))
		})
	})
})
<commit_msg>attempt some other syntax<commit_after>package pipelines_test

import (
	"github.com/concourse/testflight/gitserver"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Configuring a resource in a pipeline config", func() {
	var gitServer *gitserver.Server

	BeforeEach(func() {
		gitServer = gitserver.Start(client)

		configurePipeline(
			"-c", "fixtures/config_params.yml",
			"-v", "git-server="+gitServer.URI(),
		)

		taskFileContents := `---
platform: linux
image_resource:
  type: docker-image
  source: {repository: busybox}
run:
  path: sh
  args: ["-ec", "echo -n 'SOURCE_PARAM is '; printenv SOURCE_PARAM; echo ."]
params:
  SOURCE_PARAM: file_source
`
		gitServer.WriteFile("some-repo/task.yml", taskFileContents)
		gitServer.CommitResourceWithFile("task.yml")
	})

	AfterEach(func() {
		gitServer.Stop()
	})

	Context("when specifying file in task config", func() {
		It("executes the file with params specified in file", func() {
			watch := flyWatch("file-test")
			Expect(watch).To(gbytes.Say("file_source"))
		})

		It("executes the file with params from config", func() {
			watch := flyWatch("file-config-params-test")
			Expect(watch).To(gbytes.Say("config_params_source"))
		})

		It("executes the file with job params", func() {
			watch := flyWatch("file-params-test")
			Expect(watch).To(gbytes.Say("job_params_source"))
		})

		It("executes the file with job params, overlaying the config params", func() {
			watch := flyWatch("everything-params-test")
			Expect(watch).To(gbytes.Say("job_params_source"))
		})
	})
})
<|endoftext|>


<commit_before>package api

import (
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/stretchr/testify/assert"
)

func TestNewFileSystemRepository(t *testing.T) {
	wd, err := os.Getwd()
	assert.NoError(t, err)
	assert.Contains(t, wd, "github.com/hellofresh/janus")

	// .../github.com/hellofresh/janus/pkg/api/../../examples/apis
	exampleAPIsPath := filepath.Join(wd, "..", "..", "examples", "apis")
	info, err := os.Stat(exampleAPIsPath)
	assert.NoError(t, err)
	assert.True(t, info.IsDir())

	fsRepo, err := NewFileSystemRepository(exampleAPIsPath)
	assert.NoError(t, err)

	allDefinitions, err := fsRepo.FindAll()
	assert.NoError(t, err)
	assert.Equal(t, 2, len(allDefinitions))

	healthDefinitions, err := fsRepo.FindValidAPIHealthChecks()
	assert.NoError(t, err)
	assert.Equal(t, 1, len(healthDefinitions))
	assert.Equal(t, "example", healthDefinitions[0].Name)
	assert.Equal(t, "/example/*", healthDefinitions[0].Proxy.ListenPath)
	assert.Equal(t, "https://example.com/status", healthDefinitions[0].HealthCheck.URL)

	assertFindByName(t, fsRepo)
	assertFindByFindByListenPath(t, fsRepo)
	assertExists(t, fsRepo)

	defToAdd := &Definition{Name: "foo-bar", Proxy: &proxy.Definition{ListenPath: "/foo/bar/*"}}
	err = fsRepo.Add(defToAdd)
	assert.NoError(t, err)

	def, err := fsRepo.FindByName(defToAdd.Name)
	assert.NoError(t, err)
	assert.Equal(t, defToAdd.Name, def.Name)
	assert.Equal(t, defToAdd.Proxy.ListenPath, def.Proxy.ListenPath)

	def, err = fsRepo.FindByListenPath(defToAdd.Proxy.ListenPath)
	assert.NoError(t, err)
	assert.Equal(t, defToAdd.Name, def.Name)
	assert.Equal(t, defToAdd.Proxy.ListenPath, def.Proxy.ListenPath)

	exists, err := fsRepo.Exists(&Definition{Name: defToAdd.Name})
	assert.True(t, exists)
	assert.Equal(t, ErrAPINameExists, err)

	exists, err = fsRepo.Exists(&Definition{
		Name:  time.Now().Format(time.RFC3339Nano),
		Proxy: &proxy.Definition{ListenPath: defToAdd.Proxy.ListenPath},
	})
	assert.True(t, exists)
	assert.Equal(t, ErrAPIListenPathExists, err)

	err = fsRepo.Remove(defToAdd.Name)
	assert.NoError(t, err)

	err = fsRepo.Remove(defToAdd.Name)
	assert.Equal(t, ErrAPIDefinitionNotFound, err)

	_, err = fsRepo.FindByName(defToAdd.Name)
	assert.Equal(t, ErrAPIDefinitionNotFound, err)

	_, err = fsRepo.FindByListenPath(defToAdd.Proxy.ListenPath)
	assert.Equal(t, ErrAPIDefinitionNotFound, err)

	exists, err = fsRepo.Exists(defToAdd)
	assert.False(t, exists)
	assert.NoError(t, err)
}

func assertFindByName(t *testing.T, fsRepo *FileSystemRepository) {
	def, err := fsRepo.FindByName("example")
	assert.NoError(t, err)
	assert.Equal(t, "example", def.Name)
	assert.Equal(t, "/example/*", def.Proxy.ListenPath)

	def, err = fsRepo.FindByName("posts")
	assert.NoError(t, err)
	assert.Equal(t, "posts", def.Name)
	assert.Equal(t, "/posts/*", def.Proxy.ListenPath)

	_, err = fsRepo.FindByName("foo")
	assert.Equal(t, ErrAPIDefinitionNotFound, err)
}

func assertFindByFindByListenPath(t *testing.T, fsRepo *FileSystemRepository) {
	def, err := fsRepo.FindByListenPath("/example/*")
	assert.NoError(t, err)
	assert.Equal(t, "example", def.Name)
	assert.Equal(t, "/example/*", def.Proxy.ListenPath)

	def, err = fsRepo.FindByListenPath("/posts/*")
	assert.NoError(t, err)
	assert.Equal(t, "posts", def.Name)
	assert.Equal(t, "/posts/*", def.Proxy.ListenPath)

	_, err = fsRepo.FindByListenPath("/foo/*")
	assert.Equal(t, ErrAPIDefinitionNotFound, err)
}

func assertExists(t *testing.T, fsRepo *FileSystemRepository) {
	exists, err := fsRepo.Exists(&Definition{Name: "example"})
	assert.True(t, exists)
	assert.Equal(t, ErrAPINameExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "posts"})
	assert.True(t, exists)
	assert.Equal(t, ErrAPINameExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "example1", Proxy: &proxy.Definition{ListenPath: "/example/*"}})
	assert.True(t, exists)
	assert.Equal(t, ErrAPIListenPathExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "posts1", Proxy: &proxy.Definition{ListenPath: "/posts/*"}})
	assert.True(t, exists)
	assert.Equal(t, ErrAPIListenPathExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "example1", Proxy: &proxy.Definition{ListenPath: "/example1/*"}})
	assert.False(t, exists)
	assert.NoError(t, err)

	exists, err = fsRepo.Exists(&Definition{Name: "posts1", Proxy: &proxy.Definition{ListenPath: "/posts1/*"}})
	assert.False(t, exists)
	assert.NoError(t, err)
}
<commit_msg>Added definition validation test<commit_after>package api

import (
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/stretchr/testify/assert"
)

func newRepo(t *testing.T) *FileSystemRepository {
	wd, err := os.Getwd()
	assert.NoError(t, err)
	assert.Contains(t, wd, "github.com/hellofresh/janus")

	// .../github.com/hellofresh/janus/pkg/api/../../examples/apis
	exampleAPIsPath := filepath.Join(wd, "..", "..", "examples", "apis")
	info, err := os.Stat(exampleAPIsPath)
	assert.NoError(t, err)
	assert.True(t, info.IsDir())

	fsRepo, err := NewFileSystemRepository(exampleAPIsPath)
	assert.NoError(t, err)

	return fsRepo
}

func TestNewFileSystemRepository(t *testing.T) {
	fsRepo := newRepo(t)

	allDefinitions, err := fsRepo.FindAll()
	assert.NoError(t, err)
	assert.Equal(t, 2, len(allDefinitions))

	healthDefinitions, err := fsRepo.FindValidAPIHealthChecks()
	assert.NoError(t, err)
	assert.Equal(t, 1, len(healthDefinitions))
	assert.Equal(t, "example", healthDefinitions[0].Name)
	assert.Equal(t, "/example/*", healthDefinitions[0].Proxy.ListenPath)
	assert.Equal(t, "https://example.com/status", healthDefinitions[0].HealthCheck.URL)

	assertFindByName(t, fsRepo)
	assertFindByFindByListenPath(t, fsRepo)
	assertExists(t, fsRepo)

	defToAdd := &Definition{Name: "foo-bar", Proxy: &proxy.Definition{ListenPath: "/foo/bar/*"}}
	err = fsRepo.Add(defToAdd)
	assert.NoError(t, err)

	def, err := fsRepo.FindByName(defToAdd.Name)
	assert.NoError(t, err)
	assert.Equal(t, defToAdd.Name, def.Name)
	assert.Equal(t, defToAdd.Proxy.ListenPath, def.Proxy.ListenPath)

	def, err = fsRepo.FindByListenPath(defToAdd.Proxy.ListenPath)
	assert.NoError(t, err)
	assert.Equal(t, defToAdd.Name, def.Name)
	assert.Equal(t, defToAdd.Proxy.ListenPath, def.Proxy.ListenPath)

	exists, err := fsRepo.Exists(&Definition{Name: defToAdd.Name})
	assert.True(t, exists)
	assert.Equal(t, ErrAPINameExists, err)

	exists, err = fsRepo.Exists(&Definition{
		Name:  time.Now().Format(time.RFC3339Nano),
		Proxy: &proxy.Definition{ListenPath: defToAdd.Proxy.ListenPath},
	})
	assert.True(t, exists)
	assert.Equal(t, ErrAPIListenPathExists, err)

	err = fsRepo.Remove(defToAdd.Name)
	assert.NoError(t, err)

	err = fsRepo.Remove(defToAdd.Name)
	assert.Equal(t, ErrAPIDefinitionNotFound, err)

	_, err = fsRepo.FindByName(defToAdd.Name)
	assert.Equal(t, ErrAPIDefinitionNotFound, err)

	_, err = fsRepo.FindByListenPath(defToAdd.Proxy.ListenPath)
	assert.Equal(t, ErrAPIDefinitionNotFound, err)

	exists, err = fsRepo.Exists(defToAdd)
	assert.False(t, exists)
	assert.NoError(t, err)
}

func assertFindByName(t *testing.T, fsRepo *FileSystemRepository) {
	def, err := fsRepo.FindByName("example")
	assert.NoError(t, err)
	assert.Equal(t, "example", def.Name)
	assert.Equal(t, "/example/*", def.Proxy.ListenPath)

	def, err = fsRepo.FindByName("posts")
	assert.NoError(t, err)
	assert.Equal(t, "posts", def.Name)
	assert.Equal(t, "/posts/*", def.Proxy.ListenPath)

	_, err = fsRepo.FindByName("foo")
	assert.Equal(t, ErrAPIDefinitionNotFound, err)
}

func assertFindByFindByListenPath(t *testing.T, fsRepo *FileSystemRepository) {
	def, err := fsRepo.FindByListenPath("/example/*")
	assert.NoError(t, err)
	assert.Equal(t, "example", def.Name)
	assert.Equal(t, "/example/*", def.Proxy.ListenPath)

	def, err = fsRepo.FindByListenPath("/posts/*")
	assert.NoError(t, err)
	assert.Equal(t, "posts", def.Name)
	assert.Equal(t, "/posts/*", def.Proxy.ListenPath)

	_, err = fsRepo.FindByListenPath("/foo/*")
	assert.Equal(t, ErrAPIDefinitionNotFound, err)
}

func assertExists(t *testing.T, fsRepo *FileSystemRepository) {
	exists, err := fsRepo.Exists(&Definition{Name: "example"})
	assert.True(t, exists)
	assert.Equal(t, ErrAPINameExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "posts"})
	assert.True(t, exists)
	assert.Equal(t, ErrAPINameExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "example1", Proxy: &proxy.Definition{ListenPath: "/example/*"}})
	assert.True(t, exists)
	assert.Equal(t, ErrAPIListenPathExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "posts1", Proxy: &proxy.Definition{ListenPath: "/posts/*"}})
	assert.True(t, exists)
	assert.Equal(t, ErrAPIListenPathExists, err)

	exists, err = fsRepo.Exists(&Definition{Name: "example1", Proxy: &proxy.Definition{ListenPath: "/example1/*"}})
	assert.False(t, exists)
	assert.NoError(t, err)

	exists, err = fsRepo.Exists(&Definition{Name: "posts1", Proxy: &proxy.Definition{ListenPath: "/posts1/*"}})
	assert.False(t, exists)
	assert.NoError(t, err)
}

func TestFileSystemRepository_Add(t *testing.T) {
	fsRepo := newRepo(t)

	invalidName := &Definition{Name: ""}
	err := fsRepo.Add(invalidName)
	assert.Error(t, err)
}
<|endoftext|>


<commit_before>package connector

import (
	"context"
	"net"
	"os"
	"time"

	"github.com/datawire/ambassador/pkg/metriton"
	"github.com/datawire/dlib/dgroup"
	"github.com/datawire/dlib/dlog"
	"github.com/datawire/dlib/dutil"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"golang.org/x/crypto/ssh/terminal"
	"google.golang.org/grpc"

	"github.com/datawire/telepresence2/pkg/client"
	manager "github.com/datawire/telepresence2/pkg/rpc"
	rpc "github.com/datawire/telepresence2/pkg/rpc/connector"
	"github.com/datawire/telepresence2/pkg/rpc/daemon"
	"github.com/datawire/telepresence2/pkg/rpc/version"
)

var help = `The Telepresence Connect is a background component that manages a connection. It
requires that a daemon is already running.

Launch the Telepresence Connector:
    telepresence connect

The Connector uses the Daemon's log so its output can be found in
    ` + client.Logfile + `
to troubleshoot problems.
`

// service represents the state of the Telepresence Connector
type service struct {
	rpc.UnimplementedConnectorServer
	daemon       daemon.DaemonClient
	daemonLogger daemonLogger
	cluster      *k8sCluster
	bridge       *bridge
	trafficMgr   *trafficManager
	grpc         *grpc.Server
	ctx          context.Context
	cancel       func()
}

// Command returns the CLI sub-command for "connector-foreground"
func Command() *cobra.Command {
	var init bool
	c := &cobra.Command{
		Use:    "connector-foreground",
		Short:  "Launch Telepresence Connector in the foreground (debug)",
		Args:   cobra.ExactArgs(0),
		Hidden: true,
		Long:   help,
		RunE: func(_ *cobra.Command, args []string) error {
			return run(init)
		},
	}
	flags := c.Flags()
	flags.BoolVar(&init, "init", false, "initialize running connector (for debugging)")
	return c
}

type callCtx struct {
	context.Context
	caller context.Context
}

func (c callCtx) Deadline() (deadline time.Time, ok bool) {
	if dl, ok := c.Context.Deadline(); ok {
		return dl, true
	}
	return c.caller.Deadline()
}

func (c callCtx) Done() <-chan struct{} {
	ch := make(chan struct{})
	go func() {
		select {
		case <-c.Context.Done():
			close(ch)
		case <-c.caller.Done():
			close(ch)
		}
	}()
	return ch
}

func (c callCtx) Err() error {
	err := c.Context.Err()
	if err == nil {
		err = c.caller.Err()
	}
	return err
}

func (c callCtx) Value(key interface{}) interface{} {
	return c.Context.Value(key)
}

func (s *service) callGroup(c context.Context) *dgroup.Group {
	return dgroup.NewGroup(&callCtx{Context: s.ctx, caller: c}, dgroup.GroupConfig{})
}

func callRecovery(c context.Context, r interface{}, err error) error {
	perr := dutil.PanicToError(r)
	if perr != nil {
		if err == nil {
			err = perr
		} else {
			dlog.Errorf(c, "%+v", perr)
		}
	}
	if err != nil {
		dlog.Errorf(c, "%+v", err)
	}
	return err
}

func (s *service) Version(_ context.Context, _ *empty.Empty) (*version.VersionInfo, error) {
	return &version.VersionInfo{
		ApiVersion: client.APIVersion,
		Version:    client.Version(),
	}, nil
}

func (s *service) Status(c context.Context, _ *empty.Empty) (result *rpc.ConnectorStatus, err error) {
	g := s.callGroup(c)
	g.Go("Status", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		result = s.status(c)
		return
	})
	err = g.Wait()
	return
}

func (s *service) Connect(c context.Context, cr *rpc.ConnectRequest) (ci *rpc.ConnectInfo, err error) {
	g := s.callGroup(c)
	g.Go("Connect", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		ci = s.connect(c, cr)
		return
	})
	err = g.Wait()
	return
}

func (s *service) CreateIntercept(c context.Context, ir *manager.CreateInterceptRequest) (result *rpc.InterceptResult, err error) {
	ie, is := s.interceptStatus()
	if ie != rpc.InterceptError_UNSPECIFIED {
		return &rpc.InterceptResult{Error: ie, ErrorText: is}, nil
	}
	g := s.callGroup(c)
	g.Go("CreateIntercept", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		result, err = s.trafficMgr.addIntercept(c, s.ctx, ir)
		return
	})
	err = g.Wait()
	return
}

func (s *service) RemoveIntercept(c context.Context, rr *manager.RemoveInterceptRequest2) (result *rpc.InterceptResult, err error) {
	ie, is := s.interceptStatus()
	if ie != rpc.InterceptError_UNSPECIFIED {
		return &rpc.InterceptResult{Error: ie, ErrorText: is}, nil
	}
	g := s.callGroup(c)
	g.Go("RemoveIntercept", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		err = s.trafficMgr.removeIntercept(c, rr.Name)
		return
	})
	err = g.Wait()
	return &rpc.InterceptResult{}, err
}

func (s *service) AvailableIntercepts(_ context.Context, _ *empty.Empty) (*manager.AgentInfoSnapshot, error) {
	if s.trafficMgr.grpc == nil {
		return &manager.AgentInfoSnapshot{}, nil
	}
	return s.trafficMgr.agentInfoSnapshot(), nil
}

func (s *service) ListIntercepts(_ context.Context, _ *empty.Empty) (*manager.InterceptInfoSnapshot, error) {
	if s.trafficMgr.grpc == nil {
		return &manager.InterceptInfoSnapshot{}, nil
	}
	return s.trafficMgr.interceptInfoSnapshot(), nil
}

func (s *service) Quit(_ context.Context, _ *empty.Empty) (*empty.Empty, error) {
	s.cancel()
	return &empty.Empty{}, nil
}

// daemonLogger is an io.Writer implementation that sends data to the daemon logger
type daemonLogger struct {
	stream daemon.Daemon_LoggerClient
}

func (d *daemonLogger) Write(data []byte) (n int, err error) {
	err = d.stream.Send(&daemon.LogMessage{Text: data})
	return len(data), err
}

// connect the connector to a cluster
func (s *service) connect(c context.Context, cr *rpc.ConnectRequest) *rpc.ConnectInfo {
	reporter := &metriton.Reporter{
		Application:  "telepresence2",
		Version:      client.Version(),
		GetInstallID: func(_ *metriton.Reporter) (string, error) { return cr.InstallId, nil },
		BaseMetadata: map[string]interface{}{"mode": "daemon"},
	}

	if _, err := reporter.Report(c, map[string]interface{}{"action": "connect"}); err != nil {
		dlog.Errorf(c, "report failed: %+v", err)
	}

	// Sanity checks
	r := &rpc.ConnectInfo{}
	if s.cluster != nil {
		r.ClusterContext = s.cluster.Context
		r.ClusterServer = s.cluster.server()
		r.Error = rpc.ConnectInfo_ALREADY_CONNECTED
		return r
	}
	if s.bridge != nil {
		r.Error = rpc.ConnectInfo_DISCONNECTING
		return r
	}

	dlog.Info(c, "Connecting to traffic manager...")
	cluster, err := trackKCluster(s.ctx, cr.Context, cr.Namespace, cr.Args)
	if err != nil {
		dlog.Errorf(c, "unable to track k8s cluster: %+v", err)
		r.Error = rpc.ConnectInfo_CLUSTER_FAILED
		r.ErrorText = err.Error()
		s.cancel()
		return r
	}
	s.cluster = cluster

	/*
		previewHost, err := cluster.getClusterPreviewHostname(p)
		if err != nil {
			p.Logf("get preview URL hostname: %+v", err)
			previewHost = ""
		}
	*/

	dlog.Infof(c, "Connected to context %s (%s)", s.cluster.Context, s.cluster.server())

	r.ClusterContext = s.cluster.Context
	r.ClusterServer = s.cluster.server()

	tmgr, err := newTrafficManager(s.ctx, s.cluster, cr.InstallId, cr.IsCi)
	if err != nil {
		dlog.Errorf(c, "Unable to connect to TrafficManager: %s", err)
		r.Error = rpc.ConnectInfo_TRAFFIC_MANAGER_FAILED
		r.ErrorText = err.Error()
		if cr.InterceptEnabled {
			// No point in continuing without a traffic manager
			s.cancel()
		}
		return r
	}

	// tmgr.previewHost = previewHost
	s.trafficMgr = tmgr
	dlog.Infof(c, "Starting traffic-manager bridge in context %s, namespace %s", cluster.Context, cluster.Namespace)
	br := newBridge(cluster, s.daemon, tmgr.sshPort)
	err = br.start(s.ctx)
	if err != nil {
		dlog.Errorf(c, "Failed to start traffic-manager bridge: %s", err.Error())
		r.Error = rpc.ConnectInfo_BRIDGE_FAILED
		r.ErrorText = err.Error()
		// No point in continuing without a bridge
		s.cancel()
		return r
	}
	s.bridge = br

	if !cr.InterceptEnabled {
		return r
	}

	// Wait for traffic manager to connect
	dlog.Info(c, "Waiting for TrafficManager to connect")
	if err := tmgr.waitUntilStarted(); err != nil {
		dlog.Errorf(c, "Failed to start traffic-manager: %s", err.Error())
		r.Error = rpc.ConnectInfo_TRAFFIC_MANAGER_FAILED
		r.ErrorText = err.Error()
		// No point in continuing without a traffic manager
		s.cancel()
	}
	return r
}

// setUpLogging connects to the daemon logger
func (s *service) setUpLogging(c context.Context) (context.Context, error) {
	var err error
	s.daemonLogger.stream, err = s.daemon.Logger(c)
	if err != nil {
		return nil, err
	}

	logger := logrus.StandardLogger()
	logger.Out = &s.daemonLogger
	loggingToTerminal := terminal.IsTerminal(int(os.Stdout.Fd()))
	if loggingToTerminal {
		logger.Formatter = client.NewFormatter("15:04:05")
	} else {
		logger.Formatter = client.NewFormatter("2006/01/02 15:04:05")
	}
	logger.Level = logrus.DebugLevel
	return dlog.WithLogger(c, dlog.WrapLogrus(logger)), nil
}

// run is the main function when executing as the connector
func run(init bool) error {
	// establish a connection to the daemon gRPC service
	conn, err := client.DialSocket(client.DaemonSocketName)
	if err != nil {
		return err
	}
	defer conn.Close()
	s := &service{daemon: daemon.NewDaemonClient(conn), grpc: grpc.NewServer()}
	rpc.RegisterConnectorServer(s.grpc, s)

	c, err := s.setUpLogging(context.Background())
	if err != nil {
		return err
	}

	c = dgroup.WithGoroutineName(c, "connector")

	var cancel context.CancelFunc
	c, cancel = context.WithCancel(c)
	s.cancel = func() {
		dlog.Debug(s.ctx, "cancelling connector context")
		cancel()
	}

	g := dgroup.NewGroup(c, dgroup.GroupConfig{
		SoftShutdownTimeout:  2 * time.Second,
		EnableSignalHandling: true})

	dlog.Info(c, "---")
	dlog.Infof(c, "Telepresence Connector %s starting...", client.DisplayVersion())
	dlog.Infof(c, "PID is %d", os.Getpid())
	dlog.Info(c, "")

	svcStarted := make(chan bool)
	if init {
		g.Go("debug-init", func(c context.Context) error {
			<-svcStarted
			_, _ = s.Connect(c, &rpc.ConnectRequest{InstallId: "dummy-id"})
			return nil
		})
	}

	g.Go("service", func(c context.Context) (err error) {
		var listener net.Listener
		defer func() {
			if perr := dutil.PanicToError(recover()); perr != nil {
				if err == nil {
					err = perr
				}
				if listener != nil {
					_ = listener.Close()
				}
				_ = os.Remove(client.ConnectorSocketName)
			}
			if err != nil {
				dlog.Errorf(c, "Server ended with: %s", err.Error())
			} else {
				dlog.Debug(c, "Server ended")
			}
		}()

		// Listen on unix domain socket
		dlog.Debug(c, "Server starting")
		s.ctx = c
		listener, err = net.Listen("unix", client.ConnectorSocketName)
		if err != nil {
			return err
		}
		close(svcStarted)
		return s.grpc.Serve(listener)
	})

	g.Go("teardown", s.handleShutdown)

	err = g.Wait()
	if err != nil {
		dlog.Error(c, err.Error())
	}
	return err
}

// handleShutdown ensures that the connector quits gracefully when receiving a signal
// or when the context is cancelled.
func (s *service) handleShutdown(c context.Context) error {
	defer s.grpc.GracefulStop()

	<-c.Done()
	dlog.Info(c, "Shutting down")

	cluster := s.cluster
	if cluster == nil {
		return nil
	}
	s.cluster = nil
	trafficMgr := s.trafficMgr

	s.trafficMgr = nil
	if trafficMgr != nil {
		_ = trafficMgr.clearIntercepts(context.Background())
		_ = trafficMgr.Close()
	}
	s.bridge = nil
	return nil
}
<commit_msg>Do not wait for meriton.Reporter to report<commit_after>package connector

import (
	"context"
	"net"
	"os"
	"time"

	"github.com/datawire/ambassador/pkg/metriton"
	"github.com/datawire/dlib/dgroup"
	"github.com/datawire/dlib/dlog"
	"github.com/datawire/dlib/dutil"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"golang.org/x/crypto/ssh/terminal"
	"google.golang.org/grpc"

	"github.com/datawire/telepresence2/pkg/client"
	manager "github.com/datawire/telepresence2/pkg/rpc"
	rpc "github.com/datawire/telepresence2/pkg/rpc/connector"
	"github.com/datawire/telepresence2/pkg/rpc/daemon"
	"github.com/datawire/telepresence2/pkg/rpc/version"
)

var help = `The Telepresence Connect is a background component that manages a connection. It
requires that a daemon is already running.

Launch the Telepresence Connector:
    telepresence connect

The Connector uses the Daemon's log so its output can be found in
    ` + client.Logfile + `
to troubleshoot problems.
`

// service represents the state of the Telepresence Connector
type service struct {
	rpc.UnimplementedConnectorServer
	daemon       daemon.DaemonClient
	daemonLogger daemonLogger
	cluster      *k8sCluster
	bridge       *bridge
	trafficMgr   *trafficManager
	grpc         *grpc.Server
	ctx          context.Context
	cancel       func()
}

// Command returns the CLI sub-command for "connector-foreground"
func Command() *cobra.Command {
	var init bool
	c := &cobra.Command{
		Use:    "connector-foreground",
		Short:  "Launch Telepresence Connector in the foreground (debug)",
		Args:   cobra.ExactArgs(0),
		Hidden: true,
		Long:   help,
		RunE: func(_ *cobra.Command, args []string) error {
			return run(init)
		},
	}
	flags := c.Flags()
	flags.BoolVar(&init, "init", false, "initialize running connector (for debugging)")
	return c
}

type callCtx struct {
	context.Context
	caller context.Context
}

func (c callCtx) Deadline() (deadline time.Time, ok bool) {
	if dl, ok := c.Context.Deadline(); ok {
		return dl, true
	}
	return c.caller.Deadline()
}

func (c callCtx) Done() <-chan struct{} {
	ch := make(chan struct{})
	go func() {
		select {
		case <-c.Context.Done():
			close(ch)
		case <-c.caller.Done():
			close(ch)
		}
	}()
	return ch
}

func (c callCtx) Err() error {
	err := c.Context.Err()
	if err == nil {
		err = c.caller.Err()
	}
	return err
}

func (c callCtx) Value(key interface{}) interface{} {
	return c.Context.Value(key)
}

func (s *service) callGroup(c context.Context) *dgroup.Group {
	return dgroup.NewGroup(&callCtx{Context: s.ctx, caller: c}, dgroup.GroupConfig{})
}

func callRecovery(c context.Context, r interface{}, err error) error {
	perr := dutil.PanicToError(r)
	if perr != nil {
		if err == nil {
			err = perr
		} else {
			dlog.Errorf(c, "%+v", perr)
		}
	}
	if err != nil {
		dlog.Errorf(c, "%+v", err)
	}
	return err
}

func (s *service) Version(_ context.Context, _ *empty.Empty) (*version.VersionInfo, error) {
	return &version.VersionInfo{
		ApiVersion: client.APIVersion,
		Version:    client.Version(),
	}, nil
}

func (s *service) Status(c context.Context, _ *empty.Empty) (result *rpc.ConnectorStatus, err error) {
	g := s.callGroup(c)
	g.Go("Status", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		result = s.status(c)
		return
	})
	err = g.Wait()
	return
}

func (s *service) Connect(c context.Context, cr *rpc.ConnectRequest) (ci *rpc.ConnectInfo, err error) {
	g := s.callGroup(c)
	g.Go("Connect", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		ci = s.connect(c, cr)
		return
	})
	err = g.Wait()
	return
}

func (s *service) CreateIntercept(c context.Context, ir *manager.CreateInterceptRequest) (result *rpc.InterceptResult, err error) {
	ie, is := s.interceptStatus()
	if ie != rpc.InterceptError_UNSPECIFIED {
		return &rpc.InterceptResult{Error: ie, ErrorText: is}, nil
	}
	g := s.callGroup(c)
	g.Go("CreateIntercept", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		result, err = s.trafficMgr.addIntercept(c, s.ctx, ir)
		return
	})
	err = g.Wait()
	return
}

func (s *service) RemoveIntercept(c context.Context, rr *manager.RemoveInterceptRequest2) (result *rpc.InterceptResult, err error) {
	ie, is := s.interceptStatus()
	if ie != rpc.InterceptError_UNSPECIFIED {
		return &rpc.InterceptResult{Error: ie, ErrorText: is}, nil
	}
	g := s.callGroup(c)
	g.Go("RemoveIntercept", func(c context.Context) (err error) {
		defer func() { err = callRecovery(c, recover(), err) }()
		err = s.trafficMgr.removeIntercept(c, rr.Name)
		return
	})
	err = g.Wait()
	return &rpc.InterceptResult{}, err
}

func (s *service) AvailableIntercepts(_ context.Context, _ *empty.Empty) (*manager.AgentInfoSnapshot, error) {
	if s.trafficMgr.grpc == nil {
		return &manager.AgentInfoSnapshot{}, nil
	}
	return s.trafficMgr.agentInfoSnapshot(), nil
}

func (s *service) ListIntercepts(_ context.Context, _ *empty.Empty) (*manager.InterceptInfoSnapshot, error) {
	if s.trafficMgr.grpc == nil {
		return &manager.InterceptInfoSnapshot{}, nil
	}
	return s.trafficMgr.interceptInfoSnapshot(), nil
}

func (s *service) Quit(_ context.Context, _ *empty.Empty) (*empty.Empty, error) {
	s.cancel()
	return &empty.Empty{}, nil
}

// daemonLogger is an io.Writer implementation that sends data to the daemon logger
type daemonLogger struct {
	stream daemon.Daemon_LoggerClient
}

func (d *daemonLogger) Write(data []byte) (n int, err error) {
	err = d.stream.Send(&daemon.LogMessage{Text: data})
	return len(data), err
}

// connect the connector to a cluster
func (s *service) connect(c context.Context, cr *rpc.ConnectRequest) *rpc.ConnectInfo {
	go func() {
		reporter := &metriton.Reporter{
			Application:  "telepresence2",
			Version:      client.Version(),
			GetInstallID: func(_ *metriton.Reporter) (string, error) { return cr.InstallId, nil },
			BaseMetadata: map[string]interface{}{"mode": "daemon"},
		}

		if _, err := reporter.Report(c, map[string]interface{}{"action": "connect"}); err != nil {
			dlog.Errorf(c, "report failed: %+v", err)
		}
	}()

	// Sanity checks
	r := &rpc.ConnectInfo{}
	if s.cluster != nil {
		r.ClusterContext = s.cluster.Context
		r.ClusterServer = s.cluster.server()
		r.Error = rpc.ConnectInfo_ALREADY_CONNECTED
		return r
	}
	if s.bridge != nil {
		r.Error = rpc.ConnectInfo_DISCONNECTING
		return r
	}

	dlog.Info(c, "Connecting to traffic manager...")
	cluster, err := trackKCluster(s.ctx, cr.Context, cr.Namespace, cr.Args)
	if err != nil {
		dlog.Errorf(c, "unable to track k8s cluster: %+v", err)
		r.Error = rpc.ConnectInfo_CLUSTER_FAILED
		r.ErrorText = err.Error()
		s.cancel()
		return r
	}
	s.cluster = cluster

	/*
		previewHost, err := cluster.getClusterPreviewHostname(p)
		if err != nil {
			p.Logf("get preview URL hostname: %+v", err)
			previewHost = ""
		}
	*/

	dlog.Infof(c, "Connected to context %s (%s)", s.cluster.Context, s.cluster.server())

	r.ClusterContext = s.cluster.Context
	r.ClusterServer = s.cluster.server()

	tmgr, err := newTrafficManager(s.ctx, s.cluster, cr.InstallId, cr.IsCi)
	if err != nil {
		dlog.Errorf(c, "Unable to connect to TrafficManager: %s", err)
		r.Error = rpc.ConnectInfo_TRAFFIC_MANAGER_FAILED
		r.ErrorText = err.Error()
		if cr.InterceptEnabled {
			// No point in continuing without a traffic manager
			s.cancel()
		}
		return r
	}

	// tmgr.previewHost = previewHost
	s.trafficMgr = tmgr
	dlog.Infof(c, "Starting traffic-manager bridge in context %s, namespace %s", cluster.Context, cluster.Namespace)
	br := newBridge(cluster, s.daemon, tmgr.sshPort)
	err = br.start(s.ctx)
	if err != nil {
		dlog.Errorf(c, "Failed to start traffic-manager bridge: %s", err.Error())
		r.Error = rpc.ConnectInfo_BRIDGE_FAILED
		r.ErrorText = err.Error()
		// No point in continuing without a bridge
		s.cancel()
		return r
	}
	s.bridge = br

	if !cr.InterceptEnabled {
		return r
	}

	// Wait for traffic manager to connect
	dlog.Info(c, "Waiting for TrafficManager to connect")
	if err := tmgr.waitUntilStarted(); err != nil {
		dlog.Errorf(c, "Failed to start traffic-manager: %s", err.Error())
		r.Error = rpc.ConnectInfo_TRAFFIC_MANAGER_FAILED
		r.ErrorText = err.Error()
		// No point in continuing without a traffic manager
		s.cancel()
	}
	return r
}

// setUpLogging connects to the daemon logger
func (s *service) setUpLogging(c context.Context) (context.Context, error) {
	var err error
	s.daemonLogger.stream, err = s.daemon.Logger(c)
	if err != nil {
		return nil, err
	}

	logger := logrus.StandardLogger()
	logger.Out = &s.daemonLogger
	loggingToTerminal := terminal.IsTerminal(int(os.Stdout.Fd()))
	if loggingToTerminal {
		logger.Formatter = client.NewFormatter("15:04:05")
	} else {
		logger.Formatter = client.NewFormatter("2006/01/02 15:04:05")
	}
	logger.Level = logrus.DebugLevel
	return dlog.WithLogger(c, dlog.WrapLogrus(logger)), nil
}

// run is the main function when executing as the connector
func run(init bool) error {
	// establish a connection to the daemon gRPC service
	conn, err := client.DialSocket(client.DaemonSocketName)
	if err != nil {
		return err
	}
	defer conn.Close()
	s := &service{daemon: daemon.NewDaemonClient(conn), grpc: grpc.NewServer()}
	rpc.RegisterConnectorServer(s.grpc, s)

	c, err := s.setUpLogging(context.Background())
	if err != nil {
		return err
	}

	c = dgroup.WithGoroutineName(c, "connector")

	var cancel context.CancelFunc
	c, cancel = context.WithCancel(c)
	s.cancel = func() {
		dlog.Debug(s.ctx, "cancelling connector context")
		cancel()
	}

	g := dgroup.NewGroup(c, dgroup.GroupConfig{
		SoftShutdownTimeout:  2 * time.Second,
		EnableSignalHandling: true})

	dlog.Info(c, "---")
	dlog.Infof(c, "Telepresence Connector %s starting...", client.DisplayVersion())
	dlog.Infof(c, "PID is %d", os.Getpid())
	dlog.Info(c, "")

	svcStarted := make(chan bool)
	if init {
		g.Go("debug-init", func(c context.Context) error {
			<-svcStarted
			_, _ = s.Connect(c, &rpc.ConnectRequest{InstallId: "dummy-id"})
			return nil
		})
	}

	g.Go("service", func(c context.Context) (err error) {
		var listener net.Listener
		defer func() {
			if perr := dutil.PanicToError(recover()); perr != nil {
				if err == nil {
					err = perr
				}
				if listener != nil {
					_ = listener.Close()
				}
				_ = os.Remove(client.ConnectorSocketName)
			}
			if err != nil {
				dlog.Errorf(c, "Server ended with: %s", err.Error())
			} else {
				dlog.Debug(c, "Server ended")
			}
		}()

		// Listen on unix domain socket
		dlog.Debug(c, "Server starting")
		s.ctx = c
		listener, err = net.Listen("unix", client.ConnectorSocketName)
		if err != nil {
			return err
		}
		close(svcStarted)
		return s.grpc.Serve(listener)
	})

	g.Go("teardown", s.handleShutdown)

	err = g.Wait()
	if err != nil {
		dlog.Error(c, err.Error())
	}
	return err
}

// handleShutdown ensures that the connector quits gracefully when receiving a signal
// or when the context is cancelled.
func (s *service) handleShutdown(c context.Context) error {
	defer s.grpc.GracefulStop()

	<-c.Done()
	dlog.Info(c, "Shutting down")

	cluster := s.cluster
	if cluster == nil {
		return nil
	}
	s.cluster = nil
	trafficMgr := s.trafficMgr

	s.trafficMgr = nil
	if trafficMgr != nil {
		_ = trafficMgr.clearIntercepts(context.Background())
		_ = trafficMgr.Close()
	}
	s.bridge = nil
	return nil
}
<|endoftext|>


<commit_before>package demoinfocs_test

import (
	"fmt"
	"log"
	"os"
	"testing"

	demoinfocs "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs"
	events "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/events"
)

/*
This will print all kills of a demo in the format '[[killer]] <[[weapon]] [(HS)] [(WB)]> [[victim]]'
*/
//noinspection GoUnhandledErrorResult
func ExampleParser() {
	f, err := os.Open("../../test/cs-demos/default.demx")
	if err != nil {
		log.Panic("failed to open demo file: ", err)
	}

	defer f.Close()

	p := demoinfocs.NewParser(f)
	defer p.Close()

	// Register handler on kill events
	p.RegisterEventHandler(func(e events.Kill) {
		var hs string
		if e.IsHeadshot {
			hs = " (HS)"
		}

		var wallBang string
		if e.PenetratedObjects > 0 {
			wallBang = " (WB)"
		}

		fmt.Printf("%s <%v%s%s> %s\n", e.Killer, e.Weapon, hs, wallBang, e.Victim)
	})

	// Parse to end
	err = p.ParseToEnd()
	if err != nil {
		log.Panic("failed to parse demo: ", err)
	}
}

func TestExamplesWithoutOutput(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping long running test")
	}

	ExampleParser()
}
<commit_msg>fix error in examples_test.go<commit_after>package demoinfocs_test

import (
	"fmt"
	"log"
	"os"
	"testing"

	demoinfocs "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs"
	events "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/events"
)

/*
This will print all kills of a demo in the format '[[killer]] <[[weapon]] [(HS)] [(WB)]> [[victim]]'
*/
//noinspection GoUnhandledErrorResult
func ExampleParser() {
	f, err := os.Open("../../test/cs-demos/default.dem")
	if err != nil {
		log.Panic("failed to open demo file: ", err)
	}

	defer f.Close()

	p := demoinfocs.NewParser(f)
	defer p.Close()

	// Register handler on kill events
	p.RegisterEventHandler(func(e events.Kill) {
		var hs string
		if e.IsHeadshot {
			hs = " (HS)"
		}

		var wallBang string
		if e.PenetratedObjects > 0 {
			wallBang = " (WB)"
		}

		fmt.Printf("%s <%v%s%s> %s\n", e.Killer, e.Weapon, hs, wallBang, e.Victim)
	})

	// Parse to end
	err = p.ParseToEnd()
	if err != nil {
		log.Panic("failed to parse demo: ", err)
	}
}

func TestExamplesWithoutOutput(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping long running test")
	}

	ExampleParser()
}
<|endoftext|>


<commit_before>// Copyright 2017 The OpenSDS 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.

/*
This module implements the entry into operations of storageDock module.

*/

package discovery

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	log "github.com/golang/glog"
	"github.com/opensds/opensds/contrib/connector"
	"github.com/opensds/opensds/contrib/drivers"
	fd "github.com/opensds/opensds/contrib/drivers/filesharedrivers"
	"github.com/opensds/opensds/contrib/drivers/utils/config"
	c "github.com/opensds/opensds/pkg/context"
	"github.com/opensds/opensds/pkg/db"
	"github.com/opensds/opensds/pkg/model"
	"github.com/opensds/opensds/pkg/utils"
	. "github.com/opensds/opensds/pkg/utils/config"
	uuid "github.com/satori/go.uuid"
)

const (
	availableStatus   = "available"
	unavailableStatus = "unavailable"
)

type Context struct {
	StopChan chan bool
	ErrChan  chan error
	MetaChan chan string
}

func DiscoveryAndReport(dd DockDiscoverer, ctx *Context) {
	for {
		select {
		case <-ctx.StopChan:
			return
		default:
			if err := dd.Discover(); err != nil {
				ctx.ErrChan <- err
			}

			if err := dd.Report(); err != nil {
				ctx.ErrChan <- err
			}
		}

		time.Sleep(60 * time.Second)
	}
}

type DockDiscoverer interface {
	Init() error

	Discover() error

	Report() error
}

// NewDockDiscoverer method creates a new DockDiscoverer.
func NewDockDiscoverer(dockType string) DockDiscoverer {
	switch dockType {
	case model.DockTypeProvioner:
		return &provisionDockDiscoverer{
			DockRegister: NewDockRegister(),
		}
	case model.DockTypeAttacher:
		return &attachDockDiscoverer{
			DockRegister: NewDockRegister(),
		}
	}
	return nil
}

// provisionDockDiscoverer is a struct for exposing some operations of provision
// dock service discovery.
type provisionDockDiscoverer struct {
	*DockRegister

	dcks []*model.DockSpec
	pols []*model.StoragePoolSpec
}

func (pdd *provisionDockDiscoverer) Init() error {
	// Load resource from specified file
	bm := GetBackendsMap()
	host, err := os.Hostname()
	if err != nil {
		log.Error("When get os hostname:", err)
		return err
	}

	for _, v := range CONF.EnabledBackends {
		b := bm[v]
		if b.Name == "" {
			continue
		}

		dck := &model.DockSpec{
			BaseModel: &model.BaseModel{
				Id: uuid.NewV5(uuid.NamespaceOID, host+":"+b.DriverName).String(),
			},
			Name:        b.Name,
			Description: b.Description,
			DriverName:  b.DriverName,
			Endpoint:    CONF.OsdsDock.ApiEndpoint,
			NodeId:      host,
			Type:        model.DockTypeProvioner,
			Metadata:    map[string]string{"HostReplicationDriver": CONF.OsdsDock.HostBasedReplicationDriver},
		}
		// Update the id if the dock is already in etcd
		name := map[string][]string{
			"Name": {dck.Name},
		}
		docks, err := pdd.DockRegister.c.ListDocksWithFilter(c.NewAdminContext(), name)
		if err == nil && len(docks) != 0 {
			dck.Id = docks[0].Id
		}
		pdd.dcks = append(pdd.dcks, dck)
	}

	return nil
}

var filesharedrivers = []string{config.NFSDriverType, config.HuaweiOceanStorFileDriverType, config.ManilaDriverType, config.ChubaofsDriverType}

func (pdd *provisionDockDiscoverer) Discover() error {
	// Clear existing pool info
	pdd.pols = pdd.pols[:0]
	var pols []*model.StoragePoolSpec
	var err error
	var polsInDb []*model.StoragePoolSpec
	ctx := c.NewAdminContext()
	polsInDb, err = pdd.c.ListPools(ctx)
	if err != nil {
		return fmt.Errorf("can not read pools in db")
	}
	dbPolsMap := make(map[string]map[string]*model.StoragePoolSpec)
	for _, dck := range pdd.dcks {
		dbPolsMap[dck.Id] = make(map[string]*model.StoragePoolSpec)
	}
	for _, polInDb := range polsInDb {
		if dbPolsMap[polInDb.DockId] != nil {
			polInDb.Status = unavailableStatus
			dbPolsMap[polInDb.DockId][polInDb.Id] = polInDb
		}
	}
	for _, dck := range pdd.dcks {
		// Call function of StorageDrivers configured by storage drivers.
		if utils.Contains(filesharedrivers, dck.DriverName) {
			d := fd.Init(dck.DriverName)
			defer fd.Clean(d)
			pols, err = d.ListPools()
			for _, pol := range pols {
				log.Infof("Backend %s discovered pool %s", dck.DriverName, pol.Name)
				delete(dbPolsMap[dck.Id], pol.Id)
				pol.DockId = dck.Id
				pol.Status = availableStatus
			}
		} else {
			d := drivers.Init(dck.DriverName)
			defer drivers.Clean(d)
			pols, err = d.ListPools()

			replicationDriverName := dck.Metadata["HostReplicationDriver"]
			replicationType := model.ReplicationTypeHost
			if drivers.IsSupportArrayBasedReplication(dck.DriverName) {
				replicationType = model.ReplicationTypeArray
				replicationDriverName = dck.DriverName
			}
			for _, pol := range pols {
				log.Infof("Backend %s discovered pool %s", dck.DriverName, pol.Name)
				delete(dbPolsMap[dck.Id], pol.Id)
				pol.DockId = dck.Id
				pol.ReplicationType = replicationType
				pol.ReplicationDriverName = replicationDriverName
				pol.Status = availableStatus
			}
		}
		if err != nil {
			log.Error("Call driver to list pools failed:", err)
			continue
		}

		if len(pols) == 0 {
			log.Warningf("The pool of dock %s is empty!\n", dck.Id)
		}

		pdd.pols = append(pdd.pols, pols...)
		for _, pol := range dbPolsMap[dck.Id] {
			pdd.pols = append(pdd.pols, pol)
		}

	}
	if len(pdd.pols) == 0 {
		return fmt.Errorf("there is no pool can be found")
	}

	return nil
}

func (pdd *provisionDockDiscoverer) Report() error {
	var err error

	// Store dock resources in database.
	for _, dck := range pdd.dcks {
		if err = pdd.Register(dck); err != nil {
			break
		}
	}

	// Store pool resources in database.
	for _, pol := range pdd.pols {
		if err != nil {
			break
		}
		err = pdd.Register(pol)
	}

	return err
}

// attachDockDiscoverer is a struct for exposing some operations of attach
// dock service discovery.
type attachDockDiscoverer struct {
	*DockRegister

	dck *model.DockSpec
}

func (add *attachDockDiscoverer) Init() error { return nil }

func (add *attachDockDiscoverer) Discover() error {
	host, err := os.Hostname()
	if err != nil {
		log.Error("When get os hostname:", err)
		return err
	}

	localIqn, err := connector.NewConnector(connector.IscsiDriver).GetInitiatorInfo()
	if err != nil {
		log.Warning("get initiator failed, ", err)
	}

	bindIp := CONF.BindIp
	if bindIp == "" {
		bindIp = connector.GetHostIP()
	}

	fcInitiator, err := connector.NewConnector(connector.FcDriver).GetInitiatorInfo()
	if err != nil {
		log.Warning("get initiator failed, ", err)
	}

	var wwpns []string
	for _, v := range strings.Split(fcInitiator, ",") {
		if strings.Contains(v, "node_name") {
			wwpns = append(wwpns, strings.Split(v, ":")[1])
		}
	}

	segments := strings.Split(CONF.OsdsDock.ApiEndpoint, ":")
	endpointIp := segments[len(segments)-2]
	add.dck = &model.DockSpec{
		BaseModel: &model.BaseModel{
			Id: uuid.NewV5(uuid.NamespaceOID, host+":"+endpointIp).String(),
		},
		Endpoint: CONF.OsdsDock.ApiEndpoint,
		NodeId:   host,
		Type:     model.DockTypeAttacher,
		Metadata: map[string]string{
			"Platform":  runtime.GOARCH,
			"OsType":    runtime.GOOS,
			"HostIp":    bindIp,
			"Initiator": localIqn,
			"WWPNS":     strings.Join(wwpns, ","),
		},
	}

	return nil
}

func (add *attachDockDiscoverer) Report() error {
	return add.Register(add.dck)
}

func NewDockRegister() *DockRegister {
	return &DockRegister{c: db.C}
}

type DockRegister struct {
	c db.Client
}

func (dr *DockRegister) Register(in interface{}) error {
	ctx := c.NewAdminContext()

	switch in.(type) {
	case *model.DockSpec:
		dck := in.(*model.DockSpec)
		// Call db module to create dock resource with latest info.
		if _, err := dr.c.CreateDock(ctx, dck); err != nil {
			log.Errorf("When create dock %s in db: %v\n", dck.Id, err)
			return err
		}

		break
	case *model.StoragePoolSpec:
		pol := in.(*model.StoragePoolSpec)
		// Call db module to create pool resource.
		name := map[string][]string{
			"Name":   {pol.Name},
			"dockId": {pol.DockId},
		}
		pools, err := dr.c.ListPoolsWithFilter(ctx, name)
		if err != nil {
			break
		}
		if len(pools) != 0 {
			pol.Id = pools[0].Id
		}
		if _, err := dr.c.CreatePool(ctx, pol); err != nil {
			log.Errorf("When create pool %s in db: %v\n", pol.Id, err)
			return err
		}
		break
	default:
		return fmt.Errorf("Resource type is not supported!")
	}

	return nil
}

func (dr *DockRegister) Unregister(in interface{}) error {
	ctx := c.NewAdminContext()

	switch in.(type) {
	case *model.DockSpec:
		dck := in.(*model.DockSpec)
		// Call db module to delete dock resource.
		if err := dr.c.DeleteDock(ctx, dck.Id); err != nil {
			log.Errorf("When delete dock %s in db: %v\n", dck.Id, err)
			return err
		}
		break
	case *model.StoragePoolSpec:
		pol := in.(*model.StoragePoolSpec)
		// Call db module to delete pool resource.
		if err := dr.c.DeletePool(ctx, pol.Id); err != nil {
			log.Errorf("When delete pool %s in db: %v\n", pol.Id, err)
			return err
		}
		break
	default:
		return fmt.Errorf("Resource type is not supported!")
	}

	return nil
}
<commit_msg>Code improvement<commit_after>// Copyright 2017 The OpenSDS 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.

/*
This module implements the entry into operations of storageDock module.

*/

package discovery

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	log "github.com/golang/glog"
	"github.com/opensds/opensds/contrib/connector"
	"github.com/opensds/opensds/contrib/drivers"
	fd "github.com/opensds/opensds/contrib/drivers/filesharedrivers"
	"github.com/opensds/opensds/contrib/drivers/utils/config"
	c "github.com/opensds/opensds/pkg/context"
	"github.com/opensds/opensds/pkg/db"
	"github.com/opensds/opensds/pkg/model"
	"github.com/opensds/opensds/pkg/utils"
	. "github.com/opensds/opensds/pkg/utils/config"
	uuid "github.com/satori/go.uuid"
)

const (
	availableStatus   = "available"
	unavailableStatus = "unavailable"
)

type Context struct {
	StopChan chan bool
	ErrChan  chan error
	MetaChan chan string
}

func DiscoveryAndReport(dd DockDiscoverer, ctx *Context) {
	for {
		select {
		case <-ctx.StopChan:
			return
		default:
			if err := dd.Discover(); err != nil {
				ctx.ErrChan <- err
			}

			if err := dd.Report(); err != nil {
				ctx.ErrChan <- err
			}
		}

		time.Sleep(60 * time.Second)
	}
}

type DockDiscoverer interface {
	Init() error

	Discover() error

	Report() error
}

// NewDockDiscoverer method creates a new DockDiscoverer.
func NewDockDiscoverer(dockType string) DockDiscoverer {
	switch dockType {
	case model.DockTypeProvioner:
		return &provisionDockDiscoverer{
			DockRegister: NewDockRegister(),
		}
	case model.DockTypeAttacher:
		return &attachDockDiscoverer{
			DockRegister: NewDockRegister(),
		}
	}
	return nil
}

// provisionDockDiscoverer is a struct for exposing some operations of provision
// dock service discovery.
type provisionDockDiscoverer struct {
	*DockRegister

	dcks []*model.DockSpec
	pols []*model.StoragePoolSpec
}

func (pdd *provisionDockDiscoverer) Init() error {
	// Load resource from specified file
	bm := GetBackendsMap()
	host, err := os.Hostname()
	if err != nil {
		log.Error("When get os hostname:", err)
		return err
	}

	for _, v := range CONF.EnabledBackends {
		b := bm[v]
		if b.Name == "" {
			continue
		}

		dck := &model.DockSpec{
			BaseModel: &model.BaseModel{
				Id: uuid.NewV5(uuid.NamespaceOID, host+":"+b.DriverName).String(),
			},
			Name:        b.Name,
			Description: b.Description,
			DriverName:  b.DriverName,
			Endpoint:    CONF.OsdsDock.ApiEndpoint,
			NodeId:      host,
			Type:        model.DockTypeProvioner,
			Metadata:    map[string]string{"HostReplicationDriver": CONF.OsdsDock.HostBasedReplicationDriver},
		}
		// Update the id if the dock is already in etcd
		name := map[string][]string{
			"Name": {dck.Name},
		}
		docks, err := pdd.DockRegister.c.ListDocksWithFilter(c.NewAdminContext(), name)
		if err == nil && len(docks) != 0 {
			dck.Id = docks[0].Id
		}
		pdd.dcks = append(pdd.dcks, dck)
	}

	return nil
}

var filesharedrivers = []string{config.NFSDriverType, config.HuaweiOceanStorFileDriverType, config.ManilaDriverType, config.ChubaofsDriverType}

func (pdd *provisionDockDiscoverer) Discover() error {
	// Clear existing pool info
	pdd.pols = pdd.pols[:0]
	var pols []*model.StoragePoolSpec
	var err error
	var polsInDb []*model.StoragePoolSpec
	ctx := c.NewAdminContext()
	polsInDb, err = pdd.c.ListPools(ctx)
	if err != nil {
		return fmt.Errorf("can not read pools in db")
	}
	dbPolsMap := make(map[string]map[string]*model.StoragePoolSpec)
	for _, dck := range pdd.dcks {
		dbPolsMap[dck.Id] = make(map[string]*model.StoragePoolSpec)
	}
	for _, polInDb := range polsInDb {
		if dbPolsMap[polInDb.DockId] != nil {
			polInDb.Status = unavailableStatus
			dbPolsMap[polInDb.DockId][polInDb.Id] = polInDb
		}
	}
	for _, dck := range pdd.dcks {
		// Call function of StorageDrivers configured by storage drivers.
		if utils.Contains(filesharedrivers, dck.DriverName) {
			d := fd.Init(dck.DriverName)
			defer fd.Clean(d)
			pols, err = d.ListPools()
			for _, pol := range pols {
				log.Infof("Backend %s discovered pool %s", dck.DriverName, pol.Name)
				delete(dbPolsMap[dck.Id], pol.Id)
				pol.DockId = dck.Id
				pol.Status = availableStatus
			}
		} else {
			d := drivers.Init(dck.DriverName)
			defer drivers.Clean(d)
			pols, err = d.ListPools()

			replicationDriverName := dck.Metadata["HostReplicationDriver"]
			replicationType := model.ReplicationTypeHost
			if drivers.IsSupportArrayBasedReplication(dck.DriverName) {
				replicationType = model.ReplicationTypeArray
				replicationDriverName = dck.DriverName
			}
			for _, pol := range pols {
				log.Infof("Backend %s discovered pool %s", dck.DriverName, pol.Name)
				name := map[string][]string{
					"Name":   {pol.Name},
					"dockId": {pol.DockId},
				}
				pools, err := pdd.c.ListPoolsWithFilter(ctx, name)
				if err == nil && len(pools) != 0 {
					log.Errorf("name is %s, id is %s, not found\n", pol.Name, pol.DockId)
					pol.Id = pools[0].Id
				}

				delete(dbPolsMap[dck.Id], pol.Id)
				pol.DockId = dck.Id
				pol.ReplicationType = replicationType
				pol.ReplicationDriverName = replicationDriverName
				pol.Status = availableStatus
			}
		}
		if err != nil {
			log.Error("Call driver to list pools failed:", err)
			continue
		}

		if len(pols) == 0 {
			log.Warningf("The pool of dock %s is empty!\n", dck.Id)
		}

		pdd.pols = append(pdd.pols, pols...)
		for _, pol := range dbPolsMap[dck.Id] {
			pdd.pols = append(pdd.pols, pol)
		}

	}
	if len(pdd.pols) == 0 {
		return fmt.Errorf("there is no pool can be found")
	}

	return nil
}

func (pdd *provisionDockDiscoverer) Report() error {
	var err error

	// Store dock resources in database.
	for _, dck := range pdd.dcks {
		if err = pdd.Register(dck); err != nil {
			break
		}
	}

	// Store pool resources in database.
	for _, pol := range pdd.pols {
		if err != nil {
			break
		}
		err = pdd.Register(pol)
	}

	return err
}

// attachDockDiscoverer is a struct for exposing some operations of attach
// dock service discovery.
type attachDockDiscoverer struct {
	*DockRegister

	dck *model.DockSpec
}

func (add *attachDockDiscoverer) Init() error { return nil }

func (add *attachDockDiscoverer) Discover() error {
	host, err := os.Hostname()
	if err != nil {
		log.Error("When get os hostname:", err)
		return err
	}

	localIqn, err := connector.NewConnector(connector.IscsiDriver).GetInitiatorInfo()
	if err != nil {
		log.Warning("get initiator failed, ", err)
	}

	bindIp := CONF.BindIp
	if bindIp == "" {
		bindIp = connector.GetHostIP()
	}

	fcInitiator, err := connector.NewConnector(connector.FcDriver).GetInitiatorInfo()
	if err != nil {
		log.Warning("get initiator failed, ", err)
	}

	var wwpns []string
	for _, v := range strings.Split(fcInitiator, ",") {
		if strings.Contains(v, "node_name") {
			wwpns = append(wwpns, strings.Split(v, ":")[1])
		}
	}

	segments := strings.Split(CONF.OsdsDock.ApiEndpoint, ":")
	endpointIp := segments[len(segments)-2]
	add.dck = &model.DockSpec{
		BaseModel: &model.BaseModel{
			Id: uuid.NewV5(uuid.NamespaceOID, host+":"+endpointIp).String(),
		},
		Endpoint: CONF.OsdsDock.ApiEndpoint,
		NodeId:   host,
		Type:     model.DockTypeAttacher,
		Metadata: map[string]string{
			"Platform":  runtime.GOARCH,
			"OsType":    runtime.GOOS,
			"HostIp":    bindIp,
			"Initiator": localIqn,
			"WWPNS":     strings.Join(wwpns, ","),
		},
	}

	return nil
}

func (add *attachDockDiscoverer) Report() error {
	return add.Register(add.dck)
}

func NewDockRegister() *DockRegister {
	return &DockRegister{c: db.C}
}

type DockRegister struct {
	c db.Client
}

func (dr *DockRegister) Register(in interface{}) error {
	ctx := c.NewAdminContext()

	switch in.(type) {
	case *model.DockSpec:
		dck := in.(*model.DockSpec)
		// Call db module to create dock resource with latest info.
		if _, err := dr.c.CreateDock(ctx, dck); err != nil {
			log.Errorf("When create dock %s in db: %v\n", dck.Id, err)
			return err
		}

		break
	case *model.StoragePoolSpec:
		pol := in.(*model.StoragePoolSpec)
		// Call db module to create pool resource.
		if _, err := dr.c.CreatePool(ctx, pol); err != nil {
			log.Errorf("When create pool %s in db: %v\n", pol.Id, err)
			return err
		}
		break
	default:
		return fmt.Errorf("Resource type is not supported!")
	}

	return nil
}

func (dr *DockRegister) Unregister(in interface{}) error {
	ctx := c.NewAdminContext()

	switch in.(type) {
	case *model.DockSpec:
		dck := in.(*model.DockSpec)
		// Call db module to delete dock resource.
		if err := dr.c.DeleteDock(ctx, dck.Id); err != nil {
			log.Errorf("When delete dock %s in db: %v\n", dck.Id, err)
			return err
		}
		break
	case *model.StoragePoolSpec:
		pol := in.(*model.StoragePoolSpec)
		// Call db module to delete pool resource.
		if err := dr.c.DeletePool(ctx, pol.Id); err != nil {
			log.Errorf("When delete pool %s in db: %v\n", pol.Id, err)
			return err
		}
		break
	default:
		return fmt.Errorf("Resource type is not supported!")
	}

	return nil
}
<|endoftext|>


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

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

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

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

package cluster

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strings"
	"time"

	"github.com/docker/machine/drivers/virtualbox"
	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/host"
	"github.com/docker/machine/libmachine/state"
	"github.com/golang/glog"
	kubeApi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/sshutil"
	"k8s.io/minikube/pkg/util"
)

var (
	certs = []string{"apiserver.crt", "apiserver.key"}
)

//This init function is used to set the logtostderr variable to false so that INFO level log info does not clutter the CLI
//INFO lvl logging is displayed due to the kubernetes api calling flag.Set("logtostderr", "true") in its init()
//see: https://github.com/kubernetes/kubernetes/blob/master/pkg/util/logs.go#L32-34
func init() {
	flag.Set("logtostderr", "false")
}

// StartHost starts a host VM.
func StartHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
	if exists, err := api.Exists(constants.MachineName); err != nil {
		return nil, fmt.Errorf("Error checking if host exists: %s", err)
	} else if exists {
		glog.Infoln("Machine exists!")
		h, err := api.Load(constants.MachineName)
		if err != nil {
			return nil, fmt.Errorf("Error loading existing host: %s", err)
		}
		s, err := h.Driver.GetState()
		if err != nil {
			return nil, fmt.Errorf("Error getting state for host: %s", err)
		}
		if s != state.Running {
			if err := h.Driver.Start(); err != nil {
				return nil, fmt.Errorf("Error starting stopped host: %s", err)
			}
			if err := api.Save(h); err != nil {
				return nil, fmt.Errorf("Error saving started host: %s", err)
			}
		}
		if err := h.ConfigureAuth(); err != nil {
			return nil, fmt.Errorf("Error configuring auth on host: %s", err)
		}
		return h, nil
	} else {
		return createHost(api, config)
	}
}

// StopHost stops the host VM.
func StopHost(api libmachine.API) error {
	host, err := api.Load(constants.MachineName)
	if err != nil {
		return err
	}
	if err := host.Stop(); err != nil {
		return err
	}
	return nil
}

type multiError struct {
	Errors []error
}

func (m *multiError) Collect(err error) {
	if err != nil {
		m.Errors = append(m.Errors, err)
	}
}

func (m multiError) ToError() error {
	if len(m.Errors) == 0 {
		return nil
	}

	errStrings := []string{}
	for _, err := range m.Errors {
		errStrings = append(errStrings, err.Error())
	}
	return fmt.Errorf(strings.Join(errStrings, "\n"))
}

// DeleteHost deletes the host VM.
func DeleteHost(api libmachine.API) error {
	host, err := api.Load(constants.MachineName)
	if err != nil {
		return err
	}
	m := multiError{}
	m.Collect(host.Driver.Remove())
	m.Collect(api.Remove(constants.MachineName))
	return m.ToError()
}

// GetHostStatus gets the status of the host VM.
func GetHostStatus(api libmachine.API) (string, error) {
	dne := "Does Not Exist"
	exists, err := api.Exists(constants.MachineName)
	if err != nil {
		return "", err
	}
	if !exists {
		return dne, nil
	}

	host, err := api.Load(constants.MachineName)
	if err != nil {
		return "", err
	}

	s, err := host.Driver.GetState()
	if s.String() == "" {
		return dne, err
	}
	return s.String(), err
}

type sshAble interface {
	RunSSHCommand(string) (string, error)
}

// MachineConfig contains the parameters used to start a cluster.
type MachineConfig struct {
	MinikubeISO string
	Memory      int
	CPUs        int
	VMDriver    string
}

// StartCluster starts a k8s cluster on the specified Host.
func StartCluster(h sshAble) error {
	commands := []string{stopCommand, GetStartCommand()}

	for _, cmd := range commands {
		glog.Infoln(cmd)
		output, err := h.RunSSHCommand(cmd)
		glog.Infoln(output)
		if err != nil {
			return err
		}
	}

	return nil
}

type fileToCopy struct {
	AssetName   string
	TargetDir   string
	TargetName  string
	Permissions string
}

var assets = []fileToCopy{
	{
		AssetName:   "out/localkube",
		TargetDir:   "/usr/local/bin",
		TargetName:  "localkube",
		Permissions: "0777",
	},
	{
		AssetName:   "deploy/iso/addon-manager.yaml",
		TargetDir:   "/etc/kubernetes/manifests/",
		TargetName:  "addon-manager.yaml",
		Permissions: "0640",
	},
	{
		AssetName:   "deploy/addons/dashboard-rc.yaml",
		TargetDir:   "/etc/kubernetes/addons/",
		TargetName:  "dashboard-rc.yaml",
		Permissions: "0640",
	},
	{
		AssetName:   "deploy/addons/dashboard-svc.yaml",
		TargetDir:   "/etc/kubernetes/addons/",
		TargetName:  "dashboard-svc.yaml",
		Permissions: "0640",
	},
}

func UpdateCluster(d drivers.Driver) error {
	client, err := sshutil.NewSSHClient(d)
	if err != nil {
		return err
	}

	for _, a := range assets {
		contents, err := Asset(a.AssetName)
		if err != nil {
			glog.Infof("Error loading asset %s: %s", a.AssetName, err)
			return err
		}

		if err := sshutil.Transfer(contents, a.TargetDir, a.TargetName, a.Permissions, client); err != nil {
			return err
		}
	}
	return nil
}

// SetupCerts gets the generated credentials required to talk to the APIServer.
func SetupCerts(d drivers.Driver) error {
	localPath := constants.Minipath
	ipStr, err := d.GetIP()
	if err != nil {
		return err
	}

	ip := net.ParseIP(ipStr)
	publicPath := filepath.Join(localPath, "apiserver.crt")
	privatePath := filepath.Join(localPath, "apiserver.key")
	if err := GenerateCerts(publicPath, privatePath, ip); err != nil {
		return err
	}

	client, err := sshutil.NewSSHClient(d)
	if err != nil {
		return err
	}

	for _, cert := range certs {
		p := filepath.Join(localPath, cert)
		data, err := ioutil.ReadFile(p)
		if err != nil {
			return err
		}
		if err := sshutil.Transfer(data, util.DefaultCertPath, cert, "0644", client); err != nil {
			return err
		}
	}
	return nil
}

func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
	var driver interface{}

	switch config.VMDriver {
	case "virtualbox":
		d := virtualbox.NewDriver(constants.MachineName, constants.Minipath)
		d.Boot2DockerURL = config.MinikubeISO
		d.Memory = config.Memory
		d.CPU = config.CPUs
		driver = d
	case "vmwarefusion":
		driver = createVMwareFusionHost(config)
	case "kvm":
		driver = createKVMHost(config)
	case "xhyve":
		driver = createXhyveHost(config)
	default:
		glog.Exitf("Unsupported driver: %s\n", config.VMDriver)
	}

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

	h, err := api.NewHost(config.VMDriver, data)
	if err != nil {
		return nil, fmt.Errorf("Error creating new host: %s", err)
	}

	h.HostOptions.AuthOptions.CertDir = constants.Minipath
	h.HostOptions.AuthOptions.StorePath = constants.Minipath
	h.HostOptions.EngineOptions = &engine.Options{}

	if err := api.Create(h); err != nil {
		// Wait for all the logs to reach the client
		time.Sleep(2 * time.Second)
		return nil, fmt.Errorf("Error creating. %s", err)
	}

	if err := api.Save(h); err != nil {
		return nil, fmt.Errorf("Error attempting to save store: %s", err)
	}
	return h, nil
}

// GetHostDockerEnv gets the necessary docker env variables to allow the use of docker through minikube's vm
func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return nil, err
	}
	ip, err := host.Driver.GetIP()
	if err != nil {
		return nil, err
	}

	tcpPrefix := "tcp://"
	portDelimiter := ":"
	port := "2376"

	envMap := map[string]string{
		"DOCKER_TLS_VERIFY": "1",
		"DOCKER_HOST":       tcpPrefix + ip + portDelimiter + port,
		"DOCKER_CERT_PATH":  constants.MakeMiniPath("certs"),
	}
	return envMap, nil
}

// GetHostLogs gets the localkube logs of the host VM.
func GetHostLogs(api libmachine.API) (string, error) {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return "", err
	}
	s, err := host.RunSSHCommand(logsCommand)
	if err != nil {
		return "", nil
	}
	return s, err
}

func checkIfApiExistsAndLoad(api libmachine.API) (*host.Host, error) {
	exists, err := api.Exists(constants.MachineName)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, fmt.Errorf("Machine does not exist for api.Exists(%s)", constants.MachineName)
	}

	host, err := api.Load(constants.MachineName)
	if err != nil {
		return nil, err
	}
	return host, nil
}

func CreateSSHShell(api libmachine.API, args []string) error {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return err
	}

	currentState, err := host.Driver.GetState()
	if err != nil {
		return err
	}

	if currentState != state.Running {
		return fmt.Errorf("Error: Cannot run ssh command: Host %q is not running", constants.MachineName)
	}

	client, err := host.CreateSSHClient()
	if err != nil {
		return err
	}
	return client.Shell(strings.Join(args, " "))
}

func GetServiceURL(api libmachine.API, namespace, service string) (string, error) {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return "", err
	}

	ip, err := host.Driver.GetIP()
	if err != nil {
		return "", err
	}

	port, err := getServicePort(namespace, service)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("http://%s:%d", ip, port), nil
}

type serviceGetter interface {
	Get(name string) (*kubeApi.Service, error)
}

func getServicePort(namespace, service string) (int, error) {
	services, err := getKubernetesServicesWithNamespace(namespace)
	if err != nil {
		return 0, err
	}
	return getServicePortFromServiceGetter(services, service)
}

func getServicePortFromServiceGetter(services serviceGetter, service string) (int, error) {
	svc, err := services.Get(service)
	if err != nil {
		return 0, fmt.Errorf("Error getting %s service: %s", service, err)
	}
	return int(svc.Spec.Ports[0].NodePort), nil
}

func getKubernetesServicesWithNamespace(namespace string) (serviceGetter, error) {
	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
	configOverrides := &clientcmd.ConfigOverrides{}
	kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
	config, err := kubeConfig.ClientConfig()
	if err != nil {
		return nil, fmt.Errorf("Error creating kubeConfig: %s", err)
	}
	client, err := unversioned.New(config)
	if err != nil {
		return nil, err
	}
	services := client.Services(namespace)
	return services, nil
}
<commit_msg>Add some logging to cert generation.<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package cluster

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strings"
	"time"

	"github.com/docker/machine/drivers/virtualbox"
	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/host"
	"github.com/docker/machine/libmachine/state"
	"github.com/golang/glog"
	kubeApi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/minikube/sshutil"
	"k8s.io/minikube/pkg/util"
)

var (
	certs = []string{"apiserver.crt", "apiserver.key"}
)

//This init function is used to set the logtostderr variable to false so that INFO level log info does not clutter the CLI
//INFO lvl logging is displayed due to the kubernetes api calling flag.Set("logtostderr", "true") in its init()
//see: https://github.com/kubernetes/kubernetes/blob/master/pkg/util/logs.go#L32-34
func init() {
	flag.Set("logtostderr", "false")
}

// StartHost starts a host VM.
func StartHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
	if exists, err := api.Exists(constants.MachineName); err != nil {
		return nil, fmt.Errorf("Error checking if host exists: %s", err)
	} else if exists {
		glog.Infoln("Machine exists!")
		h, err := api.Load(constants.MachineName)
		if err != nil {
			return nil, fmt.Errorf("Error loading existing host: %s", err)
		}
		s, err := h.Driver.GetState()
		if err != nil {
			return nil, fmt.Errorf("Error getting state for host: %s", err)
		}
		if s != state.Running {
			if err := h.Driver.Start(); err != nil {
				return nil, fmt.Errorf("Error starting stopped host: %s", err)
			}
			if err := api.Save(h); err != nil {
				return nil, fmt.Errorf("Error saving started host: %s", err)
			}
		}
		if err := h.ConfigureAuth(); err != nil {
			return nil, fmt.Errorf("Error configuring auth on host: %s", err)
		}
		return h, nil
	} else {
		return createHost(api, config)
	}
}

// StopHost stops the host VM.
func StopHost(api libmachine.API) error {
	host, err := api.Load(constants.MachineName)
	if err != nil {
		return err
	}
	if err := host.Stop(); err != nil {
		return err
	}
	return nil
}

type multiError struct {
	Errors []error
}

func (m *multiError) Collect(err error) {
	if err != nil {
		m.Errors = append(m.Errors, err)
	}
}

func (m multiError) ToError() error {
	if len(m.Errors) == 0 {
		return nil
	}

	errStrings := []string{}
	for _, err := range m.Errors {
		errStrings = append(errStrings, err.Error())
	}
	return fmt.Errorf(strings.Join(errStrings, "\n"))
}

// DeleteHost deletes the host VM.
func DeleteHost(api libmachine.API) error {
	host, err := api.Load(constants.MachineName)
	if err != nil {
		return err
	}
	m := multiError{}
	m.Collect(host.Driver.Remove())
	m.Collect(api.Remove(constants.MachineName))
	return m.ToError()
}

// GetHostStatus gets the status of the host VM.
func GetHostStatus(api libmachine.API) (string, error) {
	dne := "Does Not Exist"
	exists, err := api.Exists(constants.MachineName)
	if err != nil {
		return "", err
	}
	if !exists {
		return dne, nil
	}

	host, err := api.Load(constants.MachineName)
	if err != nil {
		return "", err
	}

	s, err := host.Driver.GetState()
	if s.String() == "" {
		return dne, err
	}
	return s.String(), err
}

type sshAble interface {
	RunSSHCommand(string) (string, error)
}

// MachineConfig contains the parameters used to start a cluster.
type MachineConfig struct {
	MinikubeISO string
	Memory      int
	CPUs        int
	VMDriver    string
}

// StartCluster starts a k8s cluster on the specified Host.
func StartCluster(h sshAble) error {
	commands := []string{stopCommand, GetStartCommand()}

	for _, cmd := range commands {
		glog.Infoln(cmd)
		output, err := h.RunSSHCommand(cmd)
		glog.Infoln(output)
		if err != nil {
			return err
		}
	}

	return nil
}

type fileToCopy struct {
	AssetName   string
	TargetDir   string
	TargetName  string
	Permissions string
}

var assets = []fileToCopy{
	{
		AssetName:   "out/localkube",
		TargetDir:   "/usr/local/bin",
		TargetName:  "localkube",
		Permissions: "0777",
	},
	{
		AssetName:   "deploy/iso/addon-manager.yaml",
		TargetDir:   "/etc/kubernetes/manifests/",
		TargetName:  "addon-manager.yaml",
		Permissions: "0640",
	},
	{
		AssetName:   "deploy/addons/dashboard-rc.yaml",
		TargetDir:   "/etc/kubernetes/addons/",
		TargetName:  "dashboard-rc.yaml",
		Permissions: "0640",
	},
	{
		AssetName:   "deploy/addons/dashboard-svc.yaml",
		TargetDir:   "/etc/kubernetes/addons/",
		TargetName:  "dashboard-svc.yaml",
		Permissions: "0640",
	},
}

func UpdateCluster(d drivers.Driver) error {
	client, err := sshutil.NewSSHClient(d)
	if err != nil {
		return err
	}

	for _, a := range assets {
		contents, err := Asset(a.AssetName)
		if err != nil {
			glog.Infof("Error loading asset %s: %s", a.AssetName, err)
			return err
		}

		if err := sshutil.Transfer(contents, a.TargetDir, a.TargetName, a.Permissions, client); err != nil {
			return err
		}
	}
	return nil
}

// SetupCerts gets the generated credentials required to talk to the APIServer.
func SetupCerts(d drivers.Driver) error {
	localPath := constants.Minipath
	ipStr, err := d.GetIP()
	if err != nil {
		return err
	}
	glog.Infoln("Setting up certificates for IP: %s", ipStr)

	ip := net.ParseIP(ipStr)
	publicPath := filepath.Join(localPath, "apiserver.crt")
	privatePath := filepath.Join(localPath, "apiserver.key")
	if err := GenerateCerts(publicPath, privatePath, ip); err != nil {
		return err
	}

	client, err := sshutil.NewSSHClient(d)
	if err != nil {
		return err
	}

	for _, cert := range certs {
		p := filepath.Join(localPath, cert)
		data, err := ioutil.ReadFile(p)
		if err != nil {
			return err
		}
		if err := sshutil.Transfer(data, util.DefaultCertPath, cert, "0644", client); err != nil {
			return err
		}
	}
	return nil
}

func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
	var driver interface{}

	switch config.VMDriver {
	case "virtualbox":
		d := virtualbox.NewDriver(constants.MachineName, constants.Minipath)
		d.Boot2DockerURL = config.MinikubeISO
		d.Memory = config.Memory
		d.CPU = config.CPUs
		driver = d
	case "vmwarefusion":
		driver = createVMwareFusionHost(config)
	case "kvm":
		driver = createKVMHost(config)
	case "xhyve":
		driver = createXhyveHost(config)
	default:
		glog.Exitf("Unsupported driver: %s\n", config.VMDriver)
	}

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

	h, err := api.NewHost(config.VMDriver, data)
	if err != nil {
		return nil, fmt.Errorf("Error creating new host: %s", err)
	}

	h.HostOptions.AuthOptions.CertDir = constants.Minipath
	h.HostOptions.AuthOptions.StorePath = constants.Minipath
	h.HostOptions.EngineOptions = &engine.Options{}

	if err := api.Create(h); err != nil {
		// Wait for all the logs to reach the client
		time.Sleep(2 * time.Second)
		return nil, fmt.Errorf("Error creating. %s", err)
	}

	if err := api.Save(h); err != nil {
		return nil, fmt.Errorf("Error attempting to save store: %s", err)
	}
	return h, nil
}

// GetHostDockerEnv gets the necessary docker env variables to allow the use of docker through minikube's vm
func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return nil, err
	}
	ip, err := host.Driver.GetIP()
	if err != nil {
		return nil, err
	}

	tcpPrefix := "tcp://"
	portDelimiter := ":"
	port := "2376"

	envMap := map[string]string{
		"DOCKER_TLS_VERIFY": "1",
		"DOCKER_HOST":       tcpPrefix + ip + portDelimiter + port,
		"DOCKER_CERT_PATH":  constants.MakeMiniPath("certs"),
	}
	return envMap, nil
}

// GetHostLogs gets the localkube logs of the host VM.
func GetHostLogs(api libmachine.API) (string, error) {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return "", err
	}
	s, err := host.RunSSHCommand(logsCommand)
	if err != nil {
		return "", nil
	}
	return s, err
}

func checkIfApiExistsAndLoad(api libmachine.API) (*host.Host, error) {
	exists, err := api.Exists(constants.MachineName)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, fmt.Errorf("Machine does not exist for api.Exists(%s)", constants.MachineName)
	}

	host, err := api.Load(constants.MachineName)
	if err != nil {
		return nil, err
	}
	return host, nil
}

func CreateSSHShell(api libmachine.API, args []string) error {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return err
	}

	currentState, err := host.Driver.GetState()
	if err != nil {
		return err
	}

	if currentState != state.Running {
		return fmt.Errorf("Error: Cannot run ssh command: Host %q is not running", constants.MachineName)
	}

	client, err := host.CreateSSHClient()
	if err != nil {
		return err
	}
	return client.Shell(strings.Join(args, " "))
}

func GetServiceURL(api libmachine.API, namespace, service string) (string, error) {
	host, err := checkIfApiExistsAndLoad(api)
	if err != nil {
		return "", err
	}

	ip, err := host.Driver.GetIP()
	if err != nil {
		return "", err
	}

	port, err := getServicePort(namespace, service)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("http://%s:%d", ip, port), nil
}

type serviceGetter interface {
	Get(name string) (*kubeApi.Service, error)
}

func getServicePort(namespace, service string) (int, error) {
	services, err := getKubernetesServicesWithNamespace(namespace)
	if err != nil {
		return 0, err
	}
	return getServicePortFromServiceGetter(services, service)
}

func getServicePortFromServiceGetter(services serviceGetter, service string) (int, error) {
	svc, err := services.Get(service)
	if err != nil {
		return 0, fmt.Errorf("Error getting %s service: %s", service, err)
	}
	return int(svc.Spec.Ports[0].NodePort), nil
}

func getKubernetesServicesWithNamespace(namespace string) (serviceGetter, error) {
	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
	configOverrides := &clientcmd.ConfigOverrides{}
	kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
	config, err := kubeConfig.ClientConfig()
	if err != nil {
		return nil, fmt.Errorf("Error creating kubeConfig: %s", err)
	}
	client, err := unversioned.New(config)
	if err != nil {
		return nil, err
	}
	services := client.Services(namespace)
	return services, nil
}
<|endoftext|>


<commit_before>package trie

import "errors"

type altBranch struct {
	letter rune
	branch *altTrie
}

type altTrie struct {
	value     interface{}
	validLeaf bool
	children  []altBranch
}

// Alt returns an alternate implementation of a Trie, which is slightly faster for searching. Useful for Tries that are created and then infrequently changed.
func Alt() *altTrie {
	return &altTrie{nil, false, nil}
}

func (t altTrie) getChild(r rune) int {
	for i, child := range t.children {
		if child.letter == r {
			return i
		}
	}
	return -1
}

// Add an element to the Trie, mapped to the given value.
func (t *altTrie) Add(key string, val interface{}) error {
	runes := []rune(key)
	exists := t.add(runes, val)

	if exists {
		return errors.New("key already exists")
	}

	return nil
}

func (t *altTrie) add(r []rune, val interface{}) bool {
	if len(r) == 0 {
		return false
	}

	if i := t.getChild(r[0]); i != -1 {
		if len(r) > 1 {
			return t.children[i].branch.add(r[1:], val)
		}
		if t.children[i].branch.validLeaf {
			return true
		}
		child := t.children[i].branch
		child.validLeaf = true
		child.value = val
	} else {
		if len(r) > 1 {
			child := altBranch{
				r[0],
				&altTrie{},
			}
			t.children = append(t.children, child)

			return child.branch.add(r[1:], val)
		}
		t.children = append(t.children, altBranch{
			r[0],
			&altTrie{val, true, nil},
		})
	}
	return false
}

// Get a value from the Trie.
// Uses a comma ok format.
func (t *altTrie) Get(key string) (interface{}, bool) {
	if len(key) == 0 {
		return nil, false
	}
	return t.get([]rune(key))
}

func (t *altTrie) get(key []rune) (interface{}, bool) {
	if len(key) == 0 {
		return t.value, t.validLeaf
	}
	if i := t.getChild(key[0]); i != -1 {
		return t.children[i].branch.get(key[1:])
	}
	return nil, false
}

// Search the Trie for all keys starting with the key.
// A full listing of the Trie is possible using t.Search("")
func (t *altTrie) Search(key string) (r []interface{}) {
	r = make([]interface{}, 0, 32)
	t.search([]rune(key), &r)
	return
}

func (t *altTrie) search(key []rune, results *[]interface{}) {
iterate:
	if len(key) == 0 {
		for _, child := range t.children {
			child.branch.search(key, results)
		}
		if t.validLeaf {
			l := len(*results)

			if l < cap(*results) {
				*results = (*results)[:l+1]
				(*results)[l] = t.value
			} else {
				oldR := *results
				*results = make([]interface{}, l+1, l*2)
				copy(*results, oldR)
				(*results)[l] = t.value
			}
		}
		return
	}
	if i := t.getChild(key[0]); i != -1 {
		t = t.children[i].branch
		key = key[1:]
		goto iterate
	}
	return
}

// Remove the key from the Trie.
// The Trie will compact itself if possible.
func (t *altTrie) Remove(key string) error {
	runes := []rune(key)

	if !t.remove(runes) {
		errors.New("key not in trie")
	}

	return nil
}

func (t *altTrie) remove(key []rune) bool {
	if len(key) == 1 {
		if i := t.getChild(key[0]); i != -1 {
			child := t.children[i].branch
			if len(child.children) == 0 {
				t.children = append(t.children[:i], t.children[i+1:]...)
			} else {
				child.validLeaf = false
				child.value = nil
			}
			return true
		}
		return false
	}

	if i := t.getChild(key[0]); i != -1 {
		child := t.children[i].branch
		ret := child.remove(key[1:])

		if !child.validLeaf && len(child.children) == 0 {
			t.children = append(t.children[:i], t.children[i+1:]...)
		}
		return ret
	}
	return false
}
<commit_msg>Tuning initial result slice size.<commit_after>package trie

import "errors"

type altBranch struct {
	letter rune
	branch *altTrie
}

type altTrie struct {
	value     interface{}
	validLeaf bool
	children  []altBranch
}

// Alt returns an alternate implementation of a Trie, which is slightly faster for searching. Useful for Tries that are created and then infrequently changed.
func Alt() *altTrie {
	return &altTrie{nil, false, nil}
}

func (t altTrie) getChild(r rune) int {
	for i, child := range t.children {
		if child.letter == r {
			return i
		}
	}
	return -1
}

// Add an element to the Trie, mapped to the given value.
func (t *altTrie) Add(key string, val interface{}) error {
	runes := []rune(key)
	exists := t.add(runes, val)

	if exists {
		return errors.New("key already exists")
	}

	return nil
}

func (t *altTrie) add(r []rune, val interface{}) bool {
	if len(r) == 0 {
		return false
	}

	if i := t.getChild(r[0]); i != -1 {
		if len(r) > 1 {
			return t.children[i].branch.add(r[1:], val)
		}
		if t.children[i].branch.validLeaf {
			return true
		}
		child := t.children[i].branch
		child.validLeaf = true
		child.value = val
	} else {
		if len(r) > 1 {
			child := altBranch{
				r[0],
				&altTrie{},
			}
			t.children = append(t.children, child)

			return child.branch.add(r[1:], val)
		}
		t.children = append(t.children, altBranch{
			r[0],
			&altTrie{val, true, nil},
		})
	}
	return false
}

// Get a value from the Trie.
// Uses a comma ok format.
func (t *altTrie) Get(key string) (interface{}, bool) {
	if len(key) == 0 {
		return nil, false
	}
	return t.get([]rune(key))
}

func (t *altTrie) get(key []rune) (interface{}, bool) {
	if len(key) == 0 {
		return t.value, t.validLeaf
	}
	if i := t.getChild(key[0]); i != -1 {
		return t.children[i].branch.get(key[1:])
	}
	return nil, false
}

// Search the Trie for all keys starting with the key.
// A full listing of the Trie is possible using t.Search("")
func (t *altTrie) Search(key string) (r []interface{}) {
	r = make([]interface{}, 0, 64)
	t.search([]rune(key), &r)
	return
}

func (t *altTrie) search(key []rune, results *[]interface{}) {
iterate:
	if len(key) == 0 {
		for _, child := range t.children {
			child.branch.search(key, results)
		}
		if t.validLeaf {
			l := len(*results)

			if l < cap(*results) {
				*results = (*results)[:l+1]
				(*results)[l] = t.value
			} else {
				oldR := *results
				*results = make([]interface{}, l+1, l*2)
				copy(*results, oldR)
				(*results)[l] = t.value
			}
		}
		return
	}
	if i := t.getChild(key[0]); i != -1 {
		t = t.children[i].branch
		key = key[1:]
		goto iterate
	}
	return
}

// Remove the key from the Trie.
// The Trie will compact itself if possible.
func (t *altTrie) Remove(key string) error {
	runes := []rune(key)

	if !t.remove(runes) {
		errors.New("key not in trie")
	}

	return nil
}

func (t *altTrie) remove(key []rune) bool {
	if len(key) == 1 {
		if i := t.getChild(key[0]); i != -1 {
			child := t.children[i].branch
			if len(child.children) == 0 {
				t.children = append(t.children[:i], t.children[i+1:]...)
			} else {
				child.validLeaf = false
				child.value = nil
			}
			return true
		}
		return false
	}

	if i := t.getChild(key[0]); i != -1 {
		child := t.children[i].branch
		ret := child.remove(key[1:])

		if !child.validLeaf && len(child.children) == 0 {
			t.children = append(t.children[:i], t.children[i+1:]...)
		}
		return ret
	}
	return false
}
<|endoftext|>


<commit_before>//High-level functionality

package trion

import (
	"polydawn.net/dockctrl/crocker"
	. "fmt"
)

const ExportPath = "./" //Where to export docker images

//Helps run anyything that requires a docker connection.
//Handles creation & cleanup in one place.
func WithDocker(fn func(TrionConfig, *crocker.Dock, *Command) error ) error {
	//Load configuration, then find or start a docker
	config := FindConfig(".")
	dock, dir, ours := crocker.FindDock()
	cmd := &Command{dock.Client()}

	//Announce the docker
	if ours {
		Println("Started a docker in", dir)
	} else {
		Println("Connecting to docker", dir)
	}

	//Run the closure, kill the docker if needed, and return any errors.
	err := fn(config, dock, cmd)
	dock.Slay()
	return err
}

//Launches a docker
func Launch(config TrionConfig, dock *crocker.Dock, cmd *Command) error {
	//Start the docker and wait for it to finish
	CID := cmd.Run(config)
	cmd.Wait(CID)

	//Remove if desired
	if config.Purge {
		cmd.Purge(CID)
	}

	return nil
}

//Builds a docker
func Build(config TrionConfig, dock *crocker.Dock, cmd *Command) error {
	//Use the build command and upstream image
	buildConfig        := config
	buildConfig.Command = config.Build
	buildConfig.Image   = config.Upstream

	//Run the build
	CID := cmd.Run(buildConfig)
	cmd.Wait(CID)

	//Create a tar
	cmd.Export(CID, ExportPath)

	//Import the built docker
	// Todo: add --noImport option to goflags
	cmd.Import(config, ExportPath)

	//Remove if desired
	if config.Purge {
		cmd.Purge(CID)
	}

	return nil
}
<commit_msg>remove unused variables.<commit_after>//High-level functionality

package trion

import (
	"polydawn.net/dockctrl/crocker"
	. "fmt"
)

const ExportPath = "./" //Where to export docker images

//Helps run anyything that requires a docker connection.
//Handles creation & cleanup in one place.
func WithDocker(fn func(TrionConfig, *Command) error ) error {
	//Load configuration, then find or start a docker
	config := FindConfig(".")
	dock, dir, ours := crocker.FindDock()
	cmd := &Command{dock.Client()}

	//Announce the docker
	if ours {
		Println("Started a docker in", dir)
	} else {
		Println("Connecting to docker", dir)
	}

	//Run the closure, kill the docker if needed, and return any errors.
	err := fn(config, cmd)
	dock.Slay()
	return err
}

//Launches a docker
func Launch(config TrionConfig, cmd *Command) error {
	//Start the docker and wait for it to finish
	CID := cmd.Run(config)
	cmd.Wait(CID)

	//Remove if desired
	if config.Purge {
		cmd.Purge(CID)
	}

	return nil
}

//Builds a docker
func Build(config TrionConfig, cmd *Command) error {
	//Use the build command and upstream image
	buildConfig        := config
	buildConfig.Command = config.Build
	buildConfig.Image   = config.Upstream

	//Run the build
	CID := cmd.Run(buildConfig)
	cmd.Wait(CID)

	//Create a tar
	cmd.Export(CID, ExportPath)

	//Import the built docker
	// Todo: add --noImport option to goflags
	cmd.Import(config, ExportPath)

	//Remove if desired
	if config.Purge {
		cmd.Purge(CID)
	}

	return nil
}
<|endoftext|>