<commit_before>package api

import (
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/grafana/grafana/pkg/api/live"
	"github.com/grafana/grafana/pkg/api/routing"
	httpstatic "github.com/grafana/grafana/pkg/api/static"
	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/infra/localcache"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/infra/remotecache"
	"github.com/grafana/grafana/pkg/middleware"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/plugins"
	"github.com/grafana/grafana/pkg/registry"
	"github.com/grafana/grafana/pkg/services/datasources"
	"github.com/grafana/grafana/pkg/services/hooks"
	"github.com/grafana/grafana/pkg/services/login"
	"github.com/grafana/grafana/pkg/services/quota"
	"github.com/grafana/grafana/pkg/services/rendering"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	macaron "gopkg.in/macaron.v1"
)

func init() {
	registry.Register(&registry.Descriptor{
		Name:         "HTTPServer",
		Instance:     &HTTPServer{},
		InitPriority: registry.High,
	})
}

type ProvisioningService interface {
	ProvisionDatasources() error
	ProvisionNotifications() error
	ProvisionDashboards() error
	GetDashboardProvisionerResolvedPath(name string) string
}

type HTTPServer struct {
	log           log.Logger
	macaron       *macaron.Macaron
	context       context.Context
	streamManager *live.StreamManager
	httpSrv       *http.Server

	RouteRegister       routing.RouteRegister    `inject:""`
	Bus                 bus.Bus                  `inject:""`
	RenderService       rendering.Service        `inject:""`
	Cfg                 *setting.Cfg             `inject:""`
	HooksService        *hooks.HooksService      `inject:""`
	CacheService        *localcache.CacheService `inject:""`
	DatasourceCache     datasources.CacheService `inject:""`
	AuthTokenService    models.UserTokenService  `inject:""`
	QuotaService        *quota.QuotaService      `inject:""`
	RemoteCacheService  *remotecache.RemoteCache `inject:""`
	ProvisioningService ProvisioningService      `inject:""`
	Login               *login.LoginService      `inject:""`
}

func (hs *HTTPServer) Init() error {
	hs.log = log.New("http.server")

	hs.streamManager = live.NewStreamManager()
	hs.macaron = hs.newMacaron()
	hs.registerRoutes()

	return nil
}

func (hs *HTTPServer) Run(ctx context.Context) error {
	var err error

	hs.context = ctx

	hs.applyRoutes()
	hs.streamManager.Run(ctx)

	listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
	hs.log.Info("HTTP Server Listen", "address", listenAddr, "protocol", setting.Protocol, "subUrl", setting.AppSubUrl, "socket", setting.SocketPath)

	hs.httpSrv = &http.Server{Addr: listenAddr, Handler: hs.macaron}

	// handle http shutdown on server context done
	go func() {
		<-ctx.Done()
		// Hacky fix for race condition between ListenAndServe and Shutdown
		time.Sleep(time.Millisecond * 100)
		if err := hs.httpSrv.Shutdown(context.Background()); err != nil {
			hs.log.Error("Failed to shutdown server", "error", err)
		}
	}()

	switch setting.Protocol {
	case setting.HTTP:
		err = hs.httpSrv.ListenAndServe()
		if err == http.ErrServerClosed {
			hs.log.Debug("server was shutdown gracefully")
			return nil
		}
	case setting.HTTP2:
		err = hs.listenAndServeH2TLS(setting.CertFile, setting.KeyFile)
		if err == http.ErrServerClosed {
			hs.log.Debug("server was shutdown gracefully")
			return nil
		}
	case setting.HTTPS:
		err = hs.listenAndServeTLS(setting.CertFile, setting.KeyFile)
		if err == http.ErrServerClosed {
			hs.log.Debug("server was shutdown gracefully")
			return nil
		}
	case setting.SOCKET:
		ln, err := net.ListenUnix("unix", &net.UnixAddr{Name: setting.SocketPath, Net: "unix"})
		if err != nil {
			hs.log.Debug("server was shutdown gracefully", "err", err)
			return nil
		}

		// Make socket writable by group
		if err := os.Chmod(setting.SocketPath, 0660); err != nil {
			hs.log.Debug("server was shutdown gracefully", "err", err)
			return nil
		}

		err = hs.httpSrv.Serve(ln)
		if err != nil {
			hs.log.Debug("server was shutdown gracefully", "err", err)
			return nil
		}
	default:
		hs.log.Error("Invalid protocol", "protocol", setting.Protocol)
		err = errors.New("Invalid Protocol")
	}

	return err
}

func (hs *HTTPServer) listenAndServeTLS(certfile, keyfile string) error {
	if certfile == "" {
		return fmt.Errorf("cert_file cannot be empty when using HTTPS")
	}

	if keyfile == "" {
		return fmt.Errorf("cert_key cannot be empty when using HTTPS")
	}

	if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile)
	}

	if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile)
	}

	tlsCfg := &tls.Config{
		MinVersion:               tls.VersionTLS12,
		PreferServerCipherSuites: true,
		CipherSuites: []uint16{
			tls.TLS_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
		},
	}

	hs.httpSrv.TLSConfig = tlsCfg
	hs.httpSrv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))

	return hs.httpSrv.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
}

func (hs *HTTPServer) listenAndServeH2TLS(certfile, keyfile string) error {
	if certfile == "" {
		return fmt.Errorf("cert_file cannot be empty when using HTTP2")
	}

	if keyfile == "" {
		return fmt.Errorf("cert_key cannot be empty when using HTTP2")
	}

	if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile)
	}

	if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile)
	}

	tlsCfg := &tls.Config{
		MinVersion:               tls.VersionTLS12,
		PreferServerCipherSuites: false,
		CipherSuites: []uint16{
			tls.TLS_CHACHA20_POLY1305_SHA256,
			tls.TLS_AES_128_GCM_SHA256,
			tls.TLS_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
		},
		NextProtos: []string{"h2", "http/1.1"},
	}

	hs.httpSrv.TLSConfig = tlsCfg

	return hs.httpSrv.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
}

func (hs *HTTPServer) newMacaron() *macaron.Macaron {
	macaron.Env = setting.Env
	m := macaron.New()

	// automatically set HEAD for every GET
	m.SetAutoHead(true)

	return m
}

func (hs *HTTPServer) applyRoutes() {
	// start with middlewares & static routes
	hs.addMiddlewaresAndStaticRoutes()
	// then add view routes & api routes
	hs.RouteRegister.Register(hs.macaron)
	// then custom app proxy routes
	hs.initAppPluginRoutes(hs.macaron)
	// lastly not found route
	hs.macaron.NotFound(hs.NotFoundHandler)
}

func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
	m := hs.macaron

	m.Use(middleware.Logger())

	if setting.EnableGzip {
		m.Use(middleware.Gziper())
	}

	m.Use(middleware.Recovery())

	for _, route := range plugins.StaticRoutes {
		pluginRoute := path.Join("/public/plugins/", route.PluginId)
		hs.log.Debug("Plugins: Adding route", "route", pluginRoute, "dir", route.Directory)
		hs.mapStatic(hs.macaron, route.Directory, "", pluginRoute)
	}

	hs.mapStatic(m, setting.StaticRootPath, "build", "public/build")
	hs.mapStatic(m, setting.StaticRootPath, "", "public")
	hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt")

	if setting.ImageUploadProvider == "local" {
		hs.mapStatic(m, hs.Cfg.ImagesDir, "", "/public/img/attachments")
	}

	m.Use(middleware.AddDefaultResponseHeaders())

	if setting.ServeFromSubPath && setting.AppSubUrl != "" {
		m.SetURLPrefix(setting.AppSubUrl)
	}

	m.Use(macaron.Renderer(macaron.RenderOptions{
		Directory:  path.Join(setting.StaticRootPath, "views"),
		IndentJSON: macaron.Env != macaron.PROD,
		Delims:     macaron.Delims{Left: "[[", Right: "]]"},
	}))

	m.Use(hs.healthHandler)
	m.Use(hs.metricsEndpoint)
	m.Use(middleware.GetContextHandler(
		hs.AuthTokenService,
		hs.RemoteCacheService,
	))
	m.Use(middleware.OrgRedirect())

	// needs to be after context handler
	if setting.EnforceDomain {
		m.Use(middleware.ValidateHostHeader(setting.Domain))
	}

	m.Use(middleware.HandleNoCacheHeader())
}

func (hs *HTTPServer) metricsEndpoint(ctx *macaron.Context) {
	if !hs.Cfg.MetricsEndpointEnabled {
		return
	}

	if ctx.Req.Method != http.MethodGet || ctx.Req.URL.Path != "/metrics" {
		return
	}

	if hs.metricsEndpointBasicAuthEnabled() && !BasicAuthenticatedRequest(ctx.Req, hs.Cfg.MetricsEndpointBasicAuthUsername, hs.Cfg.MetricsEndpointBasicAuthPassword) {
		ctx.Resp.WriteHeader(http.StatusUnauthorized)
		return
	}

	promhttp.
		HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{}).
		ServeHTTP(ctx.Resp, ctx.Req.Request)
}

func (hs *HTTPServer) healthHandler(ctx *macaron.Context) {
	notHeadOrGet := ctx.Req.Method != http.MethodGet && ctx.Req.Method != http.MethodHead
	if notHeadOrGet || ctx.Req.URL.Path != "/api/health" {
		return
	}

	data := simplejson.New()
	data.Set("database", "ok")
	data.Set("version", setting.BuildVersion)
	data.Set("commit", setting.BuildCommit)

	if err := bus.Dispatch(&models.GetDBHealthQuery{}); err != nil {
		data.Set("database", "failing")
		ctx.Resp.Header().Set("Content-Type", "application/json; charset=UTF-8")
		ctx.Resp.WriteHeader(503)
	} else {
		ctx.Resp.Header().Set("Content-Type", "application/json; charset=UTF-8")
		ctx.Resp.WriteHeader(200)
	}

	dataBytes, _ := data.EncodePretty()
	if _, err := ctx.Resp.Write(dataBytes); err != nil {
		hs.log.Error("Failed to write to response", "err", err)
	}
}

func (hs *HTTPServer) mapStatic(m *macaron.Macaron, rootDir string, dir string, prefix string) {
	headers := func(c *macaron.Context) {
		c.Resp.Header().Set("Cache-Control", "public, max-age=3600")
	}

	if prefix == "public/build" {
		headers = func(c *macaron.Context) {
			c.Resp.Header().Set("Cache-Control", "public, max-age=31536000")
		}
	}

	if setting.Env == setting.DEV {
		headers = func(c *macaron.Context) {
			c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache")
		}
	}

	m.Use(httpstatic.Static(
		path.Join(rootDir, dir),
		httpstatic.StaticOptions{
			SkipLogging: true,
			Prefix:      prefix,
			AddHeaders:  headers,
		},
	))
}

