<commit_before>package goapp

import (
	"fmt"
)

// The structure contains all services build by the AppFunc function, the service is initialized when get Get
// method is called.
type App struct {
	state    int
	values   map[string]AppFunc     // contains the original closure to generate the service
	services map[string]interface{} // contains the instantiated services
}

type AppFunc func(app *App) interface{}

func (app *App) Set(name string, f AppFunc) {
	if _, ok := app.services[name]; ok {
		panic("Cannot overwrite initialized service")
	}

	app.values[name] = f
}

func (app *App) Get(name string) interface{} {
	if _, ok := app.values[name]; !ok {
		panic(fmt.Sprintf("The service does not exist: %s", name))
	}

	if _, ok := app.services[name]; !ok {
		app.services[name] = app.values[name](app)
	}

	return app.services[name]
}

func (app *App) GetString(name string) interface{} {
	return app.Get(name).(string)
}

func NewApp() *App {
	app := App{
		services: make(map[string]interface{}),
		values:   make(map[string]AppFunc),
	}

	return &app
}

<commit_msg>add methods to retrieve the state of the current app<commit_after>package goapp

import (
	"fmt"
)

// The structure contains all services build by the AppFunc function, the service is initialized when get Get
// method is called.
type App struct {
	state    int
	values   map[string]AppFunc     // contains the original closure to generate the service
	services map[string]interface{} // contains the instantiated services
}

type AppFunc func(app *App) interface{}

func NewApp() *App {
	app := App{
		services: make(map[string]interface{}),
		values:   make(map[string]AppFunc),
	}

	return &app
}

func (app *App) Set(name string, f AppFunc) {
	if _, ok := app.services[name]; ok {
		panic("Cannot overwrite initialized service")
	}

	app.values[name] = f
}

func (app *App) Get(name string) interface{} {
	if _, ok := app.values[name]; !ok {
		panic(fmt.Sprintf("The service does not exist: %s", name))
	}

	if _, ok := app.services[name]; !ok {
		app.services[name] = app.values[name](app)
	}

	return app.services[name]
}

func (app *App) GetString(name string) interface{} {
	return app.Get(name).(string)
}

func (app *App) GetState() int {
	return app.state
}

func (app *App) IsTerminated() bool {
	return app.state == Terminated
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"

	"fmt"
	"strconv"
	"time"

	"github.com/Financial-Times/base-ft-rw-app-go/baseftrwapp"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/http-handlers-go/httphandlers"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/Financial-Times/public-people-api/people"
	status "github.com/Financial-Times/service-status-go/httphandlers"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	"github.com/rcrowley/go-metrics"
)

func main() {
	app := cli.App("public-people-api-neo4j", "A public RESTful API for accessing People in neo4j")
	neoURL := app.String(cli.StringOpt{
		Name:   "neo-url",
		Value:  "http://localhost:7474/db/data",
		Desc:   "neo4j endpoint URL",
		EnvVar: "NEO_URL",
	})
	logLevel := app.String(cli.StringOpt{
		Name:   "log-level",
		Value:  "INFO",
		Desc:   "Log level to use",
		EnvVar: "LOG_LEVEL",
	})
	port := app.String(cli.StringOpt{
		Name:   "port",
		Value:  "8080",
		Desc:   "Port to listen on",
		EnvVar: "APP_PORT",
	})
	graphiteTCPAddress := app.String(cli.StringOpt{
		Name:   "graphiteTCPAddress",
		Value:  "",
		Desc:   "Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally)",
		EnvVar: "GRAPHITE_ADDRESS",
	})
	graphitePrefix := app.String(cli.StringOpt{
		Name:   "graphitePrefix",
		Value:  "",
		Desc:   "Prefix to use. Should start with content, include the environment, and the host name. e.g. content.test.public.content.by.concept.api.ftaps59382-law1a-eu-t",
		EnvVar: "GRAPHITE_PREFIX",
	})
	logMetrics := app.Bool(cli.BoolOpt{
		Name:   "logMetrics",
		Value:  false,
		Desc:   "Whether to log metrics. Set to true if running locally and you want metrics output",
		EnvVar: "LOG_METRICS",
	})
	env := app.String(cli.StringOpt{
		Name:  "env",
		Value: "local",
		Desc:  "environment this app is running in",
	})
	cacheDuration := app.String(cli.StringOpt{
		Name:   "cache-duration",
		Value:  "30s",
		Desc:   "Duration Get requests should be cached for. e.g. 2h45m would set the max-age value to '7440' seconds",
		EnvVar: "CACHE_DURATION",
	})

	app.Action = func() {
		parsedLogLevel, err := log.ParseLevel(*logLevel)
		if err != nil {
			log.WithFields(log.Fields{"logLevel": logLevel, "err": err}).Fatal("Incorrect log level")
		}
		log.SetLevel(parsedLogLevel)

		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)

		log.Infof("public-people-api will listen on port: %s, connecting to: %s", *port, *neoURL)
		runServer(*neoURL, *port, *cacheDuration, *env)
	}
	log.Infof("Application started with args %s", os.Args)
	app.Run(os.Args)
}

func runServer(neoURL string, port string, cacheDuration string, env string) {

	if duration, durationErr := time.ParseDuration(cacheDuration); durationErr != nil {
		log.Fatalf("Failed to parse cache duration string, %v", durationErr)
	} else {
		people.CacheControlHeader = fmt.Sprintf("max-age=%s, public", strconv.FormatFloat(duration.Seconds(), 'f', 0, 64))
	}

	conf := neoutils.DefaultConnectionConfig()
	db, err := neoutils.Connect(neoURL, conf)

	if err != nil {
		log.Fatalf("Error connecting to neo4j %s", err)
	}

	people.PeopleDriver = people.NewCypherDriver(db, env)

	servicesRouter := mux.NewRouter()

	// Health checks and standards first
	servicesRouter.HandleFunc("/__health", v1a.Handler("PeopleReadWriteNeo4j Healthchecks",
		"Checks for accessing neo4j", people.HealthCheck()))

	// Then API specific ones:
	servicesRouter.HandleFunc("/people/{uuid}", people.GetPerson).Methods("GET")
	servicesRouter.HandleFunc("/people/{uuid}", people.MethodNotAllowedHandler)

	var monitoringRouter http.Handler = servicesRouter
	monitoringRouter = httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), monitoringRouter)
	monitoringRouter = httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry, monitoringRouter)

	// The following endpoints should not be monitored or logged (varnish calls one of these every second, depending on config)
	// The top one of these build info endpoints feels more correct, but the lower one matches what we have in Dropwizard,
	// so it's what apps expect currently same as ping, the content of build-info needs more definition
	http.HandleFunc(status.PingPath, status.PingHandler)
	http.HandleFunc(status.PingPathDW, status.PingHandler)
	http.HandleFunc(status.BuildInfoPath, status.BuildInfoHandler)
	http.HandleFunc(status.BuildInfoPathDW, status.BuildInfoHandler)
	http.HandleFunc("/__gtg", people.GoodToGo)
	http.Handle("/", monitoringRouter)

	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatalf("Unable to start server: %v", err)
	}
}
<commit_msg>Turn off transactions so load balancing doesn't break the read<commit_after>package main

import (
	"net/http"
	"os"

	"fmt"
	"strconv"
	"time"

	"github.com/Financial-Times/base-ft-rw-app-go/baseftrwapp"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/http-handlers-go/httphandlers"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/Financial-Times/public-people-api/people"
	status "github.com/Financial-Times/service-status-go/httphandlers"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	"github.com/rcrowley/go-metrics"
)

func main() {
	app := cli.App("public-people-api-neo4j", "A public RESTful API for accessing People in neo4j")
	neoURL := app.String(cli.StringOpt{
		Name:   "neo-url",
		Value:  "http://localhost:7474/db/data",
		Desc:   "neo4j endpoint URL",
		EnvVar: "NEO_URL",
	})
	logLevel := app.String(cli.StringOpt{
		Name:   "log-level",
		Value:  "INFO",
		Desc:   "Log level to use",
		EnvVar: "LOG_LEVEL",
	})
	port := app.String(cli.StringOpt{
		Name:   "port",
		Value:  "8080",
		Desc:   "Port to listen on",
		EnvVar: "APP_PORT",
	})
	graphiteTCPAddress := app.String(cli.StringOpt{
		Name:   "graphiteTCPAddress",
		Value:  "",
		Desc:   "Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally)",
		EnvVar: "GRAPHITE_ADDRESS",
	})
	graphitePrefix := app.String(cli.StringOpt{
		Name:   "graphitePrefix",
		Value:  "",
		Desc:   "Prefix to use. Should start with content, include the environment, and the host name. e.g. content.test.public.content.by.concept.api.ftaps59382-law1a-eu-t",
		EnvVar: "GRAPHITE_PREFIX",
	})
	logMetrics := app.Bool(cli.BoolOpt{
		Name:   "logMetrics",
		Value:  false,
		Desc:   "Whether to log metrics. Set to true if running locally and you want metrics output",
		EnvVar: "LOG_METRICS",
	})
	env := app.String(cli.StringOpt{
		Name:  "env",
		Value: "local",
		Desc:  "environment this app is running in",
	})
	cacheDuration := app.String(cli.StringOpt{
		Name:   "cache-duration",
		Value:  "30s",
		Desc:   "Duration Get requests should be cached for. e.g. 2h45m would set the max-age value to '7440' seconds",
		EnvVar: "CACHE_DURATION",
	})

	app.Action = func() {
		parsedLogLevel, err := log.ParseLevel(*logLevel)
		if err != nil {
			log.WithFields(log.Fields{"logLevel": logLevel, "err": err}).Fatal("Incorrect log level")
		}
		log.SetLevel(parsedLogLevel)

		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)

		log.Infof("public-people-api will listen on port: %s, connecting to: %s", *port, *neoURL)
		runServer(*neoURL, *port, *cacheDuration, *env)
	}
	log.Infof("Application started with args %s", os.Args)
	app.Run(os.Args)
}

func runServer(neoURL string, port string, cacheDuration string, env string) {

	if duration, durationErr := time.ParseDuration(cacheDuration); durationErr != nil {
		log.Fatalf("Failed to parse cache duration string, %v", durationErr)
	} else {
		people.CacheControlHeader = fmt.Sprintf("max-age=%s, public", strconv.FormatFloat(duration.Seconds(), 'f', 0, 64))
	}

	conf := neoutils.ConnectionConfig{
		BatchSize:     1024,
		Transactional: false,
		HTTPClient: &http.Client{
			Transport: &http.Transport{
				MaxIdleConnsPerHost: 100,
			},
			Timeout: 1 * time.Minute,
		},
		BackgroundConnect: true,
	}
	db, err := neoutils.Connect(neoURL, &conf)

	if err != nil {
		log.Fatalf("Error connecting to neo4j %s", err)
	}

	people.PeopleDriver = people.NewCypherDriver(db, env)

	servicesRouter := mux.NewRouter()

	// Health checks and standards first
	servicesRouter.HandleFunc("/__health", v1a.Handler("PeopleReadWriteNeo4j Healthchecks",
		"Checks for accessing neo4j", people.HealthCheck()))

	// Then API specific ones:
	servicesRouter.HandleFunc("/people/{uuid}", people.GetPerson).Methods("GET")
	servicesRouter.HandleFunc("/people/{uuid}", people.MethodNotAllowedHandler)

	var monitoringRouter http.Handler = servicesRouter
	monitoringRouter = httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), monitoringRouter)
	monitoringRouter = httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry, monitoringRouter)

	// The following endpoints should not be monitored or logged (varnish calls one of these every second, depending on config)
	// The top one of these build info endpoints feels more correct, but the lower one matches what we have in Dropwizard,
	// so it's what apps expect currently same as ping, the content of build-info needs more definition
	http.HandleFunc(status.PingPath, status.PingHandler)
	http.HandleFunc(status.PingPathDW, status.PingHandler)
	http.HandleFunc(status.BuildInfoPath, status.BuildInfoHandler)
	http.HandleFunc(status.BuildInfoPathDW, status.BuildInfoHandler)
	http.HandleFunc("/__gtg", people.GoodToGo)
	http.Handle("/", monitoringRouter)

	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatalf("Unable to start server: %v", err)
	}
}
<|endoftext|>


<commit_before>package gogadgets

import (
	"log"
	"fmt"
)

type App struct {
	gadgets []GoGadget
	masterHost string
	pubPort int
	subPort int
	channels map[string]chan Message
}

func NewApp(config *Config) *App {
	gadgets := GetGadgets(config.Gadgets)
	if  config.PubPort == 0 {
		config.SubPort = 6111
		config.PubPort = 6112
	}
	return &App{
		masterHost: config.MasterHost,
		pubPort: config.PubPort,
		subPort: config.SubPort,
		gadgets: gadgets,
	}
}

