<commit_before>/*
   TODO: Add restore/reconnect logic
   Multihost
   Multiple ports
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/skynetservices/skydns/client"
	"github.com/skynetservices/skydns/msg"
	"io"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"time"
)

var (
	dockerPath     string
	dockerHostName string
	environment    string
	skydnsUrl      string
	secret         string
	ttl            int
	beat           int

	skydns  *client.Client
	running = make(map[string]struct{})
)

type (
	Event struct {
		ContainerId string `json:"id"`
		Status      string `json:"status"`
		Image       string `json:"from"`
	}

	ContainerConfig struct {
		Hostname     string
		Image        string
		ExposedPorts map[string]struct{}
	}

	NetworkSettings struct {
		IpAddress   string
		PortMapping map[string]map[string]string
	}

	State struct {
		Running bool
	}

	Container struct {
		Id              string
		Image           string
		Name            string
		Config          *ContainerConfig
		NetworkSettings *NetworkSettings
		State           State
	}
)

func init() {
	flag.StringVar(&dockerPath, "s", "/var/run/docker.sock", "path to the docker unix socket")
	flag.StringVar(&skydnsUrl, "skydns", "", "url to the skydns url")
	flag.StringVar(&secret, "secret", "", "skydns secret")
	flag.StringVar(&dockerHostName, "hostname", "docker", "docker host name")
	flag.StringVar(&environment, "environment", "dev", "environment name where service is running")
	flag.IntVar(&ttl, "ttl", 60, "default ttl to use when registering a service")
	flag.IntVar(&beat, "beat", 0, "heartbeat interval")
	flag.Parse()

	if beat < 1 {
		beat = ttl - (ttl / 4)
	}

	if skydnsUrl == "" {
		skydnsUrl = "http://" + os.Getenv("SKYDNS_PORT_8080_TCP_ADDR") + ":8080"
	}
}

func newClient(path string) (*httputil.ClientConn, error) {
	conn, err := net.Dial("unix", path)
	if err != nil {
		return nil, err
	}
	return httputil.NewClientConn(conn, nil), nil
}

func truncate(name string) string {
	return name[:10]
}

func fetchContainer(name, image string) (*Container, error) {
	path := fmt.Sprintf("/containers/%s/json", name)
	c, err := newClient(dockerPath)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, err
	}

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

	if resp.StatusCode == http.StatusOK {
		d := json.NewDecoder(resp.Body)
		var container *Container
		if err = d.Decode(&container); err != nil {
			return nil, err
		}
		container.Image = image
		return container, nil
	}
	return nil, fmt.Errorf("Could not fetch container %d", resp.StatusCode)
}

func removeTag(name string) string {
	return removeSlash(strings.Split(name, ":")[0])
}

func removeSlash(name string) string {
	return strings.Replace(name, "/", "", -1)
}

func cleanImageImage(name string) string {
	parts := strings.Split(name, "/")
	if len(parts) == 1 {
		return removeTag(name)
	}
	return removeTag(parts[1])
}

func heartbeat(uuid string) {
	if _, exists := running[uuid]; exists {
		return
	}
	running[uuid] = struct{}{}
	defer delete(running, uuid)

	for _ = range time.Tick(time.Duration(beat) * time.Second) {
		container, err := fetchContainer(uuid, "")
		if err != nil {
			log.Println(err)
			break
		}

		if container.State.Running {
			log.Printf("Updating ttl for %s\n", container.Name)

			if err := skydns.Update(uuid, uint32(ttl)); err != nil {
				log.Println(err)
				break
			}
		} else {
			if err := skydns.Delete(uuid); err != nil {
				log.Println(err)
				break
			}
		}
	}
}

// <uuid>.<host>.<region>.<version>.<service>.<environment>.skydns.local
func createService(container *Container) *msg.Service {
	return &msg.Service{
		Name:        cleanImageImage(container.Image), // Service name
		Version:     removeSlash(container.Name),      // Instance of the service
		Host:        container.NetworkSettings.IpAddress,
		Environment: environment,    // testing, prod, dev
		Region:      dockerHostName, // Docker host where it's running
		TTL:         uint32(ttl),    // 60 seconds
		Port:        80,             // TODO: How to handle multiple ports
	}
}

func main() {
	c, err := newClient(dockerPath)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	skydns, err = client.NewClient(skydnsUrl, secret, dockerHostName, 53)
	if err != nil {
		log.Fatal(err)
	}

	req, err := http.NewRequest("GET", "/events", nil)
	if err != nil {
		log.Fatal(err)
	}

	resp, err := c.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	dec := json.NewDecoder(resp.Body)
	log.Printf("Starting run loop...\n")
	for {
		var event *Event
		if err := dec.Decode(&event); err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		}
		uuid := truncate(event.ContainerId)

		switch event.Status {
		case "die", "stop", "kill":
			log.Printf("Removing %s for %s from skydns\n", uuid, event.Image)

			if err := skydns.Delete(uuid); err != nil {
				log.Fatal(err)
			}
		case "start", "restart":
			log.Printf("Adding %s for %s\n", uuid, event.Image)

			container, err := fetchContainer(event.ContainerId, event.Image)
			if err != nil {
				log.Fatal(err)
			}
			service := createService(container)

			if err := skydns.Add(uuid, service); err != nil {
				log.Fatal(err)
			}
			go heartbeat(uuid)
		}
	}
}
<commit_msg>restore containers on start<commit_after>/*
   TODO: Add restore/reconnect logic
   Multihost
   Multiple ports
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/skynetservices/skydns/client"
	"github.com/skynetservices/skydns/msg"
	"io"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"time"
)

var (
	dockerPath     string
	dockerHostName string
	environment    string
	skydnsUrl      string
	secret         string
	ttl            int
	beat           int

	skydns  *client.Client
	running = make(map[string]struct{})
)

type (
	Event struct {
		ContainerId string `json:"id"`
		Status      string `json:"status"`
		Image       string `json:"from"`
	}

	ContainerConfig struct {
		Hostname     string
		Image        string
		ExposedPorts map[string]struct{}
	}

	NetworkSettings struct {
		IpAddress   string
		PortMapping map[string]map[string]string
	}

	State struct {
		Running bool
	}

	Container struct {
		Id              string
		Image           string
		Name            string
		Config          *ContainerConfig
		NetworkSettings *NetworkSettings
		State           State
	}
)

func init() {
	flag.StringVar(&dockerPath, "s", "/var/run/docker.sock", "path to the docker unix socket")
	flag.StringVar(&skydnsUrl, "skydns", "", "url to the skydns url")
	flag.StringVar(&secret, "secret", "", "skydns secret")
	flag.StringVar(&dockerHostName, "hostname", "docker", "docker host name")
	flag.StringVar(&environment, "environment", "dev", "environment name where service is running")
	flag.IntVar(&ttl, "ttl", 60, "default ttl to use when registering a service")
	flag.IntVar(&beat, "beat", 0, "heartbeat interval")
	flag.Parse()

	if beat < 1 {
		beat = ttl - (ttl / 4)
	}

	if skydnsUrl == "" {
		skydnsUrl = "http://" + os.Getenv("SKYDNS_PORT_8080_TCP_ADDR") + ":8080"
	}
}

func newClient(path string) (*httputil.ClientConn, error) {
	conn, err := net.Dial("unix", path)
	if err != nil {
		return nil, err
	}
	return httputil.NewClientConn(conn, nil), nil
}

func truncate(name string) string {
	return name[:10]
}

func fetchContainer(name, image string) (*Container, error) {
	path := fmt.Sprintf("/containers/%s/json", name)
	c, err := newClient(dockerPath)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, err
	}

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

	if resp.StatusCode == http.StatusOK {
		d := json.NewDecoder(resp.Body)
		var container *Container
		if err = d.Decode(&container); err != nil {
			return nil, err
		}
		container.Image = image
		return container, nil
	}
	return nil, fmt.Errorf("Could not fetch container %d", resp.StatusCode)
}

func removeTag(name string) string {
	return removeSlash(strings.Split(name, ":")[0])
}

func removeSlash(name string) string {
	return strings.Replace(name, "/", "", -1)
}

func cleanImageImage(name string) string {
	parts := strings.Split(name, "/")
	if len(parts) == 1 {
		return removeTag(name)
	}
	return removeTag(parts[1])
}

func getUUID(id string) string {
	return truncate(id)
}

func heartbeat(uuid string) {
	if _, exists := running[uuid]; exists {
		return
	}
	running[uuid] = struct{}{}
	defer delete(running, uuid)

	for _ = range time.Tick(time.Duration(beat) * time.Second) {
		container, err := fetchContainer(uuid, "")
		if err != nil {
			log.Println(err)
			break
		}

		if container.State.Running {
			log.Printf("Updating ttl for %s\n", container.Name)

			if err := skydns.Update(uuid, uint32(ttl)); err != nil {
				log.Println(err)
				break
			}
		} else {
			if err := skydns.Delete(uuid); err != nil {
				log.Println(err)
				break
			}
		}
	}
}

func restoreContainers() {
	path := fmt.Sprintf("/containers/json")
	c, err := newClient(dockerPath)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		log.Fatal(err)
	}

	resp, err := c.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusOK {
		d := json.NewDecoder(resp.Body)
		var containers []*Container
		if err = d.Decode(&containers); err != nil {
			log.Println(err)
		}
		for _, cnt := range containers {
			container, err := fetchContainer(cnt.Id, cnt.Image)
			if err != nil {
				log.Println(err)
			}
			service := createService(container)
			uuid := getUUID(cnt.Id)
			log.Println(fmt.Sprintf("Adding %v (%v)", uuid, cleanImageImage(cnt.Image)))
			if err := skydns.Add(uuid, service); err != nil {
				log.Fatal(err)
			}
			go heartbeat(uuid)
		}
	}
}

// <uuid>.<host>.<region>.<version>.<service>.<environment>.skydns.local
func createService(container *Container) *msg.Service {
	return &msg.Service{
		Name:        cleanImageImage(container.Image), // Service name
		Version:     removeSlash(container.Name),      // Instance of the service
		Host:        container.NetworkSettings.IpAddress,
		Environment: environment,    // testing, prod, dev
		Region:      dockerHostName, // Docker host where it's running
		TTL:         uint32(ttl),    // 60 seconds
		Port:        80,             // TODO: How to handle multiple ports
	}
}

func main() {
	c, err := newClient(dockerPath)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	skydns, err = client.NewClient(skydnsUrl, secret, dockerHostName, 53)
	if err != nil {
		log.Fatal(err)
	}

	restoreContainers()
	req, err := http.NewRequest("GET", "/events", nil)
	if err != nil {
		log.Fatal(err)
	}

	resp, err := c.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	dec := json.NewDecoder(resp.Body)
	log.Printf("Starting run loop...\n")
	for {
		var event *Event
		if err := dec.Decode(&event); err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		}
		uuid := getUUID(event.ContainerId)

		switch event.Status {
		case "die", "stop", "kill":
			log.Printf("Removing %s for %s from skydns\n", uuid, event.Image)

			if err := skydns.Delete(uuid); err != nil {
				log.Fatal(err)
			}
		case "start", "restart":
			log.Printf("Adding %s for %s\n", uuid, event.Image)

			container, err := fetchContainer(event.ContainerId, event.Image)
			if err != nil {
				log.Fatal(err)
			}
			service := createService(container)

			if err := skydns.Add(uuid, service); err != nil {
				log.Fatal(err)
			}
			go heartbeat(uuid)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/openshift/origin/pkg/util/proc"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/pflag"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	kcollectors "k8s.io/kube-state-metrics/collectors"
	"k8s.io/kube-state-metrics/version"
)

const (
	metricsPath = "/metrics"
	healthzPath = "/healthz"
)

var (
	defaultCollectors = collectorSet{
		"daemonsets":               struct{}{},
		"deployments":              struct{}{},
		"limitranges":              struct{}{},
		"nodes":                    struct{}{},
		"pods":                     struct{}{},
		"replicasets":              struct{}{},
		"replicationcontrollers":   struct{}{},
		"resourcequotas":           struct{}{},
		"services":                 struct{}{},
		"jobs":                     struct{}{},
		"cronjobs":                 struct{}{},
		"statefulsets":             struct{}{},
		"persistentvolumes":        struct{}{},
		"persistentvolumeclaims":   struct{}{},
		"namespaces":               struct{}{},
		"horizontalpodautoscalers": struct{}{},
		"endpoints":                struct{}{},
	}
	availableCollectors = map[string]func(registry prometheus.Registerer, kubeClient clientset.Interface, namespace string){
		"cronjobs":                 kcollectors.RegisterCronJobCollector,
		"daemonsets":               kcollectors.RegisterDaemonSetCollector,
		"deployments":              kcollectors.RegisterDeploymentCollector,
		"jobs":                     kcollectors.RegisterJobCollector,
		"limitranges":              kcollectors.RegisterLimitRangeCollector,
		"nodes":                    kcollectors.RegisterNodeCollector,
		"pods":                     kcollectors.RegisterPodCollector,
		"replicasets":              kcollectors.RegisterReplicaSetCollector,
		"replicationcontrollers":   kcollectors.RegisterReplicationControllerCollector,
		"resourcequotas":           kcollectors.RegisterResourceQuotaCollector,
		"services":                 kcollectors.RegisterServiceCollector,
		"statefulsets":             kcollectors.RegisterStatefulSetCollector,
		"persistentvolumes":        kcollectors.RegisterPersistentVolumeCollector,
		"persistentvolumeclaims":   kcollectors.RegisterPersistentVolumeClaimCollector,
		"namespaces":               kcollectors.RegisterNamespaceCollector,
		"horizontalpodautoscalers": kcollectors.RegisterHorizontalPodAutoScalerCollector,
		"endpoints":                kcollectors.RegisterEndpointCollector,
	}
)

type collectorSet map[string]struct{}

func (c *collectorSet) String() string {
	s := *c
	ss := s.asSlice()
	sort.Strings(ss)
	return strings.Join(ss, ",")
}

func (c *collectorSet) Set(value string) error {
	s := *c
	cols := strings.Split(value, ",")
	for _, col := range cols {
		_, ok := availableCollectors[col]
		if !ok {
			glog.Fatalf("Collector \"%s\" does not exist", col)
		}
		s[col] = struct{}{}
	}
	return nil
}

func (c collectorSet) asSlice() []string {
	cols := []string{}
	for col := range c {
		cols = append(cols, col)
	}
	return cols
}

func (c collectorSet) isEmpty() bool {
	return len(c.asSlice()) == 0
}

func (c *collectorSet) Type() string {
	return "string"
}

type options struct {
	inCluster     bool
	apiserver     string
	kubeconfig    string
	help          bool
	port          int
	host          string
	telemetryPort int
	telemetryHost string
	collectors    collectorSet
	namespace     string
	version       bool
}

func main() {
	options := &options{collectors: make(collectorSet)}
	flags := pflag.NewFlagSet("", pflag.ExitOnError)
	// add glog flags
	flags.AddGoFlagSet(flag.CommandLine)
	flags.Lookup("logtostderr").Value.Set("true")
	flags.Lookup("logtostderr").DefValue = "true"
	flags.Lookup("logtostderr").NoOptDefVal = "true"
	flags.BoolVar(&options.inCluster, "in-cluster", true, `If true, use the built in kubernetes cluster for creating the client`)
	flags.StringVar(&options.apiserver, "apiserver", "", `The URL of the apiserver to use as a master`)
	flags.StringVar(&options.kubeconfig, "kubeconfig", "", "Absolute path to the kubeconfig file")
	flags.BoolVarP(&options.help, "help", "h", false, "Print help text")
	flags.IntVar(&options.port, "port", 80, `Port to expose metrics on.`)
	flags.StringVar(&options.host, "host", "0.0.0.0", `Host to expose metrics on.`)
	flags.IntVar(&options.telemetryPort, "telemetry-port", 81, `Port to expose kube-state-metrics self metrics on.`)
	flags.StringVar(&options.telemetryHost, "telemetry-host", "0.0.0.0", `Host to expose kube-state-metrics self metrics on.`)
	flags.Var(&options.collectors, "collectors", fmt.Sprintf("Comma-separated list of collectors to be enabled. Defaults to %q", &defaultCollectors))
	flags.StringVar(&options.namespace, "namespace", metav1.NamespaceAll, "namespace to be enabled for collecting resources")
	flags.BoolVarP(&options.version, "version", "", false, "kube-state-metrics build version information")

	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flags.PrintDefaults()
	}

	err := flags.Parse(os.Args)
	if err != nil {
		glog.Fatalf("Error: %s", err)
	}

	if options.version {
		fmt.Printf("%#v\n", version.GetVersion())
		os.Exit(0)
	}

	if options.help {
		flags.Usage()
		os.Exit(0)
	}

	var collectors collectorSet
	if len(options.collectors) == 0 {
		glog.Info("Using default collectors")
		collectors = defaultCollectors
	} else {
		collectors = options.collectors
	}

	if options.namespace == metav1.NamespaceAll {
		glog.Info("Using all namespace")
	} else {
		glog.Infof("Using %s namespace", options.namespace)
	}

	if isNotExists(options.kubeconfig) && !(options.inCluster) {
		glog.Fatalf("kubeconfig invalid and --in-cluster is false; kubeconfig must be set to a valid file(kubeconfig default file name: $HOME/.kube/config)")
	}
	if options.apiserver != "" {
		glog.Infof("apiserver set to: %v", options.apiserver)
	}

	proc.StartReaper()

	kubeClient, err := createKubeClient(options.inCluster, options.apiserver, options.kubeconfig)
	if err != nil {
		glog.Fatalf("Failed to create client: %v", err)
	}

	ksmMetricsRegistry := prometheus.NewRegistry()
	ksmMetricsRegistry.Register(kcollectors.ResourcesPerScrapeMetric)
	ksmMetricsRegistry.Register(kcollectors.ScrapeErrorTotalMetric)
	ksmMetricsRegistry.Register(prometheus.NewProcessCollector(os.Getpid(), ""))
	ksmMetricsRegistry.Register(prometheus.NewGoCollector())
	go telemetryServer(ksmMetricsRegistry, options.telemetryHost, options.telemetryPort)

	registry := prometheus.NewRegistry()
	registerCollectors(registry, kubeClient, collectors, options.namespace)
	metricsServer(registry, options.host, options.port)
}

func isNotExists(file string) bool {
	if file == "" {
		file = clientcmd.NewDefaultClientConfigLoadingRules().GetDefaultFilename()
	}
	_, err := os.Stat(file)
	return os.IsNotExist(err)
}

func createKubeClient(inCluster bool, apiserver string, kubeconfig string) (kubeClient clientset.Interface, err error) {
	if inCluster {
		config, err := rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
		// Allow overriding of apiserver even if using inClusterConfig
		// (necessary if kube-proxy isn't properly set up).
		if apiserver != "" {
			config.Host = apiserver
		}
		tokenPresent := false
		if len(config.BearerToken) > 0 {
			tokenPresent = true
		}
		glog.Infof("service account token present: %v", tokenPresent)
		glog.Infof("service host: %s", config.Host)
		if kubeClient, err = clientset.NewForConfig(config); err != nil {
			return nil, err
		}
	} else {
		loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
		// if you want to change the loading rules (which files in which order), you can do so here
		loadingRules.ExplicitPath = kubeconfig
		configOverrides := &clientcmd.ConfigOverrides{}
		// if you want to change override values or bind them to flags, there are methods to help you
		kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
		config, err := kubeConfig.ClientConfig()
		//config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
		//config, err := clientcmd.DefaultClientConfig.ClientConfig()
		if err != nil {
			return nil, err
		}
		kubeClient, err = clientset.NewForConfig(config)
		if err != nil {
			return nil, err
		}
	}

	// Informers don't seem to do a good job logging error messages when it
	// can't reach the server, making debugging hard. This makes it easier to
	// figure out if apiserver is configured incorrectly.
	glog.Infof("Testing communication with server")
	v, err := kubeClient.Discovery().ServerVersion()
	if err != nil {
		return nil, fmt.Errorf("ERROR communicating with apiserver: %v", err)
	}
	glog.Infof("Running with Kubernetes cluster version: v%s.%s. git version: %s. git tree state: %s. commit: %s. platform: %s",
		v.Major, v.Minor, v.GitVersion, v.GitTreeState, v.GitCommit, v.Platform)
	glog.Infof("Communication with server successful")

	return kubeClient, nil
}

func telemetryServer(registry prometheus.Gatherer, host string, port int) {
	// Address to listen on for web interface and telemetry
	listenAddress := net.JoinHostPort(host, strconv.Itoa(port))

	glog.Infof("Starting kube-state-metrics self metrics server: %s", listenAddress)

	mux := http.NewServeMux()

	// Add metricsPath
	mux.Handle(metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
	// Add index
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube-State-Metrics Metrics Server</title>

Kube-State-Metrics Metrics

<a href='` + metricsPath + `'>metrics

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, mux))
}

func metricsServer(registry prometheus.Gatherer, host string, port int) {
	// Address to listen on for web interface and telemetry
	listenAddress := net.JoinHostPort(host, strconv.Itoa(port))

	glog.Infof("Starting metrics server: %s", listenAddress)

	mux := http.NewServeMux()

	mux.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
	mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	mux.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

	// Add metricsPath
	mux.Handle(metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
	// Add healthzPath
	mux.HandleFunc(healthzPath, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("ok"))
	})
	// Add index
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube Metrics Server</title>

Kube Metrics

<a href='` + metricsPath + `'>metrics

<a href='` + healthzPath + `'>healthz

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, mux))
}

// registerCollectors creates and starts informers and initializes and
// registers metrics for collection.
func registerCollectors(registry prometheus.Registerer, kubeClient clientset.Interface, enabledCollectors collectorSet, namespace string) {
	activeCollectors := []string{}
	for c := range enabledCollectors {
		f, ok := availableCollectors[c]
		if ok {
			f(registry, kubeClient, namespace)
			activeCollectors = append(activeCollectors, c)
		}
	}

	glog.Infof("Active collectors: %s", strings.Join(activeCollectors, ","))
}
<commit_msg>enable log in the prom http handler<commit_after>/*
Copyright 2015 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 main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/openshift/origin/pkg/util/proc"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/pflag"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	kcollectors "k8s.io/kube-state-metrics/collectors"
	"k8s.io/kube-state-metrics/version"
)

const (
	metricsPath = "/metrics"
	healthzPath = "/healthz"
)

var (
	defaultCollectors = collectorSet{
		"daemonsets":               struct{}{},
		"deployments":              struct{}{},
		"limitranges":              struct{}{},
		"nodes":                    struct{}{},
		"pods":                     struct{}{},
		"replicasets":              struct{}{},
		"replicationcontrollers":   struct{}{},
		"resourcequotas":           struct{}{},
		"services":                 struct{}{},
		"jobs":                     struct{}{},
		"cronjobs":                 struct{}{},
		"statefulsets":             struct{}{},
		"persistentvolumes":        struct{}{},
		"persistentvolumeclaims":   struct{}{},
		"namespaces":               struct{}{},
		"horizontalpodautoscalers": struct{}{},
		"endpoints":                struct{}{},
	}
	availableCollectors = map[string]func(registry prometheus.Registerer, kubeClient clientset.Interface, namespace string){
		"cronjobs":                 kcollectors.RegisterCronJobCollector,
		"daemonsets":               kcollectors.RegisterDaemonSetCollector,
		"deployments":              kcollectors.RegisterDeploymentCollector,
		"jobs":                     kcollectors.RegisterJobCollector,
		"limitranges":              kcollectors.RegisterLimitRangeCollector,
		"nodes":                    kcollectors.RegisterNodeCollector,
		"pods":                     kcollectors.RegisterPodCollector,
		"replicasets":              kcollectors.RegisterReplicaSetCollector,
		"replicationcontrollers":   kcollectors.RegisterReplicationControllerCollector,
		"resourcequotas":           kcollectors.RegisterResourceQuotaCollector,
		"services":                 kcollectors.RegisterServiceCollector,
		"statefulsets":             kcollectors.RegisterStatefulSetCollector,
		"persistentvolumes":        kcollectors.RegisterPersistentVolumeCollector,
		"persistentvolumeclaims":   kcollectors.RegisterPersistentVolumeClaimCollector,
		"namespaces":               kcollectors.RegisterNamespaceCollector,
		"horizontalpodautoscalers": kcollectors.RegisterHorizontalPodAutoScalerCollector,
		"endpoints":                kcollectors.RegisterEndpointCollector,
	}
)

type collectorSet map[string]struct{}

func (c *collectorSet) String() string {
	s := *c
	ss := s.asSlice()
	sort.Strings(ss)
	return strings.Join(ss, ",")
}

func (c *collectorSet) Set(value string) error {
	s := *c
	cols := strings.Split(value, ",")
	for _, col := range cols {
		_, ok := availableCollectors[col]
		if !ok {
			glog.Fatalf("Collector \"%s\" does not exist", col)
		}
		s[col] = struct{}{}
	}
	return nil
}

func (c collectorSet) asSlice() []string {
	cols := []string{}
	for col := range c {
		cols = append(cols, col)
	}
	return cols
}

func (c collectorSet) isEmpty() bool {
	return len(c.asSlice()) == 0
}

func (c *collectorSet) Type() string {
	return "string"
}

type options struct {
	inCluster     bool
	apiserver     string
	kubeconfig    string
	help          bool
	port          int
	host          string
	telemetryPort int
	telemetryHost string
	collectors    collectorSet
	namespace     string
	version       bool
}

func main() {
	options := &options{collectors: make(collectorSet)}
	flags := pflag.NewFlagSet("", pflag.ExitOnError)
	// add glog flags
	flags.AddGoFlagSet(flag.CommandLine)
	flags.Lookup("logtostderr").Value.Set("true")
	flags.Lookup("logtostderr").DefValue = "true"
	flags.Lookup("logtostderr").NoOptDefVal = "true"
	flags.BoolVar(&options.inCluster, "in-cluster", true, `If true, use the built in kubernetes cluster for creating the client`)
	flags.StringVar(&options.apiserver, "apiserver", "", `The URL of the apiserver to use as a master`)
	flags.StringVar(&options.kubeconfig, "kubeconfig", "", "Absolute path to the kubeconfig file")
	flags.BoolVarP(&options.help, "help", "h", false, "Print help text")
	flags.IntVar(&options.port, "port", 80, `Port to expose metrics on.`)
	flags.StringVar(&options.host, "host", "0.0.0.0", `Host to expose metrics on.`)
	flags.IntVar(&options.telemetryPort, "telemetry-port", 81, `Port to expose kube-state-metrics self metrics on.`)
	flags.StringVar(&options.telemetryHost, "telemetry-host", "0.0.0.0", `Host to expose kube-state-metrics self metrics on.`)
	flags.Var(&options.collectors, "collectors", fmt.Sprintf("Comma-separated list of collectors to be enabled. Defaults to %q", &defaultCollectors))
	flags.StringVar(&options.namespace, "namespace", metav1.NamespaceAll, "namespace to be enabled for collecting resources")
	flags.BoolVarP(&options.version, "version", "", false, "kube-state-metrics build version information")

	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flags.PrintDefaults()
	}

	err := flags.Parse(os.Args)
	if err != nil {
		glog.Fatalf("Error: %s", err)
	}

	if options.version {
		fmt.Printf("%#v\n", version.GetVersion())
		os.Exit(0)
	}

	if options.help {
		flags.Usage()
		os.Exit(0)
	}

	var collectors collectorSet
	if len(options.collectors) == 0 {
		glog.Info("Using default collectors")
		collectors = defaultCollectors
	} else {
		collectors = options.collectors
	}

	if options.namespace == metav1.NamespaceAll {
		glog.Info("Using all namespace")
	} else {
		glog.Infof("Using %s namespace", options.namespace)
	}

	if isNotExists(options.kubeconfig) && !(options.inCluster) {
		glog.Fatalf("kubeconfig invalid and --in-cluster is false; kubeconfig must be set to a valid file(kubeconfig default file name: $HOME/.kube/config)")
	}
	if options.apiserver != "" {
		glog.Infof("apiserver set to: %v", options.apiserver)
	}

	proc.StartReaper()

	kubeClient, err := createKubeClient(options.inCluster, options.apiserver, options.kubeconfig)
	if err != nil {
		glog.Fatalf("Failed to create client: %v", err)
	}

	ksmMetricsRegistry := prometheus.NewRegistry()
	ksmMetricsRegistry.Register(kcollectors.ResourcesPerScrapeMetric)
	ksmMetricsRegistry.Register(kcollectors.ScrapeErrorTotalMetric)
	ksmMetricsRegistry.Register(prometheus.NewProcessCollector(os.Getpid(), ""))
	ksmMetricsRegistry.Register(prometheus.NewGoCollector())
	go telemetryServer(ksmMetricsRegistry, options.telemetryHost, options.telemetryPort)

	registry := prometheus.NewRegistry()
	registerCollectors(registry, kubeClient, collectors, options.namespace)
	metricsServer(registry, options.host, options.port)
}

func isNotExists(file string) bool {
	if file == "" {
		file = clientcmd.NewDefaultClientConfigLoadingRules().GetDefaultFilename()
	}
	_, err := os.Stat(file)
	return os.IsNotExist(err)
}

func createKubeClient(inCluster bool, apiserver string, kubeconfig string) (kubeClient clientset.Interface, err error) {
	if inCluster {
		config, err := rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
		// Allow overriding of apiserver even if using inClusterConfig
		// (necessary if kube-proxy isn't properly set up).
		if apiserver != "" {
			config.Host = apiserver
		}
		tokenPresent := false
		if len(config.BearerToken) > 0 {
			tokenPresent = true
		}
		glog.Infof("service account token present: %v", tokenPresent)
		glog.Infof("service host: %s", config.Host)
		if kubeClient, err = clientset.NewForConfig(config); err != nil {
			return nil, err
		}
	} else {
		loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
		// if you want to change the loading rules (which files in which order), you can do so here
		loadingRules.ExplicitPath = kubeconfig
		configOverrides := &clientcmd.ConfigOverrides{}
		// if you want to change override values or bind them to flags, there are methods to help you
		kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
		config, err := kubeConfig.ClientConfig()
		//config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
		//config, err := clientcmd.DefaultClientConfig.ClientConfig()
		if err != nil {
			return nil, err
		}
		kubeClient, err = clientset.NewForConfig(config)
		if err != nil {
			return nil, err
		}
	}

	// Informers don't seem to do a good job logging error messages when it
	// can't reach the server, making debugging hard. This makes it easier to
	// figure out if apiserver is configured incorrectly.
	glog.Infof("Testing communication with server")
	v, err := kubeClient.Discovery().ServerVersion()
	if err != nil {
		return nil, fmt.Errorf("ERROR communicating with apiserver: %v", err)
	}
	glog.Infof("Running with Kubernetes cluster version: v%s.%s. git version: %s. git tree state: %s. commit: %s. platform: %s",
		v.Major, v.Minor, v.GitVersion, v.GitTreeState, v.GitCommit, v.Platform)
	glog.Infof("Communication with server successful")

	return kubeClient, nil
}

func telemetryServer(registry prometheus.Gatherer, host string, port int) {
	// Address to listen on for web interface and telemetry
	listenAddress := net.JoinHostPort(host, strconv.Itoa(port))

	glog.Infof("Starting kube-state-metrics self metrics server: %s", listenAddress)

	mux := http.NewServeMux()

	// Add metricsPath
	logger := log.New(os.Stderr, "Prometheus HTTP logger: ", log.Lshortfile)
	mux.Handle(metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorLog: logger}))
	// Add index
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube-State-Metrics Metrics Server</title>

Kube-State-Metrics Metrics

<a href='` + metricsPath + `'>metrics

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, mux))
}

func metricsServer(registry prometheus.Gatherer, host string, port int) {
	// Address to listen on for web interface and telemetry
	listenAddress := net.JoinHostPort(host, strconv.Itoa(port))

	glog.Infof("Starting metrics server: %s", listenAddress)

	mux := http.NewServeMux()

	mux.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
	mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
	mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	mux.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))

	// Add metricsPath
	logger := log.New(os.Stderr, "Prometheus HTTP logger: ", log.Lshortfile)
	mux.Handle(metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorLog: logger}))
	// Add healthzPath
	mux.HandleFunc(healthzPath, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		w.Write([]byte("ok"))
	})
	// Add index
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Kube Metrics Server</title>

Kube Metrics

<a href='` + metricsPath + `'>metrics

<a href='` + healthzPath + `'>healthz

             `))
	})
	log.Fatal(http.ListenAndServe(listenAddress, mux))
}

// registerCollectors creates and starts informers and initializes and
// registers metrics for collection.
func registerCollectors(registry prometheus.Registerer, kubeClient clientset.Interface, enabledCollectors collectorSet, namespace string) {
	activeCollectors := []string{}
	for c := range enabledCollectors {
		f, ok := availableCollectors[c]
		if ok {
			f(registry, kubeClient, namespace)
			activeCollectors = append(activeCollectors, c)
		}
	}

	glog.Infof("Active collectors: %s", strings.Join(activeCollectors, ","))
}
<|endoftext|>


<commit_before>// Package bot is the top level container for ci-bot-01 code
package bot

import (
	"fmt"
	"net"
	"net/http"
)

func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	// TODO: Add check of source IP
	// https://help.github.com/articles/what-ip-addresses-does-github-use-that-i-should-whitelist/
	// https://groups.google.com/forum/embed/#!topic/golang-nuts/Usu-B5rcCJs

	fmt.Fprint(w, "Hello, world!

")
}
<commit_msg>Remove test print lines<commit_after>// Package bot is the top level container for ci-bot-01 code
package bot

import (
	"fmt"
)

func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	// TODO: Add check of source IP
	// https://help.github.com/articles/what-ip-addresses-does-github-use-that-i-should-whitelist/
	// https://groups.google.com/forum/embed/#!topic/golang-nuts/Usu-B5rcCJs

	fmt.Fprint(w, "Hello, world!

")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"path/filepath"

	"github.com/appropriate/go-virtualboxclient/virtualboxclient"
	"github.com/calavera/dkvolume"
)

type vboxwebsrvDriver struct {
}

func (g vboxwebsrvDriver) Create(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Creating volume %#v\n", r)

	client := virtualboxclient.New("", "", "http://192.168.99.1:18083")

	if err := client.Logon(); err != nil {
		return dkvolume.Response{Err: err.Error()}
	}

	location := filepath.Join("/Users/mike/.docker/machine/machines", fmt.Sprintf("%s.vmdk"))

	hardDisk, err := client.CreateHardDisk("vmdk", location)
	if err != nil {
		return dkvolume.Response{Err: err.Error()}
	}

	fmt.Printf("Hard disk: %#v\n", hardDisk)

	return dkvolume.Response{}
}

func (g vboxwebsrvDriver) Mount(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Mounting volume %#v\n", r)
	return dkvolume.Response{}
}

func (g vboxwebsrvDriver) Path(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Pathing volume %#v\n", r)
	return dkvolume.Response{}
}

func (g vboxwebsrvDriver) Remove(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Removing volume %#v\n", r)
	return dkvolume.Response{}
}

func (g vboxwebsrvDriver) Unmount(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Unmounting volume %#v\n", r)
	return dkvolume.Response{}
}

func main() {
	d := vboxwebsrvDriver{}
	h := dkvolume.NewHandler(d)
	fmt.Println(h.ServeUnix("root", "vboxwebsrv"))
}
<commit_msg>Rename driver struct to virtualboxDriver<commit_after>package main

import (
	"fmt"
	"path/filepath"

	"github.com/appropriate/go-virtualboxclient/virtualboxclient"
	"github.com/calavera/dkvolume"
)

type virtualboxDriver struct {
}

func (d virtualboxDriver) Create(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Creating volume %#v\n", r)

	client := virtualboxclient.New("", "", "http://192.168.99.1:18083")

	if err := client.Logon(); err != nil {
		return dkvolume.Response{Err: err.Error()}
	}

	location := filepath.Join("/Users/mike/.docker/machine/machines", fmt.Sprintf("%s.vmdk"))

	hardDisk, err := client.CreateHardDisk("vmdk", location)
	if err != nil {
		return dkvolume.Response{Err: err.Error()}
	}

	fmt.Printf("Hard disk: %#v\n", hardDisk)

	return dkvolume.Response{}
}

func (d virtualboxDriver) Mount(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Mounting volume %#v\n", r)
	return dkvolume.Response{}
}

func (d virtualboxDriver) Path(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Pathing volume %#v\n", r)
	return dkvolume.Response{}
}

func (d virtualboxDriver) Remove(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Removing volume %#v\n", r)
	return dkvolume.Response{}
}

func (d virtualboxDriver) Unmount(r dkvolume.Request) dkvolume.Response {
	fmt.Printf("Unmounting volume %#v\n", r)
	return dkvolume.Response{}
}

func main() {
	d := virtualboxDriver{}
	h := dkvolume.NewHandler(d)
	fmt.Println(h.ServeUnix("root", "vboxwebsrv"))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"

	"os"
	"os/signal"
	"syscall"

	log "github.com/sirupsen/logrus"

	"github.com/gost/server/configuration"
	"github.com/gost/server/database/postgis"
	"github.com/gost/server/http"
	gostLog "github.com/gost/server/log"
	"github.com/gost/server/mqtt"
	"github.com/gost/server/sensorthings/api"
	"github.com/gost/server/sensorthings/models"
)

var (
	stAPI       models.API
	gostServer  http.Server
	mqttClient  models.MQTTClient
	file        *os.File
	logger      *log.Logger
	conf        configuration.Config
	cfgFlag     = flag.String("config", "config.yaml", "path of the config file")
	installFlag = flag.String("install", "", "path to the database creation file")
)

func init() {
	flag.Parse()

	cfg := *cfgFlag
	conf, err := configuration.GetConfig(cfg)
	if err != nil {
		log.Fatal("config read error: ", err)
		return
	}

	configuration.SetEnvironmentVariables(&conf)
	logger, err = gostLog.InitializeLogger(file, conf.Logger.FileName, new(log.TextFormatter), conf.Logger.Verbose)
	if err != nil {
		fmt.Println("Error initializing logger, defaulting to stdout. Error: " + err.Error())
	}
}

func main() {
	stop := make(chan os.Signal, 2)
	signal.Notify(stop, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	go func() {
		<-stop
		cleanup()
		log.Print("GOST stopped gracefully")
		os.Exit(1)
	}()

	log.Println("Starting GOST....")
	log.Println("Showing debug logs")

	database := postgis.NewDatabase(
		conf.Database.Host,
		conf.Database.Port,
		conf.Database.User,
		conf.Database.Password,
		conf.Database.Database,
		conf.Database.Schema,
		conf.Database.SSL,
		conf.Database.MaxIdleConns,
		conf.Database.MaxOpenConns,
		conf.Server.MaxEntityResponse)
	go database.Start()

	// if install is supplied create database and close, if not start server
	sqlFile := *installFlag
	if len(sqlFile) != 0 {
		createDatabase(database, sqlFile)
	} else {
		mqttClient = mqtt.CreateMQTTClient(conf.MQTT)
		stAPI = api.NewAPI(database, conf, mqttClient)

		if conf.MQTT.Enabled {
			mqttClient.Start(&stAPI)
		}

		createAndStartServer(&stAPI)
	}
}

func createDatabase(db models.Database, sqlFile string) {
	log.Println("--CREATING DATABASE--")

	err := db.CreateSchema(sqlFile)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Database created successfully, you can start your server now")
}

// createAndStartServer creates the GOST HTTPServer and starts it
func createAndStartServer(api *models.API) {
	a := *api
	a.Start()

	config := a.GetConfig()
	gostServer = http.CreateServer(
		config.Server.Host,
		config.Server.Port,
		api,
		config.Server.HTTPS,
		config.Server.HTTPSCert,
		config.Server.HTTPSKey)
	gostServer.Start()
}

func cleanup() {
	if gostServer != nil {
		gostServer.Stop()
	}

	gostLog.CleanUp()
}
<commit_msg>Added logger entry to Main package<commit_after>package main

import (
	"flag"
	"fmt"

	"os"
	"os/signal"
	"syscall"

	log "github.com/sirupsen/logrus"

	"github.com/gost/server/configuration"
	"github.com/gost/server/database/postgis"
	"github.com/gost/server/http"
	gostLog "github.com/gost/server/log"
	"github.com/gost/server/mqtt"
	"github.com/gost/server/sensorthings/api"
	"github.com/gost/server/sensorthings/models"
)

var (
	stAPI       models.API
	gostServer  http.Server
	mqttClient  models.MQTTClient
	file        *os.File
	logger      *log.Logger
	mainLogger  *log.Entry
	conf        configuration.Config
	cfgFlag     = flag.String("config", "config.yaml", "path of the config file")
	installFlag = flag.String("install", "", "path to the database creation file")
)

func init() {
	flag.Parse()

	cfg := *cfgFlag
	conf, err := configuration.GetConfig(cfg)
	if err != nil {
		log.Fatal("config read error: ", err)
		return
	}

	configuration.SetEnvironmentVariables(&conf)
	logger, err = gostLog.InitializeLogger(file, conf.Logger.FileName, new(log.TextFormatter), conf.Logger.Verbose)
	if err != nil {
		fmt.Println("Error initializing logger, defaulting to stdout. Error: " + err.Error())
	}

	//Setting default fieleds for main logger
	mainLogger = logger.WithFields(log.Fields{"package": "main"})
}

func main() {
	stop := make(chan os.Signal, 2)
	signal.Notify(stop, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	go func() {
		<-stop
		cleanup()
		log.Print("GOST stopped gracefully")
		mainLogger.Info("GOST stopped gracefully")
		os.Exit(1)
	}()

	log.Println("Starting GOST....")
	mainLogger.Info("Starting GOST")

	database := postgis.NewDatabase(
		conf.Database.Host,
		conf.Database.Port,
		conf.Database.User,
		conf.Database.Password,
		conf.Database.Database,
		conf.Database.Schema,
		conf.Database.SSL,
		conf.Database.MaxIdleConns,
		conf.Database.MaxOpenConns,
		conf.Server.MaxEntityResponse)
	go database.Start()

	// if install is supplied create database and close, if not start server
	sqlFile := *installFlag
	if len(sqlFile) != 0 {
		createDatabase(database, sqlFile)
	} else {
		mqttClient = mqtt.CreateMQTTClient(conf.MQTT)
		stAPI = api.NewAPI(database, conf, mqttClient)

		if conf.MQTT.Enabled {
			mqttClient.Start(&stAPI)
		}

		createAndStartServer(&stAPI)
	}
}

func createDatabase(db models.Database, sqlFile string) {
	mainLogger.Info("--CREATING DATABASE--")

	err := db.CreateSchema(sqlFile)
	if err != nil {
		log.Fatal(err)
	}

	mainLogger.Info("Database created successfully, you can start your server now")
}

// createAndStartServer creates the GOST HTTPServer and starts it
func createAndStartServer(api *models.API) {
	a := *api
	a.Start()

	config := a.GetConfig()
	gostServer = http.CreateServer(
		config.Server.Host,
		config.Server.Port,
		api,
		config.Server.HTTPS,
		config.Server.HTTPSCert,
		config.Server.HTTPSKey)
	gostServer.Start()
}

func cleanup() {
	if gostServer != nil {
		gostServer.Stop()
	}

	gostLog.CleanUp()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/google/go-github/github"
)

type Contribution struct {
	Date time.Time
	Num  int
}

func (c *Contribution) UnmarshalJSON(data []byte) error {
	var i []interface{}
	err := json.Unmarshal(data, &i)
	if err != nil {
		return err
	}

	if v, ok := i[0].(string); ok {
		c.Date, err = time.Parse("2006-01-02", v)
	}
	if err != nil {
		return err
	}

	if v, ok := i[1].(float64); ok {
		c.Num = int(v)
	}

	return nil
}

func getContributions(user github.User, userData chan<- []Contribution) {
	login := github.Stringify(user.Login)
	url := "https://github.com/users/" + login[1:len(login)-1] + "/contributions"
	var contribData []Contribution

	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if data == nil {
		log.Fatalln("No data returned.")
	}

	err = json.Unmarshal(data, &contribData)
	if err != nil {
		log.Fatal(err)
	}

	userData <- contribData
}

func getOrgMembers(orgName string) []github.User {
	client := github.NewClient(nil)

	users, _, err := client.Organizations.ListMembers(orgName, nil)
	if err != nil {
		log.Fatal(err)
	}

	return users
}

func main() {
	users := getOrgMembers("linode")
	userData := make(chan []Contribution, len(users))
	for _, user := range users {
		go getContributions(user, userData)
	}

	for contribution := range userData {
		fmt.Println(contribution)
	}
}
<commit_msg>fix channel closing<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/google/go-github/github"
)

type Contribution struct {
	Date time.Time
	Num  int
}

func (c *Contribution) UnmarshalJSON(data []byte) error {
	var i []interface{}
	err := json.Unmarshal(data, &i)
	if err != nil {
		return err
	}

	if v, ok := i[0].(string); ok {
		c.Date, err = time.Parse("2006-01-02", v)
	}
	if err != nil {
		return err
	}

	if v, ok := i[1].(float64); ok {
		c.Num = int(v)
	}

	return nil
}

func getContributions(user github.User) []Contribution {
	login := github.Stringify(user.Login)
	url := "https://github.com/users/" + login[1:len(login)-1] + "/contributions"
	var contribData []Contribution

	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if data == nil {
		log.Fatalln("No data returned.")
	}

	err = json.Unmarshal(data, &contribData)
	if err != nil {
		log.Fatal(err)
	}

	return contribData
}

func getOrgMembers(orgName string) []github.User {
	client := github.NewClient(nil)

	users, _, err := client.Organizations.ListMembers(orgName, nil)
	if err != nil {
		log.Fatal(err)
	}

	return users
}

func main() {
	users := getOrgMembers("linode")
	userData := make(chan []Contribution, len(users))

	go func() {
		for {
			contribution, more := <-userData
			if more {
				fmt.Println(contribution)
			} else {
				return
			}
		}
	}()

	for _, user := range users {
		userData <- getContributions(user)
	}
	close(userData)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/cgansen/elastigo/api"
	"github.com/cgansen/elastigo/core"
	"github.com/cgansen/health-near-me/healthnearme"
)

func SearchHandler(w http.ResponseWriter, req *http.Request) {
	log.Printf("%#v", req)
	slat, slon, sdist := req.FormValue("lat"), req.FormValue("lon"), req.FormValue("dist")

	lat, err := strconv.ParseFloat(slat, 64)
	if err != nil {
		http.Error(w, "lat is required and must be a float, e.g. 41.42", 400)
		return
	}

	lon, err := strconv.ParseFloat(slon, 64)
	if err != nil {
		http.Error(w, "lon is required and must be a float, e.g. -87.88", 400)
		return
	}

	dist, err := strconv.ParseInt(sdist, 10, 64)
	if err != nil {
		http.Error(w, "dist is required and must be an integer", 400)
		return
	}

	query := fmt.Sprintf(`{"query":{
	  "filtered": {
	    "query": {
	      "match_all": {}
	    },
	    "filter": {
	      "geo_distance": {
	        "distance": "%dm",
	        "location.lat_lon": {
	          "lat": %f,
	          "lon": %f
	        }
	      }
	    }
	  }
	}
	}`, dist, lat, lon)

	log.Print(query)

	result, err := core.SearchRequest(true, "health-near-me", "health-provider", query, "", 0)
	if err != nil {
		log.Printf("error searching: %s", err)
		http.Error(w, "error searching index", 503)
		return
	}

	var hits []*healthnearme.HealthProvider

	for _, hit := range result.Hits.Hits {
		// unmarshal to a struct
		hp := &healthnearme.HealthProvider{}
		jsn, _ := hit.Source.MarshalJSON()
		if err := json.Unmarshal(jsn, hp); err != nil {
			log.Printf("could not translate to struct: %s", err)
			http.Error(w, "error translating search results", 500)
			return
		}

		hits = append(hits, hp)
	}

	jsn, err := json.MarshalIndent(hits, "", "  ")
	if err != nil {
		log.Print(err)
		http.Error(w, "error dumping search results to json", 500)
		return
	}

	w.Header().Add("Content-type", "application/json")
	// delim := ")]}',\n"
	delim := ""
	resp := fmt.Sprintf("%s%s(%s);", delim, req.FormValue("callback"), string(jsn))

	_, err = w.Write([]byte(resp))
	return

}

func main() {
	api.Domain = "localhost"

	http.HandleFunc("/search", SearchHandler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<commit_msg>sort hits by distance<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/cgansen/elastigo/api"
	"github.com/cgansen/elastigo/core"
	"github.com/cgansen/health-near-me/healthnearme"
)

func SearchHandler(w http.ResponseWriter, req *http.Request) {
	log.Printf("%#v", req)
	slat, slon, sdist := req.FormValue("lat"), req.FormValue("lon"), req.FormValue("dist")

	lat, err := strconv.ParseFloat(slat, 64)
	if err != nil {
		http.Error(w, "lat is required and must be a float, e.g. 41.42", 400)
		return
	}

	lon, err := strconv.ParseFloat(slon, 64)
	if err != nil {
		http.Error(w, "lon is required and must be a float, e.g. -87.88", 400)
		return
	}

	dist, err := strconv.ParseInt(sdist, 10, 64)
	if err != nil {
		http.Error(w, "dist is required and must be an integer", 400)
		return
	}

	query := fmt.Sprintf(`{
		"query":{
			"match_all": {}
		},
		"sort": [
			{
				"_geo_distance":{
					"location.lat_lon": {
						"lat": %f,
						"lon": %f
					},
					"order": "asc",
					"unit": "mi"
				}
			}
		],
		"filter": {
			"geo_distance": {
				"distance": "%dm",
				"location.lat_lon": {
					"lat": %f,
					"lon": %f
				}
			}
		}
	}`, lat, lon, dist, lat, lon)

	log.Print(query)

	result, err := core.SearchRequest(true, "health-near-me", "health-provider", query, "", 0)
	if err != nil {
		log.Printf("error searching: %s", err)
		http.Error(w, "error searching index", 503)
		return
	}

	var hits []*healthnearme.HealthProvider

	for _, hit := range result.Hits.Hits {
		// unmarshal to a struct
		hp := &healthnearme.HealthProvider{}
		jsn, _ := hit.Source.MarshalJSON()
		if err := json.Unmarshal(jsn, hp); err != nil {
			log.Printf("could not translate to struct: %s", err)
			http.Error(w, "error translating search results", 500)
			return
		}

		hits = append(hits, hp)
	}

	jsn, err := json.MarshalIndent(hits, "", "  ")
	if err != nil {
		log.Print(err)
		http.Error(w, "error dumping search results to json", 500)
		return
	}

	w.Header().Add("Content-type", "application/json")
	// delim := ")]}',\n"
	delim := ""
	resp := fmt.Sprintf("%s%s(%s);", delim, req.FormValue("callback"), string(jsn))

	_, err = w.Write([]byte(resp))
	return

}

func main() {
	api.Domain = "localhost"

	http.HandleFunc("/search", SearchHandler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"sort"
)

// # [1, 2, 3] 4 => 4
// # 1 + 1 + 1 + 1 = 4
// # 1 + 1 + 2 = 4
// # 1 + 3 = 4
// # 2 + 2 = 4
// # alex.favaro@affirm.com

// Denominations is the a float64slice of denominations
type Denominations []float64

// Knowing the correct denomination is way cooler than knowing the number of combinations
var denominations = Denominations{
	//	1.0,
	1.1,
	1.2,
	1.3,
	1.4,
	1.5,
	1.6,
	1.7,
	1.8,
	1.9,
	//	2.0,
	//	3.0,
}

const amount = 4.0

var denomSum = []float64{}

// exactChange is used to to calcualte the exact change types
// this should probably be a method on Denomination type.
func exactChange(amount float64, denomination float64) {
	for i := denomination; i < float64(len(denominations)); i++ {
		if denominations[int(i)] > amount {
			// Current value is higher than what is next to calculate
			exactChange(amount, denomination+1)
		} else {
			denomSum[int(i)], _ = math.Modf(amount / denominations[int(i)])
			exactChange(math.Mod(amount, denominations[int(i)]), denomination+1)
			return
		}
	}
}

// Reverse method for denominations type
func (d *Denominations) Reverse() {
	sort.Sort(
		sort.Reverse(
			sort.Float64Slice(*d), // pointer de-ref
		),
	)
}

func main() {
	fmt.Println("calculating appropriate denominations for amount:", amount)
	denominations.Reverse()
	denomSum = make([]float64, len(denominations), len(denominations))
	exactChange(amount, 0)
	fmt.Printf("The right quantity of coins and/or bills for %.2f$:\n", amount)
	for i := 0; i < len(denomSum); i++ {
		if denomSum[i] > 0 {
			fmt.Printf("\t%1.0f x $%.2f\t= $%.2f\n", denomSum[i], denominations[i], denomSum[i]*denominations[i])
		}
	}
}
<commit_msg>add spew<commit_after>package main

import (
	"fmt"
	"github.com/davecgh/go-spew/spew"
	"math"
	"sort"
)

// # [1, 2, 3] 4 => 4
// # 1 + 1 + 1 + 1 = 4
// # 1 + 1 + 2 = 4
// # 1 + 3 = 4
// # 2 + 2 = 4
// # alex.favaro@affirm.com

// Denominations is the a float64slice of denominations
type Denominations []float64

// Knowing the correct denomination is way cooler than knowing the number of combinations
var denominations = Denominations{
	1.0,
	2.0,
	3.0,
	// 1.1,
	// 1.2,
	// 1.3,
	// 1.4,
	// 1.5,
	// 1.6,
	// 1.7,
	// 1.8,
	// 1.9,
}

const amount = 4.0

var denomSum = []float64{}

// exactChange is used to to calcualte the exact change types
// this should probably be a method on Denomination type.
func exactChange(amount float64, denomination float64) {
	for i := denomination; i < float64(len(denominations)); i++ {
		if denominations[int(i)] > amount {
			// Current value is higher than what is next to calculate
			exactChange(amount, denomination+1)
		} else {
			denomSum[int(i)], _ = math.Modf(amount / denominations[int(i)])
			exactChange(math.Mod(amount, denominations[int(i)]), denomination+1)
			return
		}
	}
}

// Reverse method for denominations type
func (d *Denominations) Reverse() {
	sort.Sort(
		sort.Reverse(
			sort.Float64Slice(*d), // pointer de-ref
		),
	)
}

func main() {

	fmt.Println("calculating appropriate denominations for amount:", amount)
	denominations.Reverse()
	denomSum = make([]float64, len(denominations), len(denominations))

	// Rub some concurrency sauce on it
	exactChange(amount, 0)

	// spew
	spew.Dump(amount)
	spew.Dump(denominations)
	spew.Dump(denomSum)

	fmt.Printf("The right quantity of coins and/or bills for %.2f$:\n", amount)
	for i := 0; i < len(denomSum); i++ {
		if denomSum[i] > 0 {
			fmt.Printf("\t%1.0f x $%.2f\t= $%.2f\n", denomSum[i], denominations[i], denomSum[i]*denominations[i])
		}
	}

}
<|endoftext|>


<commit_before>package main

/* TODO:

1. [x] serve HTTP /v1/instances/:app_id to retrieve ip:port pairs for given app
3. [x] implement UDP proxy (one-way/two-way, fanout (& roundrobin))
2. [x] implement upstream-conf.d file management
4. [ ] implement TCP proxy (with pluggable impls: haproxy, lvs, ...)
5. [ ] implement HTTP(S) gateway support
6. [ ] tcp-proxy: add `accept-proxy` support
7. [ ] tcp-proxy: add `proxy-protocol` support

XXX Changes:

* `--marathon-host` is now named `--marathon-ip` and only accepts IP addresses
* `--reconnect-delay` added
* `--haproxy-cfg` removed
* `--gateway` renamed to `--enable-gateway`
* `--enable-files` added
* `--enable-tcp` added
* `--enable-udp` added
* also exposes service discovery API via HTTP endpoint

*/

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/christianparpart/serviced/marathon"
	"github.com/gorilla/mux"
	flag "github.com/ogier/pflag"
)