func (hs *HTTPServer) metricsEndpointBasicAuthEnabled() bool {
	return hs.Cfg.MetricsEndpointBasicAuthUsername != "" && hs.Cfg.MetricsEndpointBasicAuthPassword != ""
}
<commit_msg>API: Fix logging of dynamic listening port (#19644)<commit_after>package api

import (
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/grafana/grafana/pkg/api/live"
	"github.com/grafana/grafana/pkg/api/routing"
	httpstatic "github.com/grafana/grafana/pkg/api/static"
	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/infra/localcache"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/infra/remotecache"
	"github.com/grafana/grafana/pkg/middleware"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/plugins"
	"github.com/grafana/grafana/pkg/registry"
	"github.com/grafana/grafana/pkg/services/datasources"
	"github.com/grafana/grafana/pkg/services/hooks"
	"github.com/grafana/grafana/pkg/services/login"
	"github.com/grafana/grafana/pkg/services/quota"
	"github.com/grafana/grafana/pkg/services/rendering"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	macaron "gopkg.in/macaron.v1"
)

func init() {
	registry.Register(&registry.Descriptor{
		Name:         "HTTPServer",
		Instance:     &HTTPServer{},
		InitPriority: registry.High,
	})
}

type ProvisioningService interface {
	ProvisionDatasources() error
	ProvisionNotifications() error
	ProvisionDashboards() error
	GetDashboardProvisionerResolvedPath(name string) string
}

type HTTPServer struct {
	log           log.Logger
	macaron       *macaron.Macaron
	context       context.Context
	streamManager *live.StreamManager
	httpSrv       *http.Server

	RouteRegister       routing.RouteRegister    `inject:""`
	Bus                 bus.Bus                  `inject:""`
	RenderService       rendering.Service        `inject:""`
	Cfg                 *setting.Cfg             `inject:""`
	HooksService        *hooks.HooksService      `inject:""`
	CacheService        *localcache.CacheService `inject:""`
	DatasourceCache     datasources.CacheService `inject:""`
	AuthTokenService    models.UserTokenService  `inject:""`
	QuotaService        *quota.QuotaService      `inject:""`
	RemoteCacheService  *remotecache.RemoteCache `inject:""`
	ProvisioningService ProvisioningService      `inject:""`
	Login               *login.LoginService      `inject:""`
}

func (hs *HTTPServer) Init() error {
	hs.log = log.New("http.server")

	hs.streamManager = live.NewStreamManager()
	hs.macaron = hs.newMacaron()
	hs.registerRoutes()

	return nil
}

func (hs *HTTPServer) Run(ctx context.Context) error {
	var err error

	hs.context = ctx

	hs.applyRoutes()
	hs.streamManager.Run(ctx)

	listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
	listener, err := net.Listen("tcp", listenAddr)
	if err != nil {
		hs.log.Debug("server was shutdown gracefully")
		return nil
	}

	hs.log.Info("HTTP Server Listen", "address", listener.Addr().String(), "protocol", setting.Protocol, "subUrl", setting.AppSubUrl, "socket", setting.SocketPath)

	hs.httpSrv = &http.Server{Addr: listenAddr, Handler: hs.macaron}

	// handle http shutdown on server context done
	go func() {
		<-ctx.Done()
		// Hacky fix for race condition between ListenAndServe and Shutdown
		time.Sleep(time.Millisecond * 100)
		if err := hs.httpSrv.Shutdown(context.Background()); err != nil {
			hs.log.Error("Failed to shutdown server", "error", err)
		}
	}()

	switch setting.Protocol {
	case setting.HTTP:
		err = hs.httpSrv.Serve(listener)
		if err == http.ErrServerClosed {
			hs.log.Debug("server was shutdown gracefully")
			return nil
		}
	case setting.HTTP2:
		err = hs.listenAndServeH2TLS(listener, setting.CertFile, setting.KeyFile)
		if err == http.ErrServerClosed {
			hs.log.Debug("server was shutdown gracefully")
			return nil
		}
	case setting.HTTPS:
		err = hs.listenAndServeTLS(listener, setting.CertFile, setting.KeyFile)
		if err == http.ErrServerClosed {
			hs.log.Debug("server was shutdown gracefully")
			return nil
		}
	case setting.SOCKET:
		ln, err := net.ListenUnix("unix", &net.UnixAddr{Name: setting.SocketPath, Net: "unix"})
		if err != nil {
			hs.log.Debug("server was shutdown gracefully", "err", err)
			return nil
		}

		// Make socket writable by group
		if err := os.Chmod(setting.SocketPath, 0660); err != nil {
			hs.log.Debug("server was shutdown gracefully", "err", err)
			return nil
		}

		err = hs.httpSrv.Serve(ln)
		if err != nil {
			hs.log.Debug("server was shutdown gracefully", "err", err)
			return nil
		}
	default:
		hs.log.Error("Invalid protocol", "protocol", setting.Protocol)
		err = errors.New("Invalid Protocol")
	}

	return err
}

func (hs *HTTPServer) listenAndServeTLS(listener net.Listener, certfile, keyfile string) error {
	if certfile == "" {
		return fmt.Errorf("cert_file cannot be empty when using HTTPS")
	}

	if keyfile == "" {
		return fmt.Errorf("cert_key cannot be empty when using HTTPS")
	}

	if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile)
	}

	if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile)
	}

	tlsCfg := &tls.Config{
		MinVersion:               tls.VersionTLS12,
		PreferServerCipherSuites: true,
		CipherSuites: []uint16{
			tls.TLS_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
		},
	}

	hs.httpSrv.TLSConfig = tlsCfg
	hs.httpSrv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))

	return hs.httpSrv.ServeTLS(listener, setting.CertFile, setting.KeyFile)
}

func (hs *HTTPServer) listenAndServeH2TLS(listener net.Listener, certfile, keyfile string) error {
	if certfile == "" {
		return fmt.Errorf("cert_file cannot be empty when using HTTP2")
	}

	if keyfile == "" {
		return fmt.Errorf("cert_key cannot be empty when using HTTP2")
	}

	if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile)
	}

	if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) {
		return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile)
	}

	tlsCfg := &tls.Config{
		MinVersion:               tls.VersionTLS12,
		PreferServerCipherSuites: false,
		CipherSuites: []uint16{
			tls.TLS_CHACHA20_POLY1305_SHA256,
			tls.TLS_AES_128_GCM_SHA256,
			tls.TLS_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
		},
		NextProtos: []string{"h2", "http/1.1"},
	}

	hs.httpSrv.TLSConfig = tlsCfg

	return hs.httpSrv.ServeTLS(listener, setting.CertFile, setting.KeyFile)
}

func (hs *HTTPServer) newMacaron() *macaron.Macaron {
	macaron.Env = setting.Env
	m := macaron.New()

	// automatically set HEAD for every GET
	m.SetAutoHead(true)

	return m
}

func (hs *HTTPServer) applyRoutes() {
	// start with middlewares & static routes
	hs.addMiddlewaresAndStaticRoutes()
	// then add view routes & api routes
	hs.RouteRegister.Register(hs.macaron)
	// then custom app proxy routes
	hs.initAppPluginRoutes(hs.macaron)
	// lastly not found route
	hs.macaron.NotFound(hs.NotFoundHandler)
}

func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
	m := hs.macaron

	m.Use(middleware.Logger())

	if setting.EnableGzip {
		m.Use(middleware.Gziper())
	}

	m.Use(middleware.Recovery())

	for _, route := range plugins.StaticRoutes {
		pluginRoute := path.Join("/public/plugins/", route.PluginId)
		hs.log.Debug("Plugins: Adding route", "route", pluginRoute, "dir", route.Directory)
		hs.mapStatic(hs.macaron, route.Directory, "", pluginRoute)
	}

	hs.mapStatic(m, setting.StaticRootPath, "build", "public/build")
	hs.mapStatic(m, setting.StaticRootPath, "", "public")
	hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt")

	if setting.ImageUploadProvider == "local" {
		hs.mapStatic(m, hs.Cfg.ImagesDir, "", "/public/img/attachments")
	}

	m.Use(middleware.AddDefaultResponseHeaders())

	if setting.ServeFromSubPath && setting.AppSubUrl != "" {
		m.SetURLPrefix(setting.AppSubUrl)
	}

	m.Use(macaron.Renderer(macaron.RenderOptions{
		Directory:  path.Join(setting.StaticRootPath, "views"),
		IndentJSON: macaron.Env != macaron.PROD,
		Delims:     macaron.Delims{Left: "[[", Right: "]]"},
	}))

	m.Use(hs.healthHandler)
	m.Use(hs.metricsEndpoint)
	m.Use(middleware.GetContextHandler(
		hs.AuthTokenService,
		hs.RemoteCacheService,
	))
	m.Use(middleware.OrgRedirect())

	// needs to be after context handler
	if setting.EnforceDomain {
		m.Use(middleware.ValidateHostHeader(setting.Domain))
	}

	m.Use(middleware.HandleNoCacheHeader())
}

func (hs *HTTPServer) metricsEndpoint(ctx *macaron.Context) {
	if !hs.Cfg.MetricsEndpointEnabled {
		return
	}

	if ctx.Req.Method != http.MethodGet || ctx.Req.URL.Path != "/metrics" {
		return
	}

	if hs.metricsEndpointBasicAuthEnabled() && !BasicAuthenticatedRequest(ctx.Req, hs.Cfg.MetricsEndpointBasicAuthUsername, hs.Cfg.MetricsEndpointBasicAuthPassword) {
		ctx.Resp.WriteHeader(http.StatusUnauthorized)
		return
	}

	promhttp.
		HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{}).
		ServeHTTP(ctx.Resp, ctx.Req.Request)
}

func (hs *HTTPServer) healthHandler(ctx *macaron.Context) {
	notHeadOrGet := ctx.Req.Method != http.MethodGet && ctx.Req.Method != http.MethodHead
	if notHeadOrGet || ctx.Req.URL.Path != "/api/health" {
		return
	}

	data := simplejson.New()
	data.Set("database", "ok")
	data.Set("version", setting.BuildVersion)
	data.Set("commit", setting.BuildCommit)

	if err := bus.Dispatch(&models.GetDBHealthQuery{}); err != nil {
		data.Set("database", "failing")
		ctx.Resp.Header().Set("Content-Type", "application/json; charset=UTF-8")
		ctx.Resp.WriteHeader(503)
	} else {
		ctx.Resp.Header().Set("Content-Type", "application/json; charset=UTF-8")
		ctx.Resp.WriteHeader(200)
	}

	dataBytes, _ := data.EncodePretty()
	if _, err := ctx.Resp.Write(dataBytes); err != nil {
		hs.log.Error("Failed to write to response", "err", err)
	}
}

func (hs *HTTPServer) mapStatic(m *macaron.Macaron, rootDir string, dir string, prefix string) {
	headers := func(c *macaron.Context) {
		c.Resp.Header().Set("Cache-Control", "public, max-age=3600")
	}

	if prefix == "public/build" {
		headers = func(c *macaron.Context) {
			c.Resp.Header().Set("Cache-Control", "public, max-age=31536000")
		}
	}

	if setting.Env == setting.DEV {
		headers = func(c *macaron.Context) {
			c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache")
		}
	}

	m.Use(httpstatic.Static(
		path.Join(rootDir, dir),
		httpstatic.StaticOptions{
			SkipLogging: true,
			Prefix:      prefix,
			AddHeaders:  headers,
		},
	))
}

func (hs *HTTPServer) metricsEndpointBasicAuthEnabled() bool {
	return hs.Cfg.MetricsEndpointBasicAuthUsername != "" && hs.Cfg.MetricsEndpointBasicAuthPassword != ""
}
<|endoftext|>


<commit_before>package handler

import (
	"net/http"

	"github.com/skygeario/skygear-server/pkg/auth"
	coreAuth "github.com/skygeario/skygear-server/pkg/core/auth"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz/policy"
	"github.com/skygeario/skygear-server/pkg/core/db"
	"github.com/skygeario/skygear-server/pkg/core/handler"
	"github.com/skygeario/skygear-server/pkg/core/inject"
	"github.com/skygeario/skygear-server/pkg/core/server"
)