func GetGadgets(configs []GadgetConfig) []GoGadget {
	g := make([]GoGadget, len(configs))
	for i, config := range configs {
		gadget, err := NewGadget(&config)
		if err != nil {
			log.Println(err)
		}
		g[i] = gadget
	}
	return g
}

func (a *App) Start(stop <-chan bool) {
	a.gadgets = append(a.gadgets, &Runner{})
	sockets := &Sockets{
		masterHost: a.masterHost,
		pubPort: a.pubPort,
		subPort: a.subPort,
	}
	a.gadgets = append(a.gadgets, sockets)
	in := make(chan Message)
	a.channels = make(map[string]chan Message)
	for _, gadget := range a.gadgets {
		out := make(chan Message, 100)
		a.channels[gadget.GetUID()] = out
		go gadget.Start(out, collector)
	}
	keepRunning := true
	log.Println("started gagdgets")
	time.Sleep(100 * time.Millisecond)
	for keepRunning {
		msg := <-in:
		go a.sendMessage(msg)
	}
}

func (a *App) sendMessage(msg Message) {
	if msg.Target == "" {
		for uid, channel := range a.channels {
			if uid != msg.Sender {
				fmt.Println(uid)
				channel<- msg
				fmt.Println(uid)
			}
		}
	} else {
		channel, ok := a.channels[msg.Target]
		if ok {
			channel<- msg
		}
	}
}

func (a *App) AddGadget(gadget GoGadget) {
	a.gadgets = append(a.gadgets, gadget)
}
<commit_msg>fixed error<commit_after>package gogadgets

import (
	"log"
	"fmt"
)

type App struct {
	gadgets []GoGadget
	masterHost string
	pubPort int
	subPort int
	channels map[string]chan Message
}

func NewApp(config *Config) *App {
	gadgets := GetGadgets(config.Gadgets)
	if  config.PubPort == 0 {
		config.SubPort = 6111
		config.PubPort = 6112
	}
	return &App{
		masterHost: config.MasterHost,
		pubPort: config.PubPort,
		subPort: config.SubPort,
		gadgets: gadgets,
	}
}

func GetGadgets(configs []GadgetConfig) []GoGadget {
	g := make([]GoGadget, len(configs))
	for i, config := range configs {
		gadget, err := NewGadget(&config)
		if err != nil {
			log.Println(err)
		}
		g[i] = gadget
	}
	return g
}

func (a *App) Start(stop <-chan bool) {
	a.gadgets = append(a.gadgets, &Runner{})
	sockets := &Sockets{
		masterHost: a.masterHost,
		pubPort: a.pubPort,
		subPort: a.subPort,
	}
	a.gadgets = append(a.gadgets, sockets)
	in := make(chan Message)
	a.channels = make(map[string]chan Message)
	for _, gadget := range a.gadgets {
		out := make(chan Message, 100)
		a.channels[gadget.GetUID()] = out
		go gadget.Start(out, in)
	}
	keepRunning := true
	log.Println("started gagdgets")
	for keepRunning {
		msg := <-in
		go a.sendMessage(msg)
	}
}

func (a *App) sendMessage(msg Message) {
	if msg.Target == "" {
		for uid, channel := range a.channels {
			if uid != msg.Sender {
				fmt.Println(uid)
				channel<- msg
				fmt.Println(uid)
			}
		}
	} else {
		channel, ok := a.channels[msg.Target]
		if ok {
			channel<- msg
		}
	}
}

func (a *App) AddGadget(gadget GoGadget) {
	a.gadgets = append(a.gadgets, gadget)
}
<|endoftext|>


<commit_before>package kubernetes_test

import (
	"log"
	"net/http"

	"golang.org/x/build/kubernetes"
	"golang.org/x/build/kubernetes/api"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
)

func ExampleRunPod() {
	kube, err := kubernetes.NewClient("https://example.com", &http.Client{
		Transport: &oauth2.Transport{
			Source: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: "aCcessWbU3toKen"}),
		},
	})
	if err != nil {
		log.Fatalf("failed to create client: %v", err)
	}
	podResult, err := kube.RunLongLivedPod(context.Background(), &api.Pod{
		TypeMeta: api.TypeMeta{
			APIVersion: "v1",
			Kind:       "Pod",
		},
		ObjectMeta: api.ObjectMeta{
			Name: "redis-pod-example",
			Labels: map[string]string{
				"tag": "prod",
			},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Name:  "redis-container",
					Image: "redis:alpine",
				},
			},
		},
	})
	if err != nil {
		log.Fatalf("failed to run pod: %v", err)
	}
	log.Printf("pod created: %#v", podResult)
	logs, err := kube.PodLog(context.Background(), "redis-pod-example")
	if err != nil {
		log.Fatalf("failed to get pod logs: %v", err)
	}
	log.Printf("pod logs: %q", logs)
}
<commit_msg>kubernetes: add basic tests<commit_after>package kubernetes_test

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"golang.org/x/build/kubernetes"
	"golang.org/x/build/kubernetes/api"
	"golang.org/x/net/context"
)

type handlers []func(w http.ResponseWriter, r *http.Request) error

func newTestPod() *api.Pod {
	return &api.Pod{
		TypeMeta: api.TypeMeta{
			APIVersion: "v1",
			Kind:       "Pod",
		},
		ObjectMeta: api.ObjectMeta{
			Name: "test-pod",
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Name:  "test-container",
					Image: "test-image:latest",
				},
			},
		},
	}
}

func (hs *handlers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if len(*hs) == 0 {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "unexpected request: %v", r)
		return
	}
	h := (*hs)[0]
	*hs = (*hs)[1:]
	if err := h(w, r); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "unexpected error: %v", err)
		return
	}
}

func TestRunPod(t *testing.T) {
	hs := handlers{
		func(w http.ResponseWriter, r *http.Request) error {
			if r.Method != http.MethodPost {
				return fmt.Errorf("expected %q, got %q", http.MethodPost, r.Method)

			}
			w.WriteHeader(http.StatusCreated)
			json.NewEncoder(w).Encode(newTestPod())
			return nil
		},
		func(w http.ResponseWriter, r *http.Request) error {
			if r.Method != http.MethodGet {
				return fmt.Errorf("expected %q, got %q", http.MethodGet, r.Method)
			}
			w.WriteHeader(http.StatusOK)
			readyPod := newTestPod()
			readyPod.Status.Phase = api.PodRunning
			json.NewEncoder(w).Encode(readyPod)
			return nil
		},
	}
	s := httptest.NewServer(&hs)
	defer s.Close()

	c, err := kubernetes.NewClient(s.URL, http.DefaultClient)
	if err != nil {
		t.Fatalf("NewClient: %v", err)
	}
	ps, err := c.RunLongLivedPod(context.Background(), newTestPod())
	if err != nil {
		t.Fatalf("RunLongLivePod: %v", err)
	}
	if ps.Phase != api.PodRunning {
		t.Fatalf("Pod phase = %q; want %q", ps.Phase, api.PodRunning)
	}
	if len(hs) != 0 {
		t.Fatalf("failed to process all expected requests: %d left", len(hs))
	}
}
<|endoftext|>


<commit_before>package e2e

import (
	"context"
	"testing"
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	kclientset "k8s.io/client-go/kubernetes"
)

type Tester struct {
	client           kclientset.Interface
	namespace        string
	podName          string
	errorPassThrough bool
	t                *testing.T
}

func NewTester(client kclientset.Interface, ns string, t *testing.T) *Tester {
	return &Tester{client: client, namespace: ns, t: t}
}

// createExecPod creates a simple centos:7 pod in a sleep loop used as a
// vessel for kubectl exec commands.
// Returns the name of the created pod.
func (ut *Tester) CreateExecPod(name, cmd string) {
	client := ut.client.CoreV1()
	_, err := client.Pods(ut.namespace).Get(context.Background(), name, metav1.GetOptions{})
	if err == nil {
		ut.t.Log("curl job logs pod already exists")
		return
	}
	ut.t.Logf("Creating new curl pod")
	immediate := int64(0)
	execPod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: ut.namespace,
		},
		Spec: v1.PodSpec{
			ServiceAccountName: "jenkins",
			Containers: []v1.Container{
				{
					Command:         []string{"/bin/bash", "-c", cmd},
					Name:            "hostexec",
					Image:           "centos:7",
					ImagePullPolicy: v1.PullIfNotPresent,
				},
			},
			HostNetwork:                   false,
			TerminationGracePeriodSeconds: &immediate,
		},
	}
	created, err := client.Pods(ut.namespace).Create(context.Background(), execPod, metav1.CreateOptions{})
	if err != nil {
		ut.t.Fatalf("%#v", err)
	}
	err = wait.PollImmediate(1*time.Second, 5*time.Minute, func() (bool, error) {
		retrievedPod, err := client.Pods(execPod.Namespace).Get(context.Background(), created.Name, metav1.GetOptions{})
		ut.t.Logf("get of curl pod %s got err %#v", created.Name, err)
		if err != nil {
			return false, nil
		}
		for _, status := range retrievedPod.Status.ContainerStatuses {
			ut.t.Logf("looking at pod state %#v", status.State)
			if status.State.Terminated != nil {
				return true, nil
			}
		}
		ut.t.Logf("done with container state, still cehcking")
		return false, nil
	})
	if err != nil {
		ut.t.Fatalf("%#v", err)
	}
}
<commit_msg>update curl pod to conform to tighter pod security restrictions in 4.11<commit_after>package e2e

import (
	"context"
	"testing"
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	kclientset "k8s.io/client-go/kubernetes"
)

type Tester struct {
	client           kclientset.Interface
	namespace        string
	podName          string
	errorPassThrough bool
	t                *testing.T
}

func NewTester(client kclientset.Interface, ns string, t *testing.T) *Tester {
	return &Tester{client: client, namespace: ns, t: t}
}

// createExecPod creates a simple centos:7 pod in a sleep loop used as a
// vessel for kubectl exec commands.
// Returns the name of the created pod.
func (ut *Tester) CreateExecPod(name, cmd string) {
	client := ut.client.CoreV1()
	_, err := client.Pods(ut.namespace).Get(context.Background(), name, metav1.GetOptions{})
	if err == nil {
		ut.t.Log("curl job logs pod already exists")
		return
	}
	ut.t.Logf("Creating new curl pod")
	immediate := int64(0)
	user := int64(65532)
	truVal := true
	falVal := false
	execPod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: ut.namespace,
		},
		Spec: v1.PodSpec{
			ServiceAccountName: "jenkins",
			Containers: []v1.Container{
				{
					Command:         []string{"/bin/bash", "-c", cmd},
					Name:            "hostexec",
					Image:           "quay.io/redhat-developer/test-build-simples2i:latest",
					ImagePullPolicy: v1.PullIfNotPresent,
					SecurityContext: &v1.SecurityContext{
						AllowPrivilegeEscalation: &falVal,
						Capabilities: &v1.Capabilities{
							Drop: []v1.Capability{"ALL"},
						},
						RunAsNonRoot: &truVal,
						RunAsUser:    &user,
						SeccompProfile: &v1.SeccompProfile{
							Type: v1.SeccompProfileTypeRuntimeDefault,
						},
					},
				},
			},
			HostNetwork:                   false,
			TerminationGracePeriodSeconds: &immediate,
		},
	}
	created, err := client.Pods(ut.namespace).Create(context.Background(), execPod, metav1.CreateOptions{})
	if err != nil {
		ut.t.Fatalf("%#v", err)
	}
	err = wait.PollImmediate(1*time.Second, 5*time.Minute, func() (bool, error) {
		retrievedPod, err := client.Pods(execPod.Namespace).Get(context.Background(), created.Name, metav1.GetOptions{})
		ut.t.Logf("get of curl pod %s got err %#v", created.Name, err)
		if err != nil {
			return false, nil
		}
		for _, status := range retrievedPod.Status.ContainerStatuses {
			ut.t.Logf("looking at pod state %#v", status.State)
			if status.State.Terminated != nil {
				return true, nil
			}
		}
		ut.t.Logf("done with container state, still cehcking")
		return false, nil
	})
	if err != nil {
		ut.t.Fatalf("%#v", err)
	}
}
<|endoftext|>


<commit_before>// $G $D/$F.go && $L $F.$A && ./$A.out

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

// A little test program for rational arithmetics.
// Computes a Hilbert matrix, its inverse, multiplies them
// and verifies that the product is the identity matrix.

package main

import Big "bignum"
import Fmt "fmt"

func assert(p bool) {
	if !p {
		panic("assert failed");
	}
}