type mmsdHandler interface {
	Apply(apps []*marathon.App, force bool) error
	Update(app *marathon.App, task *marathon.Task) error
	IsEnabled() bool
	SetEnabled(value bool)
}

type mmsdService struct {
	MarathonScheme   string
	MarathonIP       net.IP
	MarathonPort     uint
	ReconnectDelay   time.Duration
	RunStateDir      string
	FilterGroups     string
	GatewayEnabled   bool
	GatewayPortHTTP  uint
	GatewayPortHTTPS uint
	ManagedIP        net.IP
	FilesEnabled     bool
	UDPEnabled       bool
	TCPEnabled       bool
	HaproxyBin       string
	HaproxyTailCfg   string
	HaproxyPort      uint
	ServiceBind      net.IP
	ServicePort      uint
	Verbose          bool
	Handlers         []mmsdHandler
}

func (mmsd *mmsdService) v1Apps(w http.ResponseWriter, r *http.Request) {
	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("NewService error. %v\n", err)
		return
	}

	apps, err := m.GetApps()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("GetApps error. %v\n", err)
		return
	}

	var appList []string
	for _, app := range apps {
		appList = append(appList, app.Id)
	}
	sort.Strings(appList)

	fmt.Fprintf(w, "%s\n", strings.Join(appList, "\n"))
}