func AttachMeHandler(
	server *server.Server,
	authDependency auth.DependencyMap,
) *server.Server {
	server.Handle("/me", &MeHandlerFactory{
		authDependency,
	}).Methods("POST")
	return server
}

type MeHandlerFactory struct {
	Dependency auth.DependencyMap
}

func (f MeHandlerFactory) NewHandler(request *http.Request) http.Handler {
	h := &MeHandler{}
	inject.DefaultInject(h, f.Dependency, request)
	return handler.APIHandlerToHandler(h, h.TxContext)
}

func (f MeHandlerFactory) ProvideAuthzPolicy() authz.Policy {
	return policy.AllOf(
		authz.PolicyFunc(policy.DenyNoAccessKey),
		authz.PolicyFunc(policy.RequireAuthenticated),
		authz.PolicyFunc(policy.DenyDisabledUser),
	)
}

// MeHandler handles me request
type MeHandler struct {
	AuthContext coreAuth.ContextGetter `dependency:"AuthContextGetter"`
	TxContext   db.TxContext           `dependency:"TxContext"`
}

func (h MeHandler) WithTx() bool {
	return true
}

func (h MeHandler) DecodeRequest(request *http.Request) (payload handler.RequestPayload, err error) {
	payload = handler.EmptyRequestPayload{}
	return
}

func (h MeHandler) Handle(req interface{}) (resp interface{}, err error) {
	resp = h.AuthContext.AuthInfo()
	return
}
<commit_msg>Update me to update token and user last_seen_at<commit_after>package handler

import (
	"net/http"

	"github.com/skygeario/skygear-server/pkg/auth"
	"github.com/skygeario/skygear-server/pkg/auth/response"
	coreAuth "github.com/skygeario/skygear-server/pkg/core/auth"
	"github.com/skygeario/skygear-server/pkg/core/auth/authinfo"
	"github.com/skygeario/skygear-server/pkg/core/auth/authtoken"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz/policy"
	"github.com/skygeario/skygear-server/pkg/core/db"
	"github.com/skygeario/skygear-server/pkg/core/handler"
	"github.com/skygeario/skygear-server/pkg/core/inject"
	"github.com/skygeario/skygear-server/pkg/core/server"
	"github.com/skygeario/skygear-server/pkg/server/skydb"
	"github.com/skygeario/skygear-server/pkg/server/skyerr"
)

func AttachMeHandler(
	server *server.Server,
	authDependency auth.DependencyMap,
) *server.Server {
	server.Handle("/me", &MeHandlerFactory{
		authDependency,
	}).Methods("POST")
	return server
}

type MeHandlerFactory struct {
	Dependency auth.DependencyMap
}

func (f MeHandlerFactory) NewHandler(request *http.Request) http.Handler {
	h := &MeHandler{}
	inject.DefaultInject(h, f.Dependency, request)
	return handler.APIHandlerToHandler(h, h.TxContext)
}

func (f MeHandlerFactory) ProvideAuthzPolicy() authz.Policy {
	return policy.AllOf(
		authz.PolicyFunc(policy.DenyNoAccessKey),
		authz.PolicyFunc(policy.RequireAuthenticated),
		authz.PolicyFunc(policy.DenyDisabledUser),
	)
}

// MeHandler handles me request
type MeHandler struct {
	AuthContext   coreAuth.ContextGetter `dependency:"AuthContextGetter"`
	TxContext     db.TxContext           `dependency:"TxContext"`
	TokenStore    authtoken.Store        `dependency:"TokenStore"`
	AuthInfoStore authinfo.Store         `dependency:"AuthInfoStore"`
}

func (h MeHandler) WithTx() bool {
	return true
}

func (h MeHandler) DecodeRequest(request *http.Request) (payload handler.RequestPayload, err error) {
	payload = handler.EmptyRequestPayload{}
	return
}

func (h MeHandler) Handle(req interface{}) (resp interface{}, err error) {
	authInfo := h.AuthContext.AuthInfo()

	// refresh access token with a newly generated one
	token, err := h.TokenStore.NewToken(authInfo.ID)
	if err != nil {
		panic(err)
	}

	if err = h.TokenStore.Put(&token); err != nil {
		panic(err)
	}

	resp = response.NewAuthResponse(*authInfo, skydb.Record{}, token.AccessToken)

	// Populate the activity time to user
	now := timeNow()
	authInfo.LastSeenAt = &now
	if err := h.AuthInfoStore.UpdateAuth(authInfo); err != nil {
		err = skyerr.MakeError(err)
	}

	return
}
<|endoftext|>


<commit_before>package awsutil

import (
	"fmt"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	log "github.com/sirupsen/logrus"
)

const (
	GlobalRegionID  = "global"
	DefaultRegionID = endpoints.UsEast1RegionID
)

type Credentials struct {
	Profile string

	AccessKeyID     string
	SecretAccessKey string
	SessionToken    string

	cache map[string]*session.Session
}

func (c *Credentials) HasProfile() bool {
	return strings.TrimSpace(c.Profile) != ""
}

func (c *Credentials) HasKeys() bool {
	return strings.TrimSpace(c.AccessKeyID) != "" ||
		strings.TrimSpace(c.SecretAccessKey) != "" ||
		strings.TrimSpace(c.SessionToken) != ""
}

func (c *Credentials) Validate() error {
	if c.HasProfile() == c.HasKeys() {
		return fmt.Errorf("You have to specify the --profile flag OR " +
			"--access-key-id with --secret-access-key and optionally " +
			"--session-token.\n")
	}

	return nil
}

func (c *Credentials) NewSession(region string) (*session.Session, error) {
	var opts session.Options

	global := false

	if region == GlobalRegionID {
		region = DefaultRegionID
		global = true
	}

	switch {
	case c.HasProfile() == c.HasKeys():
		return nil, fmt.Errorf("You have to specify a profile or credentials for at least one region.")

	case c.HasProfile():
		opts = session.Options{
			SharedConfigState: session.SharedConfigEnable,
			Profile:           c.Profile,
		}

	case c.HasKeys():
		opts = session.Options{
			Config: aws.Config{
				Credentials: credentials.NewStaticCredentials(
					strings.TrimSpace(c.AccessKeyID),
					strings.TrimSpace(c.SecretAccessKey),
					strings.TrimSpace(c.SessionToken),
				)}}
	}

	opts.Config.Region = aws.String(region)
	opts.Config.DisableRestProtocolURICleaning = aws.Bool(true)

	sess, err := session.NewSessionWithOptions(opts)
	if err != nil {
		return nil, err
	}

	sess.Handlers.Send.PushFront(func(r *request.Request) {
		log.Debugf("sending AWS request:\n%s", DumpRequest(r.HTTPRequest))
	})

	sess.Handlers.ValidateResponse.PushFront(func(r *request.Request) {
		log.Debugf("received AWS response:\n%s", DumpResponse(r.HTTPResponse))
	})

	sess.Handlers.Validate.PushFront(skipMissingServiceInRegionHandler)
	sess.Handlers.Validate.PushFront(skipGlobalHandler(global))

	return sess, nil
}

func (c *Credentials) Session(region string) (*session.Session, error) {
	sess, ok := c.cache[region]
	if ok {
		return sess, nil
	}

	sess, err := c.NewSession(region)
	if err != nil {
		c.cache[region] = sess
	}

	return sess, err
}

func skipMissingServiceInRegionHandler(r *request.Request) {
	region := *r.Config.Region
	service := r.ClientInfo.ServiceName

	rs, ok := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, service)
	if !ok {
		// This means that the service does not exist and this shouldn't be handled here.
		return
	}

	if len(rs) == 0 {
		// Avoid to throw an error on global services.
		return
	}

	_, ok = rs[region]
	if !ok {
		r.Error = ErrSkipRequest(fmt.Sprintf(
			"service '%s' is not available in region '%s'",
			service, region))
	}
}

func skipGlobalHandler(global bool) func(r *request.Request) {
	return func(r *request.Request) {
		service := r.ClientInfo.ServiceName

		rs, ok := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, service)
		if !ok {
			// This means that the service does not exist and this shouldn't be handled here.
			return
		}

		if len(rs) == 0 && !global {
			r.Error = ErrSkipRequest(fmt.Sprintf("service '%s' is global, but the session is not", service))
			return
		}

		if len(rs) > 0 && global {
			r.Error = ErrSkipRequest(fmt.Sprintf("service '%s' is not global, but the session is", service))
			return
		}
	}
}
<commit_msg>add fallback for missing services in endpoint list<commit_after>package awsutil

import (
	"fmt"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	log "github.com/sirupsen/logrus"
)

const (
	GlobalRegionID  = "global"
	DefaultRegionID = endpoints.UsEast1RegionID
)

type Credentials struct {
	Profile string

	AccessKeyID     string
	SecretAccessKey string
	SessionToken    string

	cache map[string]*session.Session
}

func (c *Credentials) HasProfile() bool {
	return strings.TrimSpace(c.Profile) != ""
}

func (c *Credentials) HasKeys() bool {
	return strings.TrimSpace(c.AccessKeyID) != "" ||
		strings.TrimSpace(c.SecretAccessKey) != "" ||
		strings.TrimSpace(c.SessionToken) != ""
}

func (c *Credentials) Validate() error {
	if c.HasProfile() == c.HasKeys() {
		return fmt.Errorf("You have to specify the --profile flag OR " +
			"--access-key-id with --secret-access-key and optionally " +
			"--session-token.\n")
	}

	return nil
}

func (c *Credentials) NewSession(region string) (*session.Session, error) {
	var opts session.Options

	global := false

	if region == GlobalRegionID {
		region = DefaultRegionID
		global = true
	}

	switch {
	case c.HasProfile() == c.HasKeys():
		return nil, fmt.Errorf("You have to specify a profile or credentials for at least one region.")

	case c.HasProfile():
		opts = session.Options{
			SharedConfigState: session.SharedConfigEnable,
			Profile:           c.Profile,
		}

	case c.HasKeys():
		opts = session.Options{
			Config: aws.Config{
				Credentials: credentials.NewStaticCredentials(
					strings.TrimSpace(c.AccessKeyID),
					strings.TrimSpace(c.SecretAccessKey),
					strings.TrimSpace(c.SessionToken),
				)}}
	}

	opts.Config.Region = aws.String(region)
	opts.Config.DisableRestProtocolURICleaning = aws.Bool(true)

	sess, err := session.NewSessionWithOptions(opts)
	if err != nil {
		return nil, err
	}

	sess.Handlers.Send.PushFront(func(r *request.Request) {
		log.Debugf("sending AWS request:\n%s", DumpRequest(r.HTTPRequest))
	})

	sess.Handlers.ValidateResponse.PushFront(func(r *request.Request) {
		log.Debugf("received AWS response:\n%s", DumpResponse(r.HTTPResponse))
	})

	sess.Handlers.Validate.PushFront(skipMissingServiceInRegionHandler)
	sess.Handlers.Validate.PushFront(skipGlobalHandler(global))

	return sess, nil
}

func (c *Credentials) Session(region string) (*session.Session, error) {
	sess, ok := c.cache[region]
	if ok {
		return sess, nil
	}

	sess, err := c.NewSession(region)
	if err != nil {
		c.cache[region] = sess
	}

	return sess, err
}

func skipMissingServiceInRegionHandler(r *request.Request) {
	region := *r.Config.Region
	service := r.ClientInfo.ServiceName

	rs, ok := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, service)
	if !ok {
		// This means that the service does not exist and this shouldn't be handled here.
		return
	}

	if len(rs) == 0 {
		// Avoid to throw an error on global services.
		return
	}

	_, ok = rs[region]
	if !ok {
		r.Error = ErrSkipRequest(fmt.Sprintf(
			"service '%s' is not available in region '%s'",
			service, region))
	}
}