var (
	Zero = Big.Rat(0, 1);
	One = Big.Rat(1, 1);
)

type Matrix struct {
	n, m int;
	a []*Big.Rational;
}

func (a *Matrix) at(i, j int) *Big.Rational {
	assert(0 <= i && i < a.n && 0 <= j && j < a.m);
	return a.a[i*a.m + j];
}

func (a *Matrix) set(i, j int, x *Big.Rational) {
	assert(0 <= i && i < a.n && 0 <= j && j < a.m);
	a.a[i*a.m + j] = x;
}

func NewMatrix(n, m int) *Matrix {
	assert(0 <= n && 0 <= m);
	a := new(Matrix);
	a.n = n;
	a.m = m;
	a.a = make([]*Big.Rational, n*m);
	return a;
}

func NewUnit(n int) *Matrix {
	a := NewMatrix(n, n);
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			x := Zero;
			if i == j {
				x = One;
			}
			a.set(i, j, x);
		}
	}
	return a;
}

func NewHilbert(n int) *Matrix {
	a := NewMatrix(n, n);
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			x := Big.Rat(1, i + j + 1);
			a.set(i, j, x);
		}
	}
	return a;
}

func MakeRat(x Big.Natural) *Big.Rational {
	return Big.MakeRat(Big.MakeInt(false, x), Big.Nat(1));
}

func NewInverseHilbert(n int) *Matrix {
	a := NewMatrix(n, n);
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			x0 := One;
			if (i+j)&1 != 0 {
				x0 = x0.Neg();
			}
			x1 := Big.Rat(i + j + 1, 1);
			x2 := MakeRat(Big.Binomial(uint(n+i), uint(n-j-1)));
			x3 := MakeRat(Big.Binomial(uint(n+j), uint(n-i-1)));
			x4 := MakeRat(Big.Binomial(uint(i+j), uint(i)));
			x4 = x4.Mul(x4);
			a.set(i, j, x0.Mul(x1).Mul(x2).Mul(x3).Mul(x4));
		}
	}
	return a;
}

func (a *Matrix) Mul(b *Matrix) *Matrix {
	assert(a.m == b.n);
	c := NewMatrix(a.n, b.m);
	for i := 0; i < c.n; i++ {
		for j := 0; j < c.m; j++ {
			x := Zero;
			for k := 0; k < a.m; k++ {
				x = x.Add(a.at(i, k).Mul(b.at(k, j)));
			}
			c.set(i, j, x);
		}
	}
	return c;
}

func (a *Matrix) Eql(b *Matrix) bool {
	if a.n != b.n || a.m != b.m {
		return false;
	}
	for i := 0; i < a.n; i++ {
		for j := 0; j < a.m; j++ {
			if a.at(i, j).Cmp(b.at(i,j)) != 0 {
				return false;
			}
		}
	}
	return true;
}

func (a *Matrix) String() string {
	s := "";
	for i := 0; i < a.n; i++ {
		for j := 0; j < a.m; j++ {
			s += Fmt.Sprintf("\t%s", a.at(i, j));
		}
		s += "\n";
	}
	return s;
}

func main() {
	n := 10;
	a := NewHilbert(n);
	b := NewInverseHilbert(n);
	I := NewUnit(n);
	ab := a.Mul(b);
	if !ab.Eql(I) {
		Fmt.Println("a =", a);
		Fmt.Println("b =", b);
		Fmt.Println("a*b =", ab);
		Fmt.Println("I =", I);
		panic("FAILED");
	}
}
<commit_msg>fix test<commit_after>// $G $D/$F.go && $L $F.$A && ./$A.out

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

// A little test program for rational arithmetics.
// Computes a Hilbert matrix, its inverse, multiplies them
// and verifies that the product is the identity matrix.

package main

import Big "bignum"
import Fmt "fmt"

func assert(p bool) {
	if !p {
		panic("assert failed");
	}
}

var (
	Zero = Big.Rat(0, 1);
	One = Big.Rat(1, 1);
)

type Matrix struct {
	n, m int;
	a []*Big.Rational;
}

func (a *Matrix) at(i, j int) *Big.Rational {
	assert(0 <= i && i < a.n && 0 <= j && j < a.m);
	return a.a[i*a.m + j];
}

func (a *Matrix) set(i, j int, x *Big.Rational) {
	assert(0 <= i && i < a.n && 0 <= j && j < a.m);
	a.a[i*a.m + j] = x;
}

func NewMatrix(n, m int) *Matrix {
	assert(0 <= n && 0 <= m);
	a := new(Matrix);
	a.n = n;
	a.m = m;
	a.a = make([]*Big.Rational, n*m);
	return a;
}

func NewUnit(n int) *Matrix {
	a := NewMatrix(n, n);
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			x := Zero;
			if i == j {
				x = One;
			}
			a.set(i, j, x);
		}
	}
	return a;
}

func NewHilbert(n int) *Matrix {
	a := NewMatrix(n, n);
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			x := Big.Rat(1, int64(i + j + 1));
			a.set(i, j, x);
		}
	}
	return a;
}

func MakeRat(x Big.Natural) *Big.Rational {
	return Big.MakeRat(Big.MakeInt(false, x), Big.Nat(1));
}

func NewInverseHilbert(n int) *Matrix {
	a := NewMatrix(n, n);
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			x0 := One;
			if (i+j)&1 != 0 {
				x0 = x0.Neg();
			}
			x1 := Big.Rat(int64(i + j + 1), 1);
			x2 := MakeRat(Big.Binomial(uint(n+i), uint(n-j-1)));
			x3 := MakeRat(Big.Binomial(uint(n+j), uint(n-i-1)));
			x4 := MakeRat(Big.Binomial(uint(i+j), uint(i)));
			x4 = x4.Mul(x4);
			a.set(i, j, x0.Mul(x1).Mul(x2).Mul(x3).Mul(x4));
		}
	}
	return a;
}

func (a *Matrix) Mul(b *Matrix) *Matrix {
	assert(a.m == b.n);
	c := NewMatrix(a.n, b.m);
	for i := 0; i < c.n; i++ {
		for j := 0; j < c.m; j++ {
			x := Zero;
			for k := 0; k < a.m; k++ {
				x = x.Add(a.at(i, k).Mul(b.at(k, j)));
			}
			c.set(i, j, x);
		}
	}
	return c;
}

func (a *Matrix) Eql(b *Matrix) bool {
	if a.n != b.n || a.m != b.m {
		return false;
	}
	for i := 0; i < a.n; i++ {
		for j := 0; j < a.m; j++ {
			if a.at(i, j).Cmp(b.at(i,j)) != 0 {
				return false;
			}
		}
	}
	return true;
}

func (a *Matrix) String() string {
	s := "";
	for i := 0; i < a.n; i++ {
		for j := 0; j < a.m; j++ {
			s += Fmt.Sprintf("\t%s", a.at(i, j));
		}
		s += "\n";
	}
	return s;
}

func main() {
	n := 10;
	a := NewHilbert(n);
	b := NewInverseHilbert(n);
	I := NewUnit(n);
	ab := a.Mul(b);
	if !ab.Eql(I) {
		Fmt.Println("a =", a);
		Fmt.Println("b =", b);
		Fmt.Println("a*b =", ab);
		Fmt.Println("I =", I);
		panic("FAILED");
	}
}
<|endoftext|>


<commit_before>package internet

import (
	"net"

	"v2ray.com/core/app/log"
	"v2ray.com/core/common/errors"
	v2net "v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
)

var (
	transportListenerCache = make(map[TransportProtocol]ListenFunc)
)

func RegisterTransportListener(protocol TransportProtocol, listener ListenFunc) error {
	if _, found := transportListenerCache[protocol]; found {
		return errors.New("Internet|TCPHub: ", protocol, " listener already registered.")
	}
	transportListenerCache[protocol] = listener
	return nil
}

type ListenFunc func(address v2net.Address, port v2net.Port, options ListenOptions) (Listener, error)
type ListenOptions struct {
	Stream       *StreamConfig
	RecvOrigDest bool
}

type Listener interface {
	Accept() (Connection, error)
	Close() error
	Addr() net.Addr
}

type TCPHub struct {
	listener     Listener
	connCallback ConnectionHandler
	closed       chan bool
}

func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandler, settings *StreamConfig) (*TCPHub, error) {
	options := ListenOptions{
		Stream: settings,
	}
	protocol := settings.GetEffectiveProtocol()
	listenFunc := transportListenerCache[protocol]
	if listenFunc == nil {
		return nil, errors.New("Internet|TCPHub: ", protocol, " listener not registered.")
	}
	listener, err := listenFunc(address, port, options)
	if err != nil {
		return nil, errors.Base(err).Message("Internet|TCPHub: Failed to listen on address: ", address, ":", port)
	}

	hub := &TCPHub{
		listener:     listener,
		connCallback: callback,
	}

	go hub.start()
	return hub, nil
}

func (v *TCPHub) Close() {
	select {
	case <-v.closed:
		return
	default:
		v.listener.Close()
	}
}

func (v *TCPHub) start() {
	for {
		select {
		case <-v.closed:
			return
		default:
		}
		var newConn Connection
		err := retry.ExponentialBackoff(10, 500).On(func() error {
			select {
			case <-v.closed:
				return nil
			default:
				conn, err := v.listener.Accept()
				if err != nil {
					return errors.Base(err).RequireUserAction().Message("Internet|Listener: Failed to accept new TCP connection.")
				}
				newConn = conn
				return nil
			}
		})
		if err != nil {
			if errors.IsActionRequired(err) {
				log.Warning(err)
			} else {
				log.Info(err)
			}
			continue
		}
		if newConn != nil {
			go v.connCallback(newConn)
		}
	}
}
<commit_msg>prevent double close in tcp hub<commit_after>package internet

import (
	"net"

	"v2ray.com/core/app/log"
	"v2ray.com/core/common/errors"
	v2net "v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
)

var (
	transportListenerCache = make(map[TransportProtocol]ListenFunc)
)

func RegisterTransportListener(protocol TransportProtocol, listener ListenFunc) error {
	if _, found := transportListenerCache[protocol]; found {
		return errors.New("Internet|TCPHub: ", protocol, " listener already registered.")
	}
	transportListenerCache[protocol] = listener
	return nil
}

type ListenFunc func(address v2net.Address, port v2net.Port, options ListenOptions) (Listener, error)
type ListenOptions struct {
	Stream       *StreamConfig
	RecvOrigDest bool
}

type Listener interface {
	Accept() (Connection, error)
	Close() error
	Addr() net.Addr
}

type TCPHub struct {
	listener     Listener
	connCallback ConnectionHandler
	closed       chan bool
}

func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandler, settings *StreamConfig) (*TCPHub, error) {
	options := ListenOptions{
		Stream: settings,
	}
	protocol := settings.GetEffectiveProtocol()
	listenFunc := transportListenerCache[protocol]
	if listenFunc == nil {
		return nil, errors.New("Internet|TCPHub: ", protocol, " listener not registered.")
	}
	listener, err := listenFunc(address, port, options)
	if err != nil {
		return nil, errors.Base(err).Message("Internet|TCPHub: Failed to listen on address: ", address, ":", port)
	}

	hub := &TCPHub{
		listener:     listener,
		connCallback: callback,
	}

	go hub.start()
	return hub, nil
}

func (v *TCPHub) Close() {
	defer func() {
		recover()
	}()

	select {
	case <-v.closed:
		return
	default:
		v.listener.Close()
		close(v.closed)
	}
}

func (v *TCPHub) start() {
	for {
		select {
		case <-v.closed:
			return
		default:
		}
		var newConn Connection
		err := retry.ExponentialBackoff(10, 500).On(func() error {
			select {
			case <-v.closed:
				return nil
			default:
				conn, err := v.listener.Accept()
				if err != nil {
					return errors.Base(err).RequireUserAction().Message("Internet|Listener: Failed to accept new TCP connection.")
				}
				newConn = conn
				return nil
			}
		})
		if err != nil {
			if errors.IsActionRequired(err) {
				log.Warning(err)
			} else {
				log.Info(err)
			}
			continue
		}
		if newConn != nil {
			go v.connCallback(newConn)
		}
	}
}
<|endoftext|>


<commit_before>package main

import "strings"
import "errors"
import "time"
import "os/user"
import "github.com/tj/go-debug"
import "github.com/aws/aws-sdk-go/aws"
import "github.com/aws/aws-sdk-go/aws/credentials"
import "github.com/aws/aws-sdk-go/aws/session"
import "github.com/aws/aws-sdk-go/service/sts"

var debugAws = debug.Debug("oktad:aws")