func (mmsd *mmsdService) v1Instances(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	name := vars["name"]

	var portIndex int
	if sval := r.URL.Query().Get("portIndex"); len(sval) != 0 {
		i, err := strconv.Atoi(sval)
		if err == nil {
			portIndex = i
		}
	}

	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("NewService error. %v\n", err)
		return
	}

	app, err := m.GetApp(name)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("GetApp error. %v\n", err)
		return
	}

	if app == nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	// appJson, err := json.MarshalIndent(app, "", " ")
	// w.Write(appJson)
	// fmt.Fprintf(w, "\n")
	// return

	for _, task := range app.Tasks {
		fmt.Fprintf(w, "%v:%v\n", task.Host, task.Ports[portIndex])
	}
}

func (mmsd *mmsdService) SetupEventBusListener() {
	var url = fmt.Sprintf("http://%v:%v/v2/events",
		mmsd.MarathonIP, mmsd.MarathonPort)

	var sse = NewEventSource(url, mmsd.ReconnectDelay)

	sse.OnOpen = func(event, data string) {
		log.Printf("Listening for events from Marathon on %v\n", url)
	}
	sse.OnError = func(event, data string) {
		log.Printf("Marathon Event Stream Error. %v. %v\n", event, data)
	}

	sse.AddEventListener("status_update_event", func(data string) {
		var event marathon.StatusUpdateEvent
		json.Unmarshal([]byte(data), &event)

		var alive = event.TaskStatus == marathon.TaskRunning
		mmsd.Update(event.AppId, event.TaskId, alive)
	})

	sse.AddEventListener("health_status_changed_event", func(data string) {
		var event marathon.HealthStatusChangedEvent
		json.Unmarshal([]byte(data), &event)
		mmsd.Update(event.AppId, event.TaskId, event.Alive)
	})

	go sse.RunForever()
}