func skipGlobalHandler(global bool) func(r *request.Request) {
	return func(r *request.Request) {
		service := r.ClientInfo.ServiceName

		rs, ok := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, service)
		if !ok {
			// This means that the service does not exist in the endpoints list.
			if global {
				r.Error = ErrSkipRequest(fmt.Sprintf("service '%s' is was not found in the endpoint list; assuming it is not global", service))
			}
			return
		}

		if len(rs) == 0 && !global {
			r.Error = ErrSkipRequest(fmt.Sprintf("service '%s' is global, but the session is not", service))
			return
		}

		if len(rs) > 0 && global {
			r.Error = ErrSkipRequest(fmt.Sprintf("service '%s' is not global, but the session is", service))
			return
		}
	}
}
<|endoftext|>


<commit_before>package checker

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/go-chi/chi"
	"github.com/hellofresh/health-go"
	"github.com/hellofresh/janus/pkg/api"
	log "github.com/sirupsen/logrus"
)

// NewOverviewHandler creates instance of all status checks handler
func NewOverviewHandler(repo api.Repository) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		definitions, err := repo.FindValidAPIHealthChecks()
		if err != nil {
			log.WithError(err).Error("Error fetching API definitions for health check registering")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}

		log.WithField("len", len(definitions)).Debug("Loading health check endpoints")
		health.Reset()

		for _, definition := range definitions {
			if definition.HealthCheck.URL != "" {
				log.WithField("name", definition.Name).Debug("Registering health check")
				health.Register(health.Config{
					Name:      definition.Name,
					Timeout:   time.Second * time.Duration(definition.HealthCheck.Timeout),
					SkipOnErr: true,
					Check:     check(definition),
				})
			}
		}

		health.HandlerFunc(w, r)
	}
}

// NewStatusHandler creates instance of single proxy status check handler
func NewStatusHandler(repo api.Repository) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		definitions, err := repo.FindValidAPIHealthChecks()
		if err != nil {
			log.WithError(err).Error("Error fetching API definitions for health check registering")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}

		name := chi.URLParam(r, "name")
		for _, definition := range definitions {
			if name == definition.Name {
				resp, err := doStatusRequest(definition, false)
				if err != nil {
					log.WithField("name", name).WithError(err).Error("Error requesting service health status")
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}

				body, err := ioutil.ReadAll(resp.Body)
				if closeErr := resp.Body.Close(); closeErr != nil {
					log.WithField("name", name).WithError(closeErr).Error("Error closing health status body")
				}

				if err != nil {
					log.WithField("name", name).WithError(err).Error("Error reading health status body")
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}

				w.WriteHeader(resp.StatusCode)
				w.Write(body)
				return
			}
		}

		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("Definition name is not found"))
	}
}

func doStatusRequest(definition *api.Definition, closeBody bool) (*http.Response, error) {
	req, err := http.NewRequest(http.MethodGet, definition.HealthCheck.URL, nil)
	if err != nil {
		log.WithError(err).Error("Creating the request for the health check failed")
		return nil, err
	}

	// Inform to close the connection after the transaction is complete
	req.Header.Set("Connection", "close")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.WithError(err).Error("Making the request for the health check failed")
		return resp, err
	}

	if closeBody {
		defer resp.Body.Close()
	}

	return resp, err
}

func check(definition *api.Definition) func() error {
	return func() error {
		resp, err := doStatusRequest(definition, true)
		if err != nil {
			return err
		}

		if resp.StatusCode >= http.StatusInternalServerError {
			return fmt.Errorf("%s is not available at the moment", definition.Name)
		}

		if resp.StatusCode >= http.StatusBadRequest {
			return fmt.Errorf("%s is partially available at the moment", definition.Name)
		}

		return nil
	}
}
<commit_msg>Improve error msg health check<commit_after>package checker

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/go-chi/chi"
	"github.com/hellofresh/health-go"
	"github.com/hellofresh/janus/pkg/api"
	log "github.com/sirupsen/logrus"
)

// NewOverviewHandler creates instance of all status checks handler
func NewOverviewHandler(repo api.Repository) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		definitions, err := repo.FindValidAPIHealthChecks()
		if err != nil {
			log.WithError(err).Error("Error fetching API definitions for health check registering")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}

		log.WithField("len", len(definitions)).Debug("Loading health check endpoints")
		health.Reset()

		for _, definition := range definitions {
			if definition.HealthCheck.URL != "" {
				log.WithField("name", definition.Name).Debug("Registering health check")
				health.Register(health.Config{
					Name:      definition.Name,
					Timeout:   time.Second * time.Duration(definition.HealthCheck.Timeout),
					SkipOnErr: true,
					Check:     check(definition),
				})
			}
		}

		health.HandlerFunc(w, r)
	}
}

// NewStatusHandler creates instance of single proxy status check handler
func NewStatusHandler(repo api.Repository) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		definitions, err := repo.FindValidAPIHealthChecks()
		if err != nil {
			log.WithError(err).Error("Error fetching API definitions for health check registering")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}

		name := chi.URLParam(r, "name")
		for _, definition := range definitions {
			if name == definition.Name {
				resp, err := doStatusRequest(definition, false)
				if err != nil {
					log.WithField("name", name).WithError(err).Error("Error requesting service health status")
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}

				body, err := ioutil.ReadAll(resp.Body)
				if closeErr := resp.Body.Close(); closeErr != nil {
					log.WithField("name", name).WithError(closeErr).Error("Error closing health status body")
				}

				if err != nil {
					log.WithField("name", name).WithError(err).Error("Error reading health status body")
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}

				w.WriteHeader(resp.StatusCode)
				w.Write(body)
				return
			}
		}

		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("Definition name is not found"))
	}
}

func doStatusRequest(definition *api.Definition, closeBody bool) (*http.Response, error) {
	req, err := http.NewRequest(http.MethodGet, definition.HealthCheck.URL, nil)
	if err != nil {
		log.WithError(err).Error("Creating the request for the health check failed")
		return nil, err
	}

	// Inform to close the connection after the transaction is complete
	req.Header.Set("Connection", "close")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.WithError(err).Error("Making the request for the health check failed")
		return resp, err
	}

	if closeBody {
		defer resp.Body.Close()
	}

	return resp, err
}

func check(definition *api.Definition) func() error {
	return func() error {
		resp, err := doStatusRequest(definition, true)
		if err != nil {
			return fmt.Errorf("%s health check endpoint %s is unreachable", definition.Name, definition.HealthCheck.URL)
		}

		if resp.StatusCode >= http.StatusInternalServerError {
			return fmt.Errorf("%s is not available at the moment", definition.Name)
		}

		if resp.StatusCode >= http.StatusBadRequest {
			return fmt.Errorf("%s is partially available at the moment", definition.Name)
		}

		return nil
	}
}
<|endoftext|>


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

package k8sutil

import (
	"fmt"
	"net/http"
	"time"

	"k8s.io/client-go/1.5/pkg/api/v1"
	"k8s.io/client-go/1.5/pkg/util/wait"
	"k8s.io/client-go/1.5/rest"
)

// WaitForTPRReady waits for a third party resource to be available
// for use.
func WaitForTPRReady(restClient *rest.RESTClient, tprGroup, tprVersion, tprName string) error {
	return wait.Poll(3*time.Second, 30*time.Second, func() (bool, error) {
		res := restClient.Get().AbsPath("apis", tprGroup, tprVersion, tprName).Do()
		err := res.Error()
		if err != nil {
			return false, err
		}

		var statusCode int
		res.StatusCode(&statusCode)
		switch statusCode {
		case http.StatusOK:
			return true, nil
		case http.StatusNotFound: // not set up yet. wait.
			return false, nil
		default:
			return false, fmt.Errorf("invalid status code: %d", statusCode)
		}
	})
}

// PodRunningAndReady returns whether a pod is running and each container has
// passed it's ready state.
func PodRunningAndReady(pod v1.Pod) (bool, error) {
	switch pod.Status.Phase {
	case v1.PodFailed, v1.PodSucceeded:
		return false, fmt.Errorf("pod completed")
	case v1.PodRunning:
		for _, cond := range pod.Status.Conditions {
			if cond.Type != v1.PodReady {
				continue
			}
			return cond.Status == v1.ConditionTrue, nil
		}
		return false, fmt.Errorf("pod ready condition not found")
	}
	return false, nil
}
<commit_msg>Handle errors properly waiting for TPRs<commit_after>// Copyright 2016 The prometheus-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package k8sutil

import (
	"fmt"
	"net/http"
	"time"

	"k8s.io/client-go/1.5/pkg/api/errors"
	"k8s.io/client-go/1.5/pkg/api/v1"
	"k8s.io/client-go/1.5/pkg/util/wait"
	"k8s.io/client-go/1.5/rest"
)

// WaitForTPRReady waits for a third party resource to be available
// for use.
func WaitForTPRReady(restClient *rest.RESTClient, tprGroup, tprVersion, tprName string) error {
	return wait.Poll(3*time.Second, 30*time.Second, func() (bool, error) {
		res := restClient.Get().AbsPath("apis", tprGroup, tprVersion, tprName).Do()
		err := res.Error()
		if err != nil {
			// RESTClient returns *errors.StatusError for any status codes < 200 or > 206
			// and http.Client.Do errors are returned directly.
			if se, ok := err.(*errors.StatusError); ok {
				if se.Status().Code == http.StatusNotFound {
					return false, nil
				}
			}
			return false, err
		}

		var statusCode int
		res.StatusCode(&statusCode)
		if statusCode != http.StatusOK {
			return false, fmt.Errorf("invalid status code: %d", statusCode)
		}

		return true, nil
	})
}

// PodRunningAndReady returns whether a pod is running and each container has
// passed it's ready state.
func PodRunningAndReady(pod v1.Pod) (bool, error) {
	switch pod.Status.Phase {
	case v1.PodFailed, v1.PodSucceeded:
		return false, fmt.Errorf("pod completed")
	case v1.PodRunning:
		for _, cond := range pod.Status.Conditions {
			if cond.Type != v1.PodReady {
				continue
			}
			return cond.Status == v1.ConditionTrue, nil
		}
		return false, fmt.Errorf("pod ready condition not found")
	}
	return false, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"

	"k8s.io/apiserver/pkg/util/flag"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
	cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
	"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
	"k8s.io/kubernetes/pkg/kubectl/cmd/set"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/util/i18n"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
)