// assumes the first role and returns the credentials you need for
// the second assumeRole...
// returns those credentials, the expiration time, and error if any
func assumeFirstRole(acfg AwsConfig, saml *OktaSamlResponse) (*credentials.Credentials, time.Time, error) {
	var emptyExpire time.Time
	sess := session.New(
		aws.NewConfig().WithRegion(acfg.Region),
	)
	scl := sts.New(
		sess,
	)

	var arns string

	for _, a := range saml.Attributes {
		if a.Name == "https://aws.amazon.com/SAML/Attributes/Role" {
			arns = a.Value
			debugAws("found principal ARN %s", a.Value)
			break
		}
	}

	if arns == "" {
		return nil, emptyExpire, errors.New("no arn found from saml data!")
	}

	parts := strings.Split(arns, ",")

	if len(parts) != 2 {
		return nil, emptyExpire, errors.New("invalid initial role ARN")
	}

	var roleArn, principalArn string
	for _, part := range parts {
		if strings.Contains(part, "saml-provider") {
			principalArn = part
		} else {
			roleArn = part
		}
	}

	res, err := scl.AssumeRoleWithSAML(
		&sts.AssumeRoleWithSAMLInput{
			PrincipalArn:    &principalArn,
			RoleArn:         &roleArn,
			SAMLAssertion:   &saml.raw,
			DurationSeconds: aws.Int64(3600),
		},
	)

	if err != nil {
		debugAws("error in AssumeRoleWithSAML")
		return nil, emptyExpire, err
	}

	mCreds := credentials.NewStaticCredentials(
		*res.Credentials.AccessKeyId,
		*res.Credentials.SecretAccessKey,
		*res.Credentials.SessionToken,
	)

	return mCreds, *res.Credentials.Expiration, nil
}

// behold, the moment we've been waiting for!
// we need to assume role into the second account...
// this will require the AwsConfig, which includes the final
// destination ARN, and some AWS credentials that allow us to do that
func assumeDestinationRole(acfg AwsConfig, creds *credentials.Credentials) (*credentials.Credentials, time.Time, error) {
	var emptyExpire time.Time
	sess := session.New(
		aws.NewConfig().
			WithRegion(acfg.Region).
			WithCredentials(creds),
	)
	scl := sts.New(
		sess,
	)

	var sessionName string
	if user, err := user.Current(); err != nil {
		sessionName = user.Username
	} else {
		debugAws("error getting username from OS: %s", err)
		sessionName = "unknown-user"
	}

	res, err := scl.AssumeRole(
		&sts.AssumeRoleInput{
			RoleArn:         &acfg.DestArn,
			RoleSessionName: &sessionName,
		},
	)

	if err != nil {
		debugAws("error in assumeDestinationRole! you were so close!")
		return nil, emptyExpire, err
	}

	mCreds := credentials.NewStaticCredentials(
		*res.Credentials.AccessKeyId,
		*res.Credentials.SecretAccessKey,
		*res.Credentials.SessionToken,
	)

	return mCreds, *res.Credentials.Expiration, nil
}
<commit_msg>fix condition...<commit_after>package main

import "strings"
import "errors"
import "time"
import "os/user"
import "github.com/tj/go-debug"
import "github.com/aws/aws-sdk-go/aws"
import "github.com/aws/aws-sdk-go/aws/credentials"
import "github.com/aws/aws-sdk-go/aws/session"
import "github.com/aws/aws-sdk-go/service/sts"

var debugAws = debug.Debug("oktad:aws")

// assumes the first role and returns the credentials you need for
// the second assumeRole...
// returns those credentials, the expiration time, and error if any
func assumeFirstRole(acfg AwsConfig, saml *OktaSamlResponse) (*credentials.Credentials, time.Time, error) {
	var emptyExpire time.Time
	sess := session.New(
		aws.NewConfig().WithRegion(acfg.Region),
	)
	scl := sts.New(
		sess,
	)

	var arns string

	for _, a := range saml.Attributes {
		if a.Name == "https://aws.amazon.com/SAML/Attributes/Role" {
			arns = a.Value
			debugAws("found principal ARN %s", a.Value)
			break
		}
	}

	if arns == "" {
		return nil, emptyExpire, errors.New("no arn found from saml data!")
	}

	parts := strings.Split(arns, ",")

	if len(parts) != 2 {
		return nil, emptyExpire, errors.New("invalid initial role ARN")
	}

	var roleArn, principalArn string
	for _, part := range parts {
		if strings.Contains(part, "saml-provider") {
			principalArn = part
		} else {
			roleArn = part
		}
	}

	res, err := scl.AssumeRoleWithSAML(
		&sts.AssumeRoleWithSAMLInput{
			PrincipalArn:    &principalArn,
			RoleArn:         &roleArn,
			SAMLAssertion:   &saml.raw,
			DurationSeconds: aws.Int64(3600),
		},
	)

	if err != nil {
		debugAws("error in AssumeRoleWithSAML")
		return nil, emptyExpire, err
	}

	mCreds := credentials.NewStaticCredentials(
		*res.Credentials.AccessKeyId,
		*res.Credentials.SecretAccessKey,
		*res.Credentials.SessionToken,
	)

	return mCreds, *res.Credentials.Expiration, nil
}

// behold, the moment we've been waiting for!
// we need to assume role into the second account...
// this will require the AwsConfig, which includes the final
// destination ARN, and some AWS credentials that allow us to do that
func assumeDestinationRole(acfg AwsConfig, creds *credentials.Credentials) (*credentials.Credentials, time.Time, error) {
	var emptyExpire time.Time
	sess := session.New(
		aws.NewConfig().
			WithRegion(acfg.Region).
			WithCredentials(creds),
	)
	scl := sts.New(
		sess,
	)

	var sessionName string
	if user, err := user.Current(); err == nil {
		sessionName = user.Username
	} else {
		debugAws("error getting username from OS: %s", err)
		sessionName = "unknown-user"
	}

	res, err := scl.AssumeRole(
		&sts.AssumeRoleInput{
			RoleArn:         &acfg.DestArn,
			RoleSessionName: &sessionName,
		},
	)

	if err != nil {
		debugAws("error in assumeDestinationRole! you were so close!")
		return nil, emptyExpire, err
	}

	mCreds := credentials.NewStaticCredentials(
		*res.Credentials.AccessKeyId,
		*res.Credentials.SecretAccessKey,
		*res.Credentials.SessionToken,
	)

	return mCreds, *res.Credentials.Expiration, nil
}
<|endoftext|>


<commit_before>package mpb

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

type decoratorFuncType uint

const (
	decoratorAppend decoratorFuncType = iota
	decoratorPrepend
)

// DecoratorFunc is a function that can be prepended and appended to the progress bar
type DecoratorFunc func(s *Statistics) string

type decorator struct {
	kind decoratorFuncType
	f    DecoratorFunc
}

// Bar represents a progress Bar
type Bar struct {
	total   int
	width   int
	alpha   float64
	stopped bool

	fill     byte
	empty    byte
	tip      byte
	leftEnd  byte
	rightEnd byte

	incrCh        chan int
	redrawReqCh   chan chan []byte
	progressReqCh chan chan int
	decoratorCh   chan *decorator
	flushedCh     chan struct{}
	stopCh        chan struct{}
	done          chan struct{}

	timePerItemEstimate time.Duration
}

type Statistics struct {
	Total, Completed    int
	TimePerItemEstimate time.Duration
}

// type redrawRequest struct {
// 	respCh chan []byte
// }

// type progressRequest struct {
// 	respCh chan int
// }

func newBar(total, width int, wg *sync.WaitGroup) *Bar {
	b := &Bar{
		fill:          '=',
		empty:         '-',
		tip:           '>',
		leftEnd:       '[',
		rightEnd:      ']',
		alpha:         0.25,
		total:         total,
		width:         width,
		incrCh:        make(chan int),
		redrawReqCh:   make(chan chan []byte),
		progressReqCh: make(chan chan int),
		decoratorCh:   make(chan *decorator),
		flushedCh:     make(chan struct{}),
		stopCh:        make(chan struct{}),
		done:          make(chan struct{}),
	}
	go b.server(wg)
	return b
}

// SetWidth sets width of the bar
func (b *Bar) SetWidth(n int) *Bar {
	if n <= 0 {
		return b
	}
	b.width = n
	return b
}

// SetFill sets character representing completed progress.
// Defaults to '='
func (b *Bar) SetFill(c byte) *Bar {
	b.fill = c
	return b
}

// SetTip sets character representing tip of progress.
// Defaults to '>'
func (b *Bar) SetTip(c byte) *Bar {
	b.tip = c
	return b
}

// SetEmpty sets character representing the empty progress
// Defaults to '-'
func (b *Bar) SetEmpty(c byte) *Bar {
	b.empty = c
	return b
}

// SetLeftEnd sets character representing the left most border
// Defaults to '['
func (b *Bar) SetLeftEnd(c byte) *Bar {
	b.leftEnd = c
	return b
}

// SetRightEnd sets character representing the right most border
// Defaults to ']'
func (b *Bar) SetRightEnd(c byte) *Bar {
	b.rightEnd = c
	return b
}

// SetEtaAlpha sets alfa for exponential-weighted-moving-average ETA estimator
// Defaults to 0.25
// Normally you shouldn't touch this
func (b *Bar) SetEtaAlpha(a float64) *Bar {
	b.alpha = a
	return b
}

// String returns the string representation of the bar
func (b *Bar) String() string {
	respCh := make(chan []byte)
	b.redrawReqCh <- respCh
	return string(<-respCh)
}

func (b *Bar) Incr(n int) {
	if !b.IsCompleted() {
		b.incrCh <- n
	}
}

func (b *Bar) Stop() {
	if !b.stopped {
		b.stopCh <- struct{}{}
		b.stopped = true
	}
}

func (b *Bar) IsCompleted() bool {
	select {
	case <-b.done:
		return true
	default:
		return false
	}
}

func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
	b.decoratorCh <- &decorator{decoratorPrepend, f}
	return b
}

func (b *Bar) AppendFunc(f DecoratorFunc) *Bar {
	b.decoratorCh <- &decorator{decoratorAppend, f}
	return b
}

func (b *Bar) PrependName(name string, padding int) *Bar {
	layout := "%" + strconv.Itoa(padding) + "s"
	b.PrependFunc(func(s *Statistics) string {
		return fmt.Sprintf(layout, name)
	})
	return b
}

func (b *Bar) PrependETA(padding int) *Bar {
	layout := "ETA%" + strconv.Itoa(padding) + "s"
	b.PrependFunc(func(s *Statistics) string {
		eta := time.Duration(s.Total-s.Completed) * s.TimePerItemEstimate
		return fmt.Sprintf(layout, time.Duration(eta.Seconds())*time.Second)
	})
	return b
}

func (b *Bar) AppendETA() *Bar {
	b.AppendFunc(func(s *Statistics) string {
		eta := time.Duration(s.Total-s.Completed) * s.TimePerItemEstimate
		return fmt.Sprintf("ETA %v", time.Duration(eta.Seconds())*time.Second)
	})
	return b
}

func (b *Bar) AppendPercentage() *Bar {
	b.AppendFunc(func(s *Statistics) string {
		completed := int(100 * float64(s.Completed) / float64(s.Total))
		return fmt.Sprintf("%3d %%", completed)
	})
	return b
}

func (b *Bar) PrependPercentage(padding int) *Bar {
	layout := "%" + strconv.Itoa(padding) + "d %%"
	b.PrependFunc(func(s *Statistics) string {
		completed := int(100 * float64(s.Completed) / float64(s.Total))
		return fmt.Sprintf(layout, completed)
	})
	return b
}

func (b *Bar) server(wg *sync.WaitGroup) {
	var completed int
	blockStartTime := time.Now()
	buf := make([]byte, b.width, b.width+24)
	var appendFuncs []DecoratorFunc
	var prependFuncs []DecoratorFunc
	var done bool
	for {
		select {
		case i := <-b.incrCh:
			n := completed + i
			// fmt.Fprintf(os.Stderr, "n = %+v\n", n)
			if n > b.total {
				completed = b.total
				done = true
				break
			}
			b.updateTimePerItemEstimate(i, blockStartTime)
			completed = n
			if completed == b.total && !done {
				done = true
			}
			blockStartTime = time.Now()
		case d := <-b.decoratorCh:
			switch d.kind {
			case decoratorAppend:
				appendFuncs = append(appendFuncs, d.f)
			case decoratorPrepend:
				prependFuncs = append(prependFuncs, d.f)
			}
		case respCh := <-b.redrawReqCh:
			respCh <- b.draw(buf, completed, appendFuncs, prependFuncs)
		case respCh := <-b.progressReqCh:
			respCh <- int(100 * float64(completed) / float64(b.total))
		case <-b.flushedCh:
			if done && !b.IsCompleted() {
				// fmt.Fprintln(os.Stderr, "flushedCh: wg.Done")
				close(b.done)
				wg.Done()
			}
		case <-b.stopCh:
			// fmt.Fprintln(os.Stderr, "received stop signal")
			if !done {
				// fmt.Fprintln(os.Stderr, "closing done chan: done = false")
				close(b.done)
				wg.Done()
			}
			return
		}
	}
}