// enable/disable given app:task
func (mmsd *mmsdService) Update(appID string, taskID string, alive bool) {
	// log.Printf("Update %v: %v (%v)\n", appId, taskId, alive)
	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)
	if err != nil {
		log.Printf("Update: NewService(%q, %v) failed. %v\n", mmsd.MarathonIP, mmsd.MarathonPort, err)
		return
	}

	app, err := m.GetApp(appID)
	if err != nil {
		log.Printf("Update: GetApp(%q) failed. %v\n", appID, err)
		return
	}

	task := app.GetTaskById(taskID)

	for _, handler := range mmsd.Handlers {
		if handler.IsEnabled() {
			handler.Update(app, task)
		}
	}
}

func (mmsd *mmsdService) MaybeResetFromTasks(force bool) error {
	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)
	if err != nil {
		return err
	}

	apps, err := m.GetApps()
	if err != nil {
		return err
	}

	for _, handler := range mmsd.Handlers {
		if handler.IsEnabled() {
			err = handler.Apply(apps, force)
			if err != nil {
				log.Printf("Failed to apply changes to handler. %v\n", err)
			}
		}
	}

	return nil
}

const appVersion = "0.1.0"
const appLicense = "MIT"

func (mmsd *mmsdService) Run() {
	flag.BoolVarP(&mmsd.Verbose, "verbose", "v", mmsd.Verbose, "Set verbosity level")
	flag.IPVar(&mmsd.MarathonIP, "marathon-ip", mmsd.MarathonIP, "Marathon endpoint TCP IP address")
	flag.UintVar(&mmsd.MarathonPort, "marathon-port", mmsd.MarathonPort, "Marathon endpoint TCP port number")
	flag.DurationVar(&mmsd.ReconnectDelay, "reconnect-delay", mmsd.ReconnectDelay, "Marathon reconnect delay")
	flag.StringVar(&mmsd.RunStateDir, "run-state-dir", mmsd.RunStateDir, "Path to directory to keep run-state")
	flag.StringVar(&mmsd.FilterGroups, "filter-groups", mmsd.FilterGroups, "Application group filter")
	flag.IPVar(&mmsd.ManagedIP, "managed-ip", mmsd.ManagedIP, "IP-address to manage for mmsd")
	flag.BoolVar(&mmsd.GatewayEnabled, "enable-gateway", mmsd.GatewayEnabled, "Enables gateway support")
	flag.UintVar(&mmsd.GatewayPortHTTP, "gateway-http-port", mmsd.GatewayPortHTTP, "gateway HTTP port")
	flag.UintVar(&mmsd.GatewayPortHTTPS, "gateway-https-port", mmsd.GatewayPortHTTPS, "gateway HTTP port")
	flag.BoolVar(&mmsd.TCPEnabled, "enable-tcp", mmsd.TCPEnabled, "enables haproxy TCP load balancing")
	flag.BoolVar(&mmsd.FilesEnabled, "enable-files", mmsd.FilesEnabled, "enables file based service discovery")
	flag.BoolVar(&mmsd.UDPEnabled, "enable-udp", mmsd.UDPEnabled, "enables UDP load balancing")
	flag.StringVar(&mmsd.HaproxyBin, "haproxy-bin", mmsd.HaproxyBin, "path to haproxy binary")
	flag.StringVar(&mmsd.HaproxyTailCfg, "haproxy-cfgtail", mmsd.HaproxyTailCfg, "path to haproxy tail config file")
	flag.IPVar(&mmsd.ServiceBind, "haproxy-bind", mmsd.ServiceBind, "haproxy management port")
	flag.UintVar(&mmsd.HaproxyPort, "haproxy-port", mmsd.HaproxyPort, "haproxy management port")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "mmsd - Mesos Marathon Service Discovery, version %v, licensed under %v\n", appVersion, appLicense)
		fmt.Fprintf(os.Stderr, "Written by Christian Parpart <christian@dawanda.com>\n\n")
		fmt.Fprintf(os.Stderr, "Usage: mmsd [flags ...]\n\n")
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\n")
	}

	flag.Parse()

	mmsd.SetupHandlers()
	mmsd.SetupEventBusListener()

	// HTTP service
	router := mux.NewRouter()
	v1 := router.PathPrefix("/v1").Subrouter()
	v1.HandleFunc("/apps", mmsd.v1Apps).Methods("GET")
	v1.HandleFunc("/instances{name:/.*}", mmsd.v1Instances).Methods("GET")

	serviceAddr := fmt.Sprintf("%v:%v", mmsd.ServiceBind, mmsd.ServicePort)
	log.Printf("Exposing service API on http://%v\n", serviceAddr)

	http.ListenAndServe(serviceAddr, router)
}