const (
	bash_completion_func = `# call kubectl get $1,
__kubectl_override_flag_list=(kubeconfig cluster user context namespace server)
__kubectl_override_flags()
{
    local ${__kubectl_override_flag_list[*]} two_word_of of
    for w in "${words[@]}"; do
        if [ -n "${two_word_of}" ]; then
            eval "${two_word_of}=\"--${two_word_of}=\${w}\""
            two_word_of=
            continue
        fi
        for of in "${__kubectl_override_flag_list[@]}"; do
            case "${w}" in
                --${of}=*)
                    eval "${of}=\"${w}\""
                    ;;
                --${of})
                    two_word_of="${of}"
                    ;;
            esac
        done
        if [ "${w}" == "--all-namespaces" ]; then
            namespace="--all-namespaces"
        fi
    done
    for of in "${__kubectl_override_flag_list[@]}"; do
        if eval "test -n \"\$${of}\""; then
            eval "echo \${${of}}"
        fi
    done
}

__kubectl_get_namespaces()
{
    local template kubectl_out
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_get_contexts()
{
    local template kubectl_out
    template="{{ range .contexts  }}{{ .name }} {{ end }}"
    if kubectl_out=$(kubectl config $(__kubectl_override_flags) -o template --template="${template}" view 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_parse_get()
{
    local template
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" "$1" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_get_resource()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        return 1
    fi
    __kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
}

__kubectl_get_resource_pod()
{
    __kubectl_parse_get "pod"
}

__kubectl_get_resource_rc()
{
    __kubectl_parse_get "rc"
}

__kubectl_get_resource_node()
{
    __kubectl_parse_get "node"
}

# $1 is the name of the pod we want to get the list of containers inside
__kubectl_get_containers()
{
    local template
    template="{{ range .spec.containers  }}{{ .name }} {{ end }}"
    __debug "${FUNCNAME} nouns are ${nouns[*]}"

    local len="${#nouns[@]}"
    if [[ ${len} -ne 1 ]]; then
        return
    fi
    local last=${nouns[${len} -1]}
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" pods "${last}" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

# Require both a pod and a container to be specified
__kubectl_require_pod_and_container()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        __kubectl_parse_get pods
        return 0
    fi;
    __kubectl_get_containers
    return 0
}

__custom_func() {
    case ${last_command} in
        kubectl_get | kubectl_describe | kubectl_delete | kubectl_label | kubectl_stop | kubectl_edit | kubectl_patch |\
        kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_*)
            __kubectl_get_resource
            return
            ;;
        kubectl_logs | kubectl_attach)
            __kubectl_require_pod_and_container
            return
            ;;
        kubectl_exec | kubectl_port-forward | kubectl_top_pod)
            __kubectl_get_resource_pod
            return
            ;;
        kubectl_rolling-update)
            __kubectl_get_resource_rc
            return
            ;;
        kubectl_cordon | kubectl_uncordon | kubectl_drain | kubectl_top_node)
            __kubectl_get_resource_node
            return
            ;;
        kubectl_config_use-context)
            __kubectl_get_contexts
            return
            ;;
        *)
            ;;
    esac
}
`

	// If you add a resource to this list, please also take a look at pkg/kubectl/kubectl.go
	// and add a short forms entry in expandResourceShortcut() when appropriate.
	// TODO: This should be populated using the discovery information from apiserver.
	valid_resources = `Valid resource types include:

    * all
    * certificatesigningrequests (aka 'csr')
    * clusterrolebindings
    * clusterroles
    * clusters (valid only for federation apiservers)
    * componentstatuses (aka 'cs')
    * configmaps (aka 'cm')
    * cronjobs
    * daemonsets (aka 'ds')
    * deployments (aka 'deploy')
    * endpoints (aka 'ep')
    * events (aka 'ev')
    * horizontalpodautoscalers (aka 'hpa')
    * ingresses (aka 'ing')
    * jobs
    * limitranges (aka 'limits')
    * namespaces (aka 'ns')
    * networkpolicies
    * nodes (aka 'no')
    * persistentvolumeclaims (aka 'pvc')
    * persistentvolumes (aka 'pv')
    * poddisruptionbudgets (aka 'pdb')
    * pods (aka 'po')
    * podsecuritypolicies (aka 'psp')
    * podtemplates
    * replicasets (aka 'rs')
    * replicationcontrollers (aka 'rc')
    * resourcequotas (aka 'quota')
    * rolebindings
    * roles
    * secrets
    * serviceaccounts (aka 'sa')
    * services (aka 'svc')
    * statefulsets
    * storageclasses
    * thirdpartyresources
    `
)

// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubectl",
		Short: i18n.T("kubectl controls the Kubernetes cluster manager"),
		Long: templates.LongDesc(`
      kubectl controls the Kubernetes cluster manager.

      Find more information at https://github.com/kubernetes/kubernetes.`),
		Run: runHelp,
		BashCompletionFunction: bash_completion_func,
	}

	f.BindFlags(cmds.PersistentFlags())
	f.BindExternalFlags(cmds.PersistentFlags())

	// Sending in 'nil' for the getLanguageFn() results in using
	// the LANG environment variable.
	//
	// TODO: Consider adding a flag or file preference for setting
	// the language, instead of just loading from the LANG env. variable.
	i18n.LoadTranslations("kubectl", nil)

	// From this point and forward we get warnings on flags that contain "_" separators
	cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)

	groups := templates.CommandGroups{
		{
			Message: "Basic Commands (Beginner):",
			Commands: []*cobra.Command{
				NewCmdCreate(f, out, err),
				NewCmdExposeService(f, out),
				NewCmdRun(f, in, out, err),
				set.NewCmdSet(f, out, err),
			},
		},
		{
			Message: "Basic Commands (Intermediate):",
			Commands: []*cobra.Command{
				NewCmdGet(f, out, err),
				NewCmdExplain(f, out, err),
				NewCmdEdit(f, out, err),
				NewCmdDelete(f, out, err),
			},
		},
		{
			Message: "Deploy Commands:",
			Commands: []*cobra.Command{
				rollout.NewCmdRollout(f, out, err),
				NewCmdRollingUpdate(f, out),
				NewCmdScale(f, out),
				NewCmdAutoscale(f, out),
			},
		},
		{
			Message: "Cluster Management Commands:",
			Commands: []*cobra.Command{
				NewCmdCertificate(f, out),
				NewCmdClusterInfo(f, out),
				NewCmdTop(f, out, err),
				NewCmdCordon(f, out),
				NewCmdUncordon(f, out),
				NewCmdDrain(f, out, err),
				NewCmdTaint(f, out),
			},
		},
		{
			Message: "Troubleshooting and Debugging Commands:",
			Commands: []*cobra.Command{
				NewCmdDescribe(f, out, err),
				NewCmdLogs(f, out),
				NewCmdAttach(f, in, out, err),
				NewCmdExec(f, in, out, err),
				NewCmdPortForward(f, out, err),
				NewCmdProxy(f, out),
				NewCmdCp(f, in, out, err),
				auth.NewCmdAuth(f, out, err),
			},
		},
		{
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				NewCmdApply(f, out, err),
				NewCmdPatch(f, out),
				NewCmdReplace(f, out),
				NewCmdConvert(f, out),
			},
		},
		{
			Message: "Settings Commands:",
			Commands: []*cobra.Command{
				NewCmdLabel(f, out),
				NewCmdAnnotate(f, out),
				NewCmdCompletion(f, out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{
		"options",
		Deprecated("kubectl", "delete", cmds, NewCmdStop(f, out)),
	}
	templates.ActsAsRootCommand(cmds, filters, groups...)

	if cmds.Flag("namespace") != nil {
		if cmds.Flag("namespace").Annotations == nil {
			cmds.Flag("namespace").Annotations = map[string][]string{}
		}
		cmds.Flag("namespace").Annotations[cobra.BashCompCustom] = append(
			cmds.Flag("namespace").Annotations[cobra.BashCompCustom],
			"__kubectl_get_namespaces",
		)
	}

	if cmds.Flag("context") != nil {
		if cmds.Flag("context").Annotations == nil {
			cmds.Flag("context").Annotations = map[string][]string{}
		}
		cmds.Flag("context").Annotations[cobra.BashCompCustom] = append(
			cmds.Flag("context").Annotations[cobra.BashCompCustom],
			"__kubectl_get_contexts",
		)
	}

	cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out, err))
	cmds.AddCommand(NewCmdVersion(f, out))
	cmds.AddCommand(NewCmdApiVersions(f, out))
	cmds.AddCommand(NewCmdOptions(out))

	return cmds
}

func runHelp(cmd *cobra.Command, args []string) {
	cmd.Help()
}

func printDeprecationWarning(command, alias string) {
	glog.Warningf("%s is DEPRECATED and will be removed in a future version. Use %s instead.", alias, command)
}

func Deprecated(baseName, to string, parent, cmd *cobra.Command) string {
	cmd.Long = fmt.Sprintf("Deprecated: This command is deprecated, all its functionalities are covered by \"%s %s\"", baseName, to)
	cmd.Short = fmt.Sprintf("Deprecated: %s", to)
	parent.AddCommand(cmd)
	return cmd.Name()
}
<commit_msg>Support completion for --cluster and --user<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"

	"k8s.io/apiserver/pkg/util/flag"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
	cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
	"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
	"k8s.io/kubernetes/pkg/kubectl/cmd/set"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/util/i18n"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
)

const (
	bash_completion_func = `# call kubectl get $1,
__kubectl_override_flag_list=(kubeconfig cluster user context namespace server)
__kubectl_override_flags()
{
    local ${__kubectl_override_flag_list[*]} two_word_of of
    for w in "${words[@]}"; do
        if [ -n "${two_word_of}" ]; then
            eval "${two_word_of}=\"--${two_word_of}=\${w}\""
            two_word_of=
            continue
        fi
        for of in "${__kubectl_override_flag_list[@]}"; do
            case "${w}" in
                --${of}=*)
                    eval "${of}=\"${w}\""
                    ;;
                --${of})
                    two_word_of="${of}"
                    ;;
            esac
        done
        if [ "${w}" == "--all-namespaces" ]; then
            namespace="--all-namespaces"
        fi
    done
    for of in "${__kubectl_override_flag_list[@]}"; do
        if eval "test -n \"\$${of}\""; then
            eval "echo \${${of}}"
        fi
    done
}

__kubectl_get_namespaces()
{
    local template kubectl_out
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_config_get_contexts()
{
    __kubectl_parse_config "contexts"
}

__kubectl_config_get_clusters()
{
    __kubectl_parse_config "clusters"
}

__kubectl_config_get_users()
{
    __kubectl_parse_config "users"
}

# $1 has to be "contexts", "clusters" or "users"
__kubectl_config_get()
{
    local template kubectl_out
    template="{{ range .$1  }}{{ .name }} {{ end }}"
    if kubectl_out=$(kubectl config $(__kubectl_override_flags) -o template --template="${template}" view 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_parse_get()
{
    local template
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" "$1" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_get_resource()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        return 1
    fi
    __kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
}

__kubectl_get_resource_pod()
{
    __kubectl_parse_get "pod"
}

__kubectl_get_resource_rc()
{
    __kubectl_parse_get "rc"
}

__kubectl_get_resource_node()
{
    __kubectl_parse_get "node"
}

# $1 is the name of the pod we want to get the list of containers inside
__kubectl_get_containers()
{
    local template
    template="{{ range .spec.containers  }}{{ .name }} {{ end }}"
    __debug "${FUNCNAME} nouns are ${nouns[*]}"

    local len="${#nouns[@]}"
    if [[ ${len} -ne 1 ]]; then
        return
    fi
    local last=${nouns[${len} -1]}
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" pods "${last}" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

# Require both a pod and a container to be specified
__kubectl_require_pod_and_container()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        __kubectl_parse_get pods
        return 0
    fi;
    __kubectl_get_containers
    return 0
}

__custom_func() {
    case ${last_command} in
        kubectl_get | kubectl_describe | kubectl_delete | kubectl_label | kubectl_stop | kubectl_edit | kubectl_patch |\
        kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_*)
            __kubectl_get_resource
            return
            ;;
        kubectl_logs | kubectl_attach)
            __kubectl_require_pod_and_container
            return
            ;;
        kubectl_exec | kubectl_port-forward | kubectl_top_pod)
            __kubectl_get_resource_pod
            return
            ;;
        kubectl_rolling-update)
            __kubectl_get_resource_rc
            return
            ;;
        kubectl_cordon | kubectl_uncordon | kubectl_drain | kubectl_top_node)
            __kubectl_get_resource_node
            return
            ;;
        kubectl_config_use-context)
            __kubectl_config_get_contexts
            return
            ;;
        *)
            ;;
    esac
}
`

	// If you add a resource to this list, please also take a look at pkg/kubectl/kubectl.go
	// and add a short forms entry in expandResourceShortcut() when appropriate.
	// TODO: This should be populated using the discovery information from apiserver.
	valid_resources = `Valid resource types include:

    * all
    * certificatesigningrequests (aka 'csr')
    * clusterrolebindings
    * clusterroles
    * clusters (valid only for federation apiservers)
    * componentstatuses (aka 'cs')
    * configmaps (aka 'cm')
    * cronjobs
    * daemonsets (aka 'ds')
    * deployments (aka 'deploy')
    * endpoints (aka 'ep')
    * events (aka 'ev')
    * horizontalpodautoscalers (aka 'hpa')
    * ingresses (aka 'ing')
    * jobs
    * limitranges (aka 'limits')
    * namespaces (aka 'ns')
    * networkpolicies
    * nodes (aka 'no')
    * persistentvolumeclaims (aka 'pvc')
    * persistentvolumes (aka 'pv')
    * poddisruptionbudgets (aka 'pdb')
    * pods (aka 'po')
    * podsecuritypolicies (aka 'psp')
    * podtemplates
    * replicasets (aka 'rs')
    * replicationcontrollers (aka 'rc')
    * resourcequotas (aka 'quota')
    * rolebindings
    * roles
    * secrets
    * serviceaccounts (aka 'sa')
    * services (aka 'svc')
    * statefulsets
    * storageclasses
    * thirdpartyresources
    `
)