func (b *Bar) draw(buf []byte, current int, appendFuncs, prependFuncs []DecoratorFunc) []byte {
	completedWidth := current * b.width / b.total

	for i := 0; i < completedWidth; i++ {
		buf[i] = b.fill
	}
	for i := completedWidth; i < b.width; i++ {
		buf[i] = b.empty
	}
	// set tip bit
	if completedWidth > 0 && completedWidth < b.width {
		buf[completedWidth-1] = b.tip
	}

	// set left and right ends bits
	buf[0], buf[len(buf)-1] = b.leftEnd, b.rightEnd

	s := &Statistics{b.total, current, b.timePerItemEstimate}

	// render append functions to the right of the bar
	for _, f := range appendFuncs {
		buf = append(buf, ' ')
		buf = append(buf, []byte(f(s))...)
	}

	// render prepend functions to the left of the bar
	for _, f := range prependFuncs {
		args := []byte(f(s))
		args = append(args, ' ')
		buf = append(args, buf...)
	}
	return buf
}

func (b *Bar) updateTimePerItemEstimate(items int, blockStartTime time.Time) {
	lastBlockTime := time.Since(blockStartTime)
	lastItemEstimate := float64(lastBlockTime) / float64(items)
	b.timePerItemEstimate = time.Duration((b.alpha * lastItemEstimate) + (1-b.alpha)*float64(b.timePerItemEstimate))
}

func (b *Bar) progress() int {
	respCh := make(chan int)
	b.progressReqCh <- respCh
	return <-respCh
}

type SortableBarSlice []*Bar

func (p SortableBarSlice) Len() int { return len(p) }

func (p SortableBarSlice) Less(i, j int) bool { return p[i].progress() < p[j].progress() }

func (p SortableBarSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
<commit_msg>eta method on Statistics<commit_after>package mpb

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

type decoratorFuncType uint

const (
	decoratorAppend decoratorFuncType = iota
	decoratorPrepend
)

// DecoratorFunc is a function that can be prepended and appended to the progress bar
type DecoratorFunc func(s *Statistics) string

type decorator struct {
	kind decoratorFuncType
	f    DecoratorFunc
}

// Bar represents a progress Bar
type Bar struct {
	total   int
	width   int
	alpha   float64
	stopped bool

	fill     byte
	empty    byte
	tip      byte
	leftEnd  byte
	rightEnd byte

	incrCh        chan int
	redrawReqCh   chan chan []byte
	progressReqCh chan chan int
	decoratorCh   chan *decorator
	flushedCh     chan struct{}
	stopCh        chan struct{}
	done          chan struct{}

	timePerItemEstimate time.Duration
}

type Statistics struct {
	Total, Completed    int
	TimePerItemEstimate time.Duration
}

func (s *Statistics) eta() time.Duration {
	return time.Duration(s.Total-s.Completed) * s.TimePerItemEstimate
}

// type redrawRequest struct {
// 	respCh chan []byte
// }

// type progressRequest struct {
// 	respCh chan int
// }

func newBar(total, width int, wg *sync.WaitGroup) *Bar {
	b := &Bar{
		fill:          '=',
		empty:         '-',
		tip:           '>',
		leftEnd:       '[',
		rightEnd:      ']',
		alpha:         0.25,
		total:         total,
		width:         width,
		incrCh:        make(chan int),
		redrawReqCh:   make(chan chan []byte),
		progressReqCh: make(chan chan int),
		decoratorCh:   make(chan *decorator),
		flushedCh:     make(chan struct{}),
		stopCh:        make(chan struct{}),
		done:          make(chan struct{}),
	}
	go b.server(wg)
	return b
}

// SetWidth sets width of the bar
func (b *Bar) SetWidth(n int) *Bar {
	if n <= 0 {
		return b
	}
	b.width = n
	return b
}

// SetFill sets character representing completed progress.
// Defaults to '='
func (b *Bar) SetFill(c byte) *Bar {
	b.fill = c
	return b
}

// SetTip sets character representing tip of progress.
// Defaults to '>'
func (b *Bar) SetTip(c byte) *Bar {
	b.tip = c
	return b
}

// SetEmpty sets character representing the empty progress
// Defaults to '-'
func (b *Bar) SetEmpty(c byte) *Bar {
	b.empty = c
	return b
}

// SetLeftEnd sets character representing the left most border
// Defaults to '['
func (b *Bar) SetLeftEnd(c byte) *Bar {
	b.leftEnd = c
	return b
}

// SetRightEnd sets character representing the right most border
// Defaults to ']'
func (b *Bar) SetRightEnd(c byte) *Bar {
	b.rightEnd = c
	return b
}

// SetEtaAlpha sets alfa for exponential-weighted-moving-average ETA estimator
// Defaults to 0.25
// Normally you shouldn't touch this
func (b *Bar) SetEtaAlpha(a float64) *Bar {
	b.alpha = a
	return b
}

// String returns the string representation of the bar
func (b *Bar) String() string {
	respCh := make(chan []byte)
	b.redrawReqCh <- respCh
	return string(<-respCh)
}

func (b *Bar) Incr(n int) {
	if !b.IsCompleted() {
		b.incrCh <- n
	}
}

func (b *Bar) Stop() {
	if !b.stopped {
		b.stopCh <- struct{}{}
		b.stopped = true
	}
}

func (b *Bar) IsCompleted() bool {
	select {
	case <-b.done:
		return true
	default:
		return false
	}
}

func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
	b.decoratorCh <- &decorator{decoratorPrepend, f}
	return b
}

func (b *Bar) AppendFunc(f DecoratorFunc) *Bar {
	b.decoratorCh <- &decorator{decoratorAppend, f}
	return b
}

func (b *Bar) PrependName(name string, padding int) *Bar {
	layout := "%" + strconv.Itoa(padding) + "s"
	b.PrependFunc(func(s *Statistics) string {
		return fmt.Sprintf(layout, name)
	})
	return b
}

func (b *Bar) PrependETA(padding int) *Bar {
	layout := "ETA%" + strconv.Itoa(padding) + "s"
	b.PrependFunc(func(s *Statistics) string {
		return fmt.Sprintf(layout, time.Duration(s.eta().Seconds())*time.Second)
	})
	return b
}

func (b *Bar) AppendETA() *Bar {
	b.AppendFunc(func(s *Statistics) string {
		return fmt.Sprintf("ETA %s", time.Duration(s.eta().Seconds())*time.Second)
	})
	return b
}

func (b *Bar) AppendPercentage() *Bar {
	b.AppendFunc(func(s *Statistics) string {
		completed := int(100 * float64(s.Completed) / float64(s.Total))
		return fmt.Sprintf("%3d %%", completed)
	})
	return b
}

func (b *Bar) PrependPercentage(padding int) *Bar {
	layout := "%" + strconv.Itoa(padding) + "d %%"
	b.PrependFunc(func(s *Statistics) string {
		completed := int(100 * float64(s.Completed) / float64(s.Total))
		return fmt.Sprintf(layout, completed)
	})
	return b
}

func (b *Bar) server(wg *sync.WaitGroup) {
	var completed int
	blockStartTime := time.Now()
	buf := make([]byte, b.width, b.width+24)
	var appendFuncs []DecoratorFunc
	var prependFuncs []DecoratorFunc
	var done bool
	for {
		select {
		case i := <-b.incrCh:
			n := completed + i
			// fmt.Fprintf(os.Stderr, "n = %+v\n", n)
			if n > b.total {
				completed = b.total
				done = true
				break
			}
			b.updateTimePerItemEstimate(i, blockStartTime)
			completed = n
			if completed == b.total && !done {
				done = true
			}
			blockStartTime = time.Now()
		case d := <-b.decoratorCh:
			switch d.kind {
			case decoratorAppend:
				appendFuncs = append(appendFuncs, d.f)
			case decoratorPrepend:
				prependFuncs = append(prependFuncs, d.f)
			}
		case respCh := <-b.redrawReqCh:
			respCh <- b.draw(buf, completed, appendFuncs, prependFuncs)
		case respCh := <-b.progressReqCh:
			respCh <- int(100 * float64(completed) / float64(b.total))
		case <-b.flushedCh:
			if done && !b.IsCompleted() {
				// fmt.Fprintln(os.Stderr, "flushedCh: wg.Done")
				close(b.done)
				wg.Done()
			}
		case <-b.stopCh:
			// fmt.Fprintln(os.Stderr, "received stop signal")
			if !done {
				// fmt.Fprintln(os.Stderr, "closing done chan: done = false")
				close(b.done)
				wg.Done()
			}
			return
		}
	}
}

func (b *Bar) draw(buf []byte, current int, appendFuncs, prependFuncs []DecoratorFunc) []byte {
	completedWidth := current * b.width / b.total

	for i := 0; i < completedWidth; i++ {
		buf[i] = b.fill
	}
	for i := completedWidth; i < b.width; i++ {
		buf[i] = b.empty
	}
	// set tip bit
	if completedWidth > 0 && completedWidth < b.width {
		buf[completedWidth-1] = b.tip
	}

	// set left and right ends bits
	buf[0], buf[len(buf)-1] = b.leftEnd, b.rightEnd

	s := &Statistics{b.total, current, b.timePerItemEstimate}

	// render append functions to the right of the bar
	for _, f := range appendFuncs {
		buf = append(buf, ' ')
		buf = append(buf, []byte(f(s))...)
	}

	// render prepend functions to the left of the bar
	for _, f := range prependFuncs {
		args := []byte(f(s))
		args = append(args, ' ')
		buf = append(args, buf...)
	}
	return buf
}

func (b *Bar) updateTimePerItemEstimate(items int, blockStartTime time.Time) {
	lastBlockTime := time.Since(blockStartTime)
	lastItemEstimate := float64(lastBlockTime) / float64(items)
	b.timePerItemEstimate = time.Duration((b.alpha * lastItemEstimate) + (1-b.alpha)*float64(b.timePerItemEstimate))
}

func (b *Bar) progress() int {
	respCh := make(chan int)
	b.progressReqCh <- respCh
	return <-respCh
}

type SortableBarSlice []*Bar

func (p SortableBarSlice) Len() int { return len(p) }

func (p SortableBarSlice) Less(i, j int) bool { return p[i].progress() < p[j].progress() }

