<commit_before>package server

import (
	"crypto/tls"
	"fmt"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/meatballhat/negroni-logrus"
	"github.com/ory/graceful"
	"github.com/ory/herodot"
	"github.com/ory/hydra/client"
	"github.com/ory/hydra/config"
	"github.com/ory/hydra/jwk"
	"github.com/ory/hydra/oauth2"
	"github.com/ory/hydra/pkg"
	"github.com/ory/hydra/policy"
	"github.com/ory/hydra/warden"
	"github.com/ory/hydra/warden/group"
	"github.com/ory/ladon"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/urfave/negroni"
)

func RunHost(c *config.Config) func(cmd *cobra.Command, args []string) {
	return func(cmd *cobra.Command, args []string) {
		router := httprouter.New()
		logger := c.GetLogger()
		serverHandler := &Handler{
			Config: c,
			H:      herodot.NewJSONWriter(logger),
		}
		serverHandler.registerRoutes(router)
		c.ForceHTTP, _ = cmd.Flags().GetBool("dangerous-force-http")

		if c.ClusterURL == "" {
			proto := "https"
			if c.ForceHTTP {
				proto = "http"
			}
			host := "localhost"
			if c.BindHost != "" {
				host = c.BindHost
			}
			c.ClusterURL = fmt.Sprintf("%s://%s:%d", proto, host, c.BindPort)
		}

		if ok, _ := cmd.Flags().GetBool("dangerous-auto-logon"); ok {
			logger.Warnln("Do not use flag --dangerous-auto-logon in production.")
			err := c.Persist()
			pkg.Must(err, "Could not write configuration file: %s", err)
		}

		n := negroni.New()
		n.Use(negronilogrus.NewMiddlewareFromLogger(logger, c.Issuer))
		n.UseFunc(serverHandler.rejectInsecureRequests)
		n.UseHandler(router)

		var srv = graceful.WithDefaults(&http.Server{
			Addr:    c.GetAddress(),
			Handler: n,
			TLSConfig: &tls.Config{
				Certificates: []tls.Certificate{getOrCreateTLSCertificate(cmd, c)},
			},
		})

		pkg.Must(graceful.Graceful(func() error {
			var err error
			logger.Infof("Setting up http server on %s", c.GetAddress())
			if c.ForceHTTP {
				logger.Warnln("HTTPS disabled. Never do this in production.")
				err = srv.ListenAndServe()
			} else if c.AllowTLSTermination != "" {
				logger.Infoln("TLS termination enabled, disabling https.")
				err = srv.ListenAndServe()
			} else {
				err = srv.ListenAndServeTLS("", "")
			}

			return err
		}, srv.Shutdown), "Could not gracefully run server")
	}
}

type Handler struct {
	Clients *client.Handler
	Keys    *jwk.Handler
	OAuth2  *oauth2.Handler
	Policy  *policy.Handler
	Groups  *group.Handler
	Warden  *warden.WardenHandler
	Config  *config.Config
	H       herodot.Writer
}

func (h *Handler) registerRoutes(router *httprouter.Router) {
	c := h.Config
	ctx := c.Context()

	// Set up dependencies
	injectJWKManager(c)
	clientsManager := newClientManager(c)
	injectFositeStore(c, clientsManager)
	oauth2Provider := newOAuth2Provider(c, ctx.KeyManager)

	// set up warden
	ctx.Warden = &warden.LocalWarden{
		Warden: &ladon.Ladon{
			Manager: ctx.LadonManager,
		},
		OAuth2:              oauth2Provider,
		Issuer:              c.Issuer,
		AccessTokenLifespan: c.GetAccessTokenLifespan(),
		Groups:              ctx.GroupManager,
		L:                   c.GetLogger(),
	}

	// Set up handlers
	h.Clients = newClientHandler(c, router, clientsManager)
	h.Keys = newJWKHandler(c, router)
	h.Policy = newPolicyHandler(c, router)
	h.OAuth2 = newOAuth2Handler(c, router, ctx.KeyManager, oauth2Provider)
	h.Warden = warden.NewHandler(c, router)
	h.Groups = &group.Handler{
		H:       herodot.NewJSONWriter(c.GetLogger()),
		W:       ctx.Warden,
		Manager: ctx.GroupManager,
	}
	h.Groups.SetRoutes(router)

	router.GET("/health", func(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		rw.WriteHeader(http.StatusNoContent)
	})

	// Create root account if new install
	createRS256KeysIfNotExist(c, oauth2.ConsentEndpointKey, "private", "sig")
	createRS256KeysIfNotExist(c, oauth2.ConsentChallengeKey, "private", "sig")

	h.createRootIfNewInstall(c)
}

func (h *Handler) rejectInsecureRequests(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.TLS != nil || h.Config.ForceHTTP {
		next.ServeHTTP(rw, r)
		return
	}

	if err := h.Config.DoesRequestSatisfyTermination(r); err == nil {
		next.ServeHTTP(rw, r)
		return
	} else {
		h.Config.GetLogger().WithError(err).Warnln("Could not serve http connection")
	}

	h.H.WriteErrorCode(rw, r, http.StatusBadGateway, errors.New("Can not serve request over insecure http"))
}
<commit_msg>cmd/server: resolve gorilla session mem leak - closes #461<commit_after>package server

import (
	"crypto/tls"
	"fmt"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/meatballhat/negroni-logrus"
	"github.com/ory/graceful"
	"github.com/ory/herodot"
	"github.com/ory/hydra/client"
	"github.com/ory/hydra/config"
	"github.com/ory/hydra/jwk"
	"github.com/ory/hydra/oauth2"
	"github.com/ory/hydra/pkg"
	"github.com/ory/hydra/policy"
	"github.com/ory/hydra/warden"
	"github.com/ory/hydra/warden/group"
	"github.com/ory/ladon"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/urfave/negroni"
	"github.com/gorilla/context"
)

func RunHost(c *config.Config) func(cmd *cobra.Command, args []string) {
	return func(cmd *cobra.Command, args []string) {
		router := httprouter.New()
		logger := c.GetLogger()
		serverHandler := &Handler{
			Config: c,
			H:      herodot.NewJSONWriter(logger),
		}
		serverHandler.registerRoutes(router)
		c.ForceHTTP, _ = cmd.Flags().GetBool("dangerous-force-http")

		if c.ClusterURL == "" {
			proto := "https"
			if c.ForceHTTP {
				proto = "http"
			}
			host := "localhost"
			if c.BindHost != "" {
				host = c.BindHost
			}
			c.ClusterURL = fmt.Sprintf("%s://%s:%d", proto, host, c.BindPort)
		}

		if ok, _ := cmd.Flags().GetBool("dangerous-auto-logon"); ok {
			logger.Warnln("Do not use flag --dangerous-auto-logon in production.")
			err := c.Persist()
			pkg.Must(err, "Could not write configuration file: %s", err)
		}

		n := negroni.New()
		n.Use(negronilogrus.NewMiddlewareFromLogger(logger, c.Issuer))
		n.UseFunc(serverHandler.rejectInsecureRequests)
		n.UseHandler(router)

		var srv = graceful.WithDefaults(&http.Server{
			Addr:    c.GetAddress(),
			Handler: context.ClearHandler(n),
			TLSConfig: &tls.Config{
				Certificates: []tls.Certificate{getOrCreateTLSCertificate(cmd, c)},
			},
		})

		pkg.Must(graceful.Graceful(func() error {
			var err error
			logger.Infof("Setting up http server on %s", c.GetAddress())
			if c.ForceHTTP {
				logger.Warnln("HTTPS disabled. Never do this in production.")
				err = srv.ListenAndServe()
			} else if c.AllowTLSTermination != "" {
				logger.Infoln("TLS termination enabled, disabling https.")
				err = srv.ListenAndServe()
			} else {
				err = srv.ListenAndServeTLS("", "")
			}

			return err
		}, srv.Shutdown), "Could not gracefully run server")
	}
}

type Handler struct {
	Clients *client.Handler
	Keys    *jwk.Handler
	OAuth2  *oauth2.Handler
	Policy  *policy.Handler
	Groups  *group.Handler
	Warden  *warden.WardenHandler
	Config  *config.Config
	H       herodot.Writer
}

func (h *Handler) registerRoutes(router *httprouter.Router) {
	c := h.Config
	ctx := c.Context()

	// Set up dependencies
	injectJWKManager(c)
	clientsManager := newClientManager(c)
	injectFositeStore(c, clientsManager)
	oauth2Provider := newOAuth2Provider(c, ctx.KeyManager)

	// set up warden
	ctx.Warden = &warden.LocalWarden{
		Warden: &ladon.Ladon{
			Manager: ctx.LadonManager,
		},
		OAuth2:              oauth2Provider,
		Issuer:              c.Issuer,
		AccessTokenLifespan: c.GetAccessTokenLifespan(),
		Groups:              ctx.GroupManager,
		L:                   c.GetLogger(),
	}

	// Set up handlers
	h.Clients = newClientHandler(c, router, clientsManager)
	h.Keys = newJWKHandler(c, router)
	h.Policy = newPolicyHandler(c, router)
	h.OAuth2 = newOAuth2Handler(c, router, ctx.KeyManager, oauth2Provider)
	h.Warden = warden.NewHandler(c, router)
	h.Groups = &group.Handler{
		H:       herodot.NewJSONWriter(c.GetLogger()),
		W:       ctx.Warden,
		Manager: ctx.GroupManager,
	}
	h.Groups.SetRoutes(router)

	router.GET("/health", func(rw http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		rw.WriteHeader(http.StatusNoContent)
	})

	// Create root account if new install
	createRS256KeysIfNotExist(c, oauth2.ConsentEndpointKey, "private", "sig")
	createRS256KeysIfNotExist(c, oauth2.ConsentChallengeKey, "private", "sig")

	h.createRootIfNewInstall(c)
}

func (h *Handler) rejectInsecureRequests(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.TLS != nil || h.Config.ForceHTTP {
		next.ServeHTTP(rw, r)
		return
	}

	if err := h.Config.DoesRequestSatisfyTermination(r); err == nil {
		next.ServeHTTP(rw, r)
		return
	} else {
		h.Config.GetLogger().WithError(err).Warnln("Could not serve http connection")
	}

	h.H.WriteErrorCode(rw, r, http.StatusBadGateway, errors.New("Can not serve request over insecure http"))
}
<|endoftext|>


<commit_before>package views

import (
	"bytes"
	"bufio"
	"fmt"
	"io"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/dchest/uniuri"
	"github.com/gin-gonic/gin"

	"github.com/Depado/goploader/server/conf"
	"github.com/Depado/goploader/server/logger"
	"github.com/Depado/goploader/server/models"
	"github.com/Depado/goploader/server/utils"
)