func (mmsd *mmsdService) SetupHandlers() {
	mmsd.Handlers = []mmsdHandler{
		NewUdpManager(
			mmsd.ServiceBind,
			mmsd.Verbose,
			mmsd.UDPEnabled,
		),
		&HaproxyMgr{
			Enabled:        mmsd.TCPEnabled,
			ConfigTailPath: mmsd.HaproxyTailCfg,
			ConfigPath:     filepath.Join(mmsd.RunStateDir, "haproxy.cfg"),
			PidFile:        filepath.Join(mmsd.RunStateDir, "haproxy.pid"),
			ManagementAddr: mmsd.ServiceBind,
			ManagementPort: mmsd.HaproxyPort,
		},
		&FilesManager{
			Enabled:  mmsd.FilesEnabled,
			Verbose:  mmsd.Verbose,
			BasePath: mmsd.RunStateDir + "/confd",
		},
	}

	// trigger initial run
	err := mmsd.MaybeResetFromTasks(true)
	if err != nil {
		log.Printf("Could not force task state reset. %v\n", err)
	}
}

func main() {
	var mmsd = mmsdService{
		MarathonScheme:   "http",
		MarathonIP:       net.ParseIP("127.0.0.1"),
		MarathonPort:     8080,
		ReconnectDelay:   time.Second * 4,
		RunStateDir:      "/var/run/mmsd",
		FilterGroups:     "*",
		GatewayEnabled:   false,
		GatewayPortHTTP:  80,
		GatewayPortHTTPS: 443,
		FilesEnabled:     true,
		UDPEnabled:       true,
		TCPEnabled:       false,
		HaproxyBin:       "/usr/bin/haproxy",
		HaproxyTailCfg:   "/etc/mmsd/haproxy-tail.cfg",
		HaproxyPort:      8081,
		ServiceBind:      net.ParseIP("0.0.0.0"),
		ServicePort:      8082,
		Verbose:          false,
	}

	mmsd.Run()
}
<commit_msg>enable log print on task change event, to aid finding the cause of that crash<commit_after>package main