func (p SortableBarSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
<|endoftext|>


<commit_before>// Tabix queries for go
package bix

import (
	"bufio"
	"compress/gzip"
	"io"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/biogo/hts/bgzf"
	"github.com/biogo/hts/bgzf/index"
	"github.com/biogo/hts/tabix"
	"github.com/brentp/irelate/interfaces"
	"github.com/brentp/irelate/parsers"
	"github.com/brentp/vcfgo"
)

const (
	VCF = iota
	BED
	GENERIC
)

type location struct {
	chrom string
	start int
	end   int
}

func (s location) RefName() string {
	return s.chrom
}
func (s location) Start() int {
	return s.start
}
func (s location) End() int {
	return s.end
}

// Bix provides read access to tabix files.
type Bix struct {
	*tabix.Index
	bgzf   *bgzf.Reader
	path   string
	Header string

	vReader    *vcfgo.Reader
	lastChunks []bgzf.Chunk
	cache      []interfaces.IPosition
}

func chunksEqual(a, b []bgzf.Chunk) bool {
	if len(a) != len(b) || len(a) == 0 || len(b) == 0 {
		return false
	}
	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// New returns a &Bix
func New(path string, workers ...int) (*Bix, error) {
	f, err := os.Open(path + ".tbi")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	gz, err := gzip.NewReader(f)
	if err != nil {
		return nil, err
	}
	defer gz.Close()

	idx, err := tabix.ReadFrom(gz)
	if err != nil {
		return nil, err
	}
	n := 1
	if len(workers) > 0 {
		n = workers[0]
	}

	b, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	bgz, err := bgzf.NewReader(b, n)
	bgz.Blocked = false
	if err != nil {
		return nil, err
	}

	/*
		c := cache.NewFIFO(4)
		bgz.SetCache(c)
	*/

	buf := bufio.NewReaderSize(bgz, 16384)
	h := make([]string, 0)
	tbx := &Bix{bgzf: bgz, path: path, cache: make([]interfaces.IPosition, 0, 4000)}

	l, err := buf.ReadString('\n')
	if err != nil {
		return tbx, err
	}

	for i := 0; i < int(idx.Skip) || rune(l[0]) == idx.MetaChar; i++ {
		h = append(h, l)
		l, err = buf.ReadString('\n')
		if err != nil {
			return tbx, err
		}
	}
	tbx.Header = strings.Join(h, "")

	if len(h) > 0 && strings.HasSuffix(tbx.path, ".vcf.gz") {
		rdr := strings.NewReader(tbx.Header)
		var err error
		tbx.vReader, err = vcfgo.NewReader(rdr, true)
		if err != nil {
			return nil, err
		}
	}

	tbx.Index = idx
	return tbx, nil
}

// bixReader is return from Bix.Query() it meets the io.Reader interface
type bixReader struct {
	startCol int
	endCol   int
	maxCol   int
	add      int

	start int
	end   int

	rdr   *bufio.Reader
	isVCF bool

	buf []byte
}

func newReader(tbx *Bix, cr *index.ChunkReader, start, end int) (io.Reader, error) {
	r := &bixReader{}
	r.startCol = int(tbx.BeginColumn - 1)
	r.endCol = int(tbx.EndColumn - 1)
	r.maxCol = r.endCol
	if r.startCol > r.endCol {
		r.maxCol = r.startCol
	}
	r.start = start
	r.end = end
	r.maxCol += 2
	if !tbx.ZeroBased {
		r.add = -1
	}
	r.rdr = bufio.NewReader(cr)
	r.buf = make([]byte, 0)
	r.isVCF = strings.HasSuffix(tbx.path, ".vcf.gz")
	if r.isVCF {
		r.maxCol = 9
	}

	return r, nil
}

func (r *bixReader) inBounds(line string) (bool, error, []string) {

	var readErr error
	toks := strings.SplitN(line, "\t", r.maxCol+1)
	toks[len(toks)-1] = strings.TrimRight(toks[len(toks)-1], "\r\n")

	s, err := strconv.Atoi(toks[r.startCol])
	if err != nil {
		return false, err, toks
	}

	pos := s + r.add
	if pos >= r.end {
		return false, io.EOF, toks
	}

	if r.endCol != -1 {
		e, err := strconv.Atoi(toks[r.endCol])
		if err != nil {
			return false, err, toks
		}
		if e < r.start {
			return false, readErr, toks
		}
		return true, readErr, toks
	} else if r.isVCF {
		alt := strings.Split(toks[4], ",")
		lref := len(toks[3])
		if r.start >= pos+lref {
			for _, a := range alt {
				if a[0] != '<' {
					e := pos + lref
					if e > r.start {
						return true, readErr, toks
					}
				} else if strings.HasPrefix(a, "<DEL") || strings.HasPrefix(a, "<DUP") || strings.HasPrefix(a, "<INV") || strings.HasPrefix(a, "<CN") {
					info := toks[7]
					if idx := strings.Index(info, ";END="); idx != -1 {
						v := info[idx+5 : idx+5+strings.Index(info[idx+5:], ";")]
						e, err := strconv.Atoi(v)
						if err != nil {
							return false, err, toks
						}
						if e > r.start {
							return true, readErr, toks
						}
					} else {
						log.Println("no end")
					}
				}
			}
		} else {
			return true, readErr, toks
		}
		return false, readErr, toks
	}
	return false, readErr, toks

}

func (tbx *Bix) fillCache(br *bixReader) {
	// this is a naive cache. It just parses the entire chunk.
	// Even if we only read up to the requested location, then
	// a Future Bix.Get() call would have a new reader and it would
	// have to bgzf.Read() again through the block, past what we already
	// knew. We could do one big Read(), then just parse each time, but
	// this version actually works quite well.
	if len(tbx.cache) != 0 {
		return
	}
	var err error
	for err == nil {
		line, err := br.rdr.ReadString('\n')
		if err != nil && err != io.EOF {
			log.Println(err)
			return
		}
		if len(line) == 0 || (err == io.EOF && line[len(line)-1] != '\n') {
			return
		}
		toks := strings.SplitN(line, "\t", br.maxCol)
		ip := tbx.toPosition(toks)
		tbx.cache = append(tbx.cache, ip)
	}

}

func (tbx *Bix) Get(q interfaces.IPosition) []interfaces.IPosition {
	overlaps := make([]interfaces.IPosition, 0)
	chunkReader, err := tbx.chunkedReader(location{q.Chrom(), int(q.Start()), int(q.End())})
	if err == index.ErrNoReference {
		if strings.HasPrefix(q.Chrom(), "chr") {
			chunkReader, err = tbx.chunkedReader(location{q.Chrom()[3:], int(q.Start()), int(q.End())})
		} else {
			chunkReader, err = tbx.chunkedReader(location{"chr" + q.Chrom(), int(q.Start()), int(q.End())})
		}
	}

	if err != nil {
		return overlaps
	}
	br := chunkReader.(*bixReader)

	var k int
	sizeCutoff := uint32(65536 / 2)

	if len(tbx.cache) == 0 && q.End()-q.Start() < sizeCutoff {
		tbx.fillCache(br)
	}
	for {
		if q.End()-q.Start() < sizeCutoff {
			if k >= len(tbx.cache) {
				break
			}
			v := tbx.cache[k]
			if v != nil {
				if interfaces.OverlapsPosition(v, q) {
					overlaps = append(overlaps, v)
				} else if v.Start() >= q.End() {
					break
				}
			}
			k += 1
		} else {
			line, err := br.rdr.ReadString('\n')

			if err != nil && err != io.EOF {
				log.Println(err)
				break
			}
			if len(line) == 0 || (err == io.EOF && line[len(line)-1] != '\n') {
				break
			}
			k += 1
			if err != nil {
				log.Println(err)
			}
			in, rerr, toks := br.inBounds(line)

			if !in {
				if rerr == io.EOF {
					err = io.EOF
					break
				}
				continue
			}
			ip := tbx.toPosition(toks)
			if ip != nil {
				overlaps = append(overlaps, ip)
			}
			if err == io.EOF {
				break
			}
		}
	}
	return overlaps
}

func (tbx *Bix) toPosition(toks []string) interfaces.IPosition {
	isVCF := tbx.vReader != nil

	if isVCF {
		v := tbx.vReader.Parse(toks)
		return v
	} else {

		g, _ := newgeneric(toks, int(tbx.Index.NameColumn-1), int(tbx.Index.BeginColumn-1),
			int(tbx.Index.EndColumn-1), tbx.Index.ZeroBased)
		return g
	}
}

// return an interval using the info from the tabix index
func newgeneric(fields []string, chromCol int, startCol int, endCol int, zeroBased bool) (*parsers.Interval, error) {
	s, err := strconv.Atoi(fields[startCol])
	if err != nil {
		return nil, err
	}
	if !zeroBased {
		s -= 1
	}
	e, err := strconv.Atoi(fields[endCol])
	if err != nil {
		return nil, err
	}

	return parsers.NewInterval(fields[chromCol], uint32(s), uint32(e), fields, uint32(0), nil), nil
}

// Read from a BixReader (will contain only overlapping intervals).
func (r *bixReader) Read(p []byte) (int, error) {
	var readErr error
	var line string

	for len(r.buf) < len(p) {
		line, readErr = r.rdr.ReadString('\n')
		if readErr == io.EOF {
			if len(line) == 0 {
				break
			}
		} else if readErr != nil {
			log.Println(readErr)
			break
		}
		var in bool
		var err error
		if in, err, _ = r.inBounds(line); in {
			r.buf = append(r.buf, line...)
		}
		if err == io.EOF {
			readErr = err
			break
		} else if err != nil {
			log.Println(err)
		}
	}
	if len(r.buf) >= len(p) {
		copy(p, r.buf[:len(p)])
		r.buf = r.buf[len(p):]
		if len(r.buf) > 0 && readErr == io.EOF {
			readErr = nil
		}
		return len(p), readErr
	}
	copy(p, r.buf)
	l := len(r.buf)
	r.buf = r.buf[:0]
	return l, readErr
}

func (tbx *Bix) chunkedReader(l location) (io.Reader, error) {
	chunks, err := tbx.Chunks(l)
	if err != nil {
		return nil, err
	}

	if !chunksEqual(chunks, tbx.lastChunks) {
		(*tbx).lastChunks = chunks
		tbx.cache = tbx.cache[:0]
	}

	chunkReader, err := index.NewChunkReader(tbx.bgzf, chunks)
	if err != nil {
		return nil, err
	}
	rdr, err := newReader(tbx, chunkReader, l.start, l.end)
	if err != nil {
		return nil, err
	}
	return rdr, nil
}

// Query a Bix struct with genomic coordinates. Returns an io.Reader.
func (tbx *Bix) Query(chrom string, start int, end int, printHeader bool) (io.Reader, error) {

	rdr, err := (*tbx).chunkedReader(location{chrom: chrom, start: start, end: end})
	if err != nil {
		return nil, err
	}
	if printHeader {
		rdr.(*bixReader).buf = []byte(tbx.Header)
	}
	return rdr, err
}

// Close closes the files associate with a Bix struct.
func (tbx *Bix) Close() {
	tbx.bgzf.Close()
}

func (tbx *Bix) AddInfoToHeader(id, number, vtype, desc string) {
	if tbx.vReader == nil {
		return
	}
	tbx.vReader.AddInfoToHeader(id, number, vtype, desc)
}
<commit_msg>pull 'chr' checking into chunkedReader<commit_after>// Tabix queries for go
package bix

import (
	"bufio"
	"compress/gzip"
	"io"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/biogo/hts/bgzf"
	"github.com/biogo/hts/bgzf/index"
	"github.com/biogo/hts/tabix"
	"github.com/brentp/irelate/interfaces"
	"github.com/brentp/irelate/parsers"
	"github.com/brentp/vcfgo"
)

const (
	VCF = iota
	BED
	GENERIC
)

type location struct {
	chrom string
	start int
	end   int
}

func (s location) RefName() string {
	return s.chrom
}
func (s location) Start() int {
	return s.start
}
func (s location) End() int {
	return s.end
}

// Bix provides read access to tabix files.
type Bix struct {
	*tabix.Index
	bgzf   *bgzf.Reader
	path   string
	Header string

	vReader    *vcfgo.Reader
	lastChunks []bgzf.Chunk
	cache      []interfaces.IPosition
}

func chunksEqual(a, b []bgzf.Chunk) bool {
	if len(a) != len(b) || len(a) == 0 || len(b) == 0 {
		return false
	}
	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// New returns a &Bix
func New(path string, workers ...int) (*Bix, error) {
	f, err := os.Open(path + ".tbi")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	gz, err := gzip.NewReader(f)
	if err != nil {
		return nil, err
	}
	defer gz.Close()

	idx, err := tabix.ReadFrom(gz)
	if err != nil {
		return nil, err
	}
	n := 1
	if len(workers) > 0 {
		n = workers[0]
	}

	b, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	bgz, err := bgzf.NewReader(b, n)
	bgz.Blocked = false
	if err != nil {
		return nil, err
	}

	/*
		c := cache.NewFIFO(4)
		bgz.SetCache(c)
	*/

	buf := bufio.NewReaderSize(bgz, 16384)
	h := make([]string, 0)
	tbx := &Bix{bgzf: bgz, path: path, cache: make([]interfaces.IPosition, 0, 4000)}

	l, err := buf.ReadString('\n')
	if err != nil {
		return tbx, err
	}

	for i := 0; i < int(idx.Skip) || rune(l[0]) == idx.MetaChar; i++ {
		h = append(h, l)
		l, err = buf.ReadString('\n')
		if err != nil {
			return tbx, err
		}
	}
	tbx.Header = strings.Join(h, "")

	if len(h) > 0 && strings.HasSuffix(tbx.path, ".vcf.gz") {
		rdr := strings.NewReader(tbx.Header)
		var err error
		tbx.vReader, err = vcfgo.NewReader(rdr, true)
		if err != nil {
			return nil, err
		}
	}

	tbx.Index = idx
	return tbx, nil
}

// bixReader is return from Bix.Query() it meets the io.Reader interface
type bixReader struct {
	startCol int
	endCol   int
	maxCol   int
	add      int

	start int
	end   int

	cr    *index.ChunkReader
	rdr   *bufio.Reader
	isVCF bool

	buf []byte
}

func newReader(tbx *Bix, cr *index.ChunkReader, start, end int) (io.ReadCloser, error) {
	r := &bixReader{}
	r.startCol = int(tbx.BeginColumn - 1)
	r.endCol = int(tbx.EndColumn - 1)
	r.maxCol = r.endCol
	if r.startCol > r.endCol {
		r.maxCol = r.startCol
	}
	r.start = start
	r.end = end
	r.maxCol += 2
	if !tbx.ZeroBased {
		r.add = -1
	}
	r.rdr = bufio.NewReader(cr)
	r.cr = cr
	r.buf = make([]byte, 0)
	r.isVCF = strings.HasSuffix(tbx.path, ".vcf.gz")
	if r.isVCF {
		r.maxCol = 9
	}

	return r, nil
}

func (r *bixReader) Close() error {
	return r.cr.Close()
}

func (r *bixReader) inBounds(line string) (bool, error, []string) {

	var readErr error
	toks := strings.SplitN(line, "\t", r.maxCol+1)
	toks[len(toks)-1] = strings.TrimRight(toks[len(toks)-1], "\r\n")

	s, err := strconv.Atoi(toks[r.startCol])
	if err != nil {
		return false, err, toks
	}

	pos := s + r.add
	if pos >= r.end {
		return false, io.EOF, toks
	}

	if r.endCol != -1 {
		e, err := strconv.Atoi(toks[r.endCol])
		if err != nil {
			return false, err, toks
		}
		if e < r.start {
			return false, readErr, toks
		}
		return true, readErr, toks
	} else if r.isVCF {
		alt := strings.Split(toks[4], ",")
		lref := len(toks[3])
		if r.start >= pos+lref {
			for _, a := range alt {
				if a[0] != '<' {
					e := pos + lref
					if e > r.start {
						return true, readErr, toks
					}
				} else if strings.HasPrefix(a, "<DEL") || strings.HasPrefix(a, "<DUP") || strings.HasPrefix(a, "<INV") || strings.HasPrefix(a, "<CN") {
					info := toks[7]
					if idx := strings.Index(info, ";END="); idx != -1 {
						v := info[idx+5 : idx+5+strings.Index(info[idx+5:], ";")]
						e, err := strconv.Atoi(v)
						if err != nil {
							return false, err, toks
						}
						if e > r.start {
							return true, readErr, toks
						}
					} else {
						log.Println("no end")
					}
				}
			}
		} else {
			return true, readErr, toks
		}
		return false, readErr, toks
	}
	return false, readErr, toks

}

func (tbx *Bix) fillCache(br *bixReader) {
	// this is a naive cache. It just parses the entire chunk.
	// Even if we only read up to the requested location, then
	// a Future Bix.Get() call would have a new reader and it would
	// have to bgzf.Read() again through the block, past what we already
	// knew. We could do one big Read(), then just parse each time, but
	// this version actually works quite well.
	if len(tbx.cache) != 0 {
		return
	}
	var err error
	for err == nil {
		line, err := br.rdr.ReadString('\n')
		if err != nil && err != io.EOF {
			log.Println(err)
			return
		}
		if len(line) == 0 || (err == io.EOF && line[len(line)-1] != '\n') {
			return
		}
		toks := strings.SplitN(line, "\t", br.maxCol)
		ip := tbx.toPosition(toks)
		tbx.cache = append(tbx.cache, ip)
	}

}

func (tbx *Bix) Get(q interfaces.IPosition) []interfaces.IPosition {
	overlaps := make([]interfaces.IPosition, 0)
	chunkReader, err := tbx.chunkedReader(location{q.Chrom(), int(q.Start()), int(q.End())})

	if err != nil {
		return overlaps
	}
	br := chunkReader.(*bixReader)

	var k int
	sizeCutoff := uint32(65536 / 2)

	if len(tbx.cache) == 0 && q.End()-q.Start() < sizeCutoff {
		tbx.fillCache(br)
	}
	for {
		if q.End()-q.Start() < sizeCutoff {
			if k >= len(tbx.cache) {
				break
			}
			v := tbx.cache[k]
			if v != nil {
				if interfaces.OverlapsPosition(v, q) {
					overlaps = append(overlaps, v)
				} else if v.Start() >= q.End() {
					break
				}
			}
			k += 1
		} else {
			line, err := br.rdr.ReadString('\n')

			if err != nil && err != io.EOF {
				log.Println(err)
				break
			}
			if len(line) == 0 || (err == io.EOF && line[len(line)-1] != '\n') {
				break
			}
			k += 1
			if err != nil {
				log.Println(err)
			}
			in, rerr, toks := br.inBounds(line)

			if !in {
				if rerr == io.EOF {
					err = io.EOF
					break
				}
				continue
			}
			ip := tbx.toPosition(toks)
			if ip != nil {
				overlaps = append(overlaps, ip)
			}
			if err == io.EOF {
				break
			}
		}
	}
	return overlaps
}

func (tbx *Bix) toPosition(toks []string) interfaces.IPosition {
	isVCF := tbx.vReader != nil

	if isVCF {
		v := tbx.vReader.Parse(toks)
		return v
	} else {

		g, _ := newgeneric(toks, int(tbx.Index.NameColumn-1), int(tbx.Index.BeginColumn-1),
			int(tbx.Index.EndColumn-1), tbx.Index.ZeroBased)
		return g
	}
}

// return an interval using the info from the tabix index
func newgeneric(fields []string, chromCol int, startCol int, endCol int, zeroBased bool) (*parsers.Interval, error) {
	s, err := strconv.Atoi(fields[startCol])
	if err != nil {
		return nil, err
	}
	if !zeroBased {
		s -= 1
	}
	e, err := strconv.Atoi(fields[endCol])
	if err != nil {
		return nil, err
	}

	return parsers.NewInterval(fields[chromCol], uint32(s), uint32(e), fields, uint32(0), nil), nil
}

// Read from a BixReader (will contain only overlapping intervals).
func (r *bixReader) Read(p []byte) (int, error) {
	var readErr error
	var line string

	for len(r.buf) < len(p) {
		line, readErr = r.rdr.ReadString('\n')
		if readErr == io.EOF {
			if len(line) == 0 {
				break
			}
		} else if readErr != nil {
			log.Println(readErr)
			break
		}
		var in bool
		var err error
		if in, err, _ = r.inBounds(line); in {
			r.buf = append(r.buf, line...)
		}
		if err == io.EOF {
			readErr = err
			break
		} else if err != nil {
			log.Println(err)
		}
	}
	if len(r.buf) >= len(p) {
		copy(p, r.buf[:len(p)])
		r.buf = r.buf[len(p):]
		if len(r.buf) > 0 && readErr == io.EOF {
			readErr = nil
		}
		return len(p), readErr
	}
	copy(p, r.buf)
	l := len(r.buf)
	r.buf = r.buf[:0]
	return l, readErr
}

func (tbx *Bix) chunkedReader(l location) (io.ReadCloser, error) {
	chunks, err := tbx.Chunks(l)
	if err == index.ErrNoReference {
		if strings.HasPrefix(l.chrom, "chr") {
			l.chrom = l.chrom[3:]
			chunks, err = tbx.Chunks(l)
		} else {
			l.chrom = "chr" + l.chrom
			chunks, err = tbx.Chunks(l)
		}
	}
	if err != nil {
		return nil, err
	}

	if !chunksEqual(chunks, tbx.lastChunks) {
		(*tbx).lastChunks = chunks
		tbx.cache = tbx.cache[:0]
	}

	chunkReader, err := index.NewChunkReader(tbx.bgzf, chunks)
	if err != nil {
		return nil, err
	}
	rdr, err := newReader(tbx, chunkReader, l.start, l.end)
	if err != nil {
		return nil, err
	}
	return rdr, nil
}

// Query a Bix struct with genomic coordinates. Returns an io.Reader.
func (tbx *Bix) Query(chrom string, start int, end int, printHeader bool) (io.ReadCloser, error) {

	rdr, err := (*tbx).chunkedReader(location{chrom: chrom, start: start, end: end})
	if err != nil {
		return nil, err
	}
	if printHeader {
		rdr.(*bixReader).buf = []byte(tbx.Header)
	}
	return rdr, err
}

// Close closes the files associate with a Bix struct.
func (tbx *Bix) Close() {
	tbx.bgzf.Close()
}

func (tbx *Bix) AddInfoToHeader(id, number, vtype, desc string) {
	if tbx.vReader == nil {
		return
	}
	tbx.vReader.AddInfoToHeader(id, number, vtype, desc)
}
<|endoftext|>


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

package installer

import (
	"bytes"
	"fmt"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru-client/tsuru/admin"
	tclient "github.com/tsuru/tsuru-client/tsuru/client"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/provision"
)

var TsuruComponents = []TsuruComponent{
	&MongoDB{},
	&Redis{},
	&PlanB{},
	&Registry{},
	&TsuruAPI{},
}

type InstallConfig struct {
	Registry string
}

func NewInstallConfig() *InstallConfig {
	registry, err := config.GetString("registry")
	if err != nil {
		registry = ""
	}
	return &InstallConfig{Registry: registry}
}

func (i *InstallConfig) fullImageName(name string) string {
	if i.Registry != "" {
		return fmt.Sprintf("%s/%s", i.Registry, name)
	}
	return name
}

type TsuruComponent interface {
	Name() string
	Install(*Machine, *InstallConfig) error
	Status(*Machine) (*ComponentStatus, error)
}

type MongoDB struct{}

func (c *MongoDB) Name() string {
	return "MongoDB"
}

func (c *MongoDB) Install(machine *Machine, i *InstallConfig) error {
	image := i.fullImageName("mongo:latest")
	return createContainer(machine, "mongo", &docker.Config{Image: image}, nil)
}

func (c *MongoDB) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("mongo", machine)
}

type PlanB struct{}

func (c *PlanB) Name() string {
	return "PlanB"
}

func (c *PlanB) Install(machine *Machine, i *InstallConfig) error {
	config := &docker.Config{
		Image: i.fullImageName("tsuru/planb:latest"),
		Cmd:   []string{"--listen", ":80", "--read-redis-host", machine.IP, "--write-redis-host", machine.IP},
	}
	hostConfig := &docker.HostConfig{
		PortBindings: make(map[docker.Port][]docker.PortBinding),
	}
	hostConfig.PortBindings["80"] = []docker.PortBinding{{HostIP: "0.0.0.0", HostPort: "80"}}
	return createContainer(machine, "planb", config, hostConfig)
}

func (c *PlanB) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("planb", machine)
}

type Redis struct{}

func (c *Redis) Name() string {
	return "Redis"
}

func (c *Redis) Install(machine *Machine, i *InstallConfig) error {
	image := i.fullImageName("redis:latest")
	return createContainer(machine, "redis", &docker.Config{Image: image}, nil)
}

func (c *Redis) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("redis", machine)
}