var (
	bash_completion_flags = map[string]string{
		"namespace": "__kubectl_get_namespaces",
		"context":   "__kubectl_config_get_contexts",
		"cluster":   "__kubectl_config_get_clusters",
		"user":      "__kubectl_config_get_users",
	}
)

// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubectl",
		Short: i18n.T("kubectl controls the Kubernetes cluster manager"),
		Long: templates.LongDesc(`
      kubectl controls the Kubernetes cluster manager.

      Find more information at https://github.com/kubernetes/kubernetes.`),
		Run: runHelp,
		BashCompletionFunction: bash_completion_func,
	}

	f.BindFlags(cmds.PersistentFlags())
	f.BindExternalFlags(cmds.PersistentFlags())

	// Sending in 'nil' for the getLanguageFn() results in using
	// the LANG environment variable.
	//
	// TODO: Consider adding a flag or file preference for setting
	// the language, instead of just loading from the LANG env. variable.
	i18n.LoadTranslations("kubectl", nil)

	// From this point and forward we get warnings on flags that contain "_" separators
	cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)

	groups := templates.CommandGroups{
		{
			Message: "Basic Commands (Beginner):",
			Commands: []*cobra.Command{
				NewCmdCreate(f, out, err),
				NewCmdExposeService(f, out),
				NewCmdRun(f, in, out, err),
				set.NewCmdSet(f, out, err),
			},
		},
		{
			Message: "Basic Commands (Intermediate):",
			Commands: []*cobra.Command{
				NewCmdGet(f, out, err),
				NewCmdExplain(f, out, err),
				NewCmdEdit(f, out, err),
				NewCmdDelete(f, out, err),
			},
		},
		{
			Message: "Deploy Commands:",
			Commands: []*cobra.Command{
				rollout.NewCmdRollout(f, out, err),
				NewCmdRollingUpdate(f, out),
				NewCmdScale(f, out),
				NewCmdAutoscale(f, out),
			},
		},
		{
			Message: "Cluster Management Commands:",
			Commands: []*cobra.Command{
				NewCmdCertificate(f, out),
				NewCmdClusterInfo(f, out),
				NewCmdTop(f, out, err),
				NewCmdCordon(f, out),
				NewCmdUncordon(f, out),
				NewCmdDrain(f, out, err),
				NewCmdTaint(f, out),
			},
		},
		{
			Message: "Troubleshooting and Debugging Commands:",
			Commands: []*cobra.Command{
				NewCmdDescribe(f, out, err),
				NewCmdLogs(f, out),
				NewCmdAttach(f, in, out, err),
				NewCmdExec(f, in, out, err),
				NewCmdPortForward(f, out, err),
				NewCmdProxy(f, out),
				NewCmdCp(f, in, out, err),
				auth.NewCmdAuth(f, out, err),
			},
		},
		{
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				NewCmdApply(f, out, err),
				NewCmdPatch(f, out),
				NewCmdReplace(f, out),
				NewCmdConvert(f, out),
			},
		},
		{
			Message: "Settings Commands:",
			Commands: []*cobra.Command{
				NewCmdLabel(f, out),
				NewCmdAnnotate(f, out),
				NewCmdCompletion(f, out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{
		"options",
		Deprecated("kubectl", "delete", cmds, NewCmdStop(f, out)),
	}
	templates.ActsAsRootCommand(cmds, filters, groups...)

	for name, completion := range bash_completion_flags {
		if cmds.Flag(name) != nil {
			if cmds.Flag(name).Annotations == nil {
				cmds.Flag(name).Annotations = map[string][]string{}
			}
			cmds.Flag(name).Annotations[cobra.BashCompCustom] = append(
				cmds.Flag(name).Annotations[cobra.BashCompCustom],
				completion,
			)
		}
	}

	cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out, err))
	cmds.AddCommand(NewCmdVersion(f, out))
	cmds.AddCommand(NewCmdApiVersions(f, out))
	cmds.AddCommand(NewCmdOptions(out))

	return cmds
}

func runHelp(cmd *cobra.Command, args []string) {
	cmd.Help()
}

func printDeprecationWarning(command, alias string) {
	glog.Warningf("%s is DEPRECATED and will be removed in a future version. Use %s instead.", alias, command)
}

func Deprecated(baseName, to string, parent, cmd *cobra.Command) string {
	cmd.Long = fmt.Sprintf("Deprecated: This command is deprecated, all its functionalities are covered by \"%s %s\"", baseName, to)
	cmd.Short = fmt.Sprintf("Deprecated: %s", to)
	parent.AddCommand(cmd)
	return cmd.Name()
}
<|endoftext|>


<commit_before>package project