/* TODO:

1. [x] serve HTTP /v1/instances/:app_id to retrieve ip:port pairs for given app
3. [x] implement UDP proxy (one-way/two-way, fanout (& roundrobin))
2. [x] implement upstream-conf.d file management
4. [ ] implement TCP proxy (with pluggable impls: haproxy, lvs, ...)
5. [ ] implement HTTP(S) gateway support
6. [ ] tcp-proxy: add `accept-proxy` support
7. [ ] tcp-proxy: add `proxy-protocol` support

XXX Changes:

* `--marathon-host` is now named `--marathon-ip` and only accepts IP addresses
* `--reconnect-delay` added
* `--haproxy-cfg` removed
* `--gateway` renamed to `--enable-gateway`
* `--enable-files` added
* `--enable-tcp` added
* `--enable-udp` added
* also exposes service discovery API via HTTP endpoint

*/

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/christianparpart/serviced/marathon"
	"github.com/gorilla/mux"
	flag "github.com/ogier/pflag"
)

type mmsdHandler interface {
	Apply(apps []*marathon.App, force bool) error
	Update(app *marathon.App, task *marathon.Task) error
	IsEnabled() bool
	SetEnabled(value bool)
}

type mmsdService struct {
	MarathonScheme   string
	MarathonIP       net.IP
	MarathonPort     uint
	ReconnectDelay   time.Duration
	RunStateDir      string
	FilterGroups     string
	GatewayEnabled   bool
	GatewayPortHTTP  uint
	GatewayPortHTTPS uint
	ManagedIP        net.IP
	FilesEnabled     bool
	UDPEnabled       bool
	TCPEnabled       bool
	HaproxyBin       string
	HaproxyTailCfg   string
	HaproxyPort      uint
	ServiceBind      net.IP
	ServicePort      uint
	Verbose          bool
	Handlers         []mmsdHandler
}

func (mmsd *mmsdService) v1Apps(w http.ResponseWriter, r *http.Request) {
	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("NewService error. %v\n", err)
		return
	}

	apps, err := m.GetApps()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("GetApps error. %v\n", err)
		return
	}

	var appList []string
	for _, app := range apps {
		appList = append(appList, app.Id)
	}
	sort.Strings(appList)

	fmt.Fprintf(w, "%s\n", strings.Join(appList, "\n"))
}

func (mmsd *mmsdService) v1Instances(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	name := vars["name"]

	var portIndex int
	if sval := r.URL.Query().Get("portIndex"); len(sval) != 0 {
		i, err := strconv.Atoi(sval)
		if err == nil {
			portIndex = i
		}
	}

	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("NewService error. %v\n", err)
		return
	}

	app, err := m.GetApp(name)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("GetApp error. %v\n", err)
		return
	}

	if app == nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	// appJson, err := json.MarshalIndent(app, "", " ")
	// w.Write(appJson)
	// fmt.Fprintf(w, "\n")
	// return

	for _, task := range app.Tasks {
		fmt.Fprintf(w, "%v:%v\n", task.Host, task.Ports[portIndex])
	}
}

func (mmsd *mmsdService) SetupEventBusListener() {
	var url = fmt.Sprintf("http://%v:%v/v2/events",
		mmsd.MarathonIP, mmsd.MarathonPort)

	var sse = NewEventSource(url, mmsd.ReconnectDelay)

	sse.OnOpen = func(event, data string) {
		log.Printf("Listening for events from Marathon on %v\n", url)
	}
	sse.OnError = func(event, data string) {
		log.Printf("Marathon Event Stream Error. %v. %v\n", event, data)
	}

	sse.AddEventListener("status_update_event", func(data string) {
		var event marathon.StatusUpdateEvent
		json.Unmarshal([]byte(data), &event)

		var alive = event.TaskStatus == marathon.TaskRunning
		mmsd.Update(event.AppId, event.TaskId, alive)
	})

	sse.AddEventListener("health_status_changed_event", func(data string) {
		var event marathon.HealthStatusChangedEvent
		json.Unmarshal([]byte(data), &event)
		mmsd.Update(event.AppId, event.TaskId, event.Alive)
	})

	go sse.RunForever()
}

// enable/disable given app:task
func (mmsd *mmsdService) Update(appID string, taskID string, alive bool) {
	log.Printf("Update %v: %v (%v)\n", appID, taskID, alive)
	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)
	if err != nil {
		log.Printf("Update: NewService(%q, %v) failed. %v\n", mmsd.MarathonIP, mmsd.MarathonPort, err)
		return
	}

	app, err := m.GetApp(appID)
	if err != nil {
		log.Printf("Update: GetApp(%q) failed. %v\n", appID, err)
		return
	}

	task := app.GetTaskById(taskID)

	for _, handler := range mmsd.Handlers {
		if handler.IsEnabled() {
			handler.Update(app, task)
		}
	}
}

func (mmsd *mmsdService) MaybeResetFromTasks(force bool) error {
	m, err := marathon.NewService(mmsd.MarathonIP, mmsd.MarathonPort)
	if err != nil {
		return err
	}

	apps, err := m.GetApps()
	if err != nil {
		return err
	}

	for _, handler := range mmsd.Handlers {
		if handler.IsEnabled() {
			err = handler.Apply(apps, force)
			if err != nil {
				log.Printf("Failed to apply changes to handler. %v\n", err)
			}
		}
	}

	return nil
}

const appVersion = "0.1.0"
const appLicense = "MIT"

func (mmsd *mmsdService) Run() {
	flag.BoolVarP(&mmsd.Verbose, "verbose", "v", mmsd.Verbose, "Set verbosity level")
	flag.IPVar(&mmsd.MarathonIP, "marathon-ip", mmsd.MarathonIP, "Marathon endpoint TCP IP address")
	flag.UintVar(&mmsd.MarathonPort, "marathon-port", mmsd.MarathonPort, "Marathon endpoint TCP port number")
	flag.DurationVar(&mmsd.ReconnectDelay, "reconnect-delay", mmsd.ReconnectDelay, "Marathon reconnect delay")
	flag.StringVar(&mmsd.RunStateDir, "run-state-dir", mmsd.RunStateDir, "Path to directory to keep run-state")
	flag.StringVar(&mmsd.FilterGroups, "filter-groups", mmsd.FilterGroups, "Application group filter")
	flag.IPVar(&mmsd.ManagedIP, "managed-ip", mmsd.ManagedIP, "IP-address to manage for mmsd")
	flag.BoolVar(&mmsd.GatewayEnabled, "enable-gateway", mmsd.GatewayEnabled, "Enables gateway support")
	flag.UintVar(&mmsd.GatewayPortHTTP, "gateway-http-port", mmsd.GatewayPortHTTP, "gateway HTTP port")
	flag.UintVar(&mmsd.GatewayPortHTTPS, "gateway-https-port", mmsd.GatewayPortHTTPS, "gateway HTTP port")
	flag.BoolVar(&mmsd.TCPEnabled, "enable-tcp", mmsd.TCPEnabled, "enables haproxy TCP load balancing")
	flag.BoolVar(&mmsd.FilesEnabled, "enable-files", mmsd.FilesEnabled, "enables file based service discovery")
	flag.BoolVar(&mmsd.UDPEnabled, "enable-udp", mmsd.UDPEnabled, "enables UDP load balancing")
	flag.StringVar(&mmsd.HaproxyBin, "haproxy-bin", mmsd.HaproxyBin, "path to haproxy binary")
	flag.StringVar(&mmsd.HaproxyTailCfg, "haproxy-cfgtail", mmsd.HaproxyTailCfg, "path to haproxy tail config file")
	flag.IPVar(&mmsd.ServiceBind, "haproxy-bind", mmsd.ServiceBind, "haproxy management port")
	flag.UintVar(&mmsd.HaproxyPort, "haproxy-port", mmsd.HaproxyPort, "haproxy management port")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "mmsd - Mesos Marathon Service Discovery, version %v, licensed under %v\n", appVersion, appLicense)
		fmt.Fprintf(os.Stderr, "Written by Christian Parpart <christian@dawanda.com>\n\n")
		fmt.Fprintf(os.Stderr, "Usage: mmsd [flags ...]\n\n")
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\n")
	}

	flag.Parse()

	mmsd.SetupHandlers()
	mmsd.SetupEventBusListener()

	// HTTP service
	router := mux.NewRouter()
	v1 := router.PathPrefix("/v1").Subrouter()
	v1.HandleFunc("/apps", mmsd.v1Apps).Methods("GET")
	v1.HandleFunc("/instances{name:/.*}", mmsd.v1Instances).Methods("GET")

	serviceAddr := fmt.Sprintf("%v:%v", mmsd.ServiceBind, mmsd.ServicePort)
	log.Printf("Exposing service API on http://%v\n", serviceAddr)

	http.ListenAndServe(serviceAddr, router)
}