type Registry struct{}

func (c *Registry) Name() string {
	return "Docker Registry"
}

func (c *Registry) Install(machine *Machine, i *InstallConfig) error {
	config := &docker.Config{
		Image: i.fullImageName("registry:2"),
		Env: []string{
			"REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry",
			"REGISTRY_HTTP_TLS_CERTIFICATE=/certs/cert.crt",
			"REGISTRY_HTTP_TLS_KEY=/certs/key.pem",
			"REGISTRY_HTTP_TLS_CLIENTCAS= - /certs/ca.pem",
		},
	}
	hostConfig := &docker.HostConfig{
		Binds: []string{"/var/lib/registry:/var/lib/registry", "/home/docker/certs:/certs"},
	}
	return createContainer(machine, "registry", config, hostConfig)
}

func (c *Registry) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("registry", machine)
}

type TsuruAPI struct{}

func (c *TsuruAPI) Name() string {
	return "Tsuru API"
}

func (c *TsuruAPI) Install(machine *Machine, i *InstallConfig) error {
	env := []string{fmt.Sprintf("MONGODB_ADDR=%s", machine.IP),
		"MONGODB_PORT=27017",
		fmt.Sprintf("REDIS_ADDR=%s", machine.IP),
		"REDIS_PORT=6379",
		fmt.Sprintf("HIPACHE_DOMAIN=%s.nip.io", machine.IP),
		fmt.Sprintf("REGISTRY_ADDR=%s", machine.IP),
		"REGISTRY_PORT=5000",
	}
	config := &docker.Config{
		Image: i.fullImageName("tsuru/api:latest"),
		Env:   env,
	}
	err := createContainer(machine, "tsuru", config, nil)
	if err != nil {
		return err
	}
	err = c.setupRootUser(machine)
	if err != nil {
		return err
	}
	return c.bootstrapEnv("admin@example.com", "admin123", machine.IP, machine.Address)
}

func (c *TsuruAPI) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("tsuru", machine)
}