var (
	description        = "The aws-operator manages Kubernetes clusters running on AWS."
	gitSHA             = "n/a"
	name        string = "aws-operator"
	source      string = "https://github.com/giantswarm/aws-operator"
	version            = "11.8.0"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<commit_msg>Bump version to 11.8.1-dev (#3316)<commit_after>package project

var (
	description        = "The aws-operator manages Kubernetes clusters running on AWS."
	gitSHA             = "n/a"
	name        string = "aws-operator"
	source      string = "https://github.com/giantswarm/aws-operator"
	version            = "11.8.1-dev"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package utils

import (
	"time"

	"github.com/golang/glog"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
)

var (
	KeyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc
)

// TaskQueue is a rate limited operation queue.
type TaskQueue interface {
	Run(period time.Duration, stopCh <-chan struct{})
	Enqueue(objs ...interface{})
	Shutdown()
}

// PeriodicTaskQueue invokes the given sync function for every work item
// inserted. If the sync() function results in an error, the item is put on
// the work queue after a rate-limit.
type PeriodicTaskQueue struct {
	// resource is used for logging to distinguish the queue being used.
	resource string
	// keyFunc translates an object to a string-based key.
	keyFunc func(obj interface{}) (string, error)
	// queue is the work queue the worker polls.
	queue workqueue.RateLimitingInterface
	// sync is called for each item in the queue.
	sync func(string) error
	// workerDone is closed when the worker exits.
	workerDone chan struct{}
}

// Run the task queue. This will block until the Shutdown() has been called.
// TODO: seems redundant to both have stopCh and Shutdown().
func (t *PeriodicTaskQueue) Run(period time.Duration, stopCh <-chan struct{}) {
	wait.Until(t.worker, period, stopCh)
}

// Enqueue one or more keys to the work queue.
func (t *PeriodicTaskQueue) Enqueue(objs ...interface{}) {
	for _, obj := range objs {
		key, err := t.keyFunc(obj)
		if err != nil {
			glog.Errorf("Couldn't get key for object %+v (type %T): %v", obj, obj, err)
			return
		}
		glog.V(4).Infof("Enqueue key=%q (%v)", key, t.resource)
		t.queue.Add(key)
	}
}

// Shutdown shuts down the work queue and waits for the worker to ACK
func (t *PeriodicTaskQueue) Shutdown() {
	glog.V(2).Infof("Shutdown")
	t.queue.ShutDown()
	<-t.workerDone
}

// worker processes work in the queue through sync.
func (t *PeriodicTaskQueue) worker() {
	for {
		key, quit := t.queue.Get()
		if quit {
			close(t.workerDone)
			return
		}
		glog.V(4).Infof("Syncing %v (%v)", key, t.resource)
		if err := t.sync(key.(string)); err != nil {
			glog.Errorf("Requeuing %q due to error: %v (%v)", key, err, t.resource)
			t.queue.AddRateLimited(key)
		} else {
			glog.V(4).Infof("Finished syncing %v", key)
			t.queue.Forget(key)
		}
		t.queue.Done(key)
	}
}

// NewPeriodicTaskQueue creates a new task queue with the given sync function.
// The sync function is called for every element inserted into the queue.
func NewPeriodicTaskQueue(resource string, syncFn func(string) error) *PeriodicTaskQueue {
	return &PeriodicTaskQueue{
		resource:   resource,
		keyFunc:    KeyFunc,
		queue:      workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
		sync:       syncFn,
		workerDone: make(chan struct{}),
	}
}
<commit_msg>Allow for setting the rate limiter on the work queue<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package utils

import (
	"time"

	"github.com/golang/glog"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
)

var (
	KeyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc
)

// TaskQueue is a rate limited operation queue.
type TaskQueue interface {
	Run(period time.Duration, stopCh <-chan struct{})
	Enqueue(objs ...interface{})
	Shutdown()
}

// PeriodicTaskQueue invokes the given sync function for every work item
// inserted. If the sync() function results in an error, the item is put on
// the work queue after a rate-limit.
type PeriodicTaskQueue struct {
	// resource is used for logging to distinguish the queue being used.
	resource string
	// keyFunc translates an object to a string-based key.
	keyFunc func(obj interface{}) (string, error)
	// queue is the work queue the worker polls.
	queue workqueue.RateLimitingInterface
	// sync is called for each item in the queue.
	sync func(string) error
	// workerDone is closed when the worker exits.
	workerDone chan struct{}
}

// Run the task queue. This will block until the Shutdown() has been called.
// TODO: seems redundant to both have stopCh and Shutdown().
func (t *PeriodicTaskQueue) Run(period time.Duration, stopCh <-chan struct{}) {
	wait.Until(t.worker, period, stopCh)
}

// Enqueue one or more keys to the work queue.
func (t *PeriodicTaskQueue) Enqueue(objs ...interface{}) {
	for _, obj := range objs {
		key, err := t.keyFunc(obj)
		if err != nil {
			glog.Errorf("Couldn't get key for object %+v (type %T): %v", obj, obj, err)
			return
		}
		glog.V(4).Infof("Enqueue key=%q (%v)", key, t.resource)
		t.queue.Add(key)
	}
}

// Shutdown shuts down the work queue and waits for the worker to ACK
func (t *PeriodicTaskQueue) Shutdown() {
	glog.V(2).Infof("Shutdown")
	t.queue.ShutDown()
	<-t.workerDone
}

// worker processes work in the queue through sync.
func (t *PeriodicTaskQueue) worker() {
	for {
		key, quit := t.queue.Get()
		if quit {
			close(t.workerDone)
			return
		}
		glog.V(4).Infof("Syncing %v (%v)", key, t.resource)
		if err := t.sync(key.(string)); err != nil {
			glog.Errorf("Requeuing %q due to error: %v (%v)", key, err, t.resource)
			t.queue.AddRateLimited(key)
		} else {
			glog.V(4).Infof("Finished syncing %v", key)
			t.queue.Forget(key)
		}
		t.queue.Done(key)
	}
}

// NewPeriodicTaskQueue creates a new task queue with the default rate limiter.
func NewPeriodicTaskQueue(resource string, syncFn func(string) error) *PeriodicTaskQueue {
	rl := workqueue.DefaultControllerRateLimiter()
	return NewPeriodicTaskQueueWithLimiter(resource, syncFn, rl)
}

// NewPeriodicTaskQueueWithLimiter creates a new task queue with the given sync function
// and rate limiter. The sync function is called for every element inserted into the queue.
func NewPeriodicTaskQueueWithLimiter(resource string, syncFn func(string) error, rl workqueue.RateLimiter) *PeriodicTaskQueue {
	return &PeriodicTaskQueue{
		resource:   resource,
		keyFunc:    KeyFunc,
		queue:      workqueue.NewRateLimitingQueue(rl),
		sync:       syncFn,
		workerDone: make(chan struct{}),
	}
}
<|endoftext|>


<commit_before>/*
Copyright The Helm Authors.

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

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

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

package version // import "k8s.io/helm/pkg/version"

import "k8s.io/helm/pkg/proto/hapi/version"

var (
	// Version is the current version of the Helm.
	// Update this whenever making a new release.
	// The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata]
	//
	// Increment major number for new feature additions and behavioral changes.
	// Increment minor number for bug fixes and performance enhancements.
	// Increment patch number for critical fixes to existing releases.
	Version = "v2.14"

	// BuildMetadata is extra build time data
	BuildMetadata = "unreleased"
	// GitCommit is the git sha1
	GitCommit = ""
	// GitTreeState is the state of the git tree
	GitTreeState = ""
)

// GetVersion returns the semver string of the version
func GetVersion() string {
	if BuildMetadata == "" {
		return Version
	}
	return Version + "+" + BuildMetadata
}

// GetVersionProto returns protobuf representing the version
func GetVersionProto() *version.Version {
	return &version.Version{
		SemVer:       GetVersion(),
		GitCommit:    GitCommit,
		GitTreeState: GitTreeState,
	}
}
<commit_msg>bump version to v2.15<commit_after>/*
Copyright The Helm Authors.

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

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

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

package version // import "k8s.io/helm/pkg/version"

import "k8s.io/helm/pkg/proto/hapi/version"

var (
	// Version is the current version of the Helm.
	// Update this whenever making a new release.
	// The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata]
	//
	// Increment major number for new feature additions and behavioral changes.
	// Increment minor number for bug fixes and performance enhancements.
	// Increment patch number for critical fixes to existing releases.
	Version = "v2.15"

	// BuildMetadata is extra build time data
	BuildMetadata = "unreleased"
	// GitCommit is the git sha1
	GitCommit = ""
	// GitTreeState is the state of the git tree
	GitTreeState = ""
)

// GetVersion returns the semver string of the version
func GetVersion() string {
	if BuildMetadata == "" {
		return Version
	}
	return Version + "+" + BuildMetadata
}

// GetVersionProto returns protobuf representing the version
func GetVersionProto() *version.Version {
	return &version.Version{
		SemVer:       GetVersion(),
		GitCommit:    GitCommit,
		GitTreeState: GitTreeState,
	}
}
<|endoftext|>


<commit_before>package ethdb

import (
	"time"

	"github.com/ethereum/go-ethereum/compression/rle"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/rcrowley/go-metrics"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/opt"
)

var OpenFileLimit = 64

type LDBDatabase struct {
	fn string      // filename for reporting
	db *leveldb.DB // LevelDB instance

	GetTimer   metrics.Timer // Timer for measuring the database get request counts and latencies
	PutTimer   metrics.Timer // Timer for measuring the database put request counts and latencies
	DelTimer   metrics.Timer // Timer for measuring the database delete request counts and latencies
	MissMeter  metrics.Meter // MEter for measuring the missed database get requests
	ReadMeter  metrics.Meter // Meter for measuring the database get request data usage
	WriteMeter metrics.Meter // Meter for measuring the database put request data usage
}

// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by
// it self but requires a background poller which syncs every X. `Flush` should be called
// when data needs to be stored and written to disk.
func NewLDBDatabase(file string) (*LDBDatabase, error) {
	// Open the db
	db, err := leveldb.OpenFile(file, &opt.Options{OpenFilesCacheCapacity: OpenFileLimit})
	// check for curruption and attempt to recover
	if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted {
		db, err = leveldb.RecoverFile(file, nil)
	}
	// (re) check for errors and abort if opening of the db failed
	if err != nil {
		return nil, err
	}
	database := &LDBDatabase{
		fn: file,
		db: db,
	}

	return database, nil
}

// Put puts the given key / value to the queue
func (self *LDBDatabase) Put(key []byte, value []byte) error {
	// Measure the database put latency, if requested
	if self.PutTimer != nil {
		start := time.Now()
		defer self.PutTimer.UpdateSince(start)
	}
	// Generate the data to write to disk, update the meter and write
	dat := rle.Compress(value)

	if self.WriteMeter != nil {
		self.WriteMeter.Mark(int64(len(dat)))
	}
	return self.db.Put(key, dat, nil)
}

// Get returns the given key if it's present.
func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
	// Measure the database get latency, if requested
	if self.GetTimer != nil {
		start := time.Now()
		defer self.GetTimer.UpdateSince(start)
	}
	// Retrieve the key and increment the miss counter if not found
	dat, err := self.db.Get(key, nil)
	if err != nil {
		if self.MissMeter != nil {
			self.MissMeter.Mark(1)
		}
		return nil, err
	}
	// Otherwise update the actually retrieved amount of data
	if self.ReadMeter != nil {
		self.ReadMeter.Mark(int64(len(dat)))
	}
	return rle.Decompress(dat)
}

// Delete deletes the key from the queue and database
func (self *LDBDatabase) Delete(key []byte) error {
	// Measure the database delete latency, if requested
	if self.DelTimer != nil {
		start := time.Now()
		defer self.DelTimer.UpdateSince(start)
	}
	// Execute the actual operation
	return self.db.Delete(key, nil)
}

func (self *LDBDatabase) NewIterator() iterator.Iterator {
	return self.db.NewIterator(nil, nil)
}

// Flush flushes out the queue to leveldb
func (self *LDBDatabase) Flush() error {
	return nil
}

func (self *LDBDatabase) Close() {
	if err := self.Flush(); err != nil {
		glog.V(logger.Error).Infof("error: flush '%s': %v\n", self.fn, err)
	}

	self.db.Close()
	glog.V(logger.Error).Infoln("flushed and closed db:", self.fn)
}
<commit_msg>ethdb: accessor for LDB. TODO remove this interface<commit_after>package ethdb

import (
	"time"

	"github.com/ethereum/go-ethereum/compression/rle"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/rcrowley/go-metrics"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/opt"
)

var OpenFileLimit = 64

type LDBDatabase struct {
	fn string      // filename for reporting
	db *leveldb.DB // LevelDB instance

	GetTimer   metrics.Timer // Timer for measuring the database get request counts and latencies
	PutTimer   metrics.Timer // Timer for measuring the database put request counts and latencies
	DelTimer   metrics.Timer // Timer for measuring the database delete request counts and latencies
	MissMeter  metrics.Meter // MEter for measuring the missed database get requests
	ReadMeter  metrics.Meter // Meter for measuring the database get request data usage
	WriteMeter metrics.Meter // Meter for measuring the database put request data usage
}

// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by
// it self but requires a background poller which syncs every X. `Flush` should be called
// when data needs to be stored and written to disk.
func NewLDBDatabase(file string) (*LDBDatabase, error) {
	// Open the db
	db, err := leveldb.OpenFile(file, &opt.Options{OpenFilesCacheCapacity: OpenFileLimit})
	// check for curruption and attempt to recover
	if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted {
		db, err = leveldb.RecoverFile(file, nil)
	}
	// (re) check for errors and abort if opening of the db failed
	if err != nil {
		return nil, err
	}
	database := &LDBDatabase{
		fn: file,
		db: db,
	}

	return database, nil
}

// Put puts the given key / value to the queue
func (self *LDBDatabase) Put(key []byte, value []byte) error {
	// Measure the database put latency, if requested
	if self.PutTimer != nil {
		start := time.Now()
		defer self.PutTimer.UpdateSince(start)
	}
	// Generate the data to write to disk, update the meter and write
	dat := rle.Compress(value)

	if self.WriteMeter != nil {
		self.WriteMeter.Mark(int64(len(dat)))
	}
	return self.db.Put(key, dat, nil)
}

// Get returns the given key if it's present.
func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
	// Measure the database get latency, if requested
	if self.GetTimer != nil {
		start := time.Now()
		defer self.GetTimer.UpdateSince(start)
	}
	// Retrieve the key and increment the miss counter if not found
	dat, err := self.db.Get(key, nil)
	if err != nil {
		if self.MissMeter != nil {
			self.MissMeter.Mark(1)
		}
		return nil, err
	}
	// Otherwise update the actually retrieved amount of data
	if self.ReadMeter != nil {
		self.ReadMeter.Mark(int64(len(dat)))
	}
	return rle.Decompress(dat)
}

// Delete deletes the key from the queue and database
func (self *LDBDatabase) Delete(key []byte) error {
	// Measure the database delete latency, if requested
	if self.DelTimer != nil {
		start := time.Now()
		defer self.DelTimer.UpdateSince(start)
	}
	// Execute the actual operation
	return self.db.Delete(key, nil)
}

func (self *LDBDatabase) NewIterator() iterator.Iterator {
	return self.db.NewIterator(nil, nil)
}

// Flush flushes out the queue to leveldb
func (self *LDBDatabase) Flush() error {
	return nil
}

func (self *LDBDatabase) Close() {
	if err := self.Flush(); err != nil {
		glog.V(logger.Error).Infof("error: flush '%s': %v\n", self.fn, err)
	}

	self.db.Close()
	glog.V(logger.Error).Infoln("flushed and closed db:", self.fn)
}

func (self *LDBDatabase) LDB() *leveldb.DB {
	return self.db
}
<|endoftext|>


<commit_before>package ethlog

import (
  "fmt"
  "sync"
  "log"
  "io"
  "os"
)

type LogSystem interface {
  GetLogLevel() LogLevel
  SetLogLevel(i LogLevel)
  Println(v ...interface{})
  Printf(format string, v ...interface{})
}

type logMessage struct {
  LogLevel  LogLevel
  format    bool
  msg       string
}

func newPrintlnLogMessage(level LogLevel, tag string, v...interface{}) *logMessage {
  return &logMessage{level, false, fmt.Sprintf("[%s] %s", tag, fmt.Sprint(v...))}
}

func newPrintfLogMessage(level LogLevel, tag string, format string, v...interface{}) *logMessage {
  return &logMessage{level, true, fmt.Sprintf("[%s] %s", tag, fmt.Sprintf(format, v...))}
}

func (msg *logMessage) send(logger LogSystem) {
  if msg.format {
    logger.Printf(msg.msg)
  } else {
    logger.Println(msg.msg)
  }
}

var logMessages chan(*logMessage)
var logSystems  []LogSystem
var drained = true

type LogLevel uint8

const (
  Silence LogLevel = iota
  ErrorLevel
  WarnLevel
  InfoLevel
  DebugLevel
)

// log messages are dispatched to log writers
func start() {
  for {
    select {
      case msg := <- logMessages:
        for _, logSystem := range logSystems {
          if logSystem.GetLogLevel() >= msg.LogLevel {
            msg.send(logSystem)
          }
        }
      default:
        drained = true
    }
  }
}

// waits until log messages are drained (dispatched to log writers)
func Flush() {
  for !drained {}
}

type Logger struct {
  tag string
}

func NewLogger(tag string) *Logger {
  return &Logger{tag}
}

func AddLogSystem(logSystem LogSystem) {
  var mutex = &sync.Mutex{}
  mutex.Lock()
  defer mutex.Unlock()
  if logSystems == nil {
    logMessages = make(chan *logMessage)
    go start()
  }
  logSystems = append(logSystems, logSystem)
}

func (logger *Logger) sendln(level LogLevel, v...interface{}) {
  if logMessages != nil {
    msg := newPrintlnLogMessage(level, logger.tag, v...)
    drained = false
    logMessages <- msg
  }
}

func (logger *Logger) sendf(level LogLevel, format string, v...interface{}) {
  if logMessages != nil {
    msg := newPrintfLogMessage(level, logger.tag, format, v...)
    drained = false
    logMessages <- msg
  }
}

func (logger *Logger) Errorln(v...interface{}) {
  logger.sendln(ErrorLevel, v...)
}

func (logger *Logger) Warnln(v...interface{}) {
  logger.sendln(WarnLevel, v...)
}

func (logger *Logger) Infoln(v...interface{}) {
  logger.sendln(InfoLevel, v...)
}

func (logger *Logger) Debugln(v...interface{}) {
  logger.sendln(DebugLevel, v...)
}

func (logger *Logger) Errorf(format string, v...interface{}) {
  logger.sendf(ErrorLevel, format, v...)
}

func (logger *Logger) Warnf(format string, v...interface{}) {
  logger.sendf(WarnLevel, format, v...)
}

func (logger *Logger) Infof(format string, v...interface{}) {
  logger.sendf(InfoLevel, format, v...)
}

func (logger *Logger) Debugf(format string, v...interface{}) {
  logger.sendf(DebugLevel, format, v...)
}

func (logger *Logger) Fatalln (v...interface{}) {
  logger.sendln(ErrorLevel, v...)
  Flush()
  os.Exit(0)
}

func (logger *Logger) Fatalf (format string, v...interface{}) {
  logger.sendf(ErrorLevel, format, v...)
  Flush()
  os.Exit(0)
}

type StdLogSystem struct {
  logger *log.Logger
  level LogLevel
}

func (t *StdLogSystem) Println(v ...interface{}) {
  t.logger.Println(v...)
}

func (t *StdLogSystem) Printf(format string, v ...interface{}) {
  t.logger.Printf(format, v...)
}

func (t *StdLogSystem) SetLogLevel(i LogLevel) {
  t.level = i
}

func (t *StdLogSystem) GetLogLevel() LogLevel {
  return t.level
}

func NewStdLogSystem(writer io.Writer, flags int, level LogLevel) *StdLogSystem {
  logger := log.New(writer, "", flags)
  return &StdLogSystem{logger, level}
}

<commit_msg>implement DebugDetail loglevel and named print methods<commit_after>package ethlog

import (
  "fmt"
  "sync"
  "log"
  "io"
  "os"
)

type LogSystem interface {
  GetLogLevel() LogLevel
  SetLogLevel(i LogLevel)
  Println(v ...interface{})
  Printf(format string, v ...interface{})
}

type logMessage struct {
  LogLevel  LogLevel
  format    bool
  msg       string
}

func newPrintlnLogMessage(level LogLevel, tag string, v...interface{}) *logMessage {
  return &logMessage{level, false, fmt.Sprintf("[%s] %s", tag, fmt.Sprint(v...))}
}

func newPrintfLogMessage(level LogLevel, tag string, format string, v...interface{}) *logMessage {
  return &logMessage{level, true, fmt.Sprintf("[%s] %s", tag, fmt.Sprintf(format, v...))}
}

func (msg *logMessage) send(logger LogSystem) {
  if msg.format {
    logger.Printf(msg.msg)
  } else {
    logger.Println(msg.msg)
  }
}

var logMessages chan(*logMessage)
var logSystems  []LogSystem
var drained = true

type LogLevel uint8

const (
  Silence LogLevel = iota
  ErrorLevel
  WarnLevel
  InfoLevel
  DebugLevel
  DebugDetailLevel
)

// log messages are dispatched to log writers
func start() {
  for {
    select {
      case msg := <- logMessages:
        for _, logSystem := range logSystems {
          if logSystem.GetLogLevel() >= msg.LogLevel {
            msg.send(logSystem)
          }
        }
      default:
        drained = true
    }
  }
}

// waits until log messages are drained (dispatched to log writers)
func Flush() {
  for !drained {}
}

type Logger struct {
  tag string
}

func NewLogger(tag string) *Logger {
  return &Logger{tag}
}

func AddLogSystem(logSystem LogSystem) {
  var mutex = &sync.Mutex{}
  mutex.Lock()
  defer mutex.Unlock()
  if logSystems == nil {
    logMessages = make(chan *logMessage)
    go start()
  }
  logSystems = append(logSystems, logSystem)
}

func (logger *Logger) sendln(level LogLevel, v...interface{}) {
  if logMessages != nil {
    msg := newPrintlnLogMessage(level, logger.tag, v...)
    drained = false
    logMessages <- msg
  }
}

func (logger *Logger) sendf(level LogLevel, format string, v...interface{}) {
  if logMessages != nil {
    msg := newPrintfLogMessage(level, logger.tag, format, v...)
    drained = false
    logMessages <- msg
  }
}

func (logger *Logger) Errorln(v...interface{}) {
  logger.sendln(ErrorLevel, v...)
}

func (logger *Logger) Warnln(v...interface{}) {
  logger.sendln(WarnLevel, v...)
}

func (logger *Logger) Infoln(v...interface{}) {
  logger.sendln(InfoLevel, v...)
}

func (logger *Logger) Debugln(v...interface{}) {
  logger.sendln(DebugLevel, v...)
}

func (logger *Logger) DebugDetailln(v...interface{}) {
  logger.sendln(DebugDetailLevel, v...)
}

func (logger *Logger) Errorf(format string, v...interface{}) {
  logger.sendf(ErrorLevel, format, v...)
}

func (logger *Logger) Warnf(format string, v...interface{}) {
  logger.sendf(WarnLevel, format, v...)
}

func (logger *Logger) Infof(format string, v...interface{}) {
  logger.sendf(InfoLevel, format, v...)
}

func (logger *Logger) Debugf(format string, v...interface{}) {
  logger.sendf(DebugLevel, format, v...)
}

func (logger *Logger) DebugDetailf(format string, v...interface{}) {
  logger.sendf(DebugDetailLevel, format, v...)
}

func (logger *Logger) Fatalln (v...interface{}) {
  logger.sendln(ErrorLevel, v...)
  Flush()
  os.Exit(0)
}

func (logger *Logger) Fatalf (format string, v...interface{}) {
  logger.sendf(ErrorLevel, format, v...)
  Flush()
  os.Exit(0)
}

type StdLogSystem struct {
  logger *log.Logger
  level LogLevel
}

func (t *StdLogSystem) Println(v ...interface{}) {
  t.logger.Println(v...)
}

func (t *StdLogSystem) Printf(format string, v ...interface{}) {
  t.logger.Printf(format, v...)
}

func (t *StdLogSystem) SetLogLevel(i LogLevel) {
  t.level = i
}

func (t *StdLogSystem) GetLogLevel() LogLevel {
  return t.level
}

func NewStdLogSystem(writer io.Writer, flags int, level LogLevel) *StdLogSystem {
  logger := log.New(writer, "", flags)
  return &StdLogSystem{logger, level}
}

<|endoftext|>


<commit_before>package ethutil

import (
	"flag"
	"fmt"
	"github.com/rakyll/globalconf"
	"os"
	"runtime"
)

// Config struct
type config struct {
	Db Database

	ExecPath     string
	Debug        bool
	Ver          string
	ClientString string
	Pubkey       []byte
	Identifier   string

	conf *globalconf.GlobalConf
}

var Config *config

// Read config
//
// Initialize Config from Config File
func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config {
	if Config == nil {
		// create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags
		_, err := os.Stat(ConfigFile)
		if err != nil && os.IsNotExist(err) {
			fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile)
			os.Create(ConfigFile)
		}
		g, err := globalconf.NewWithOptions(&globalconf.Options{
			Filename:  ConfigFile,
			EnvPrefix: EnvPrefix,
		})
		if err != nil {
			fmt.Println(err)
		} else {
			g.ParseAll()
		}
		Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier}
		Config.SetClientString("Ethereum(G)")
	}
	return Config
}

// Set client string
//
func (c *config) SetClientString(str string) {
	os := runtime.GOOS
	cust := c.Identifier
	Config.ClientString = fmt.Sprintf("%s/v%s/%s/%s/Go", str, c.Ver, cust, os)
}

func (c *config) SetIdentifier(id string) {
	c.Identifier = id
	c.Set("id", id)
}

// provides persistence for flags
func (c *config) Set(key, value string) {
	f := &flag.Flag{Name: key, Value: &confValue{value}}
	c.conf.Set("", f)
}

type confValue struct {
	value string
}

func (self confValue) String() string     { return self.value }
func (self confValue) Set(s string) error { self.value = s; return nil }
<commit_msg>bump v5.15<commit_after>package ethutil

import (
	"flag"
	"fmt"
	"github.com/rakyll/globalconf"
	"os"
	"runtime"
)

// Config struct
type config struct {
	Db Database

	ExecPath     string
	Debug        bool
	Ver          string
	ClientString string
	Pubkey       []byte
	Identifier   string

	conf *globalconf.GlobalConf
}

var Config *config

// Read config
//
// Initialize Config from Config File
func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config {
	if Config == nil {
		// create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags
		_, err := os.Stat(ConfigFile)
		if err != nil && os.IsNotExist(err) {
			fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile)
			os.Create(ConfigFile)
		}
		g, err := globalconf.NewWithOptions(&globalconf.Options{
			Filename:  ConfigFile,
			EnvPrefix: EnvPrefix,
		})
		if err != nil {
			fmt.Println(err)
		} else {
			g.ParseAll()
		}
		Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier}
		Config.SetClientString("Ethereum(G)")
	}
	return Config
}

// Set client string
//
func (c *config) SetClientString(str string) {
	os := runtime.GOOS
	cust := c.Identifier
	Config.ClientString = fmt.Sprintf("%s/v%s/%s/%s/Go", str, c.Ver, cust, os)
}

func (c *config) SetIdentifier(id string) {
	c.Identifier = id
	c.Set("id", id)
}

// provides persistence for flags
func (c *config) Set(key, value string) {
	f := &flag.Flag{Name: key, Value: &confValue{value}}
	c.conf.Set("", f)
}

type confValue struct {
	value string
}

func (self confValue) String() string     { return self.value }
func (self confValue) Set(s string) error { self.value = s; return nil }
<|endoftext|>