func (mmsd *mmsdService) SetupHandlers() {
	mmsd.Handlers = []mmsdHandler{
		NewUdpManager(
			mmsd.ServiceBind,
			mmsd.Verbose,
			mmsd.UDPEnabled,
		),
		&HaproxyMgr{
			Enabled:        mmsd.TCPEnabled,
			ConfigTailPath: mmsd.HaproxyTailCfg,
			ConfigPath:     filepath.Join(mmsd.RunStateDir, "haproxy.cfg"),
			PidFile:        filepath.Join(mmsd.RunStateDir, "haproxy.pid"),
			ManagementAddr: mmsd.ServiceBind,
			ManagementPort: mmsd.HaproxyPort,
		},
		&FilesManager{
			Enabled:  mmsd.FilesEnabled,
			Verbose:  mmsd.Verbose,
			BasePath: mmsd.RunStateDir + "/confd",
		},
	}

	// trigger initial run
	err := mmsd.MaybeResetFromTasks(true)
	if err != nil {
		log.Printf("Could not force task state reset. %v\n", err)
	}
}

func main() {
	var mmsd = mmsdService{
		MarathonScheme:   "http",
		MarathonIP:       net.ParseIP("127.0.0.1"),
		MarathonPort:     8080,
		ReconnectDelay:   time.Second * 4,
		RunStateDir:      "/var/run/mmsd",
		FilterGroups:     "*",
		GatewayEnabled:   false,
		GatewayPortHTTP:  80,
		GatewayPortHTTPS: 443,
		FilesEnabled:     true,
		UDPEnabled:       true,
		TCPEnabled:       false,
		HaproxyBin:       "/usr/bin/haproxy",
		HaproxyTailCfg:   "/etc/mmsd/haproxy-tail.cfg",
		HaproxyPort:      8081,
		ServiceBind:      net.ParseIP("0.0.0.0"),
		ServicePort:      8082,
		Verbose:          false,
	}

	mmsd.Run()
}
<|endoftext|>


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

package main

import (
	"os"

	"github.com/danryan/hal"
	_ "github.com/danryan/hal/adapter/irc"
	_ "github.com/danryan/hal/adapter/shell"
	_ "github.com/danryan/hal/store/memory"
	_ "github.com/danryan/hal/store/redis"
)

// handler is an interface for objects to implement in order to respond to messages.
type handler interface {
	Handle(res *hal.Response) error
}

var pingHandler = hear(`ping`, func(res *hal.Response) error {
	return res.Send("PONG")
})

var fooHandler = hear(`foo`, func(res *hal.Response) error {
	return res.Send("BAR")
})

var synHandler = hear(`SYN`, func(res *hal.Response) error {
	return res.Send("ACK")
})

var selfHandler = hear(`who are you`, func(res *hal.Response) error {
	return res.Send("I'm Ash, the friendly #chadev bot.  I can preform a variety of tasks, and I am learning new tricks all the time.  I am open source, and pull requests are welcome!")
})

var helpHandler = hear(`help`, func(res *hal.Response) error {
	helpMsg := `HAL Chadev IRC Edition
Supported commands:
events    - Get next 7 events from the Chadev calendar
foo       - Causes HAL to reply with a BAR
help      - Displays this message
issues    - Give the URL to the issue queue for the named GitHub repo
ping      - Causes HAL to reply with a PONG
source    - Give the URL to the named GitHub repo
SYN       - Causes HAL to reply with an ACK
tableflip - ...
cageme    - Sends Nic Cage to infiltrate your brain
who is    - Find out who a user is
(name) is - Tell HAL who the user is`

	return res.Send(helpMsg)
})

func main() {
	os.Exit(run())
}

func run() int {
	robot, err := hal.NewRobot()
	if err != nil {
		hal.Logger.Error(err)
		return 1
	}

	robot.Handle(
		fooHandler,
		tableFlipHandler,
		eventHandler,
		synHandler,
		helpHandler,
		pingHandler,
		sourceHandler,
		issueHandler,
		cageMeHandler,
		whoisHandler,
		isHandler,
		selfHandler,
		whoamHandler,
		fizzBuzzHandler,
	)

	if err := robot.Run(); err != nil {
		hal.Logger.Error(err)
		return 1
	}
	return 0
}

func hear(pattern string, fn func(res *hal.Response) error) handler {
	return hal.Hear("^(?i)Ash "+pattern, fn)
}
<commit_msg>added docstring for FizzBuzz<commit_after>// Copyright 2014 Chadev. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"os"

	"github.com/danryan/hal"
	_ "github.com/danryan/hal/adapter/irc"
	_ "github.com/danryan/hal/adapter/shell"
	_ "github.com/danryan/hal/store/memory"
	_ "github.com/danryan/hal/store/redis"
)

// handler is an interface for objects to implement in order to respond to messages.
type handler interface {
	Handle(res *hal.Response) error
}

var pingHandler = hear(`ping`, func(res *hal.Response) error {
	return res.Send("PONG")
})

var fooHandler = hear(`foo`, func(res *hal.Response) error {
	return res.Send("BAR")
})

var synHandler = hear(`SYN`, func(res *hal.Response) error {
	return res.Send("ACK")
})

var selfHandler = hear(`who are you`, func(res *hal.Response) error {
	return res.Send("I'm Ash, the friendly #chadev bot.  I can preform a variety of tasks, and I am learning new tricks all the time.  I am open source, and pull requests are welcome!")
})

var helpHandler = hear(`help`, func(res *hal.Response) error {
	helpMsg := `HAL Chadev IRC Edition
Supported commands:
events    - Get next 7 events from the Chadev calendar
foo       - Causes HAL to reply with a BAR
fb n      - Returns the result of FizzBuzz for n
help      - Displays this message
issues    - Give the URL to the issue queue for the named GitHub repo
ping      - Causes HAL to reply with a PONG
source    - Give the URL to the named GitHub repo
SYN       - Causes HAL to reply with an ACK
tableflip - ...
cageme    - Sends Nic Cage to infiltrate your brain
who is    - Find out who a user is
(name) is - Tell HAL who the user is`

	return res.Send(helpMsg)
})

func main() {
	os.Exit(run())
}

func run() int {
	robot, err := hal.NewRobot()
	if err != nil {
		hal.Logger.Error(err)
		return 1
	}

	robot.Handle(
		fooHandler,
		tableFlipHandler,
		eventHandler,
		synHandler,
		helpHandler,
		pingHandler,
		sourceHandler,
		issueHandler,
		cageMeHandler,
		whoisHandler,
		isHandler,
		selfHandler,
		whoamHandler,
		fizzBuzzHandler,
	)

	if err := robot.Run(); err != nil {
		hal.Logger.Error(err)
		return 1
	}
	return 0
}

func hear(pattern string, fn func(res *hal.Response) error) handler {
	return hal.Hear("^(?i)Ash "+pattern, fn)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"crypto/tls"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"time"

	"github.com/cloudfoundry-incubator/datadog-firehose-nozzle/datadogclient"
	"github.com/cloudfoundry-incubator/uaago"
	"github.com/cloudfoundry/noaa"
	"github.com/cloudfoundry/sonde-go/events"
)

type nozzleConfig struct {
	UAAURL                 string
	Username               string
	Password               string
	TrafficControllerURL   string
	FirehoseSubscriptionID string
	DataDogURL             string
	DataDogAPIKey          string
	FlushDurationSeconds   uint32
	InsecureSSLSkipVerify  bool
	MetricPrefix           string
}

func main() {
	var (
		configFilePath = flag.String("config", "config/datadog-firehose-nozzle.json", "Location of the nozzle config json file")
	)
	flag.Parse()
	config, err := parseConfig(*configFilePath)

	if err != nil {
		log.Fatalf("Error parsing config: %s", err.Error())
	}

	uaaClient, err := uaago.NewClient(config.UAAURL)
	if err != nil {
		log.Fatalf("Error creating uaa client: %s", err.Error())
	}

	authToken, err := uaaClient.GetAuthToken(config.Username, config.Password, config.InsecureSSLSkipVerify)
	if err != nil {
		log.Fatalf("Error getting oauth token: %s. Please check your username and password.", err.Error())
	}

	consumer := noaa.NewConsumer(
		config.TrafficControllerURL,
		&tls.Config{InsecureSkipVerify: config.InsecureSSLSkipVerify},
		nil)
	messages := make(chan *events.Envelope)
	errs := make(chan error)
	done := make(chan struct{})
	go consumer.Firehose(config.FirehoseSubscriptionID, authToken, messages, errs, done)

	go func() {
		err := <-errs
		log.Printf("Error while reading from the firehose: %s", err.Error())
		close(done)
	}()

	client := datadogclient.New(config.DataDogURL, config.DataDogAPIKey, config.MetricPrefix)
	ticker := time.NewTicker(time.Duration(config.FlushDurationSeconds) * time.Second)

	for {
		select {
		case <-ticker.C:
			postMetrics(client)
		case envelope := <-messages:
			client.AddMetric(envelope)
		case <-done:
			postMetrics(client)
			return
		}
	}
}

func parseConfig(configPath string) (nozzleConfig, error) {
	configBytes, err := ioutil.ReadFile(configPath)
	var config nozzleConfig
	if err != nil {
		return config, fmt.Errorf("Can not read config file [%s]: %s", configPath, err)
	}

	err = json.Unmarshal(configBytes, &config)
	if err != nil {
		return config, fmt.Errorf("Can not parse config file %s: %s", configPath, err)
	}
	return config, err
}

func postMetrics(client *datadogclient.Client) {
	err := client.PostMetrics()
	if err != nil {
		log.Printf("Error: %s", err.Error())
	}
}
<commit_msg>Updates due to noaa API change<commit_after>package main

import (
	"fmt"

	"crypto/tls"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"time"

	"github.com/cloudfoundry-incubator/datadog-firehose-nozzle/datadogclient"
	"github.com/cloudfoundry-incubator/uaago"
	"github.com/cloudfoundry/noaa"
	"github.com/cloudfoundry/sonde-go/events"
)

type nozzleConfig struct {
	UAAURL                 string
	Username               string
	Password               string
	TrafficControllerURL   string
	FirehoseSubscriptionID string
	DataDogURL             string
	DataDogAPIKey          string
	FlushDurationSeconds   uint32
	InsecureSSLSkipVerify  bool
	MetricPrefix           string
}