// Create handles the multipart form upload and creates a file
func Create(c *gin.Context) {
	var err error
	var duration time.Duration
	var once bool

	c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, conf.C.SizeLimit*utils.MegaByte)

	once = c.PostForm("once") != ""
	d := c.DefaultPostForm("duration", "1d")

	if val, ok := models.DurationMap[d]; ok {
		duration = val
	} else {
		logger.ErrC(c, "server", "Invalid duration", d)
		c.String(http.StatusBadRequest, "Invalid duration\n")
		c.AbortWithStatus(http.StatusBadRequest)
		return
	}

	fd, h, err := c.Request.FormFile("file")
	if err != nil {
		logger.ErrC(c, "server", "Couldn't read file", err)
		c.String(http.StatusRequestEntityTooLarge, "Entity is too large (Max : %v MB)\n", conf.C.SizeLimit)
		c.AbortWithStatus(http.StatusRequestEntityTooLarge)
		return
	}
	defer fd.Close()

	u := uniuri.NewLen(conf.C.UniURILength)
	file, err := os.Create(path.Join(conf.C.UploadDir, u))
	if err != nil {
		logger.ErrC(c, "server", "Couldn't create file", err)
		c.String(http.StatusInternalServerError, "Something went wrong on the server side. Try again later.")
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	defer file.Close()

	wr, err := io.Copy(file, bufio.NewReaderSize(fd, 512))
	if err != nil {
		logger.ErrC(c, "server", "Couldn't write file", err)
		c.String(http.StatusInternalServerError, "Something went wrong on the server side. Try again later.")
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	if conf.C.DiskQuota > 0 {
		if models.S.CurrentSize+uint64(wr) > uint64(conf.C.DiskQuota*utils.GigaByte) {
			logger.ErrC(c, "server", "Quota exceeded")
			c.String(http.StatusBadRequest, "Not enough free space. Try again later.")
			c.AbortWithStatus(http.StatusBadRequest)
			os.Remove(path.Join(conf.C.UploadDir, u))
			return
		}
	}
	newres := &models.Resource{
		Key:      u,
		Name:     h.Filename,
		Once:     once,
		DeleteAt: time.Now().Add(duration),
		Size:     wr,
	}
	if err = newres.Save(); err != nil {
		logger.ErrC(c, "server", "Couldn't save in database", err)
		c.String(http.StatusInternalServerError, "Something went wrong on the server. Try again later.")
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	newres.LogCreated(c)
	ns := conf.C.NameServer
	if conf.C.AppendPort {
		ns = fmt.Sprintf("%s:%d", conf.C.NameServer, conf.C.Port)
	}
	c.String(http.StatusCreated, "%v://%s/v/%s\n", utils.DetectScheme(c), ns, u)
}

// View handles the file views
func View(c *gin.Context) {
	var err error

	id := c.Param("uniuri")
	re := models.Resource{}

	if err = re.Get(id); err != nil || re.Key == "" {
		logger.InfoC(c, "server", "Not found", id)
		c.AbortWithStatus(http.StatusNotFound)
		return
	}
	re.LogFetched(c)
	f, err := os.Open(path.Join(conf.C.UploadDir, re.Key))
	if err != nil {
		logger.ErrC(c, "server", fmt.Sprintf("Couldn't open %s", re.Key), err)
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	if conf.C.AlwaysDownload {
		c.Header("Content-Type", "application/octet-stream")
		c.Header("Content-Disposition", "attachment; filename=\""+re.Name+"\"")
	} else {
		c.Header("Content-Disposition", "filename=\""+re.Name+"\"")
	}
	io.Copy(c.Writer, f)
	if re.Once {
		re.Delete()
		re.LogDeleted(c)
	}
}

// Head handles the head request for an encryptd file
func Head(c *gin.Context) {
	var err error

	id := c.Param("uniuri")
	re := models.Resource{}

	if err = re.Get(id); err != nil || re.Key == "" {
		logger.InfoC(c, "server", "Not found", id)
		c.AbortWithStatus(http.StatusNotFound)
		return
	}
	re.LogFetched(c)
	f, err := os.Open(path.Join(conf.C.UploadDir, re.Key))
	if err != nil {
		logger.ErrC(c, "server", fmt.Sprintf("Couldn't open %s", re.Key), err)
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	if conf.C.AlwaysDownload {
		c.Header("Content-Type", "application/octet-stream")
		c.Header("Content-Disposition", "attachment; filename=\""+re.Name+"\"")
	} else {
		c.Header("Content-Disposition", "filename=\""+re.Name+"\"")
	}
	io.Copy(c.Writer, f)
}

// ViewCode allows to see the file with syntax highliting and extra options
func ViewCode(c *gin.Context) {
	var err error

	id := c.Param("uniuri")
	lang := c.Param("lang")
	theme := c.DefaultQuery("theme", "dark")
	lines := c.Query("lines") == "true"
	re := models.Resource{}

	if err = re.Get(id); err != nil || re.Key == "" {
		logger.InfoC(c, "server", "Not found", id)
		c.AbortWithStatus(http.StatusNotFound)
		return
	}
	re.LogFetched(c)
	f, err := os.Open(path.Join(conf.C.UploadDir, re.Key))
	if err != nil {
		logger.ErrC(c, "server", fmt.Sprintf("Couldn't open %s", re.Key), err)
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	c.Header("Content-Disposition", "filename=\""+re.Name+"\"")
	buf := new(bytes.Buffer)
	buf.ReadFrom(f)
	bb := buf.Bytes()
	c.HTML(http.StatusOK, "code.tmpl", gin.H{
		"code":  string(bb),
		"lang":  lang,
		"theme": theme,
		"lines": lines,
		"name":  re.Name,
	})
	if re.Once {
		re.Delete()
		re.LogDeleted(c)
	}
}
<commit_msg>Add UnixDeleteAt for unencrypted uploads<commit_after>package views

import (
	"bytes"
	"bufio"
	"fmt"
	"io"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/dchest/uniuri"
	"github.com/gin-gonic/gin"

	"github.com/Depado/goploader/server/conf"
	"github.com/Depado/goploader/server/logger"
	"github.com/Depado/goploader/server/models"
	"github.com/Depado/goploader/server/utils"
)

// Create handles the multipart form upload and creates a file
func Create(c *gin.Context) {
	var err error
	var duration time.Duration
	var once bool

	c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, conf.C.SizeLimit*utils.MegaByte)

	once = c.PostForm("once") != ""
	d := c.DefaultPostForm("duration", "1d")

	if val, ok := models.DurationMap[d]; ok {
		duration = val
	} else {
		logger.ErrC(c, "server", "Invalid duration", d)
		c.String(http.StatusBadRequest, "Invalid duration\n")
		c.AbortWithStatus(http.StatusBadRequest)
		return
	}

	fd, h, err := c.Request.FormFile("file")
	if err != nil {
		logger.ErrC(c, "server", "Couldn't read file", err)
		c.String(http.StatusRequestEntityTooLarge, "Entity is too large (Max : %v MB)\n", conf.C.SizeLimit)
		c.AbortWithStatus(http.StatusRequestEntityTooLarge)
		return
	}
	defer fd.Close()

	u := uniuri.NewLen(conf.C.UniURILength)
	file, err := os.Create(path.Join(conf.C.UploadDir, u))
	if err != nil {
		logger.ErrC(c, "server", "Couldn't create file", err)
		c.String(http.StatusInternalServerError, "Something went wrong on the server side. Try again later.")
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	defer file.Close()

	wr, err := io.Copy(file, bufio.NewReaderSize(fd, 512))
	if err != nil {
		logger.ErrC(c, "server", "Couldn't write file", err)
		c.String(http.StatusInternalServerError, "Something went wrong on the server side. Try again later.")
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	if conf.C.DiskQuota > 0 {
		if models.S.CurrentSize+uint64(wr) > uint64(conf.C.DiskQuota*utils.GigaByte) {
			logger.ErrC(c, "server", "Quota exceeded")
			c.String(http.StatusBadRequest, "Not enough free space. Try again later.")
			c.AbortWithStatus(http.StatusBadRequest)
			os.Remove(path.Join(conf.C.UploadDir, u))
			return
		}
	}
	del := time.Now().Add(duration)
	newres := &models.Resource{
		Key:      u,
		Name:     h.Filename,
		Once:     once,
		DeleteAt: del,
		UnixDeleteAt: del.Unix(),
		Size:     wr,
	}
	if err = newres.Save(); err != nil {
		logger.ErrC(c, "server", "Couldn't save in database", err)
		c.String(http.StatusInternalServerError, "Something went wrong on the server. Try again later.")
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	newres.LogCreated(c)
	ns := conf.C.NameServer
	if conf.C.AppendPort {
		ns = fmt.Sprintf("%s:%d", conf.C.NameServer, conf.C.Port)
	}
	c.String(http.StatusCreated, "%v://%s/v/%s\n", utils.DetectScheme(c), ns, u)
}

// View handles the file views
func View(c *gin.Context) {
	var err error

	id := c.Param("uniuri")
	re := models.Resource{}

	if err = re.Get(id); err != nil || re.Key == "" {
		logger.InfoC(c, "server", "Not found", id)
		c.AbortWithStatus(http.StatusNotFound)
		return
	}
	re.LogFetched(c)
	f, err := os.Open(path.Join(conf.C.UploadDir, re.Key))
	if err != nil {
		logger.ErrC(c, "server", fmt.Sprintf("Couldn't open %s", re.Key), err)
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	if conf.C.AlwaysDownload {
		c.Header("Content-Type", "application/octet-stream")
		c.Header("Content-Disposition", "attachment; filename=\""+re.Name+"\"")
	} else {
		c.Header("Content-Disposition", "filename=\""+re.Name+"\"")
	}
	io.Copy(c.Writer, f)
	if re.Once {
		re.Delete()
		re.LogDeleted(c)
	}
}

// Head handles the head request for an encryptd file
func Head(c *gin.Context) {
	var err error

	id := c.Param("uniuri")
	re := models.Resource{}

	if err = re.Get(id); err != nil || re.Key == "" {
		logger.InfoC(c, "server", "Not found", id)
		c.AbortWithStatus(http.StatusNotFound)
		return
	}
	re.LogFetched(c)
	f, err := os.Open(path.Join(conf.C.UploadDir, re.Key))
	if err != nil {
		logger.ErrC(c, "server", fmt.Sprintf("Couldn't open %s", re.Key), err)
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	if conf.C.AlwaysDownload {
		c.Header("Content-Type", "application/octet-stream")
		c.Header("Content-Disposition", "attachment; filename=\""+re.Name+"\"")
	} else {
		c.Header("Content-Disposition", "filename=\""+re.Name+"\"")
	}
	io.Copy(c.Writer, f)
}

// ViewCode allows to see the file with syntax highliting and extra options
func ViewCode(c *gin.Context) {
	var err error

	id := c.Param("uniuri")
	lang := c.Param("lang")
	theme := c.DefaultQuery("theme", "dark")
	lines := c.Query("lines") == "true"
	re := models.Resource{}

	if err = re.Get(id); err != nil || re.Key == "" {
		logger.InfoC(c, "server", "Not found", id)
		c.AbortWithStatus(http.StatusNotFound)
		return
	}
	re.LogFetched(c)
	f, err := os.Open(path.Join(conf.C.UploadDir, re.Key))
	if err != nil {
		logger.ErrC(c, "server", fmt.Sprintf("Couldn't open %s", re.Key), err)
		c.AbortWithStatus(http.StatusInternalServerError)
		return
	}
	c.Header("Content-Disposition", "filename=\""+re.Name+"\"")
	buf := new(bytes.Buffer)
	buf.ReadFrom(f)
	bb := buf.Bytes()
	c.HTML(http.StatusOK, "code.tmpl", gin.H{
		"code":  string(bb),
		"lang":  lang,
		"theme": theme,
		"lines": lines,
		"name":  re.Name,
	})
	if re.Once {
		re.Delete()
		re.LogDeleted(c)
	}
}
<|endoftext|>


<commit_before>package apply

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/slinga/engine/diff"
	"github.com/Aptomi/aptomi/pkg/slinga/external"
	"github.com/Aptomi/aptomi/pkg/slinga/language"
	"github.com/Aptomi/aptomi/pkg/slinga/util"
	"math/rand"
	"strconv"
	"testing"
	"time"
)

func BenchmarkEngineSmall(b *testing.B) {
	t := &testing.T{}

	// small policy
	smallPolicy, smallExternalData := NewPolicyGenerator(
		239,
		30,
		50,
		6,
		6,
		4,
		2,
		100,
		500,
	).makePolicyAndExternalData()

	for i := 0; i < b.N; i++ {
		RunEngine(t, "small", smallPolicy, smallExternalData)
	}
}

func BenchmarkEngineMedium(b *testing.B) {
	t := &testing.T{}

	// medium policy
	mediumPolicy, mediumExternalData := NewPolicyGenerator(
		239,
		30,
		100,
		6,
		6,
		4,
		2,
		10000,
		2000,
	).makePolicyAndExternalData()

	for i := 0; i < b.N; i++ {
		RunEngine(t, "medium", mediumPolicy, mediumExternalData)
	}
}

type PolicyGenerator struct {
	random                    *rand.Rand
	labels                    int
	services                  int
	serviceCodeComponents     int
	codeParams                int
	serviceDependencyMaxChain int
	contextsPerContract       int
	users                     int
	dependencies              int

	generatedLabels    map[string]string
	generatedLabelKeys []string

	generatedServices []*language.Service
	policy            *language.Policy
	externalData      *external.Data
}

func NewPolicyGenerator(randSeed int64, labels, services, serviceCodeComponents, codeParams, serviceDependencyMaxChain, contextsPerContract, users, dependencies int) *PolicyGenerator {
	return &PolicyGenerator{
		random:                    rand.New(rand.NewSource(randSeed)),
		labels:                    labels,
		services:                  services,
		serviceCodeComponents:     serviceCodeComponents,
		codeParams:                codeParams,
		serviceDependencyMaxChain: serviceDependencyMaxChain,
		contextsPerContract:       contextsPerContract,
		users:                     users,
		dependencies:              dependencies,
		policy:                    language.NewPolicy(),
	}
}

func (gen *PolicyGenerator) makePolicyAndExternalData() (*language.Policy, *external.Data) {
	// pre-generate the list of labels
	gen.makeLabels()

	// generate services
	maxChainLen := gen.makeServices()

	// generate contracts
	gen.makeContracts()

	// generate dependencies
	gen.makeDependencies()

	// generate cluster
	gen.makeCluster()

	// every user will have the same set of labels
	gen.externalData = external.NewData(
		NewUserLoaderImpl(gen.users, gen.generatedLabels),
		NewSecretLoaderImpl(),
	)

	fmt.Printf("Generated policy. Services = %d (max chain %d), Contexts = %d, Dependencies = %d, Users = %d\n",
		len(gen.policy.Services),
		maxChainLen,
		len(gen.policy.Contracts)*gen.contextsPerContract,
		len(gen.policy.Dependencies.DependenciesByID),
		len(gen.externalData.UserLoader.LoadUsersAll().Users),
	)

	// there will be one context matching for each service. it will re-define some of those labels
	// there will be other contexts, not matching
	return gen.policy, gen.externalData
}

func (gen *PolicyGenerator) randomString(length int) string {
	charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, length)
	for i := range b {
		if i == 0 {
			// first letter non-numeric
			b[i] = charset[gen.random.Intn(len(charset)-10)]
		} else {
			// other letters any
			b[i] = charset[gen.random.Intn(len(charset))]
		}
	}
	return string(b)
}

func (gen *PolicyGenerator) makeLabels() {
	gen.generatedLabels = make(map[string]string)
	for i := 0; i < gen.labels; i++ {
		name := gen.randomString(10)
		value := gen.randomString(25)
		gen.generatedLabels[name] = value
	}

	gen.generatedLabelKeys = []string{}
	for key := range gen.generatedLabels {
		gen.generatedLabelKeys = append(gen.generatedLabelKeys, key)
	}
}

func (gen *PolicyGenerator) makeServices() int {
	gen.generatedServices = make([]*language.Service, gen.services)
	for i := 0; i < gen.services; i++ {
		gen.generatedServices[i] = gen.makeService()
	}

	// add some dependencies
	cnt := make([]int, gen.services)
	maxChainLen := 0
	for i := 0; i < gen.services; i++ {
		if maxChainLen < cnt[i] {
			maxChainLen = cnt[i]
		}

		// see if we have exceeded the max chain length
		if cnt[i]+1 > gen.serviceDependencyMaxChain {
			continue
		}

		// try to add at most one dependency from each service
		j := gen.random.Intn(gen.services)
		if j <= i {
			continue
		}

		if cnt[j] < cnt[i]+1 {
			cnt[j] = cnt[i] + 1
		}

		component := &language.ServiceComponent{
			Name:     "dep-" + strconv.Itoa(i),
			Contract: "contract-" + strconv.Itoa(j),
		}
		gen.generatedServices[i].Components = append(gen.generatedServices[i].Components, component)
	}
	return maxChainLen
}

func (gen *PolicyGenerator) makeService() *language.Service {
	id := len(gen.policy.Services)

	service := &language.Service{
		Metadata: language.Metadata{
			Kind:      language.ServiceObject.Kind,
			Namespace: "main",
			Name:      "service-" + strconv.Itoa(id),
		},
		Owner:      "user-" + strconv.Itoa(gen.random.Intn(gen.users)),
		Components: []*language.ServiceComponent{},
	}

	for i := 0; i < gen.serviceCodeComponents; i++ {
		labelName := gen.generatedLabelKeys[gen.random.Intn(len(gen.generatedLabelKeys))]

		params := util.NestedParameterMap{}
		params["cluster"] = "cluster-test"
		for j := 0; j < gen.codeParams; j++ {
			name := "param-" + strconv.Itoa(j)
			value := "prefix-{{ .Labels." + labelName + " }}-suffix"
			params[name] = value
		}

		component := &language.ServiceComponent{
			Name: "component-" + strconv.Itoa(i),
			Code: &language.Code{
				Type:   "aptomi/code/unittests",
				Params: params,
			},
		}
		service.Components = append(service.Components, component)
	}

	gen.policy.AddObject(service)
	return service
}

func (gen *PolicyGenerator) makeContracts() {
	for i := 0; i < gen.services; i++ {
		contract := &language.Contract{
			Metadata: language.Metadata{
				Kind:      language.ContractObject.Kind,
				Namespace: "main",
				Name:      "contract-" + strconv.Itoa(i),
			},
			Contexts: []*language.Context{},
		}

		// generate non-matching contexts
		for i := 0; i < gen.contextsPerContract-1; i++ {
			context := &language.Context{
				Name: "context-" + gen.randomString(20),
				Criteria: &language.Criteria{
					RequireAll: []string{"true"},
					RequireAny: []string{
						gen.randomString(20) + "=='" + gen.randomString(20) + "'",
						gen.randomString(20) + "=='" + gen.randomString(20) + "'",
						gen.randomString(20) + "=='" + gen.randomString(20) + "'",
					},
				},
				Allocation: &language.Allocation{
					Service: "service-" + strconv.Itoa(i),
				},
			}
			contract.Contexts = append(contract.Contexts, context)
		}

		// generate matching context
		context := &language.Context{
			Name: "context-" + gen.randomString(20),
			Criteria: &language.Criteria{
				RequireAll: []string{"true"},
			},
			Allocation: &language.Allocation{
				Service: "service-" + strconv.Itoa(i),
			},
		}
		contract.Contexts = append(contract.Contexts, context)

		// add service contract to the policy
		gen.policy.AddObject(contract)
	}
}

func (gen *PolicyGenerator) makeDependencies() {
	for i := 0; i < gen.dependencies; i++ {
		dependency := &language.Dependency{
			Metadata: language.Metadata{
				Kind:      language.DependencyObject.Kind,
				Namespace: "main",
				Name:      "dependency-" + strconv.Itoa(i),
			},
			UserID:   "user-" + strconv.Itoa(gen.random.Intn(gen.users)),
			Contract: "contract-" + strconv.Itoa(gen.random.Intn(gen.services)),
		}
		gen.policy.AddObject(dependency)
	}
}

func (gen *PolicyGenerator) makeCluster() {
	cluster := &language.Cluster{
		Metadata: language.Metadata{
			Kind:      language.ClusterObject.Kind,
			Namespace: "main",
			Name:      "cluster-test",
		},
	}
	gen.policy.AddObject(cluster)
}

type UserLoaderImpl struct {
	users  int
	labels map[string]string

	cachedUsers *language.GlobalUsers
}

func NewUserLoaderImpl(users int, labels map[string]string) *UserLoaderImpl {
	return &UserLoaderImpl{
		users:  users,
		labels: labels,
	}
}

func (loader *UserLoaderImpl) LoadUsersAll() language.GlobalUsers {
	if loader.cachedUsers == nil {
		userMap := make(map[string]*language.User)
		for i := 0; i < loader.users; i++ {
			user := &language.User{
				ID:     "user-" + strconv.Itoa(i),
				Name:   "user-" + strconv.Itoa(i),
				Labels: loader.labels,
			}
			userMap[user.ID] = user
		}
		loader.cachedUsers = &language.GlobalUsers{Users: userMap}
	}
	return *loader.cachedUsers
}

func (loader *UserLoaderImpl) LoadUserByID(id string) *language.User {
	return loader.LoadUsersAll().Users[id]
}

func (loader *UserLoaderImpl) Summary() string {
	return "Synthetic user loader"
}

type SecretLoaderImpl struct {
}

func NewSecretLoaderImpl() *SecretLoaderImpl {
	return &SecretLoaderImpl{}
}

func (loader *SecretLoaderImpl) LoadSecretsByUserID(string) map[string]string {
	return nil
}

func RunEngine(t *testing.T, testName string, desiredPolicy *language.Policy, externalData *external.Data) {
	fmt.Printf("Running engine for '%s'\n", testName)

	timeStart := time.Now()

	actualPolicy := language.NewPolicy()
	actualState := resolvePolicy(t, actualPolicy, externalData)
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// process all actions
	actions := diff.NewPolicyResolutionDiff(desiredState, actualState, 0).Actions

	applier := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		NewNoOpActionStateUpdater(),
		externalData,
		NewTestPluginRegistry("fail-components-like-these"),
		actions,
	)

	actualState = applyAndCheck(t, applier, ResSuccess, 0, "")

	timeEnd := time.Now()
	timeDiff := timeEnd.Sub(timeStart)

	fmt.Printf("[%s] Time = %s, Resolved dependencies = %d, Resolved Components = %d\n", testName, timeDiff.String(), len(desiredState.DependencyInstanceMap), len(actualState.ComponentInstanceMap))
}
<commit_msg>fixed benchmark by adding rules into it<commit_after>package apply

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/slinga/engine/diff"
	"github.com/Aptomi/aptomi/pkg/slinga/external"
	"github.com/Aptomi/aptomi/pkg/slinga/language"
	"github.com/Aptomi/aptomi/pkg/slinga/util"
	"math/rand"
	"strconv"
	"testing"
	"time"
)

func BenchmarkEngineSmall(b *testing.B) {
	t := &testing.T{}

	// small policy
	smallPolicy, smallExternalData := NewPolicyGenerator(
		239,
		30,
		50,
		6,
		6,
		4,
		2,
		25,
		100,
		500,
	).makePolicyAndExternalData()

	for i := 0; i < b.N; i++ {
		RunEngine(t, "small", smallPolicy, smallExternalData)
	}
}

func BenchmarkEngineMedium(b *testing.B) {
	t := &testing.T{}

	// medium policy
	mediumPolicy, mediumExternalData := NewPolicyGenerator(
		239,
		30,
		100,
		6,
		6,
		4,
		2,
		25,
		10000,
		2000,
	).makePolicyAndExternalData()

	for i := 0; i < b.N; i++ {
		RunEngine(t, "medium", mediumPolicy, mediumExternalData)
	}
}

type PolicyGenerator struct {
	random                    *rand.Rand
	labels                    int
	services                  int
	serviceCodeComponents     int
	codeParams                int
	serviceDependencyMaxChain int
	contextsPerContract       int
	rules                     int
	users                     int
	dependencies              int

	generatedLabels    map[string]string
	generatedLabelKeys []string

	generatedServices []*language.Service
	policy            *language.Policy
	externalData      *external.Data
}

func NewPolicyGenerator(randSeed int64, labels, services, serviceCodeComponents, codeParams, serviceDependencyMaxChain, contextsPerContract, rules, users, dependencies int) *PolicyGenerator {
	return &PolicyGenerator{
		random:                    rand.New(rand.NewSource(randSeed)),
		labels:                    labels,
		services:                  services,
		serviceCodeComponents:     serviceCodeComponents,
		codeParams:                codeParams,
		serviceDependencyMaxChain: serviceDependencyMaxChain,
		contextsPerContract:       contextsPerContract,
		rules:                     rules,
		users:                     users,
		dependencies:              dependencies,
		policy:                    language.NewPolicy(),
	}
}

func (gen *PolicyGenerator) makePolicyAndExternalData() (*language.Policy, *external.Data) {
	// pre-generate the list of labels
	gen.makeLabels()

	// generate services
	maxChainLen := gen.makeServices()

	// generate contracts
	gen.makeContracts()

	// generate rules
	gen.makeRules()

	// generate dependencies
	gen.makeDependencies()

	// generate cluster
	gen.makeCluster()

	// every user will have the same set of labels
	gen.externalData = external.NewData(
		NewUserLoaderImpl(gen.users, gen.generatedLabels),
		NewSecretLoaderImpl(),
	)

	fmt.Printf("Generated policy. Services = %d (max chain %d), Contexts = %d, Dependencies = %d, Users = %d\n",
		len(gen.policy.Services),
		maxChainLen,
		len(gen.policy.Contracts)*gen.contextsPerContract,
		len(gen.policy.Dependencies.DependenciesByID),
		len(gen.externalData.UserLoader.LoadUsersAll().Users),
	)

	// there will be one context matching for each service. it will re-define some of those labels
	// there will be other contexts, not matching
	return gen.policy, gen.externalData
}

func (gen *PolicyGenerator) randomString(length int) string {
	charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	b := make([]byte, length)
	for i := range b {
		if i == 0 {
			// first letter non-numeric
			b[i] = charset[gen.random.Intn(len(charset)-10)]
		} else {
			// other letters any
			b[i] = charset[gen.random.Intn(len(charset))]
		}
	}
	return string(b)
}

func (gen *PolicyGenerator) makeLabels() {
	gen.generatedLabels = make(map[string]string)
	for i := 0; i < gen.labels; i++ {
		name := gen.randomString(10)
		value := gen.randomString(25)
		gen.generatedLabels[name] = value
	}

	gen.generatedLabelKeys = []string{}
	for key := range gen.generatedLabels {
		gen.generatedLabelKeys = append(gen.generatedLabelKeys, key)
	}
}

func (gen *PolicyGenerator) makeServices() int {
	gen.generatedServices = make([]*language.Service, gen.services)
	for i := 0; i < gen.services; i++ {
		gen.generatedServices[i] = gen.makeService()
	}

	// add some dependencies
	cnt := make([]int, gen.services)
	maxChainLen := 0
	for i := 0; i < gen.services; i++ {
		if maxChainLen < cnt[i] {
			maxChainLen = cnt[i]
		}

		// see if we have exceeded the max chain length
		if cnt[i]+1 > gen.serviceDependencyMaxChain {
			continue
		}

		// try to add at most one dependency from each service
		j := gen.random.Intn(gen.services)
		if j <= i {
			continue
		}

		if cnt[j] < cnt[i]+1 {
			cnt[j] = cnt[i] + 1
		}

		component := &language.ServiceComponent{
			Name:     "dep-" + strconv.Itoa(i),
			Contract: "contract-" + strconv.Itoa(j),
		}
		gen.generatedServices[i].Components = append(gen.generatedServices[i].Components, component)
	}
	return maxChainLen
}

func (gen *PolicyGenerator) makeService() *language.Service {
	id := len(gen.policy.Services)

	service := &language.Service{
		Metadata: language.Metadata{
			Kind:      language.ServiceObject.Kind,
			Namespace: "main",
			Name:      "service-" + strconv.Itoa(id),
		},
		Owner:      "user-" + strconv.Itoa(gen.random.Intn(gen.users)),
		Components: []*language.ServiceComponent{},
	}

	for i := 0; i < gen.serviceCodeComponents; i++ {
		labelName := gen.generatedLabelKeys[gen.random.Intn(len(gen.generatedLabelKeys))]

		params := util.NestedParameterMap{}
		params["cluster"] = "cluster-test"
		for j := 0; j < gen.codeParams; j++ {
			name := "param-" + strconv.Itoa(j)
			value := "prefix-{{ .Labels." + labelName + " }}-suffix"
			params[name] = value
		}

		component := &language.ServiceComponent{
			Name: "component-" + strconv.Itoa(i),
			Code: &language.Code{
				Type:   "aptomi/code/unittests",
				Params: params,
			},
		}
		service.Components = append(service.Components, component)
	}

	gen.policy.AddObject(service)
	return service
}

func (gen *PolicyGenerator) makeRules() {
	// generate non-matching rules
	for i := 0; i < gen.rules-1; i++ {
		gen.policy.AddObject(&language.Rule{
			Metadata: language.Metadata{
				Kind:      language.RuleObject.Kind,
				Namespace: "main",
				Name:      "rule",
			},
			Weight: i,
			Criteria: &language.Criteria{
				RequireAll: []string{"service.Name == 'some-name-" + strconv.Itoa(i) + "'"},
			},
			Actions: &language.RuleActions{
				Dependency: language.DependencyAction("reject"),
			},
		})
	}

	// generate rule which allows all dependencies
	gen.policy.AddObject(&language.Rule{
		Metadata: language.Metadata{
			Kind:      language.RuleObject.Kind,
			Namespace: "main",
			Name:      "rule",
		},
		Weight: gen.rules,
		Criteria: &language.Criteria{
			RequireAll: []string{"true"},
		},
		Actions: &language.RuleActions{
			Dependency:   language.DependencyAction("allow"),
			ChangeLabels: language.ChangeLabelsAction(language.NewLabelOperationsSetSingleLabel("cluster", "cluster-test")),
		},
	})
}

func (gen *PolicyGenerator) makeContracts() {
	for i := 0; i < gen.services; i++ {
		contract := &language.Contract{
			Metadata: language.Metadata{
				Kind:      language.ContractObject.Kind,
				Namespace: "main",
				Name:      "contract-" + strconv.Itoa(i),
			},
			Contexts: []*language.Context{},
		}

		// generate non-matching contexts
		for i := 0; i < gen.contextsPerContract-1; i++ {
			context := &language.Context{
				Name: "context-" + gen.randomString(20),
				Criteria: &language.Criteria{
					RequireAll: []string{"true"},
					RequireAny: []string{
						gen.randomString(20) + "=='" + gen.randomString(20) + "'",
						gen.randomString(20) + "=='" + gen.randomString(20) + "'",
						gen.randomString(20) + "=='" + gen.randomString(20) + "'",
					},
				},
				Allocation: &language.Allocation{
					Service: "service-" + strconv.Itoa(i),
				},
			}
			contract.Contexts = append(contract.Contexts, context)
		}

		// generate matching context
		context := &language.Context{
			Name: "context-" + gen.randomString(20),
			Criteria: &language.Criteria{
				RequireAll: []string{"true"},
			},
			Allocation: &language.Allocation{
				Service: "service-" + strconv.Itoa(i),
			},
		}
		contract.Contexts = append(contract.Contexts, context)

		// add service contract to the policy
		gen.policy.AddObject(contract)
	}
}

func (gen *PolicyGenerator) makeDependencies() {
	for i := 0; i < gen.dependencies; i++ {
		dependency := &language.Dependency{
			Metadata: language.Metadata{
				Kind:      language.DependencyObject.Kind,
				Namespace: "main",
				Name:      "dependency-" + strconv.Itoa(i),
			},
			UserID:   "user-" + strconv.Itoa(gen.random.Intn(gen.users)),
			Contract: "contract-" + strconv.Itoa(gen.random.Intn(gen.services)),
		}
		gen.policy.AddObject(dependency)
	}
}

func (gen *PolicyGenerator) makeCluster() {
	cluster := &language.Cluster{
		Metadata: language.Metadata{
			Kind:      language.ClusterObject.Kind,
			Namespace: "main",
			Name:      "cluster-test",
		},
	}
	gen.policy.AddObject(cluster)
}

type UserLoaderImpl struct {
	users  int
	labels map[string]string

	cachedUsers *language.GlobalUsers
}

func NewUserLoaderImpl(users int, labels map[string]string) *UserLoaderImpl {
	return &UserLoaderImpl{
		users:  users,
		labels: labels,
	}
}

func (loader *UserLoaderImpl) LoadUsersAll() language.GlobalUsers {
	if loader.cachedUsers == nil {
		userMap := make(map[string]*language.User)
		for i := 0; i < loader.users; i++ {
			user := &language.User{
				ID:     "user-" + strconv.Itoa(i),
				Name:   "user-" + strconv.Itoa(i),
				Labels: loader.labels,
			}
			userMap[user.ID] = user
		}
		loader.cachedUsers = &language.GlobalUsers{Users: userMap}
	}
	return *loader.cachedUsers
}

func (loader *UserLoaderImpl) LoadUserByID(id string) *language.User {
	return loader.LoadUsersAll().Users[id]
}

func (loader *UserLoaderImpl) Summary() string {
	return "Synthetic user loader"
}

type SecretLoaderImpl struct {
}

func NewSecretLoaderImpl() *SecretLoaderImpl {
	return &SecretLoaderImpl{}
}

func (loader *SecretLoaderImpl) LoadSecretsByUserID(string) map[string]string {
	return nil
}

func RunEngine(t *testing.T, testName string, desiredPolicy *language.Policy, externalData *external.Data) {
	fmt.Printf("Running engine for '%s'\n", testName)

	timeStart := time.Now()

	actualPolicy := language.NewPolicy()
	actualState := resolvePolicy(t, actualPolicy, externalData)
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// process all actions
	actions := diff.NewPolicyResolutionDiff(desiredState, actualState, 0).Actions

	applier := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		NewNoOpActionStateUpdater(),
		externalData,
		NewTestPluginRegistry("fail-components-like-these"),
		actions,
	)

	actualState = applyAndCheck(t, applier, ResSuccess, 0, "")

	timeEnd := time.Now()
	timeDiff := timeEnd.Sub(timeStart)

	fmt.Printf("[%s] Time = %s, Resolved = dependencies %d, components %d\n", testName, timeDiff.String(), len(desiredState.DependencyInstanceMap), len(actualState.ComponentInstanceMap))

	if len(desiredState.DependencyInstanceMap) <= 0 {
		panic("No dependencies resolved")
	}
}
<|endoftext|>


<commit_before>// +build !providerless
// +build linux

/*
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 azure_dd

import (
	"fmt"
	"path/filepath"
	"strconv"
	libstrings "strings"

	"k8s.io/klog"
	utilexec "k8s.io/utils/exec"
)

// exclude those used by azure as resource and OS root in /dev/disk/azure
func listAzureDiskPath(io ioHandler) []string {
	azureDiskPath := "/dev/disk/azure/"
	var azureDiskList []string
	if dirs, err := io.ReadDir(azureDiskPath); err == nil {
		for _, f := range dirs {
			name := f.Name()
			diskPath := azureDiskPath + name
			if link, linkErr := io.Readlink(diskPath); linkErr == nil {
				sd := link[(libstrings.LastIndex(link, "/") + 1):]
				azureDiskList = append(azureDiskList, sd)
			}
		}
	}
	klog.V(12).Infof("Azure sys disks paths: %v", azureDiskList)
	return azureDiskList
}

// getDiskLinkByDevName get disk link by device name from devLinkPath, e.g. /dev/disk/azure/, /dev/disk/by-id/
func getDiskLinkByDevName(io ioHandler, devLinkPath, devName string) (string, error) {
	dirs, err := io.ReadDir(devLinkPath)
	klog.V(12).Infof("azureDisk - begin to find %s from %s", devName, devLinkPath)
	if err == nil {
		for _, f := range dirs {
			diskPath := devLinkPath + f.Name()
			klog.V(12).Infof("azureDisk - begin to Readlink: %s", diskPath)
			link, linkErr := io.Readlink(diskPath)
			if linkErr != nil {
				klog.Warningf("azureDisk - read link (%s) error: %v", diskPath, linkErr)
				continue
			}
			if libstrings.HasSuffix(link, devName) {
				return diskPath, nil
			}
		}
		return "", fmt.Errorf("device name(%s) is not found under %s", devName, devLinkPath)
	}
	return "", fmt.Errorf("read %s error: %v", devLinkPath, err)
}

func scsiHostRescan(io ioHandler, exec utilexec.Interface) {
	scsi_path := "/sys/class/scsi_host/"
	if dirs, err := io.ReadDir(scsi_path); err == nil {
		for _, f := range dirs {
			name := scsi_path + f.Name() + "/scan"
			data := []byte("- - -")
			if err = io.WriteFile(name, data, 0666); err != nil {
				klog.Warningf("failed to rescan scsi host %s", name)
			}
		}
	} else {
		klog.Warningf("failed to read %s, err %v", scsi_path, err)
	}
}

func findDiskByLun(lun int, io ioHandler, exec utilexec.Interface) (string, error) {
	azureDisks := listAzureDiskPath(io)
	return findDiskByLunWithConstraint(lun, io, azureDisks)
}

// finds a device mounted to "current" node
func findDiskByLunWithConstraint(lun int, io ioHandler, azureDisks []string) (string, error) {
	var err error
	sys_path := "/sys/bus/scsi/devices"
	if dirs, err := io.ReadDir(sys_path); err == nil {
		for _, f := range dirs {
			name := f.Name()
			// look for path like /sys/bus/scsi/devices/3:0:0:1
			arr := libstrings.Split(name, ":")
			if len(arr) < 4 {
				continue
			}
			if len(azureDisks) == 0 {
				klog.V(4).Infof("/dev/disk/azure is not populated, now try to parse %v directly", name)
				target, err := strconv.Atoi(arr[0])
				if err != nil {
					klog.Errorf("failed to parse target from %v (%v), err %v", arr[0], name, err)
					continue
				}
				// as observed, targets 0-3 are used by OS disks. Skip them
				if target <= 3 {
					continue
				}
			}

			// extract LUN from the path.
			// LUN is the last index of the array, i.e. 1 in /sys/bus/scsi/devices/3:0:0:1
			l, err := strconv.Atoi(arr[3])
			if err != nil {
				// unknown path format, continue to read the next one
				klog.V(4).Infof("azure disk - failed to parse lun from %v (%v), err %v", arr[3], name, err)
				continue
			}
			if lun == l {
				// find the matching LUN
				// read vendor and model to ensure it is a VHD disk
				vendorPath := filepath.Join(sys_path, name, "vendor")
				vendorBytes, err := io.ReadFile(vendorPath)
				if err != nil {
					klog.Errorf("failed to read device vendor, err: %v", err)
					continue
				}
				vendor := libstrings.TrimSpace(string(vendorBytes))
				if libstrings.ToUpper(vendor) != "MSFT" {
					klog.V(4).Infof("vendor doesn't match VHD, got %s", vendor)
					continue
				}

				modelPath := filepath.Join(sys_path, name, "model")
				modelBytes, err := io.ReadFile(modelPath)
				if err != nil {
					klog.Errorf("failed to read device model, err: %v", err)
					continue
				}
				model := libstrings.TrimSpace(string(modelBytes))
				if libstrings.ToUpper(model) != "VIRTUAL DISK" {
					klog.V(4).Infof("model doesn't match VIRTUAL DISK, got %s", model)
					continue
				}

				// find a disk, validate name
				dir := filepath.Join(sys_path, name, "block")
				if dev, err := io.ReadDir(dir); err == nil {
					found := false
					devName := dev[0].Name()
					for _, diskName := range azureDisks {
						klog.V(12).Infof("azureDisk - validating disk %q with sys disk %q", devName, diskName)
						if devName == diskName {
							found = true
							break
						}
					}
					if !found {
						devLinkPaths := []string{"/dev/disk/azure/scsi1/", "/dev/disk/by-id/"}
						for _, devLinkPath := range devLinkPaths {
							diskPath, err := getDiskLinkByDevName(io, devLinkPath, devName)
							if err == nil {
								klog.V(4).Infof("azureDisk - found %s by %s under %s", diskPath, devName, devLinkPath)
								return diskPath, nil
							}
							klog.Warningf("azureDisk - getDiskLinkByDevName by %s under %s failed, error: %v", devName, devLinkPath, err)
						}
						return "/dev/" + devName, nil
					}
				}
			}
		}
	}
	return "", err
}
<commit_msg>fix: azure disk could not mounted on Standard_DC4s/DC2s instances<commit_after>// +build !providerless
// +build linux

/*
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 azure_dd

import (
	"fmt"
	"path/filepath"
	"strconv"
	libstrings "strings"

	"k8s.io/klog"
	utilexec "k8s.io/utils/exec"
)

// exclude those used by azure as resource and OS root in /dev/disk/azure, /dev/disk/azure/scsi0
// "/dev/disk/azure/scsi0" dir is populated in Standard_DC4s/DC2s on Ubuntu 18.04
func listAzureDiskPath(io ioHandler) []string {
	var azureDiskList []string
	azureResourcePaths := []string{"/dev/disk/azure/", "/dev/disk/azure/scsi0/"}
	for _, azureDiskPath := range azureResourcePaths {
		if dirs, err := io.ReadDir(azureDiskPath); err == nil {
			for _, f := range dirs {
				name := f.Name()
				diskPath := filepath.Join(azureDiskPath, name)
				if link, linkErr := io.Readlink(diskPath); linkErr == nil {
					sd := link[(libstrings.LastIndex(link, "/") + 1):]
					azureDiskList = append(azureDiskList, sd)
				}
			}
		}
	}
	klog.V(12).Infof("Azure sys disks paths: %v", azureDiskList)
	return azureDiskList
}

// getDiskLinkByDevName get disk link by device name from devLinkPath, e.g. /dev/disk/azure/, /dev/disk/by-id/
func getDiskLinkByDevName(io ioHandler, devLinkPath, devName string) (string, error) {
	dirs, err := io.ReadDir(devLinkPath)
	klog.V(12).Infof("azureDisk - begin to find %s from %s", devName, devLinkPath)
	if err == nil {
		for _, f := range dirs {
			diskPath := devLinkPath + f.Name()
			klog.V(12).Infof("azureDisk - begin to Readlink: %s", diskPath)
			link, linkErr := io.Readlink(diskPath)
			if linkErr != nil {
				klog.Warningf("azureDisk - read link (%s) error: %v", diskPath, linkErr)
				continue
			}
			if libstrings.HasSuffix(link, devName) {
				return diskPath, nil
			}
		}
		return "", fmt.Errorf("device name(%s) is not found under %s", devName, devLinkPath)
	}
	return "", fmt.Errorf("read %s error: %v", devLinkPath, err)
}

func scsiHostRescan(io ioHandler, exec utilexec.Interface) {
	scsi_path := "/sys/class/scsi_host/"
	if dirs, err := io.ReadDir(scsi_path); err == nil {
		for _, f := range dirs {
			name := scsi_path + f.Name() + "/scan"
			data := []byte("- - -")
			if err = io.WriteFile(name, data, 0666); err != nil {
				klog.Warningf("failed to rescan scsi host %s", name)
			}
		}
	} else {
		klog.Warningf("failed to read %s, err %v", scsi_path, err)
	}
}

func findDiskByLun(lun int, io ioHandler, exec utilexec.Interface) (string, error) {
	azureDisks := listAzureDiskPath(io)
	return findDiskByLunWithConstraint(lun, io, azureDisks)
}

// finds a device mounted to "current" node
func findDiskByLunWithConstraint(lun int, io ioHandler, azureDisks []string) (string, error) {
	var err error
	sys_path := "/sys/bus/scsi/devices"
	if dirs, err := io.ReadDir(sys_path); err == nil {
		for _, f := range dirs {
			name := f.Name()
			// look for path like /sys/bus/scsi/devices/3:0:0:1
			arr := libstrings.Split(name, ":")
			if len(arr) < 4 {
				continue
			}
			if len(azureDisks) == 0 {
				klog.V(4).Infof("/dev/disk/azure is not populated, now try to parse %v directly", name)
				target, err := strconv.Atoi(arr[0])
				if err != nil {
					klog.Errorf("failed to parse target from %v (%v), err %v", arr[0], name, err)
					continue
				}
				// as observed, targets 0-3 are used by OS disks. Skip them
				if target <= 3 {
					continue
				}
			}

			// extract LUN from the path.
			// LUN is the last index of the array, i.e. 1 in /sys/bus/scsi/devices/3:0:0:1
			l, err := strconv.Atoi(arr[3])
			if err != nil {
				// unknown path format, continue to read the next one
				klog.V(4).Infof("azure disk - failed to parse lun from %v (%v), err %v", arr[3], name, err)
				continue
			}
			if lun == l {
				// find the matching LUN
				// read vendor and model to ensure it is a VHD disk
				vendorPath := filepath.Join(sys_path, name, "vendor")
				vendorBytes, err := io.ReadFile(vendorPath)
				if err != nil {
					klog.Errorf("failed to read device vendor, err: %v", err)
					continue
				}
				vendor := libstrings.TrimSpace(string(vendorBytes))
				if libstrings.ToUpper(vendor) != "MSFT" {
					klog.V(4).Infof("vendor doesn't match VHD, got %s", vendor)
					continue
				}

				modelPath := filepath.Join(sys_path, name, "model")
				modelBytes, err := io.ReadFile(modelPath)
				if err != nil {
					klog.Errorf("failed to read device model, err: %v", err)
					continue
				}
				model := libstrings.TrimSpace(string(modelBytes))
				if libstrings.ToUpper(model) != "VIRTUAL DISK" {
					klog.V(4).Infof("model doesn't match VIRTUAL DISK, got %s", model)
					continue
				}

				// find a disk, validate name
				dir := filepath.Join(sys_path, name, "block")
				if dev, err := io.ReadDir(dir); err == nil {
					found := false
					devName := dev[0].Name()
					for _, diskName := range azureDisks {
						klog.V(12).Infof("azureDisk - validating disk %q with sys disk %q", devName, diskName)
						if devName == diskName {
							found = true
							break
						}
					}
					if !found {
						devLinkPaths := []string{"/dev/disk/azure/scsi1/", "/dev/disk/by-id/"}
						for _, devLinkPath := range devLinkPaths {
							diskPath, err := getDiskLinkByDevName(io, devLinkPath, devName)
							if err == nil {
								klog.V(4).Infof("azureDisk - found %s by %s under %s", diskPath, devName, devLinkPath)
								return diskPath, nil
							}
							klog.Warningf("azureDisk - getDiskLinkByDevName by %s under %s failed, error: %v", devName, devLinkPath, err)
						}
						return "/dev/" + devName, nil
					}
				}
			}
		}
	}
	return "", err
}
<|endoftext|>


<commit_before>package create

const (
	decryptTLSAssetsScriptTemplate = `#!/bin/bash -e

rkt run \
	--volume=ssl,kind=host,source=/etc/kubernetes/ssl,readOnly=false \
	--mount=volume=ssl,target=/etc/kubernetes/ssl \
	--uuid-file-save=/var/run/coreos/decrypt-tls-assets.uuid \
	--volume=dns,kind=host,source=/etc/resolv.conf,readOnly=true --mount volume=dns,target=/etc/resolv.conf \
	--net=host \
	--trust-keys-from-https \
	quay.io/coreos/awscli:025a357f05242fdad6a81e8a6b520098aa65a600 --exec=/bin/bash -- \
		-ec \
		'echo decrypting tls assets
		shopt -s nullglob
		for encKey in $(find /etc/kubernetes/ssl -name "*.pem.enc"); do
			echo decrypting $encKey
			f=$(mktemp $encKey.XXXXXXXX)
			/usr/bin/aws \
				--region {{.AWS.Region}} kms decrypt \
				--ciphertext-blob fileb://$encKey \
				--output text \
				--query Plaintext \
			| base64 -d > $f
			mv -f $f ${encKey%.enc}
		done;
		echo done.'

rkt rm --uuid-file=/var/run/coreos/decrypt-tls-assets.uuid || :`

	decryptTLSAssetsServiceTemplate = `
[Unit]
Description=Decrypt TLS certificates

[Service]
Type=oneshot
ExecStart=/opt/bin/decrypt-tls-assets

[Install]
WantedBy=multi-user.target`

	userDataScriptTemplate = `#!/bin/bash

# user-data in EC2 instances has a 16KB limit.
# To circumvent this limit, we:
#
# 1. Upload the final cloudconfig to s3
# 2. Generate a "small cloudconfig" whose only task is fetching the
#    final cloudconfig from s3
# 3. Configure the instance to be able to access the s3 URI where the
#    final cloudconfig is stored
# 4. Start the instance with the "small cloudconfig"
#
# This file is the "small cloudconfig" mentioned before. Here we simply fetch a
# gzip+base64 file (the final cloudconfig) from AWS S3 and run coreos-cloudinit
# with it as an argument.

. /etc/environment
USERDATA_FILE={{.MachineType}}

/usr/bin/rkt run \
    --net=host \
    --volume=dns,kind=host,source=/etc/resolv.conf,readOnly=true --mount volume=dns,target=/etc/resolv.conf  \
    --volume=awsenv,kind=host,source=/var/run/coreos,readOnly=false --mount volume=awsenv,target=/var/run/coreos \
    --trust-keys-from-https \
    quay.io/coreos/awscli:025a357f05242fdad6a81e8a6b520098aa65a600 -- aws s3 --region {{.Region}} cp s3://{{.S3DirURI}}/$USERDATA_FILE /var/run/coreos/temp.txt
base64 -d /var/run/coreos/temp.txt | gunzip > /var/run/coreos/$USERDATA_FILE
exec /usr/bin/coreos-cloudinit --from-file /var/run/coreos/$USERDATA_FILE`
)
<commit_msg>templates: Chown /etc/kubernetes/ssl/etcd for etcd:etcd<commit_after>package create

const (
	decryptTLSAssetsScriptTemplate = `#!/bin/bash -e

rkt run \
	--volume=ssl,kind=host,source=/etc/kubernetes/ssl,readOnly=false \
	--mount=volume=ssl,target=/etc/kubernetes/ssl \
	--uuid-file-save=/var/run/coreos/decrypt-tls-assets.uuid \
	--volume=dns,kind=host,source=/etc/resolv.conf,readOnly=true --mount volume=dns,target=/etc/resolv.conf \
	--net=host \
	--trust-keys-from-https \
	quay.io/coreos/awscli:025a357f05242fdad6a81e8a6b520098aa65a600 --exec=/bin/bash -- \
		-ec \
		'echo decrypting tls assets
		shopt -s nullglob
		for encKey in $(find /etc/kubernetes/ssl -name "*.pem.enc"); do
			echo decrypting $encKey
			f=$(mktemp $encKey.XXXXXXXX)
			/usr/bin/aws \
				--region {{.AWS.Region}} kms decrypt \
				--ciphertext-blob fileb://$encKey \
				--output text \
				--query Plaintext \
			| base64 -d > $f
			mv -f $f ${encKey%.enc}
		done;
		echo done.'

rkt rm --uuid-file=/var/run/coreos/decrypt-tls-assets.uuid || :

chown -R etcd:etcd /etc/kubernetes/ssl/etcd`

	decryptTLSAssetsServiceTemplate = `
[Unit]
Description=Decrypt TLS certificates

[Service]
Type=oneshot
ExecStart=/opt/bin/decrypt-tls-assets

[Install]
WantedBy=multi-user.target`

	userDataScriptTemplate = `#!/bin/bash

# user-data in EC2 instances has a 16KB limit.
# To circumvent this limit, we:
#
# 1. Upload the final cloudconfig to s3
# 2. Generate a "small cloudconfig" whose only task is fetching the
#    final cloudconfig from s3
# 3. Configure the instance to be able to access the s3 URI where the
#    final cloudconfig is stored
# 4. Start the instance with the "small cloudconfig"
#
# This file is the "small cloudconfig" mentioned before. Here we simply fetch a
# gzip+base64 file (the final cloudconfig) from AWS S3 and run coreos-cloudinit
# with it as an argument.

. /etc/environment
USERDATA_FILE={{.MachineType}}

/usr/bin/rkt run \
    --net=host \
    --volume=dns,kind=host,source=/etc/resolv.conf,readOnly=true --mount volume=dns,target=/etc/resolv.conf  \
    --volume=awsenv,kind=host,source=/var/run/coreos,readOnly=false --mount volume=awsenv,target=/var/run/coreos \
    --trust-keys-from-https \
    quay.io/coreos/awscli:025a357f05242fdad6a81e8a6b520098aa65a600 -- aws s3 --region {{.Region}} cp s3://{{.S3DirURI}}/$USERDATA_FILE /var/run/coreos/temp.txt
base64 -d /var/run/coreos/temp.txt | gunzip > /var/run/coreos/$USERDATA_FILE
exec /usr/bin/coreos-cloudinit --from-file /var/run/coreos/$USERDATA_FILE`
)
<|endoftext|>


<commit_before>package httplog

import (

	"net/http"
)

func (httplogger *internalHttpLogger) setLogsInHttpHeaders(w http.ResponseWriter) {

	header := w.Header()

	for _, logMessage := range httplogger.logs {
		header.Set("X-Log", logMessage)
	}
}
<commit_msg>git doesnt seem to all multiple instances of the same HTTP heder in the response. so tweaked things so dont just do a "X-Log" header over and over again. but instead of "X-Log.1", "X-Log.2", ... etc.<commit_after>package httplog

import (
	"fmt"
	"net/http"
)

func (httplogger *internalHttpLogger) setLogsInHttpHeaders(w http.ResponseWriter) {

	header := w.Header()

	for i, logMessage := range httplogger.logs {
		headerName := fmt.Sprintf("X-Log.%d", 1+i)

		header.Set(headerName, logMessage)
	}
}
<|endoftext|>


<commit_before>package calc

import (
	"errors"
	"fmt"
	"io"
	"math"
	"sort"
	"strings"

	"github.com/ianremmler/clac"
)

var (
	cl     = clac.New()
	cmdMap = map[string]func() error{
		"neg":    cl.Neg,
		"abs":    cl.Abs,
		"inv":    cl.Inv,
		"+":      cl.Add,
		"-":      cl.Sub,
		"*":      cl.Mul,
		"/":      cl.Div,
		"mod":    cl.Mod,
		"exp":    cl.Exp,
		"^":      cl.Pow,
		"^2":     cl.Pow2,
		"^10":    cl.Pow10,
		"ln":     cl.Ln,
		"log":    cl.Log,
		"lg":     cl.Lg,
		"sqrt":   cl.Sqrt,
		"hypot":  cl.Hypot,
		"gamma":  cl.Gamma,
		"!":      cl.Factorial,
		"comb":   cl.Comb,
		"perm":   cl.Perm,
		"sin":    cl.Sin,
		"cos":    cl.Cos,
		"tan":    cl.Tan,
		"asin":   cl.Asin,
		"acos":   cl.Acos,
		"atan":   cl.Atan,
		"sinh":   cl.Sin,
		"cosh":   cl.Cos,
		"tanh":   cl.Tan,
		"asinh":  cl.Asin,
		"acosh":  cl.Acos,
		"atanh":  cl.Atan,
		"atan2":  cl.Atan2,
		"d->r":   cl.DegToRad,
		"r->d":   cl.RadToDeg,
		"floor":  cl.Floor,
		"r->p":   cl.RectToPolar,
		"p->r":   cl.PolarToRect,
		"ceil":   cl.Ceil,
		"trunc":  cl.Trunc,
		"and":    cl.And,
		"or":     cl.Or,
		"xor":    cl.Xor,
		"not":    cl.Not,
		"andn":   cl.Andn,
		"orn":    cl.Orn,
		"xorn":   cl.Xorn,
		"sum":    cl.Sum,
		"avg":    cl.Avg,
		"clear":  cl.Clear,
		"drop":   cl.Drop,
		"dropn":  cl.Dropn,
		"dropr":  cl.Dropr,
		"dup":    cl.Dup,
		"dupn":   cl.Dupn,
		"dupr":   cl.Dupr,
		"pick":   cl.Pick,
		"swap":   cl.Swap,
		"depth":  cl.Depth,
		"undo":   cl.Undo,
		"redo":   cl.Redo,
		"min":    cl.Min,
		"max":    cl.Max,
		"minn":   cl.Minn,
		"maxn":   cl.Maxn,
		"rot":    cl.Rot,
		"rotr":   cl.Rotr,
		"unrot":  cl.Unrot,
		"unrotr": cl.Unrotr,
		"pi":     func() error { return cl.Push(math.Pi) },
		"e":      func() error { return cl.Push(math.E) },
		"phi":    func() error { return cl.Push(math.Phi) },
	}
	helpStr string
)

func init() {
	cmdList := []string{"help"}
	for cmd := range cmdMap {
		cmdList = append(cmdList, cmd)
	}
	sort.Strings(cmdList)
	helpStr = strings.Join(cmdList, " ")
}

func Calc(input string, isPub bool) (string, error) {
	cl.Reset()
	cmdReader := strings.NewReader(input)
	for {
		tok := ""
		if _, err := fmt.Fscan(cmdReader, &tok); err != nil {
			if err != io.EOF {
				return "", err
			}
			break
		}
		if tok == "help" {
			if isPub {
				return "", errors.New("Shhh, that's private...")
			}
			return helpStr, nil
		}
		num, err := clac.ParseNum(tok)
		if err == nil {
			if err = cl.Exec(func() error { return cl.Push(num) }); err != nil {
				return "", errors.New("push: " + err.Error())
			}
			continue
		}
		if cmd, ok := cmdMap[tok]; ok {
			if err = cl.Exec(cmd); err != nil {
				return "", errors.New(tok + ": " + err.Error())
			}
			continue
		}
		return "", errors.New(tok + ": invalid input")
	}
	stack := cl.Stack()
	if len(stack) == 0 {
		return "", errors.New("empty stack")
	}
	ans := ""
	for i := range stack {
		val := stack[len(stack)-i-1]
		ans += fmt.Sprintf("%g", val)
		if math.Abs(val) < math.MaxInt64 {
			ans += fmt.Sprintf("(%#x)", int64(val))
		}
		if i < len(stack)-1 {
			ans += " "
		}
	}
	return ans, nil
}
<commit_msg>Update clac commands.<commit_after>package calc

import (
	"errors"
	"fmt"
	"io"
	"math"
	"sort"
	"strings"

	"github.com/ianremmler/clac"
)

var (
	cl     = clac.New()
	cmdMap = map[string]func() error{
		"neg":    cl.Neg,
		"abs":    cl.Abs,
		"inv":    cl.Inv,
		"+":      cl.Add,
		"-":      cl.Sub,
		"*":      cl.Mul,
		"/":      cl.Div,
		"mod":    cl.Mod,
		"exp":    cl.Exp,
		"^":      cl.Pow,
		"2^":     cl.Pow2,
		"10^":    cl.Pow10,
		"ln":     cl.Ln,
		"log":    cl.Log,
		"lg":     cl.Lg,
		"sqrt":   cl.Sqrt,
		"hypot":  cl.Hypot,
		"gamma":  cl.Gamma,
		"!":      cl.Factorial,
		"comb":   cl.Comb,
		"perm":   cl.Perm,
		"sin":    cl.Sin,
		"cos":    cl.Cos,
		"tan":    cl.Tan,
		"asin":   cl.Asin,
		"acos":   cl.Acos,
		"atan":   cl.Atan,
		"sinh":   cl.Sin,
		"cosh":   cl.Cos,
		"tanh":   cl.Tan,
		"asinh":  cl.Asin,
		"acosh":  cl.Acos,
		"atanh":  cl.Atan,
		"atan2":  cl.Atan2,
		"dtor":   cl.DegToRad,
		"rtod":   cl.RadToDeg,
		"floor":  cl.Floor,
		"rtop":   cl.RectToPolar,
		"ptor":   cl.PolarToRect,
		"ceil":   cl.Ceil,
		"trunc":  cl.Trunc,
		"and":    cl.And,
		"or":     cl.Or,
		"xor":    cl.Xor,
		"not":    cl.Not,
		"andn":   cl.AndN,
		"orn":    cl.OrN,
		"xorn":   cl.XorN,
		"sum":    cl.Sum,
		"avg":    cl.Avg,
		"dot":    cl.Dot,
		"dot3":   cl.Dot3,
		"cross":  cl.Cross,
		"mag":    cl.Mag,
		"clear":  cl.Clear,
		"drop":   cl.Drop,
		"dropn":  cl.DropN,
		"dropr":  cl.DropR,
		"dup":    cl.Dup,
		"dupn":   cl.DupN,
		"dupr":   cl.DupR,
		"pick":   cl.Pick,
		"swap":   cl.Swap,
		"depth":  cl.Depth,
		"undo":   cl.Undo,
		"redo":   cl.Redo,
		"min":    cl.Min,
		"max":    cl.Max,
		"minn":   cl.MinN,
		"maxn":   cl.MaxN,
		"rot":    cl.Rot,
		"rotr":   cl.RotR,
		"unrot":  cl.Unrot,
		"unrotr": cl.UnrotR,
		"pi":     func() error { return cl.Push(math.Pi) },
		"e":      func() error { return cl.Push(math.E) },
		"phi":    func() error { return cl.Push(math.Phi) },
	}
	helpStr string
)

func init() {
	cmdList := []string{"help"}
	for cmd := range cmdMap {
		cmdList = append(cmdList, cmd)
	}
	sort.Strings(cmdList)
	helpStr = strings.Join(cmdList, " ")
}

func Calc(input string, isPub bool) (string, error) {
	cl.Reset()
	cmdReader := strings.NewReader(input)
	for {
		tok := ""
		if _, err := fmt.Fscan(cmdReader, &tok); err != nil {
			if err != io.EOF {
				return "", err
			}
			break
		}
		if tok == "help" {
			if isPub {
				return "", errors.New("Shhh, that's private...")
			}
			return helpStr, nil
		}
		num, err := clac.ParseNum(tok)
		if err == nil {
			if err = cl.Exec(func() error { return cl.Push(num) }); err != nil {
				return "", errors.New("push: " + err.Error())
			}
			continue
		}
		if cmd, ok := cmdMap[tok]; ok {
			if err = cl.Exec(cmd); err != nil {
				return "", errors.New(tok + ": " + err.Error())
			}
			continue
		}
		return "", errors.New(tok + ": invalid input")
	}
	stack := cl.Stack()
	if len(stack) == 0 {
		return "", errors.New("empty stack")
	}
	ans := ""
	for i := range stack {
		val := stack[len(stack)-i-1]
		ans += fmt.Sprintf("%g", val)
		if math.Abs(val) < math.MaxInt64 {
			ans += fmt.Sprintf("(%#x)", int64(val))
		}
		if i < len(stack)-1 {
			ans += " "
		}
	}
	return ans, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"

	"github.com/hackebrot/turtle"
	"github.com/spf13/cobra"
)

func newKeywordCmd(w io.Writer) *cobra.Command {
	return &cobra.Command{
		Use:   "keyword",
		Short: "Print all emojis with the keyword",
		Long:  "Print all emojis with the keyword",
		RunE: func(cmd *cobra.Command, args []string) error {
			return runKeyword(w, args[0])
		},
		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) != 1 {
				return fmt.Errorf("require one keyword")
			}
			return nil
		},
	}
}

func runKeyword(w io.Writer, k string) error {

	emojis := turtle.Keyword(k)

	if emojis == nil {
		return fmt.Errorf("cannot find emojis for keyword %q", k)
	}

	j, err := NewJSONWriter(w, WithIndent(prefix, indent))

	if err != nil {
		return fmt.Errorf("error creating JSONWriter: %v", err)
	}

	return j.WriteEmojis(emojis)
}
<commit_msg>Update Use and Args for keyword cmd<commit_after>package main

import (
	"fmt"
	"io"

	"github.com/hackebrot/turtle"
	"github.com/spf13/cobra"
)

func newKeywordCmd(w io.Writer) *cobra.Command {
	return &cobra.Command{
		Use:   "keyword [KEYWORD]",
		Short: "Print all emojis with the keyword",
		Long:  "Print all emojis with the keyword",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return runKeyword(w, args[0])
		},
	}
}

func runKeyword(w io.Writer, k string) error {

	emojis := turtle.Keyword(k)

	if emojis == nil {
		return fmt.Errorf("cannot find emojis for keyword %q", k)
	}

	j, err := NewJSONWriter(w, WithIndent(prefix, indent))

	if err != nil {
		return fmt.Errorf("error creating JSONWriter: %v", err)
	}

	return j.WriteEmojis(emojis)
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
	vaultapi "github.com/hashicorp/vault/api"
	"github.com/spf13/cast"
)

type sanitizedEnviron []string

var sanitizeEnvmap = map[string]bool{
	"VAULT_TOKEN":           true,
	"VAULT_ADDR":            true,
	"VAULT_CACERT":          true,
	"VAULT_CAPATH":          true,
	"VAULT_CLIENT_CERT":     true,
	"VAULT_CLIENT_KEY":      true,
	"VAULT_CLIENT_TIMEOUT":  true,
	"VAULT_CLUSTER_ADDR":    true,
	"VAULT_MAX_RETRIES":     true,
	"VAULT_REDIRECT_ADDR":   true,
	"VAULT_SKIP_VERIFY":     true,
	"VAULT_TLS_SERVER_NAME": true,
	"VAULT_CLI_NO_COLOR":    true,
	"VAULT_RATE_LIMIT":      true,
	"VAULT_NAMESPACE":       true,
	"VAULT_MFA":             true,
	"VAULT_ROLE":            true,
	"VAULT_PATH":            true,
}

// Appends variable an entry (name=value) into the environ list.
// VAULT_* variables are not populated into this list.
func (environ *sanitizedEnviron) append(iname interface{}, ivalue interface{}) {
	name, value := iname.(string), ivalue.(string)
	if _, ok := sanitizeEnvmap[name]; !ok {
		*environ = append(*environ, fmt.Sprintf("%s=%s", name, value))
	}
}

func main() {

	role := os.Getenv("VAULT_ROLE")
	if role == "" {
		role = "default"
	}
	path := os.Getenv("VAULT_PATH")
	if path == "" {
		path = "kubernetes"
	}

	client, err := vault.NewClientWithConfig(vaultapi.DefaultConfig(), role, path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create vault client: %s\n", err.Error())
		os.Exit(1)
	}

	// initial and sanitized environs
	environ := syscall.Environ()
	sanitized := make(sanitizedEnviron, 0, len(environ))

	for _, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		var update bool
		if strings.HasPrefix(value, ">>") {
			value = strings.TrimPrefix(value, ">>")
			update = true
		} else {
			update = false
		}
		if strings.HasPrefix(value, "vault:") {
			path := strings.TrimPrefix(value, "vault:")
			split := strings.SplitN(path, "#", 3)
			path = split[0]

			var key string
			if len(split) > 1 {
				key = split[1]
			}

			version := "-1"
			if len(split) == 3 {
				version = split[2]
			}

			var secret *vaultapi.Secret
			var err error

			if update {
				var empty map[string]interface{}
				secret, err = client.Vault().Logical().Write(path, empty)
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to write secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			} else {
				secret, err = client.Vault().Logical().ReadWithData(path, map[string][]string{"version": {version}})
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to read secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			}

			if secret == nil {
				fmt.Fprintf(os.Stderr, "path not found: %s\n", path)
				os.Exit(1)
			} else {
				var data map[string]interface{}
				v2Data, ok := secret.Data["data"]

				if ok {
					data = cast.ToStringMap(v2Data)

					// Check if a given version of a path is destroyed
					metadata := secret.Data["metadata"].(map[string]interface{})
					if metadata["destroyed"].(bool) {
						fmt.Fprintf(os.Stderr, "Version %s of %s secret has been permanently destroyed\n", version, path)
					}

					// Check if a given version of a path still exists
					if metadata["deletion_time"].(string) != "" {
						fmt.Fprintf(os.Stderr, "Cannot find data for path: %s, given version (%s) has been deleted at %s\n", path, version, metadata["deletion_time"])
					}
				} else {
					data = cast.ToStringMap(secret.Data)
				}
				if value, ok := data[key]; ok {
					sanitized.append(name, value)
				} else {
					fmt.Fprintf(os.Stderr, "key not found: %s\n", key)
					os.Exit(1)
				}
			}
		} else {
			sanitized.append(name, value)
		}
	}

	if len(os.Args) == 1 {
		fmt.Fprintf(os.Stderr, "no command is given, currently vault-env can't determine the entrypoint (command), please specify it explicitly")
		os.Exit(1)
	} else {
		binary, err := exec.LookPath(os.Args[1])
		if err != nil {
			fmt.Fprintf(os.Stderr, "binary not found: %s\n", os.Args[1])
			os.Exit(1)
		}
		err = syscall.Exec(binary, os.Args[1:], sanitized)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to exec process '%s': %s\n", binary, err.Error())
			os.Exit(1)
		}
	}
}
<commit_msg>Fix deprecated client constructor usage<commit_after>// Copyright © 2018 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	vaultapi "github.com/hashicorp/vault/api"
	"github.com/spf13/cast"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
)

type sanitizedEnviron []string

var sanitizeEnvmap = map[string]bool{
	"VAULT_TOKEN":           true,
	"VAULT_ADDR":            true,
	"VAULT_CACERT":          true,
	"VAULT_CAPATH":          true,
	"VAULT_CLIENT_CERT":     true,
	"VAULT_CLIENT_KEY":      true,
	"VAULT_CLIENT_TIMEOUT":  true,
	"VAULT_CLUSTER_ADDR":    true,
	"VAULT_MAX_RETRIES":     true,
	"VAULT_REDIRECT_ADDR":   true,
	"VAULT_SKIP_VERIFY":     true,
	"VAULT_TLS_SERVER_NAME": true,
	"VAULT_CLI_NO_COLOR":    true,
	"VAULT_RATE_LIMIT":      true,
	"VAULT_NAMESPACE":       true,
	"VAULT_MFA":             true,
	"VAULT_ROLE":            true,
	"VAULT_PATH":            true,
}

// Appends variable an entry (name=value) into the environ list.
// VAULT_* variables are not populated into this list.
func (environ *sanitizedEnviron) append(iname interface{}, ivalue interface{}) {
	name, value := iname.(string), ivalue.(string)
	if _, ok := sanitizeEnvmap[name]; !ok {
		*environ = append(*environ, fmt.Sprintf("%s=%s", name, value))
	}
}

func main() {
	client, err := vault.NewClientWithOptions(
		vault.ClientRole(os.Getenv("VAULT_ROLE")),
		vault.ClientAuthPath(os.Getenv("VAULT_PATH")),
	)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create vault client: %s\n", err.Error())
		os.Exit(1)
	}

	// initial and sanitized environs
	environ := syscall.Environ()
	sanitized := make(sanitizedEnviron, 0, len(environ))

	for _, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		var update bool
		if strings.HasPrefix(value, ">>") {
			value = strings.TrimPrefix(value, ">>")
			update = true
		} else {
			update = false
		}
		if strings.HasPrefix(value, "vault:") {
			path := strings.TrimPrefix(value, "vault:")
			split := strings.SplitN(path, "#", 3)
			path = split[0]

			var key string
			if len(split) > 1 {
				key = split[1]
			}

			version := "-1"
			if len(split) == 3 {
				version = split[2]
			}

			var secret *vaultapi.Secret
			var err error

			if update {
				var empty map[string]interface{}
				secret, err = client.Vault().Logical().Write(path, empty)
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to write secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			} else {
				secret, err = client.Vault().Logical().ReadWithData(path, map[string][]string{"version": {version}})
				if err != nil {
					fmt.Fprintf(os.Stderr, "failed to read secret '%s': %s\n", path, err.Error())
					os.Exit(1)
				}
			}

			if secret == nil {
				fmt.Fprintf(os.Stderr, "path not found: %s\n", path)
				os.Exit(1)
			} else {
				var data map[string]interface{}
				v2Data, ok := secret.Data["data"]

				if ok {
					data = cast.ToStringMap(v2Data)

					// Check if a given version of a path is destroyed
					metadata := secret.Data["metadata"].(map[string]interface{})
					if metadata["destroyed"].(bool) {
						fmt.Fprintf(os.Stderr, "Version %s of %s secret has been permanently destroyed\n", version, path)
					}

					// Check if a given version of a path still exists
					if metadata["deletion_time"].(string) != "" {
						fmt.Fprintf(os.Stderr, "Cannot find data for path: %s, given version (%s) has been deleted at %s\n", path, version, metadata["deletion_time"])
					}
				} else {
					data = cast.ToStringMap(secret.Data)
				}
				if value, ok := data[key]; ok {
					sanitized.append(name, value)
				} else {
					fmt.Fprintf(os.Stderr, "key not found: %s\n", key)
					os.Exit(1)
				}
			}
		} else {
			sanitized.append(name, value)
		}
	}

	if len(os.Args) == 1 {
		fmt.Fprintf(os.Stderr, "no command is given, currently vault-env can't determine the entrypoint (command), please specify it explicitly")
		os.Exit(1)
	} else {
		binary, err := exec.LookPath(os.Args[1])
		if err != nil {
			fmt.Fprintf(os.Stderr, "binary not found: %s\n", os.Args[1])
			os.Exit(1)
		}
		err = syscall.Exec(binary, os.Args[1:], sanitized)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to exec process '%s': %s\n", binary, err.Error())
			os.Exit(1)
		}
	}
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
	vaultapi "github.com/hashicorp/vault/api"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cast"
)

type sanitizedEnviron []string

var sanitizeEnvmap = map[string]bool{
	"VAULT_TOKEN":                  true,
	"VAULT_ADDR":                   true,
	"VAULT_CACERT":                 true,
	"VAULT_CAPATH":                 true,
	"VAULT_CLIENT_CERT":            true,
	"VAULT_CLIENT_KEY":             true,
	"VAULT_CLIENT_TIMEOUT":         true,
	"VAULT_CLUSTER_ADDR":           true,
	"VAULT_MAX_RETRIES":            true,
	"VAULT_REDIRECT_ADDR":          true,
	"VAULT_SKIP_VERIFY":            true,
	"VAULT_TLS_SERVER_NAME":        true,
	"VAULT_CLI_NO_COLOR":           true,
	"VAULT_RATE_LIMIT":             true,
	"VAULT_NAMESPACE":              true,
	"VAULT_MFA":                    true,
	"VAULT_ROLE":                   true,
	"VAULT_PATH":                   true,
	"VAULT_IGNORE_MISSING_SECRETS": true,
	"VAULT_ENV_PASSTHROUGH":        true,
}

// Appends variable an entry (name=value) into the environ list.
// VAULT_* variables are not populated into this list.
func (environ *sanitizedEnviron) append(iname interface{}, ivalue interface{}) {
	name, value := iname.(string), ivalue.(string)
	if _, ok := sanitizeEnvmap[name]; !ok {
		*environ = append(*environ, fmt.Sprintf("%s=%s", name, value))
	}
}

func main() {
	ignoreMissingSecrets := os.Getenv("VAULT_IGNORE_MISSING_SECRETS") == "true"

	// The login procedure takes the token from a file (if using Vault Agent)
	// or requests one for itself (Kubernetes Auth), so if we got a VAULT_TOKEN
	// for the special value with "vault:login"
	originalVaultTokenEnvVar := os.Getenv("VAULT_TOKEN")
	if originalVaultTokenEnvVar != "" {
		os.Unsetenv("VAULT_TOKEN")
	}

	client, err := vault.NewClientWithOptions(
		vault.ClientRole(os.Getenv("VAULT_ROLE")),
		vault.ClientAuthPath(os.Getenv("VAULT_PATH")),
	)
	if err != nil {
		log.Fatal("failed to create vault client", err.Error())
	}

	passthroughEnvVars := strings.Split(os.Getenv("VAULT_ENV_PASSTHROUGH"), ",")

	if originalVaultTokenEnvVar != "" {
		os.Setenv("VAULT_TOKEN", originalVaultTokenEnvVar)
		if originalVaultTokenEnvVar == "vault:login" {
			passthroughEnvVars = append(passthroughEnvVars, "VAULT_TOKEN")
		}
	}

	// do not sanitize env vars specified in VAULT_ENV_PASSTHROUGH
	for _, envVar := range passthroughEnvVars {
		if trimmed := strings.TrimSpace(envVar); trimmed != "" {
			delete(sanitizeEnvmap, trimmed)
		}
	}

	// initial and sanitized environs
	environ := syscall.Environ()
	sanitized := make(sanitizedEnviron, 0, len(environ))

	for _, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		var update bool
		if strings.HasPrefix(value, ">>") {
			value = strings.TrimPrefix(value, ">>")
			update = true
		} else {
			update = false
		}
		if strings.HasPrefix(value, "vault:") {
			path := strings.TrimPrefix(value, "vault:")

			// handle special case for vault:login env value
			// namely pass through the the VAULT_TOKEN received from the Vault login procedure
			if name == "VAULT_TOKEN" && path == "login" {
				value = client.RawClient().Token()
				sanitized.append(name, value)
				continue
			}

			split := strings.SplitN(path, "#", 3)
			path = split[0]

			var key string
			if len(split) > 1 {
				key = split[1]
			}

			version := "-1"
			if len(split) == 3 {
				version = split[2]
			}

			var secret *vaultapi.Secret
			var err error

			if update {
				var empty map[string]interface{}
				secret, err = client.Vault().Logical().Write(path, empty)
				if err != nil {
					log.Fatalln("failed to write secret to path:", path, err.Error())
				}
			} else {
				secret, err = client.Vault().Logical().ReadWithData(path, map[string][]string{"version": {version}})
				if err != nil {
					if ignoreMissingSecrets {
						log.Errorln("failed to read secret from path:", path, err.Error())
					} else {
						log.Fatalln("failed to read secret from path:", path, err.Error())
					}
				}
			}

			if secret == nil {
				if ignoreMissingSecrets {
					log.Warnln("path not found:", path)
				} else {
					log.Fatalln("path not found:", path)
				}
			} else {
				var data map[string]interface{}
				v2Data, ok := secret.Data["data"]
				if ok {
					data = cast.ToStringMap(v2Data)

					// Check if a given version of a path is destroyed
					metadata := secret.Data["metadata"].(map[string]interface{})
					if metadata["destroyed"].(bool) {
						log.Warnln("version of secret has been permanently destroyed version:", version, "path:", path)
					}

					// Check if a given version of a path still exists
					if deletionTime, ok := metadata["deletion_time"].(string); ok && deletionTime != "" {
						log.Warnln("cannot find data for path, given version has been deleted",
							"path:", path, "version:", version,
							"deletion_time", deletionTime)
					}
				} else {
					data = cast.ToStringMap(secret.Data)
				}
				if value, ok := data[key]; ok {
					sanitized.append(name, value)
				} else {
					log.Fatalln("key not found:", key)
				}
			}
		} else {
			sanitized.append(name, value)
		}
	}

	var entrypointCmd []string
	if len(os.Args) == 1 {
		log.Fatalln("no command is given, vault-env can't determine the entrypoint (command), please specify it explicitly or let the webhook query it (see documentation)")
	} else {
		entrypointCmd = os.Args[1:]
	}
	binary, err := exec.LookPath(entrypointCmd[0])
	if err != nil {
		log.Fatalln("binary not found", entrypointCmd[0])
	}
	err = syscall.Exec(binary, entrypointCmd, sanitized)
	if err != nil {
		log.Fatalln("failed to exec process", binary, entrypointCmd, err.Error())
	}
}
<commit_msg>vault-env: unset VAULT_TOKEN in case of login only<commit_after>// Copyright © 2018 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
	vaultapi "github.com/hashicorp/vault/api"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cast"
)

// The special value for VAULT_ENV which marks that the login token needs to be passed through to the application
// which was acquired during the new Vault client creation
const vaultLogin = "vault:login"

type sanitizedEnviron []string

var sanitizeEnvmap = map[string]bool{
	"VAULT_TOKEN":                  true,
	"VAULT_ADDR":                   true,
	"VAULT_CACERT":                 true,
	"VAULT_CAPATH":                 true,
	"VAULT_CLIENT_CERT":            true,
	"VAULT_CLIENT_KEY":             true,
	"VAULT_CLIENT_TIMEOUT":         true,
	"VAULT_CLUSTER_ADDR":           true,
	"VAULT_MAX_RETRIES":            true,
	"VAULT_REDIRECT_ADDR":          true,
	"VAULT_SKIP_VERIFY":            true,
	"VAULT_TLS_SERVER_NAME":        true,
	"VAULT_CLI_NO_COLOR":           true,
	"VAULT_RATE_LIMIT":             true,
	"VAULT_NAMESPACE":              true,
	"VAULT_MFA":                    true,
	"VAULT_ROLE":                   true,
	"VAULT_PATH":                   true,
	"VAULT_IGNORE_MISSING_SECRETS": true,
	"VAULT_ENV_PASSTHROUGH":        true,
}

// Appends variable an entry (name=value) into the environ list.
// VAULT_* variables are not populated into this list.
func (environ *sanitizedEnviron) append(iname interface{}, ivalue interface{}) {
	name, value := iname.(string), ivalue.(string)
	if _, ok := sanitizeEnvmap[name]; !ok {
		*environ = append(*environ, fmt.Sprintf("%s=%s", name, value))
	}
}

func main() {
	ignoreMissingSecrets := os.Getenv("VAULT_IGNORE_MISSING_SECRETS") == "true"

	// The login procedure takes the token from a file (if using Vault Agent)
	// or requests one for itself (Kubernetes Auth), so if we got a VAULT_TOKEN
	// for the special value with "vault:login"
	originalVaultTokenEnvVar := os.Getenv("VAULT_TOKEN")
	if originalVaultTokenEnvVar == vaultLogin {
		os.Unsetenv("VAULT_TOKEN")
	}

	client, err := vault.NewClientWithOptions(
		vault.ClientRole(os.Getenv("VAULT_ROLE")),
		vault.ClientAuthPath(os.Getenv("VAULT_PATH")),
	)
	if err != nil {
		log.Fatal("failed to create vault client", err.Error())
	}

	passthroughEnvVars := strings.Split(os.Getenv("VAULT_ENV_PASSTHROUGH"), ",")

	if originalVaultTokenEnvVar == vaultLogin {
		os.Setenv("VAULT_TOKEN", vaultLogin)
		passthroughEnvVars = append(passthroughEnvVars, "VAULT_TOKEN")
	}

	// do not sanitize env vars specified in VAULT_ENV_PASSTHROUGH
	for _, envVar := range passthroughEnvVars {
		if trimmed := strings.TrimSpace(envVar); trimmed != "" {
			delete(sanitizeEnvmap, trimmed)
		}
	}

	// initial and sanitized environs
	environ := syscall.Environ()
	sanitized := make(sanitizedEnviron, 0, len(environ))

	for _, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		var update bool
		if strings.HasPrefix(value, ">>") {
			value = strings.TrimPrefix(value, ">>")
			update = true
		} else {
			update = false
		}
		if strings.HasPrefix(value, "vault:") {
			path := strings.TrimPrefix(value, "vault:")

			// handle special case for vault:login env value
			// namely pass through the the VAULT_TOKEN received from the Vault login procedure
			if name == "VAULT_TOKEN" && path == "login" {
				value = client.RawClient().Token()
				sanitized.append(name, value)
				continue
			}

			split := strings.SplitN(path, "#", 3)
			path = split[0]

			var key string
			if len(split) > 1 {
				key = split[1]
			}

			version := "-1"
			if len(split) == 3 {
				version = split[2]
			}

			var secret *vaultapi.Secret
			var err error

			if update {
				var empty map[string]interface{}
				secret, err = client.Vault().Logical().Write(path, empty)
				if err != nil {
					log.Fatalln("failed to write secret to path:", path, err.Error())
				}
			} else {
				secret, err = client.Vault().Logical().ReadWithData(path, map[string][]string{"version": {version}})
				if err != nil {
					if ignoreMissingSecrets {
						log.Errorln("failed to read secret from path:", path, err.Error())
					} else {
						log.Fatalln("failed to read secret from path:", path, err.Error())
					}
				}
			}

			if secret == nil {
				if ignoreMissingSecrets {
					log.Warnln("path not found:", path)
				} else {
					log.Fatalln("path not found:", path)
				}
			} else {
				var data map[string]interface{}
				v2Data, ok := secret.Data["data"]
				if ok {
					data = cast.ToStringMap(v2Data)

					// Check if a given version of a path is destroyed
					metadata := secret.Data["metadata"].(map[string]interface{})
					if metadata["destroyed"].(bool) {
						log.Warnln("version of secret has been permanently destroyed version:", version, "path:", path)
					}

					// Check if a given version of a path still exists
					if deletionTime, ok := metadata["deletion_time"].(string); ok && deletionTime != "" {
						log.Warnln("cannot find data for path, given version has been deleted",
							"path:", path, "version:", version,
							"deletion_time", deletionTime)
					}
				} else {
					data = cast.ToStringMap(secret.Data)
				}
				if value, ok := data[key]; ok {
					sanitized.append(name, value)
				} else {
					log.Fatalln("key not found:", key)
				}
			}
		} else {
			sanitized.append(name, value)
		}
	}

	var entrypointCmd []string
	if len(os.Args) == 1 {
		log.Fatalln("no command is given, vault-env can't determine the entrypoint (command), please specify it explicitly or let the webhook query it (see documentation)")
	} else {
		entrypointCmd = os.Args[1:]
	}
	binary, err := exec.LookPath(entrypointCmd[0])
	if err != nil {
		log.Fatalln("binary not found", entrypointCmd[0])
	}
	err = syscall.Exec(binary, entrypointCmd, sanitized)
	if err != nil {
		log.Fatalln("failed to exec process", binary, entrypointCmd, err.Error())
	}
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
	vaultapi "github.com/hashicorp/vault/api"
	"github.com/spf13/cast"
)

func main() {

	role := os.Getenv("VAULT_ROLE")
	if role == "" {
		role = "default"
	}
	path := os.Getenv("VAULT_PATH")
	if path == "" {
		path = "kubernetes"
	}

	client, err := vault.NewClientWithConfig(vaultapi.DefaultConfig(), role, path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create vault client: %s\n", err.Error())
		os.Exit(1)
	}

	environ := syscall.Environ()

	for i, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		if strings.HasPrefix(value, "vault:") {

			path := strings.TrimPrefix(value, "vault:")
			split := strings.SplitN(path, "#", 2)
			path = split[0]

			var key string
			if len(split) > 0 {
				key = split[1]
			}

			secret, err := client.Vault().Logical().Read(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "failed to read secret '%s': %s\n", path, err.Error())
				os.Exit(1)
			}

			if secret == nil {
				fmt.Fprintf(os.Stderr, "path not found: %s\n", path)
				os.Exit(1)
			} else {
				data := cast.ToStringMap(secret.Data["data"])
				if value, ok := data[key]; ok {
					environ[i] = fmt.Sprintf("%s=%s", name, value)
				} else {
					fmt.Fprintf(os.Stderr, "key not found: %s\n", key)
					os.Exit(1)
				}
			}
		}
	}

	if len(os.Args) == 1 {
		fmt.Fprintf(os.Stderr, "no command is given, currently vault-env can't determine the entrypoint (command), please specify it explicitly")
		os.Exit(1)
	} else {
		binary, err := exec.LookPath(os.Args[1])
		if err != nil {
			fmt.Fprintf(os.Stderr, "binary not found: %s\n", os.Args[1])
			os.Exit(1)
		}
		err = syscall.Exec(binary, os.Args[1:], environ)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to exec process '%s': %s\n", binary, err.Error())
			os.Exit(1)
		}
	}
}
<commit_msg>Remove unnecessary data property.<commit_after>// Copyright © 2018 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/banzaicloud/bank-vaults/pkg/vault"
	vaultapi "github.com/hashicorp/vault/api"
	"github.com/spf13/cast"
)

func main() {

	role := os.Getenv("VAULT_ROLE")
	if role == "" {
		role = "default"
	}
	path := os.Getenv("VAULT_PATH")
	if path == "" {
		path = "kubernetes"
	}

	client, err := vault.NewClientWithConfig(vaultapi.DefaultConfig(), role, path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create vault client: %s\n", err.Error())
		os.Exit(1)
	}

	environ := syscall.Environ()

	for i, env := range environ {
		split := strings.SplitN(env, "=", 2)
		name := split[0]
		value := split[1]
		if strings.HasPrefix(value, "vault:") {

			path := strings.TrimPrefix(value, "vault:")
			split := strings.SplitN(path, "#", 2)
			path = split[0]

			var key string
			if len(split) > 0 {
				key = split[1]
			}

			secret, err := client.Vault().Logical().Read(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "failed to read secret '%s': %s\n", path, err.Error())
				os.Exit(1)
			}

			if secret == nil {
				fmt.Fprintf(os.Stderr, "path not found: %s\n", path)
				os.Exit(1)
			} else {
				data := cast.ToStringMap(secret.Data)
				if value, ok := data[key]; ok {
					environ[i] = fmt.Sprintf("%s=%s", name, value)
				} else {
					fmt.Fprintf(os.Stderr, "key not found: %s\n", key)
					os.Exit(1)
				}
			}
		}
	}

	if len(os.Args) == 1 {
		fmt.Fprintf(os.Stderr, "no command is given, currently vault-env can't determine the entrypoint (command), please specify it explicitly")
		os.Exit(1)
	} else {
		binary, err := exec.LookPath(os.Args[1])
		if err != nil {
			fmt.Fprintf(os.Stderr, "binary not found: %s\n", os.Args[1])
			os.Exit(1)
		}
		err = syscall.Exec(binary, os.Args[1:], environ)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to exec process '%s': %s\n", binary, err.Error())
			os.Exit(1)
		}
	}
}
<|endoftext|>