func (c *TsuruAPI) setupRootUser(machine *Machine) error {
	cmd := []string{"tsurud", "root-user-create", "admin@example.com"}
	passwordConfirmation := strings.NewReader("admin123\nadmin123\n")
	client, err := machine.dockerClient()
	if err != nil {
		return err
	}
	exec, err := client.CreateExec(docker.CreateExecOptions{
		Cmd:          cmd,
		Container:    "tsuru",
		AttachStdout: true,
		AttachStderr: true,
		AttachStdin:  true,
	})
	if err != nil {
		return err
	}
	return client.StartExec(exec.ID, docker.StartExecOptions{
		InputStream:  passwordConfirmation,
		Detach:       false,
		OutputStream: os.Stdout,
		ErrorStream:  os.Stderr,
		RawTerminal:  true,
	})
}

type ComponentStatus struct {
	containerState *docker.State
	addresses      []string
}

func containerStatus(name string, m *Machine) (*ComponentStatus, error) {
	client, err := m.dockerClient()
	if err != nil {
		return nil, fmt.Errorf("failed create docker client: %s", err)
	}
	container, err := client.InspectContainer(name)
	if err != nil {
		return nil, err
	}
	var addresses []string
	for p := range container.HostConfig.PortBindings {
		address := fmt.Sprintf("%s://%s:%s", p.Proto(), m.IP, p.Port())
		addresses = append(addresses, address)
	}
	return &ComponentStatus{
		containerState: &container.State,
		addresses:      addresses,
	}, nil
}

func (c *TsuruAPI) bootstrapEnv(login, password, target, node string) error {
	var stdout, stderr bytes.Buffer
	manager := cmd.BuildBaseManager("setup-client", "0.0.0", "", nil)
	provisioners := provision.Registry()
	for _, p := range provisioners {
		if c, ok := p.(cmd.AdminCommandable); ok {
			commands := c.AdminCommands()
			for _, cmd := range commands {
				manager.Register(cmd)
			}
		}
	}
	client := cmd.NewClient(&http.Client{}, nil, manager)
	context := cmd.Context{
		Args:   []string{"test", fmt.Sprintf("%s:8080", target)},
		Stdout: &stdout,
		Stderr: &stderr,
	}
	context.RawOutput()
	println("adding target")
	targetset := manager.Commands["target-add"]
	t, _ := targetset.(cmd.FlaggedCommand)
	err := t.Flags().Parse(true, []string{"-s"})
	if err != nil {
		return err
	}
	err = t.Run(&context, client)
	if err != nil {
		return err
	}
	println("logging")
	logincmd := manager.Commands["login"]
	context.Args = []string{login}
	context.Stdin = strings.NewReader(fmt.Sprintf("%s\n", password))
	err = logincmd.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{"theonepool"}
	context.Stdin = nil
	println("adding pool")
	poolAdd := admin.AddPoolToSchedulerCmd{}
	err = poolAdd.Flags().Parse(true, []string{"-d", "-p"})
	if err != nil {
		return err
	}
	err = poolAdd.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{fmt.Sprintf("address=%s", node), "pool=theonepool"}
	println("adding node")
	nodeAdd := manager.Commands["docker-node-add"]
	n, _ := nodeAdd.(cmd.FlaggedCommand)
	err = n.Flags().Parse(true, []string{"--register"})
	if err != nil {
		return err
	}
	err = n.Run(&context, client)
	if err != nil {
		return err
	}
	time.Sleep(15 * time.Second)
	context.Args = []string{"python"}
	println("adding platform")
	platformAdd := admin.PlatformAdd{}
	err = platformAdd.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{"admin"}
	println("adding team")
	teamCreate := tclient.TeamCreate{}
	err = teamCreate.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{"tsuru-dashboard", "python"}
	println("adding dashboard")
	createDashboard := tclient.AppCreate{}
	err = createDashboard.Flags().Parse(true, []string{"-t", "admin"})
	if err != nil {
		return err
	}
	err = createDashboard.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{}
	println("deploying dashboard")
	deployDashboard := tclient.AppDeploy{}
	err = deployDashboard.Flags().Parse(true, []string{"-a", "tsuru-dashboard", "-i", "tsuru/dashboard"})
	if err != nil {
		return err
	}
	return deployDashboard.Run(&context, client)
}
<commit_msg>fix registry certificate setup<commit_after>// Copyright 2016 tsuru-client authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package installer

import (
	"bytes"
	"fmt"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru-client/tsuru/admin"
	tclient "github.com/tsuru/tsuru-client/tsuru/client"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/provision"
)

var TsuruComponents = []TsuruComponent{
	&MongoDB{},
	&Redis{},
	&PlanB{},
	&Registry{},
	&TsuruAPI{},
}

type InstallConfig struct {
	Registry string
}

func NewInstallConfig() *InstallConfig {
	registry, err := config.GetString("registry")
	if err != nil {
		registry = ""
	}
	return &InstallConfig{Registry: registry}
}

func (i *InstallConfig) fullImageName(name string) string {
	if i.Registry != "" {
		return fmt.Sprintf("%s/%s", i.Registry, name)
	}
	return name
}

type TsuruComponent interface {
	Name() string
	Install(*Machine, *InstallConfig) error
	Status(*Machine) (*ComponentStatus, error)
}

type MongoDB struct{}

func (c *MongoDB) Name() string {
	return "MongoDB"
}

func (c *MongoDB) Install(machine *Machine, i *InstallConfig) error {
	image := i.fullImageName("mongo:latest")
	return createContainer(machine, "mongo", &docker.Config{Image: image}, nil)
}

func (c *MongoDB) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("mongo", machine)
}

type PlanB struct{}

func (c *PlanB) Name() string {
	return "PlanB"
}

func (c *PlanB) Install(machine *Machine, i *InstallConfig) error {
	config := &docker.Config{
		Image: i.fullImageName("tsuru/planb:latest"),
		Cmd:   []string{"--listen", ":80", "--read-redis-host", machine.IP, "--write-redis-host", machine.IP},
	}
	hostConfig := &docker.HostConfig{
		PortBindings: make(map[docker.Port][]docker.PortBinding),
	}
	hostConfig.PortBindings["80"] = []docker.PortBinding{{HostIP: "0.0.0.0", HostPort: "80"}}
	return createContainer(machine, "planb", config, hostConfig)
}

func (c *PlanB) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("planb", machine)
}

type Redis struct{}

func (c *Redis) Name() string {
	return "Redis"
}

func (c *Redis) Install(machine *Machine, i *InstallConfig) error {
	image := i.fullImageName("redis:latest")
	return createContainer(machine, "redis", &docker.Config{Image: image}, nil)
}

func (c *Redis) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("redis", machine)
}

type Registry struct{}

func (c *Registry) Name() string {
	return "Docker Registry"
}

func (c *Registry) Install(machine *Machine, i *InstallConfig) error {
	config := &docker.Config{
		Image: i.fullImageName("registry:2"),
		Env: []string{
			"REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry",
			"REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.pem",
			"REGISTRY_HTTP_TLS_KEY=/certs/registry-key.pem",
		},
	}
	hostConfig := &docker.HostConfig{
		Binds: []string{"/var/lib/registry:/var/lib/registry", "/home/docker/certs:/certs"},
	}
	return createContainer(machine, "registry", config, hostConfig)
}

func (c *Registry) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("registry", machine)
}

type TsuruAPI struct{}

func (c *TsuruAPI) Name() string {
	return "Tsuru API"
}

func (c *TsuruAPI) Install(machine *Machine, i *InstallConfig) error {
	env := []string{fmt.Sprintf("MONGODB_ADDR=%s", machine.IP),
		"MONGODB_PORT=27017",
		fmt.Sprintf("REDIS_ADDR=%s", machine.IP),
		"REDIS_PORT=6379",
		fmt.Sprintf("HIPACHE_DOMAIN=%s.nip.io", machine.IP),
		fmt.Sprintf("REGISTRY_ADDR=%s", machine.IP),
		"REGISTRY_PORT=5000",
	}
	config := &docker.Config{
		Image: i.fullImageName("tsuru/api:latest"),
		Env:   env,
	}
	err := createContainer(machine, "tsuru", config, nil)
	if err != nil {
		return err
	}
	err = c.setupRootUser(machine)
	if err != nil {
		return err
	}
	return c.bootstrapEnv("admin@example.com", "admin123", machine.IP, machine.Address)
}

func (c *TsuruAPI) Status(machine *Machine) (*ComponentStatus, error) {
	return containerStatus("tsuru", machine)
}

func (c *TsuruAPI) setupRootUser(machine *Machine) error {
	cmd := []string{"tsurud", "root-user-create", "admin@example.com"}
	passwordConfirmation := strings.NewReader("admin123\nadmin123\n")
	client, err := machine.dockerClient()
	if err != nil {
		return err
	}
	exec, err := client.CreateExec(docker.CreateExecOptions{
		Cmd:          cmd,
		Container:    "tsuru",
		AttachStdout: true,
		AttachStderr: true,
		AttachStdin:  true,
	})
	if err != nil {
		return err
	}
	return client.StartExec(exec.ID, docker.StartExecOptions{
		InputStream:  passwordConfirmation,
		Detach:       false,
		OutputStream: os.Stdout,
		ErrorStream:  os.Stderr,
		RawTerminal:  true,
	})
}

type ComponentStatus struct {
	containerState *docker.State
	addresses      []string
}

func containerStatus(name string, m *Machine) (*ComponentStatus, error) {
	client, err := m.dockerClient()
	if err != nil {
		return nil, fmt.Errorf("failed create docker client: %s", err)
	}
	container, err := client.InspectContainer(name)
	if err != nil {
		return nil, err
	}
	var addresses []string
	for p := range container.HostConfig.PortBindings {
		address := fmt.Sprintf("%s://%s:%s", p.Proto(), m.IP, p.Port())
		addresses = append(addresses, address)
	}
	return &ComponentStatus{
		containerState: &container.State,
		addresses:      addresses,
	}, nil
}

func (c *TsuruAPI) bootstrapEnv(login, password, target, node string) error {
	var stdout, stderr bytes.Buffer
	manager := cmd.BuildBaseManager("setup-client", "0.0.0", "", nil)
	provisioners := provision.Registry()
	for _, p := range provisioners {
		if c, ok := p.(cmd.AdminCommandable); ok {
			commands := c.AdminCommands()
			for _, cmd := range commands {
				manager.Register(cmd)
			}
		}
	}
	client := cmd.NewClient(&http.Client{}, nil, manager)
	context := cmd.Context{
		Args:   []string{"test", fmt.Sprintf("%s:8080", target)},
		Stdout: &stdout,
		Stderr: &stderr,
	}
	context.RawOutput()
	println("adding target")
	targetset := manager.Commands["target-add"]
	t, _ := targetset.(cmd.FlaggedCommand)
	err := t.Flags().Parse(true, []string{"-s"})
	if err != nil {
		return err
	}
	err = t.Run(&context, client)
	if err != nil {
		return err
	}
	println("logging")
	logincmd := manager.Commands["login"]
	context.Args = []string{login}
	context.Stdin = strings.NewReader(fmt.Sprintf("%s\n", password))
	err = logincmd.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{"theonepool"}
	context.Stdin = nil
	println("adding pool")
	poolAdd := admin.AddPoolToSchedulerCmd{}
	err = poolAdd.Flags().Parse(true, []string{"-d", "-p"})
	if err != nil {
		return err
	}
	err = poolAdd.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{fmt.Sprintf("address=%s", node), "pool=theonepool"}
	println("adding node")
	nodeAdd := manager.Commands["docker-node-add"]
	n, _ := nodeAdd.(cmd.FlaggedCommand)
	err = n.Flags().Parse(true, []string{"--register"})
	if err != nil {
		return err
	}
	err = n.Run(&context, client)
	if err != nil {
		return err
	}
	time.Sleep(15 * time.Second)
	context.Args = []string{"python"}
	println("adding platform")
	platformAdd := admin.PlatformAdd{}
	err = platformAdd.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{"admin"}
	println("adding team")
	teamCreate := tclient.TeamCreate{}
	err = teamCreate.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{"tsuru-dashboard", "python"}
	println("adding dashboard")
	createDashboard := tclient.AppCreate{}
	err = createDashboard.Flags().Parse(true, []string{"-t", "admin"})
	if err != nil {
		return err
	}
	err = createDashboard.Run(&context, client)
	if err != nil {
		return err
	}
	context.Args = []string{}
	println("deploying dashboard")
	deployDashboard := tclient.AppDeploy{}
	err = deployDashboard.Flags().Parse(true, []string{"-a", "tsuru-dashboard", "-i", "tsuru/dashboard"})
	if err != nil {
		return err
	}
	return deployDashboard.Run(&context, client)
}
<|endoftext|>