func main() {
	var (
		configFilePath = flag.String("config", "config/datadog-firehose-nozzle.json", "Location of the nozzle config json file")
	)
	flag.Parse()
	config, err := parseConfig(*configFilePath)

	if err != nil {
		log.Fatalf("Error parsing config: %s", err.Error())
	}

	uaaClient, err := uaago.NewClient(config.UAAURL)
	if err != nil {
		log.Fatalf("Error creating uaa client: %s", err.Error())
	}

	authToken, err := uaaClient.GetAuthToken(config.Username, config.Password, config.InsecureSSLSkipVerify)
	if err != nil {
		log.Fatalf("Error getting oauth token: %s. Please check your username and password.", err.Error())
	}

	consumer := noaa.NewConsumer(
		config.TrafficControllerURL,
		&tls.Config{InsecureSkipVerify: config.InsecureSSLSkipVerify},
		nil)
	messages := make(chan *events.Envelope)
	errs := make(chan error)
	done := make(chan struct{})
	go consumer.Firehose(config.FirehoseSubscriptionID, authToken, messages, errs)

	go func() {
		err := <-errs
		log.Printf("Error while reading from the firehose: %s", err.Error())
		close(done)
	}()

	client := datadogclient.New(config.DataDogURL, config.DataDogAPIKey, config.MetricPrefix)
	ticker := time.NewTicker(time.Duration(config.FlushDurationSeconds) * time.Second)

	for {
		select {
		case <-ticker.C:
			postMetrics(client)
		case envelope := <-messages:
			client.AddMetric(envelope)
		case <-done:
			postMetrics(client)
			consumer.Close()
			return
		}
	}
}

func parseConfig(configPath string) (nozzleConfig, error) {
	configBytes, err := ioutil.ReadFile(configPath)
	var config nozzleConfig
	if err != nil {
		return config, fmt.Errorf("Can not read config file [%s]: %s", configPath, err)
	}

	err = json.Unmarshal(configBytes, &config)
	if err != nil {
		return config, fmt.Errorf("Can not parse config file %s: %s", configPath, err)
	}
	return config, err
}

func postMetrics(client *datadogclient.Client) {
	err := client.PostMetrics()
	if err != nil {
		log.Printf("Error: %s", err.Error())
	}
}
<|endoftext|>


<commit_before>package core

import (
	"io/ioutil"
	"log"
	"os"
	"os/user"
)

/*
Tinzenite is the struct on which all important operations should be called.
*/
type Tinzenite struct {
	Name     string
	Path     string
	Username string
	peer     *Peer
	channel  *Channel
	allPeers []*Peer
	// model    *Objectinfo
}

/*
CreateTinzenite makes a directory a new Tinzenite directory. Will return error
if already so.
*/
func CreateTinzenite(dirname, dirpath, peername, username string, encrypted bool) (*Tinzenite, error) {
	// encrypted peer for now unsupported
	if encrypted {
		return nil, ErrUnsupported
	}
	if IsTinzenite(dirpath) {
		return nil, ErrIsTinzenite
	}
	// Build
	var tinzenite = &Tinzenite{
		Name:     dirname,
		Path:     dirpath,
		Username: username}
	// build channel
	channel, err := CreateChannel(peername, nil, tinzenite)
	if err != nil {
		return nil, err
	}
	tinzenite.channel = channel
	// build self peer
	address, err := channel.Address()
	if err != nil {
		return nil, err
	}
	peer, err := CreatePeer(peername, address)
	if err != nil {
		return nil, err
	}
	tinzenite.peer = peer
	tinzenite.allPeers = []*Peer{peer}
	// save
	err = tinzenite.write()
	if err != nil {
		return nil, err
	}
	// save that this directory is now a tinzenite dir
	err = tinzenite.storeGlobalConfig()
	if err != nil {
		return nil, err
	}
	// make sure model is ready
	// tinzenite.createModel()
	return tinzenite, nil
}

/*
LoadTinzenite will try to load the given directory path as a Tinzenite directory.
If not one it won't work: use CreateTinzenite to create a new peer.
*/
func LoadTinzenite(path string) (*Tinzenite, error) {
	if !IsTinzenite(path) {
		return nil, ErrNotTinzenite
	}
	/*
			TODO
		   - load dir from given path (validate that path IS tinzenite first)
	*/
	return nil, ErrUnsupported
}

/*
RemoveTinzenite directory. Specifically leaves all user files but removes all
Tinzenite specific items.
*/
func RemoveTinzenite(path string) error {
	if !IsTinzenite(path) {
		return ErrNotTinzenite
	}
	// TODO remove from directory list
	return os.RemoveAll(path + "/" + TINZENITEDIR)
}

/*
SyncModel TODO
*/
func (tinzenite *Tinzenite) SyncModel() error {
	/*
		TODO
		- fetches model from other peers and syncs (this is for manual sync)
	*/
	// first ensure that local model is up to date
	err := tinzenite.updateModel()
	if err != nil {
		return err
	}
	// following concurrently?
	// iterate over all known peers
	// if online -> continue
	// if not init -> init
	// sync
	return nil
}

/*
Address of this Tinzenite peer.
*/
func (tinzenite *Tinzenite) Address() string {
	return tinzenite.peer.Address
}

/*
Close cleanly stores everything and shuts Tinzenite down.
*/
func (tinzenite *Tinzenite) Close() {
	tinzenite.channel.Close()
}

// RENAME + include in SyncModel?
func (tinzenite *Tinzenite) updateModel() error {
	// TODO
	/*
				- updates from disk
				- How does this function know which context to use?
		        - add override for with path --> faster detection because not everything
		                              has to be rechecked
				- watch out that it doesn't bite itself with whatever method is used
						              to fetch models from online
	*/
	// use matcher on a per directory basis!
	return nil
}

/*
write the tinzenite directory structure to disk.
*/
func (tinzenite *Tinzenite) write() error {
	// TODO
	/*
		Writes everything in the .tinzenite directory.
	*/
	root := tinzenite.Path + "/" + TINZENITEDIR
	// build directory structure
	err := makeDirectories(root,
		"org/peers", "temp", "removed")
	if err != nil {
		return err
	}
	// write all peers to files
	for _, peer := range tinzenite.allPeers {
		err = ioutil.WriteFile(root+"/org/peers/"+peer.identification, []byte(peer.Name), FILEPERMISSIONMODE)
		if err != nil {
			return err
		}
	}
	return nil
}

/*
callbackNewConnection is called when a new connection request comes in.
*/
func (tinzenite *Tinzenite) CallbackNewConnection(address, message string) {
	log.Printf("New connection from <%s> with message <%s>\n", address, message)
	err := tinzenite.channel.AcceptConnection(address)
	if err != nil {
		log.Println(err.Error())
	}
}

/*
callbackMessage is called when a message is received.
*/
func (tinzenite *Tinzenite) CallbackMessage(address, message string) {
	log.Printf("Message from <%s> with message <%s>\n", address, message)
	tinzenite.channel.Send(address, "ACK")
}

/*
storeGlobalConfig stores the path value into the user's home directory so that clients
can locate it.
*/
func (tinzenite *Tinzenite) storeGlobalConfig() error {
	// ready outside data
	user, err := user.Current()
	if err != nil {
		return err
	}
	path := user.HomeDir + "/.config/tinzenite"
	err = makeDirectory(path)
	if err != nil {
		return err
	}
	path += "/" + DIRECTORYLIST
	file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_APPEND, FILEPERMISSIONMODE)
	if err != nil {
		return err
	}
	defer file.Close()
	// write path to file
	_, err = file.WriteString(tinzenite.Path + "\n")
	if err != nil {
		return err
	}
	// ensure that the file is valid
	return PrettifyDirectoryList()
}
<commit_msg>started integration into tinzenite<commit_after>package core

import (
	"io/ioutil"
	"log"
	"os"
	"os/user"
)

/*
Tinzenite is the struct on which all important operations should be called.
*/
type Tinzenite struct {
	Name     string
	Path     string
	Username string
	selfpeer *Peer
	channel  *Channel
	allPeers []*Peer
	model    *Model
}

/*
CreateTinzenite makes a directory a new Tinzenite directory. Will return error
if already so.
*/
func CreateTinzenite(dirname, dirpath, peername, username string, encrypted bool) (*Tinzenite, error) {
	// encrypted peer for now unsupported
	if encrypted {
		return nil, ErrUnsupported
	}
	if IsTinzenite(dirpath) {
		return nil, ErrIsTinzenite
	}
	// Build
	var tinzenite = &Tinzenite{
		Name:     dirname,
		Path:     dirpath,
		Username: username}
	// build channel
	channel, err := CreateChannel(peername, nil, tinzenite)
	if err != nil {
		return nil, err
	}
	tinzenite.channel = channel
	// build self peer
	address, err := channel.Address()
	if err != nil {
		return nil, err
	}
	peer, err := CreatePeer(peername, address)
	if err != nil {
		return nil, err
	}
	tinzenite.selfpeer = peer
	tinzenite.allPeers = []*Peer{peer}
	// save
	err = tinzenite.write()
	if err != nil {
		return nil, err
	}
	// save that this directory is now a tinzenite dir
	err = tinzenite.storeGlobalConfig()
	if err != nil {
		return nil, err
	}
	// build model (can block for long!)
	m, err := LoadModel(dirpath)
	if err != nil {
		return nil, err
	}
	tinzenite.model = m
	/*TODO later implement that model updates are sent to all online peers*/
	return tinzenite, nil
}

/*
LoadTinzenite will try to load the given directory path as a Tinzenite directory.
If not one it won't work: use CreateTinzenite to create a new peer.
*/
func LoadTinzenite(path string) (*Tinzenite, error) {
	if !IsTinzenite(path) {
		return nil, ErrNotTinzenite
	}
	/*
			TODO
		   - load dir from given path (validate that path IS tinzenite first)
	*/
	return nil, ErrUnsupported
}

/*
RemoveTinzenite directory. Specifically leaves all user files but removes all
Tinzenite specific items.
*/
func RemoveTinzenite(path string) error {
	if !IsTinzenite(path) {
		return ErrNotTinzenite
	}
	/* TODO remove from directory list*/
	return os.RemoveAll(path + "/" + TINZENITEDIR)
}

/*
SyncModel TODO

fetches model from other peers and syncs (this is for manual sync)
*/
func (tinzenite *Tinzenite) SyncModel() error {
	// first ensure that local model is up to date
	err := tinzenite.model.Update()
	if err != nil {
		return err
	}
	// iterate over all known peers
	for _, peer := range tinzenite.allPeers {
		if peer == tinzenite.selfpeer {
			continue
		}
		/*TODO - also make this concurrent?*/
		tinzenite.channel.Send(peer.Address, "Want update!")
		// if online -> continue
		// if not init -> init
		// sync
		/*TODO must store init state in allPeers too, also in future encryption*/
	}
	return nil
}

/*
Address of this Tinzenite peer.
*/
func (tinzenite *Tinzenite) Address() string {
	return tinzenite.selfpeer.Address
}

/*
Close cleanly stores everything and shuts Tinzenite down.
*/
func (tinzenite *Tinzenite) Close() {
	tinzenite.model.Update()
	tinzenite.channel.Close()
}

/*
write the tinzenite directory structure to disk.
*/
func (tinzenite *Tinzenite) write() error {
	// TODO
	/*
		Writes everything in the .tinzenite directory.
	*/
	root := tinzenite.Path + "/" + TINZENITEDIR
	// build directory structure
	err := makeDirectories(root,
		"org/peers", "temp", "removed", "local")
	if err != nil {
		return err
	}
	// write all peers to files
	for _, peer := range tinzenite.allPeers {
		err = ioutil.WriteFile(root+"/org/peers/"+peer.identification, []byte(peer.Name), FILEPERMISSIONMODE)
		if err != nil {
			return err
		}
	}
	return nil
}

/*
CallbackNewConnection is called when a new connection request comes in.
*/
func (tinzenite *Tinzenite) CallbackNewConnection(address, message string) {
	log.Printf("New connection from <%s> with message <%s>\n", address, message)
	err := tinzenite.channel.AcceptConnection(address)
	if err != nil {
		log.Println(err.Error())
	}
}

/*
CallbackMessage is called when a message is received.
*/
func (tinzenite *Tinzenite) CallbackMessage(address, message string) {
	log.Printf("Message from <%s> with message <%s>\n", address, message)
	tinzenite.channel.Send(address, "ACK")
}

/*
storeGlobalConfig stores the path value into the user's home directory so that clients
can locate it.
*/
func (tinzenite *Tinzenite) storeGlobalConfig() error {
	// ready outside data
	user, err := user.Current()
	if err != nil {
		return err
	}
	path := user.HomeDir + "/.config/tinzenite"
	err = makeDirectory(path)
	if err != nil {
		return err
	}
	path += "/" + DIRECTORYLIST
	file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_APPEND, FILEPERMISSIONMODE)
	if err != nil {
		return err
	}
	defer file.Close()
	// write path to file
	_, err = file.WriteString(tinzenite.Path + "\n")
	if err != nil {
		return err
	}
	// ensure that the file is valid
	return PrettifyDirectoryList()
}
<|endoftext|>