<commit_before>/*
Copyright 2013 CoreOS Inc.

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 kontrol

import (
	"net"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/coreos/etcd/third_party/github.com/coreos/raft"

	"github.com/coreos/etcd/config"
	ehttp "github.com/coreos/etcd/http"
	elog "github.com/coreos/etcd/log"
	"github.com/coreos/etcd/metrics"
	"github.com/coreos/etcd/server"
	"github.com/coreos/etcd/store"
)

func runEtcd(ready chan bool) {
	// Load configuration.
	var config = config.New()

	// Disable command line argument parsing for etcd
	//
	// if err := config.Load(os.Args[1:]); err != nil {
	// 	fmt.Println(server.Usage() + "\n")
	// 	fmt.Println(err.Error() + "\n")
	// 	os.Exit(1)
	// } else if config.ShowVersion {
	// 	fmt.Println(server.ReleaseVersion)
	// 	os.Exit(0)
	// } else if config.ShowHelp {
	// 	fmt.Println(server.Usage() + "\n")
	// 	os.Exit(0)
	// }
	config.Load([]string{})

	// Enable options.
	if config.VeryVeryVerbose {
		elog.Verbose = true
		raft.SetLogLevel(raft.Trace)
	} else if config.VeryVerbose {
		elog.Verbose = true
		raft.SetLogLevel(raft.Debug)
	} else if config.Verbose {
		elog.Verbose = true
	}
	if config.CPUProfileFile != "" {
		profile(config.CPUProfileFile)
	}

	if config.DataDir == "" {
		elog.Fatal("The data dir was not set and could not be guessed from machine name")
	}

	// Create data directory if it doesn't already exist.
	if err := os.MkdirAll(config.DataDir, 0744); err != nil {
		elog.Fatalf("Unable to create path: %s", err)
	}

	// Warn people if they have an info file
	info := filepath.Join(config.DataDir, "info")
	if _, err := os.Stat(info); err == nil {
		elog.Warnf("All cached configuration is now ignored. The file %s can be removed.", info)
	}

	var mbName string
	if config.Trace() {
		mbName = config.MetricsBucketName()
		runtime.SetBlockProfileRate(1)
	}

	mb := metrics.NewBucket(mbName)

	if config.GraphiteHost != "" {
		err := mb.Publish(config.GraphiteHost)
		if err != nil {
			panic(err)
		}
	}

	// Retrieve CORS configuration
	corsInfo, err := ehttp.NewCORSInfo(config.CorsOrigins)
	if err != nil {
		elog.Fatal("CORS:", err)
	}

	// Create etcd key-value store and registry.
	store := store.New()
	registry := server.NewRegistry(store)

	// Create stats objects
	followersStats := server.NewRaftFollowersStats(config.Name)
	serverStats := server.NewRaftServerStats(config.Name)

	// Calculate all of our timeouts
	heartbeatTimeout := time.Duration(config.Peer.HeartbeatTimeout) * time.Millisecond
	electionTimeout := time.Duration(config.Peer.ElectionTimeout) * time.Millisecond
	dialTimeout := (3 * heartbeatTimeout) + electionTimeout
	responseHeaderTimeout := (3 * heartbeatTimeout) + electionTimeout

	// Create peer server
	psConfig := server.PeerServerConfig{
		Name:           config.Name,
		Scheme:         config.PeerTLSInfo().Scheme(),
		URL:            config.Peer.Addr,
		SnapshotCount:  config.SnapshotCount,
		MaxClusterSize: config.MaxClusterSize,
		RetryTimes:     config.MaxRetryAttempts,
		RetryInterval:  config.RetryInterval,
	}
	ps := server.NewPeerServer(psConfig, registry, store, &mb, followersStats, serverStats)

	var psListener net.Listener
	if psConfig.Scheme == "https" {
		peerServerTLSConfig, err := config.PeerTLSInfo().ServerConfig()
		if err != nil {
			elog.Fatal("peer server TLS error: ", err)
		}

		psListener, err = server.NewTLSListener(config.Peer.BindAddr, peerServerTLSConfig)
		if err != nil {
			elog.Fatal("Failed to create peer listener: ", err)
		}
	} else {
		psListener, err = server.NewListener(config.Peer.BindAddr)
		if err != nil {
			elog.Fatal("Failed to create peer listener: ", err)
		}
	}

	// Create raft transporter and server
	raftTransporter := server.NewTransporter(followersStats, serverStats, registry, heartbeatTimeout, dialTimeout, responseHeaderTimeout)
	if psConfig.Scheme == "https" {
		raftClientTLSConfig, err := config.PeerTLSInfo().ClientConfig()
		if err != nil {
			elog.Fatal("raft client TLS error: ", err)
		}
		raftTransporter.SetTLSConfig(*raftClientTLSConfig)
	}
	raftServer, err := raft.NewServer(config.Name, config.DataDir, raftTransporter, store, ps, "")
	if err != nil {
		elog.Fatal(err)
	}
	raftServer.SetElectionTimeout(electionTimeout)
	raftServer.SetHeartbeatInterval(heartbeatTimeout)
	ps.SetRaftServer(raftServer)

	// Create etcd server
	s := server.New(config.Name, config.Addr, ps, registry, store, &mb)

	if config.Trace() {
		s.EnableTracing()
	}

	var sListener net.Listener
	if config.EtcdTLSInfo().Scheme() == "https" {
		etcdServerTLSConfig, err := config.EtcdTLSInfo().ServerConfig()
		if err != nil {
			elog.Fatal("etcd TLS error: ", err)
		}

		sListener, err = server.NewTLSListener(config.BindAddr, etcdServerTLSConfig)
		if err != nil {
			elog.Fatal("Failed to create TLS etcd listener: ", err)
		}
	} else {
		sListener, err = server.NewListener(config.BindAddr)
		if err != nil {
			elog.Fatal("Failed to create etcd listener: ", err)
		}
	}

	ps.SetServer(s)
	ps.Start(config.Snapshot, config.Peers)

	go func() {
		elog.Infof("peer server [name %s, listen on %s, advertised url %s]", ps.Config.Name, psListener.Addr(), ps.Config.URL)
		sHTTP := &ehttp.CORSHandler{ps.HTTPHandler(), corsInfo}
		elog.Fatal(http.Serve(psListener, sHTTP))
	}()

	elog.Infof("etcd server [name %s, listen on %s, advertised url %s]", s.Name, sListener.Addr(), s.URL())
	sHTTP := &ehttp.CORSHandler{s.HTTPHandler(), corsInfo}
	go func() { elog.Fatal(http.Serve(sListener, sHTTP)) }()

	close(ready)
}

// profile starts CPU profiling.
func profile(path string) {
	f, err := os.Create(path)
	if err != nil {
		elog.Fatal(err)
	}
	pprof.StartCPUProfile(f)

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		sig := <-c
		elog.Infof("captured %v, stopping profiler and exiting..", sig)
		pprof.StopCPUProfile()
		os.Exit(1)
	}()
}
<commit_msg>add comment for etcd function<commit_after>/*
Copyright 2013 CoreOS Inc.

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 kontrol

import (
	"net"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/coreos/etcd/third_party/github.com/coreos/raft"

	"github.com/coreos/etcd/config"
	ehttp "github.com/coreos/etcd/http"
	elog "github.com/coreos/etcd/log"
	"github.com/coreos/etcd/metrics"
	"github.com/coreos/etcd/server"
	"github.com/coreos/etcd/store"
)

// This function is copied and modified from github.com/coreos/etcd/main.go file.
func runEtcd(ready chan bool) {
	// Load configuration.
	var config = config.New()

	// Disable command line argument parsing for etcd
	//
	// if err := config.Load(os.Args[1:]); err != nil {
	// 	fmt.Println(server.Usage() + "\n")
	// 	fmt.Println(err.Error() + "\n")
	// 	os.Exit(1)
	// } else if config.ShowVersion {
	// 	fmt.Println(server.ReleaseVersion)
	// 	os.Exit(0)
	// } else if config.ShowHelp {
	// 	fmt.Println(server.Usage() + "\n")
	// 	os.Exit(0)
	// }
	config.Load([]string{})

	// Enable options.
	if config.VeryVeryVerbose {
		elog.Verbose = true
		raft.SetLogLevel(raft.Trace)
	} else if config.VeryVerbose {
		elog.Verbose = true
		raft.SetLogLevel(raft.Debug)
	} else if config.Verbose {
		elog.Verbose = true
	}
	if config.CPUProfileFile != "" {
		profile(config.CPUProfileFile)
	}

	if config.DataDir == "" {
		elog.Fatal("The data dir was not set and could not be guessed from machine name")
	}

	// Create data directory if it doesn't already exist.
	if err := os.MkdirAll(config.DataDir, 0744); err != nil {
		elog.Fatalf("Unable to create path: %s", err)
	}

	// Warn people if they have an info file
	info := filepath.Join(config.DataDir, "info")
	if _, err := os.Stat(info); err == nil {
		elog.Warnf("All cached configuration is now ignored. The file %s can be removed.", info)
	}

	var mbName string
	if config.Trace() {
		mbName = config.MetricsBucketName()
		runtime.SetBlockProfileRate(1)
	}

	mb := metrics.NewBucket(mbName)

	if config.GraphiteHost != "" {
		err := mb.Publish(config.GraphiteHost)
		if err != nil {
			panic(err)
		}
	}

	// Retrieve CORS configuration
	corsInfo, err := ehttp.NewCORSInfo(config.CorsOrigins)
	if err != nil {
		elog.Fatal("CORS:", err)
	}

	// Create etcd key-value store and registry.
	store := store.New()
	registry := server.NewRegistry(store)

	// Create stats objects
	followersStats := server.NewRaftFollowersStats(config.Name)
	serverStats := server.NewRaftServerStats(config.Name)

	// Calculate all of our timeouts
	heartbeatTimeout := time.Duration(config.Peer.HeartbeatTimeout) * time.Millisecond
	electionTimeout := time.Duration(config.Peer.ElectionTimeout) * time.Millisecond
	dialTimeout := (3 * heartbeatTimeout) + electionTimeout
	responseHeaderTimeout := (3 * heartbeatTimeout) + electionTimeout

	// Create peer server
	psConfig := server.PeerServerConfig{
		Name:           config.Name,
		Scheme:         config.PeerTLSInfo().Scheme(),
		URL:            config.Peer.Addr,
		SnapshotCount:  config.SnapshotCount,
		MaxClusterSize: config.MaxClusterSize,
		RetryTimes:     config.MaxRetryAttempts,
		RetryInterval:  config.RetryInterval,
	}
	ps := server.NewPeerServer(psConfig, registry, store, &mb, followersStats, serverStats)

	var psListener net.Listener
	if psConfig.Scheme == "https" {
		peerServerTLSConfig, err := config.PeerTLSInfo().ServerConfig()
		if err != nil {
			elog.Fatal("peer server TLS error: ", err)
		}

		psListener, err = server.NewTLSListener(config.Peer.BindAddr, peerServerTLSConfig)
		if err != nil {
			elog.Fatal("Failed to create peer listener: ", err)
		}
	} else {
		psListener, err = server.NewListener(config.Peer.BindAddr)
		if err != nil {
			elog.Fatal("Failed to create peer listener: ", err)
		}
	}

	// Create raft transporter and server
	raftTransporter := server.NewTransporter(followersStats, serverStats, registry, heartbeatTimeout, dialTimeout, responseHeaderTimeout)
	if psConfig.Scheme == "https" {
		raftClientTLSConfig, err := config.PeerTLSInfo().ClientConfig()
		if err != nil {
			elog.Fatal("raft client TLS error: ", err)
		}
		raftTransporter.SetTLSConfig(*raftClientTLSConfig)
	}
	raftServer, err := raft.NewServer(config.Name, config.DataDir, raftTransporter, store, ps, "")
	if err != nil {
		elog.Fatal(err)
	}
	raftServer.SetElectionTimeout(electionTimeout)
	raftServer.SetHeartbeatInterval(heartbeatTimeout)
	ps.SetRaftServer(raftServer)

	// Create etcd server
	s := server.New(config.Name, config.Addr, ps, registry, store, &mb)

	if config.Trace() {
		s.EnableTracing()
	}

	var sListener net.Listener
	if config.EtcdTLSInfo().Scheme() == "https" {
		etcdServerTLSConfig, err := config.EtcdTLSInfo().ServerConfig()
		if err != nil {
			elog.Fatal("etcd TLS error: ", err)
		}

		sListener, err = server.NewTLSListener(config.BindAddr, etcdServerTLSConfig)
		if err != nil {
			elog.Fatal("Failed to create TLS etcd listener: ", err)
		}
	} else {
		sListener, err = server.NewListener(config.BindAddr)
		if err != nil {
			elog.Fatal("Failed to create etcd listener: ", err)
		}
	}

	ps.SetServer(s)
	ps.Start(config.Snapshot, config.Peers)

	go func() {
		elog.Infof("peer server [name %s, listen on %s, advertised url %s]", ps.Config.Name, psListener.Addr(), ps.Config.URL)
		sHTTP := &ehttp.CORSHandler{ps.HTTPHandler(), corsInfo}
		elog.Fatal(http.Serve(psListener, sHTTP))
	}()

	elog.Infof("etcd server [name %s, listen on %s, advertised url %s]", s.Name, sListener.Addr(), s.URL())
	sHTTP := &ehttp.CORSHandler{s.HTTPHandler(), corsInfo}
	go func() { elog.Fatal(http.Serve(sListener, sHTTP)) }()

	close(ready)
}

// profile starts CPU profiling.
func profile(path string) {
	f, err := os.Create(path)
	if err != nil {
		elog.Fatal(err)
	}
	pprof.StartCPUProfile(f)

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		sig := <-c
		elog.Infof("captured %v, stopping profiler and exiting..", sig)
		pprof.StopCPUProfile()
		os.Exit(1)
	}()
}
<|endoftext|>


<commit_before>package cion

import (
	"encoding/json"
	"github.com/zenazn/goji/web"
	"log"
	"net/http"
	"strconv"
)

func NewJobHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]
	branch := c.URLParams["branch"]

	j := NewJob(owner, repo, branch, "")
	if err := js.Save(j); err != nil {
		log.Println("error saving job:", err)
	}

	jr := &JobRequest{
		Job:      j,
		Executor: e,
		Store:    js,
	}

	go jr.Run()

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(j, "", "\t")
	w.Write(b)
}

func GetJobHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]
	number, _ := strconv.ParseUint(c.URLParams["number"], 0, 64)

	j, err := js.GetByNumber(owner, repo, number)
	if err != nil {
		log.Println("error getting job:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(j, "", "\t")
	w.Write(b)
}

func GetLogHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]
	number, _ := strconv.ParseUint(c.URLParams["number"], 0, 64)

	j, err := js.GetByNumber(owner, repo, number)
	if err != nil {
		log.Println("error getting job:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	if _, err := js.GetLogger(j).WriteTo(w); err != nil {
		log.Println("error getting job logs:", err)
	}
}

func ListJobsHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]

	l, err := js.List(owner, repo)
	if err != nil {
		log.Println("error getting job list:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(l, "", "\t")
	w.Write(b)
}

func ListOwnersHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	l, err := js.ListOwners()
	if err != nil {
		log.Println("error getting owners list:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(l, "", "\t")
	w.Write(b)
}

func ListReposHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	l, err := js.ListRepos(c.URLParams["owner"])
	if err != nil {
		log.Println("error getting repos list:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(l, "", "\t")
	w.Write(b)
}
<commit_msg>Use the correct Content-Type for logs<commit_after>package cion

import (
	"encoding/json"
	"github.com/zenazn/goji/web"
	"log"
	"net/http"
	"strconv"
)

func NewJobHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]
	branch := c.URLParams["branch"]

	j := NewJob(owner, repo, branch, "")
	if err := js.Save(j); err != nil {
		log.Println("error saving job:", err)
	}

	jr := &JobRequest{
		Job:      j,
		Executor: e,
		Store:    js,
	}

	go jr.Run()

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(j, "", "\t")
	w.Write(b)
}

func GetJobHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]
	number, _ := strconv.ParseUint(c.URLParams["number"], 0, 64)

	j, err := js.GetByNumber(owner, repo, number)
	if err != nil {
		log.Println("error getting job:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(j, "", "\t")
	w.Write(b)
}

func GetLogHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]
	number, _ := strconv.ParseUint(c.URLParams["number"], 0, 64)

	j, err := js.GetByNumber(owner, repo, number)
	if err != nil {
		log.Println("error getting job:", err)
	}

	w.Header().Set("Content-Type", "text/plain")
	if _, err := js.GetLogger(j).WriteTo(w); err != nil {
		log.Println("error getting job logs:", err)
	}
}

func ListJobsHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	owner := c.URLParams["owner"]
	repo := c.URLParams["repo"]

	l, err := js.List(owner, repo)
	if err != nil {
		log.Println("error getting job list:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(l, "", "\t")
	w.Write(b)
}

func ListOwnersHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	l, err := js.ListOwners()
	if err != nil {
		log.Println("error getting owners list:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(l, "", "\t")
	w.Write(b)
}

func ListReposHandler(c web.C, w http.ResponseWriter, r *http.Request) {
	l, err := js.ListRepos(c.URLParams["owner"])
	if err != nil {
		log.Println("error getting repos list:", err)
	}

	w.Header().Set("Content-Type", "application/json")
	b, _ := json.MarshalIndent(l, "", "\t")
	w.Write(b)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net"
	"strings"
)

// Returns client authentication token from header or url params
func getClientToken(c *gin.Context) string {
	// Try fetching auth token from headers first
	token := c.Req.Header.Get("Token")

	// Try to fetch from url param if blank
	if token == "" {
		if len(c.Req.URL.Query()["token"]) > 0 {
			token = c.Req.URL.Query()["token"][0]
		}
	}

	return token
}

func RequireAuthToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := getClientToken(c)

		if token != options.Token {
			c.Abort(401)
		}
	}
}

func renderAvailableServices(c *gin.Context) {
	names := []string{}

	for _, svc := range services {
		names = append(names, svc.Name)
	}

	c.String(200, strings.Join(names, "\n")+"\n")
}

func renderServiceEnvironments(c *gin.Context) {
	serviceName := c.Params.ByName("service")

	service, err := getService(serviceName)
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	names := strings.Join(service.EnvironmentNames(), "\n") + "\n"
	c.String(200, names)
}

func renderServiceEnvironment(c *gin.Context) {
	serviceName := c.Params.ByName("service")
	envName := c.Params.ByName("env")

	environment, err := getEnvironment(serviceName, envName)

	// Respond with 400 if service does not exist
	// Todo: maybe respond with 404
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Get remote IP address
	host, _, err := net.SplitHostPort(c.Req.RemoteAddr)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Check if environment has allowed hosts
	if len(environment.Hosts) > 0 {
		// Reject requests from non-whitelisted hosts
		if environment.HostEnabled(host) == false {
			c.String(401, "Restricted\n")
			return
		}
	}

	// Check if environment has access token
	// Environment tokens DO NOT work if global access token is set
	// Global token is set with -t flag or via TOKEN env variable
	if !options.Auth && environment.Token != "" {
		token := getClientToken(c)

		if token != environment.Token {
			c.Abort(401)
			return
		}
	}

	c.String(200, environment.ToString()+"\n")
}

func renderReloadServices(c *gin.Context) {
	new_services, err := readServices(options.Path)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Replace current configuration
	services = new_services

	c.String(200, "OK\n")
}

func startServer() {
	api := gin.Default()

	if options.Auth {
		fmt.Println("authentication enabled")
		api.Use(RequireAuthToken())
	} else {
		fmt.Println("authentication disabled")
	}

	api.GET("/", renderAvailableServices)
	api.GET("/:service", renderServiceEnvironments)
	api.GET("/:service/:env", renderServiceEnvironment)
	api.POST("/reload", renderReloadServices)

	host := fmt.Sprintf("%s:%d", options.Host, options.Port)

	fmt.Println("starting server on", host)
	api.Run(host)
}
<commit_msg>Allow localhost as whitelist host<commit_after>package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net"
	"strings"
)

// Returns client authentication token from header or url params
func getClientToken(c *gin.Context) string {
	// Try fetching auth token from headers first
	token := c.Req.Header.Get("Token")

	// Try to fetch from url param if blank
	if token == "" {
		if len(c.Req.URL.Query()["token"]) > 0 {
			token = c.Req.URL.Query()["token"][0]
		}
	}

	return token
}

func RequireAuthToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := getClientToken(c)

		if token != options.Token {
			c.Abort(401)
		}
	}
}

func renderAvailableServices(c *gin.Context) {
	names := []string{}

	for _, svc := range services {
		names = append(names, svc.Name)
	}

	c.String(200, strings.Join(names, "\n")+"\n")
}

func renderServiceEnvironments(c *gin.Context) {
	serviceName := c.Params.ByName("service")

	service, err := getService(serviceName)
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	names := strings.Join(service.EnvironmentNames(), "\n") + "\n"
	c.String(200, names)
}

func renderServiceEnvironment(c *gin.Context) {
	serviceName := c.Params.ByName("service")
	envName := c.Params.ByName("env")

	environment, err := getEnvironment(serviceName, envName)

	// Respond with 400 if service does not exist
	// Todo: maybe respond with 404
	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Get remote IP address
	host, _, err := net.SplitHostPort(c.Req.RemoteAddr)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Check if environment has allowed hosts. Localhost is allowed.
	if host != "::1" && len(environment.Hosts) > 0 {
		// Reject requests from non-whitelisted hosts
		if environment.HostEnabled(host) == false {
			c.String(401, "Restricted\n")
			return
		}
	}

	// Check if environment has access token
	// Environment tokens DO NOT work if global access token is set
	// Global token is set with -t flag or via TOKEN env variable
	if !options.Auth && environment.Token != "" {
		token := getClientToken(c)

		if token != environment.Token {
			c.Abort(401)
			return
		}
	}

	c.String(200, environment.ToString()+"\n")
}

func renderReloadServices(c *gin.Context) {
	new_services, err := readServices(options.Path)

	if err != nil {
		c.String(400, err.Error()+"\n")
		return
	}

	// Replace current configuration
	services = new_services

	c.String(200, "OK\n")
}

func startServer() {
	api := gin.Default()

	if options.Auth {
		fmt.Println("authentication enabled")
		api.Use(RequireAuthToken())
	} else {
		fmt.Println("authentication disabled")
	}

	api.GET("/", renderAvailableServices)
	api.GET("/:service", renderServiceEnvironments)
	api.GET("/:service/:env", renderServiceEnvironment)
	api.POST("/reload", renderReloadServices)

	host := fmt.Sprintf("%s:%d", options.Host, options.Port)

	fmt.Println("starting server on", host)
	api.Run(host)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net"
	"net/http"

	"github.com/vincent-petithory/kraken"
	"github.com/vincent-petithory/kraken/fileserver"
)

var adminAddr string

func init() {
	flag.StringVar(&adminAddr, "http", ":4214", "The addr on which the admin http api will listen on. Defaults to :4214")
	flag.Parse()
}

func main() {
	// Register fileservers
	fsf := make(fileserver.Factory)

	// Init server pool, run existing servers and listen for new ones
	serverPool := kraken.NewServerPool(fsf)
	go serverPool.ListenAndRun()

	// Start administration server
	spah := kraken.NewServerPoolAdminHandler(serverPool)

	ln, err := net.Listen("tcp", adminAddr)
	if err != nil {
		log.Fatal(err)
	}
	srv := &http.Server{
		Handler: spah,
	}
	log.Printf("[admin] Listening on %s", ln.Addr())
	log.Fatal(srv.Serve(ln))
}
<commit_msg>krakend: allow to specify addr through KRAKEND_ADDR env var<commit_after>package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/vincent-petithory/kraken"
	"github.com/vincent-petithory/kraken/fileserver"
)

var adminAddr string

// Environnement var for the addr of the admin service.
// It takes precedence on the -http flag.
const envKrakendAddr = "KRAKEND_ADDR"

func init() {
	flag.StringVar(&adminAddr, "http", ":4214", "The address on which the admin http api will listen on. Defaults to :4214")
	flag.Parse()
}

func main() {
	// Register fileservers
	fsf := make(fileserver.Factory)

	// Init server pool, run existing servers and listen for new ones
	serverPool := kraken.NewServerPool(fsf)
	go serverPool.ListenAndRun()

	// Start administration server
	spah := kraken.NewServerPoolAdminHandler(serverPool)

	if envAdminAddr := os.Getenv(envKrakendAddr); envAdminAddr != "" {
		adminAddr = envAdminAddr
	}
	ln, err := net.Listen("tcp", adminAddr)
	if err != nil {
		log.Fatal(err)
	}
	srv := &http.Server{
		Handler: spah,
	}
	log.Printf("[admin] Listening on %s", ln.Addr())
	log.Fatal(srv.Serve(ln))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/kataras/iris"
)

func main() {
	iris.Get("/hi", func(ctx *iris.Context) {
		ctx.Write("Hello world %s", "iris")

		fmt.Println("Hello world")

	})
	fmt.Println("Start Service....")
	iris.Listen(":8080")
}
<commit_msg>- update code<commit_after>package main

import (
	"fmt"

	"github.com/kataras/iris"
)

func main() {
	iris.Get("/hi", func(ctx *iris.Context) {
		ctx.Write("Hello world %s", "iris")
	})
	fmt.Println("Start Service....")
	iris.Listen(":8080")
}
<|endoftext|>


<commit_before>/*
gopcap is pure-Go implementation of a parser for .pcap files. Written from the
ground up for plugging directly into other components, the API is focused on
simplicity and clarity. To this end, it exposes the barest minimum of
functionality in as clear an API as possible.
*/
package gopcap

import (
	"io"
	"time"
)

// Link encodes a given Link-Layer header type. See http://www.tcpdump.org/linktypes.html for a more-full
// explanation of each header type.
type Link uint32

const (
	NULL                       Link = 0
	ETHERNET                   Link = 1
	AX25                       Link = 3
	IEEE802_5                  Link = 6
	ARCNET_BSD                 Link = 7
	SLIP                       Link = 8
	PPP                        Link = 9
	FDDI                       Link = 10
	PPP_HDLC                   Link = 50
	PPP_ETHER                  Link = 51
	ATM_RFC1483                Link = 100
	RAW                        Link = 101
	C_HDLC                     Link = 104
	IEEE802_11                 Link = 105
	FRELAY                     Link = 107
	LOOP                       Link = 108
	LINUX_SLL                  Link = 113
	LTALK                      Link = 114
	PFLOG                      Link = 117
	IEEE802_11_PRISM           Link = 119
	IP_OVER_FC                 Link = 122
	SUNATM                     Link = 123
	IEEE802_11_RADIOTAP        Link = 127
	ARCNET_LINUX               Link = 129
	APPLE_IP_OVER_IEEE1394     Link = 138
	MTP2_WITH_PHDR             Link = 139
	MTP2                       Link = 140
	MTP3                       Link = 141
	SCCP                       Link = 142
	DOCSIS                     Link = 143
	LINUX_IRDA                 Link = 144
	IEEE802_11_AVS             Link = 163
	BACNET_MS_TP               Link = 165
	PPP_PPPD                   Link = 166
	GPRS_LLC                   Link = 169
	LINUX_LAPD                 Link = 177
	BLUETOOTH_HCI_H4           Link = 187
	USB_LINUX                  Link = 189
	PPI                        Link = 192
	IEEE802_15_4               Link = 195
	SITA                       Link = 196
	ERF                        Link = 197
	BLUETOOTH_HCI_H4_WITH_PHDR Link = 201
	AX25_KISS                  Link = 202
	LAPD                       Link = 203
	PPP_WITH_DIR               Link = 204
	C_HDLC_WITH_DIR            Link = 205
	FRELAY_WITH_DIR            Link = 206
	IPMB_LINUX                 Link = 209
	IEEE802_15_4_NONASK_PHY    Link = 215
	USB_LINUX_MMAPPED          Link = 220
	FC_2                       Link = 224
	FC_2_WITH_FRAME_DELIMS     Link = 225
	IPNET                      Link = 226
	CAN_SOCKETCAN              Link = 227
	IPV4                       Link = 228
	IPV6                       Link = 229
	IEEE802_15_4_NOFCS         Link = 230
	DBUS                       Link = 231
	DVB_CI                     Link = 235
	MUX27010                   Link = 236
	STANAG_5066_D_PDU          Link = 237
	NFLOG                      Link = 239
	NETANALYZER                Link = 240
	NETANALYZER_TRANSPARENT    Link = 241
	IPOIB                      Link = 242
	MPEG_2_TS                  Link = 243
	NG40                       Link = 244
	NFC_LLCP                   Link = 245
	INFINIBAND                 Link = 247
	SCTP                       Link = 248
	USBPCAP                    Link = 249
	RTAC_SERIAL                Link = 250
	BLUETOOTH_LE_LL            Link = 251
)

// PcapFile represents the parsed form of a single .pcap file. The structure
// contains some details about the file itself, but is mostly a container for
// the parsed Packets.
type PcapFile struct {
	MajorVersion uint16
	MinorVersion uint16
	TZCorrection int32 // In seconds east of UTC
	SigFigs      uint32
	MaxLen       uint32
	LinkType     Link
	Packets      []Packet
}

// Packet is a representation of a single network packet. The structure
// contains the timestamp on the packet, some information about packet size,
// and the recorded bytes from the packet.
type Packet struct {
	Timestamp   time.Time
	IncludedLen uint32
	ActualLen   uint32
	Data        []byte
}

// Parse is the external API of gopcap. It takes anything that implements the
// io.Reader interface, but will mostly expect a file produced by anything that
// produces .pcap files. It will attempt to parse the entire file. If an error
// is encountered, as much of the parsed content as is possible will be returned,
// along with an error value.
func Parse(src io.Reader) (PcapFile, error) {}
<commit_msg>Some parsing utility functions.<commit_after>/*
gopcap is pure-Go implementation of a parser for .pcap files. Written from the
ground up for plugging directly into other components, the API is focused on
simplicity and clarity. To this end, it exposes the barest minimum of
functionality in as clear an API as possible.
*/
package gopcap

import (
	"bytes"
	"errors"
	"io"
	"time"
)

// Link encodes a given Link-Layer header type. See http://www.tcpdump.org/linktypes.html for a more-full
// explanation of each header type.
type Link uint32

const (
	NULL                       Link = 0
	ETHERNET                   Link = 1
	AX25                       Link = 3
	IEEE802_5                  Link = 6
	ARCNET_BSD                 Link = 7
	SLIP                       Link = 8
	PPP                        Link = 9
	FDDI                       Link = 10
	PPP_HDLC                   Link = 50
	PPP_ETHER                  Link = 51
	ATM_RFC1483                Link = 100
	RAW                        Link = 101
	C_HDLC                     Link = 104
	IEEE802_11                 Link = 105
	FRELAY                     Link = 107
	LOOP                       Link = 108
	LINUX_SLL                  Link = 113
	LTALK                      Link = 114
	PFLOG                      Link = 117
	IEEE802_11_PRISM           Link = 119
	IP_OVER_FC                 Link = 122
	SUNATM                     Link = 123
	IEEE802_11_RADIOTAP        Link = 127
	ARCNET_LINUX               Link = 129
	APPLE_IP_OVER_IEEE1394     Link = 138
	MTP2_WITH_PHDR             Link = 139
	MTP2                       Link = 140
	MTP3                       Link = 141
	SCCP                       Link = 142
	DOCSIS                     Link = 143
	LINUX_IRDA                 Link = 144
	IEEE802_11_AVS             Link = 163
	BACNET_MS_TP               Link = 165
	PPP_PPPD                   Link = 166
	GPRS_LLC                   Link = 169
	LINUX_LAPD                 Link = 177
	BLUETOOTH_HCI_H4           Link = 187
	USB_LINUX                  Link = 189
	PPI                        Link = 192
	IEEE802_15_4               Link = 195
	SITA                       Link = 196
	ERF                        Link = 197
	BLUETOOTH_HCI_H4_WITH_PHDR Link = 201
	AX25_KISS                  Link = 202
	LAPD                       Link = 203
	PPP_WITH_DIR               Link = 204
	C_HDLC_WITH_DIR            Link = 205
	FRELAY_WITH_DIR            Link = 206
	IPMB_LINUX                 Link = 209
	IEEE802_15_4_NONASK_PHY    Link = 215
	USB_LINUX_MMAPPED          Link = 220
	FC_2                       Link = 224
	FC_2_WITH_FRAME_DELIMS     Link = 225
	IPNET                      Link = 226
	CAN_SOCKETCAN              Link = 227
	IPV4                       Link = 228
	IPV6                       Link = 229
	IEEE802_15_4_NOFCS         Link = 230
	DBUS                       Link = 231
	DVB_CI                     Link = 235
	MUX27010                   Link = 236
	STANAG_5066_D_PDU          Link = 237
	NFLOG                      Link = 239
	NETANALYZER                Link = 240
	NETANALYZER_TRANSPARENT    Link = 241
	IPOIB                      Link = 242
	MPEG_2_TS                  Link = 243
	NG40                       Link = 244
	NFC_LLCP                   Link = 245
	INFINIBAND                 Link = 247
	SCTP                       Link = 248
	USBPCAP                    Link = 249
	RTAC_SERIAL                Link = 250
	BLUETOOTH_LE_LL            Link = 251
)

// PcapFile represents the parsed form of a single .pcap file. The structure
// contains some details about the file itself, but is mostly a container for
// the parsed Packets.
type PcapFile struct {
	MajorVersion uint16
	MinorVersion uint16
	TZCorrection int32 // In seconds east of UTC
	SigFigs      uint32
	MaxLen       uint32
	LinkType     Link
	Packets      []Packet
}

// Packet is a representation of a single network packet. The structure
// contains the timestamp on the packet, some information about packet size,
// and the recorded bytes from the packet.
type Packet struct {
	Timestamp   time.Time
	IncludedLen uint32
	ActualLen   uint32
	Data        []byte
}

// Parse is the external API of gopcap. It takes anything that implements the
// io.Reader interface, but will mostly expect a file produced by anything that
// produces .pcap files. It will attempt to parse the entire file. If an error
// is encountered, as much of the parsed content as is possible will be returned,
// along with an error value.
func Parse(src io.Reader) (PcapFile, error) {
	file := new(PcapFile)

	// Check whether this is a libpcap file at all, and if so what byte ordering it has.
	cont, flipped, err := checkMagicNum(src)
	if err != nil {
		return *file, err
	}

	return *file, nil
}

// checkMagicNum checks the first four bytes of a pcap file, searching for the magic number
// and checking the byte order. Returns three values: whether the file is a pcap file, whether
// the byte order needs flipping, and any error that was encountered. If error is returned,
// the other values are invalid.
func checkMagicNum(src io.Reader) (bool, bool, error) {
	// These magic numbers form the header of a pcap file.
	magic := []byte{0xa1, 0xb2, 0xc3, 0xd4}
	magic_reverse := []byte{0xd4, 0xc3, 0xb2, 0xa1}

	buffer := make([]byte, 4)
	read_count, err := src.Read(buffer)

	if err != nil {
		return false, false, err
	}
	if read_count != 4 {
		return false, false, errors.New("Insufficent length.")
	}

	if bytes.Compare(buffer, magic) == 0 {
		return true, false, nil
	} else if bytes.Compare(buffer, magic_reverse) == 0 {
		return true, true, nil
	}

	return false, false, errors.New("Not a pcap file.")
}

// populateFileHeader reads the next 20 bytes out of the .pcap file and uses it to populate the
// PcapFile structure.
func populateFileHeader(file *PcapFile, src io.Reader, flipped bool) error {
	buffer := make([]byte, 20)
	read_count, err := src.Read(buffer)

	if err != nil {
		return err
	} else if read_count != 20 {
		return errors.New("Insufficient length.")
	}

	// First two bytes are the major version number.
	file.MajorVersion = getUint16(buffer[0:2], flipped)

	// Next two are the minor version number.
	file.MinorVersion = getUint16(buffer[2:4], flipped)

	// GMT to local correction, in seconds east of UTC.
	file.TZCorrection = getInt32(buffer[4:8], flipped)

	// Next is the number of significant figures in the timestamps. Almost always zero.
	file.SigFigs = getUint32(buffer[8:12], flipped)

	// Now the maximum length of the captured packet data.
	file.MaxLen = getUint32(buffer[12:16], flipped)

	// And the link type.
	file.LinkType = Link(getUint32(buffer[16:20], flipped))

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/appc/spec/schema"
	"github.com/blablacar/dgr/bin-dgr/common"
	"github.com/ghodss/yaml"
	"github.com/n0rad/go-erlog/data"
	"github.com/n0rad/go-erlog/errs"
	"github.com/n0rad/go-erlog/logs"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
)

const PATH_GRAPH_DOT = "/graph.dot"
const PATH_INSTALLED = "/installed"
const PATH_IMAGE_ACI = "/image.aci"
const PATH_IMAGE_ACI_ZIP = "/image-zip.aci"
const PATH_TARGET = "/target"
const PATH_ACI_MANIFEST = "/aci-manifest.yml"
const PATH_MANIFEST_JSON = "/manifest.json"
const PATH_TMP = "/tmp"

const PATH_BUILDER = "/builder"
const PATH_BUILDER_UUID = "/builder.uuid"

const PATH_TEST_BUILDER = "/test-builder"
const PATH_TEST_BUILDER_UUID = "/test-builder.uuid"

const MANIFEST_DRG_BUILDER = "dgr-builder"
const MANIFEST_DRG_VERSION = "dgr-version"

const PREFIX_TEST_BUILDER = "test-builder/"
const PREFIX_BUILDER = "builder/"

type Aci struct {
	fields          data.Fields
	path            string
	target          string
	podName         *common.ACFullname
	manifest        *AciManifest
	args            BuildArgs
	FullyResolveDep bool
}

func NewAciWithManifest(path string, args BuildArgs, manifest *AciManifest) (*Aci, error) {
	if manifest.NameAndVersion == "" {
		logs.WithField("path", path).Fatal("name is mandatory in manifest")
	}

	fields := data.WithField("aci", manifest.NameAndVersion.String())
	logs.WithF(fields).WithFields(data.Fields{"args": args, "path": path, "manifest": manifest}).Debug("New aci")

	fullPath, err := filepath.Abs(path)
	if err != nil {
		return nil, errs.WithEF(err, fields, "Cannot get fullpath of project")
	}

	target := fullPath + PATH_TARGET
	if Home.Config.TargetWorkDir != "" {
		currentAbsDir, err := filepath.Abs(Home.Config.TargetWorkDir + "/" + manifest.NameAndVersion.ShortName())
		if err != nil {
			return nil, errs.WithEF(err, fields.WithField("path", path), "Invalid target path")
		}
		target = currentAbsDir
	}

	aci := &Aci{
		fields:          fields,
		args:            args,
		path:            fullPath,
		manifest:        manifest,
		target:          target,
		FullyResolveDep: true,
	}

	froms, err := manifest.GetFroms()
	if err != nil {
		logs.WithEF(err, aci.fields).Fatal("Invalid from data")
	}
	if len(froms) != 0 {
		logs.WithF(aci.fields).Warn("From is deprecated and processed as dependency. move from to dependencies")
		aci.manifest.Aci.Dependencies = append(froms, aci.manifest.Aci.Dependencies...)
	}

	go aci.checkCompatibilityVersions()
	go aci.checkLatestVersions()
	return aci, nil
}

func NewAci(path string, args BuildArgs) (*Aci, error) {
	manifest, err := readAciManifest(path + PATH_ACI_MANIFEST)
	if err != nil {
		manifest2, err2 := readAciManifest(path + "/cnt-manifest.yml")
		if err2 != nil {
			return nil, errs.WithEF(err, data.WithField("path", path+PATH_ACI_MANIFEST).WithField("err2", err2), "Cannot read manifest")
		}
		logs.WithField("old", "cnt-manifest.yml").WithField("new", "aci-manifest.yml").Warn("You are using the old aci configuration file")
		manifest = manifest2
	}
	return NewAciWithManifest(path, args, manifest)
}

//////////////////////////////////////////////////////////////////

func readAciManifest(manifestPath string) (*AciManifest, error) {
	manifest := AciManifest{Aci: AciDefinition{}}

	source, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(source), &manifest)
	if err != nil {
		return nil, errs.WithE(err, "Cannot unmarshall manifest")
	}

	return &manifest, nil
}

func (aci *Aci) tarAci(path string, zip bool) error {
	target := PATH_IMAGE_ACI[1:]
	if zip {
		target = PATH_IMAGE_ACI_ZIP[1:]
	}
	dir, _ := os.Getwd()
	logs.WithField("path", path).Debug("chdir")
	os.Chdir(path)
	if err := common.Tar(zip, target, common.PATH_MANIFEST[1:], common.PATH_ROOTFS[1:]); err != nil {
		return errs.WithEF(err, aci.fields.WithField("path", path), "Failed to tar container")
	}
	logs.WithField("path", dir).Debug("chdir")
	os.Chdir(dir)
	return nil
}

func (aci *Aci) checkCompatibilityVersions() {
	for _, dep := range aci.manifest.Aci.Dependencies {
		depFields := aci.fields.WithField("dependency", dep.String())
		common.ExecCmdGetStdoutAndStderr("rkt", "--insecure-options=image", "fetch", dep.String())

		version, err := GetDependencyDgrVersion(dep)
		if err != nil {
			logs.WithEF(err, depFields).Error("Failed to check compatibility version of dependency")
		} else {
			if version < 55 {
				logs.WithF(aci.fields).
					WithField("dependency", dep).
					WithField("require", ">=55").
					Error("dependency was not build with a compatible version of dgr")
			}
		}

	}
}

func GetDependencyDgrVersion(acName common.ACFullname) (int, error) {
	depFields := data.WithField("dependency", acName.String())
	out, err := common.ExecCmdGetOutput("rkt", "image", "cat-manifest", acName.String())
	if err != nil {
		return 0, errs.WithEF(err, depFields, "Dependency not found")
	}

	im := schema.ImageManifest{}
	if err := im.UnmarshalJSON([]byte(out)); err != nil {
		return 0, errs.WithEF(err, depFields.WithField("content", out), "Cannot read manifest cat by rkt image")
	}

	version, ok := im.Annotations.Get(MANIFEST_DRG_VERSION)
	var val int
	if ok {
		val, err = strconv.Atoi(version)
		if err != nil {
			return 0, errs.WithEF(err, depFields.WithField("version", version), "Failed to parse "+MANIFEST_DRG_VERSION+" from manifest")
		}
	}
	return val, nil
}

func (aci *Aci) giveBackUserRightsToTarget() {
	giveBackUserRights(aci.target)
}

func (aci *Aci) checkLatestVersions() {
	for _, dep := range aci.manifest.Aci.Dependencies {
		if dep.Version() == "" {
			continue
		}
		version, _ := dep.LatestVersion()
		if version != "" && Version(dep.Version()).LessThan(Version(version)) {
			logs.WithField("newer", dep.Name()+":"+version).
				WithField("current", dep.String()).
				Warn("Newer 'dependency' version")
		}
	}
}
<commit_msg>ignore empty from<commit_after>package main

import (
	"github.com/appc/spec/schema"
	"github.com/blablacar/dgr/bin-dgr/common"
	"github.com/ghodss/yaml"
	"github.com/n0rad/go-erlog/data"
	"github.com/n0rad/go-erlog/errs"
	"github.com/n0rad/go-erlog/logs"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
)

const PATH_GRAPH_DOT = "/graph.dot"
const PATH_INSTALLED = "/installed"
const PATH_IMAGE_ACI = "/image.aci"
const PATH_IMAGE_ACI_ZIP = "/image-zip.aci"
const PATH_TARGET = "/target"
const PATH_ACI_MANIFEST = "/aci-manifest.yml"
const PATH_MANIFEST_JSON = "/manifest.json"
const PATH_TMP = "/tmp"

const PATH_BUILDER = "/builder"
const PATH_BUILDER_UUID = "/builder.uuid"

const PATH_TEST_BUILDER = "/test-builder"
const PATH_TEST_BUILDER_UUID = "/test-builder.uuid"

const MANIFEST_DRG_BUILDER = "dgr-builder"
const MANIFEST_DRG_VERSION = "dgr-version"

const PREFIX_TEST_BUILDER = "test-builder/"
const PREFIX_BUILDER = "builder/"

type Aci struct {
	fields          data.Fields
	path            string
	target          string
	podName         *common.ACFullname
	manifest        *AciManifest
	args            BuildArgs
	FullyResolveDep bool
}

func NewAciWithManifest(path string, args BuildArgs, manifest *AciManifest) (*Aci, error) {
	if manifest.NameAndVersion == "" {
		logs.WithField("path", path).Fatal("name is mandatory in manifest")
	}

	fields := data.WithField("aci", manifest.NameAndVersion.String())
	logs.WithF(fields).WithFields(data.Fields{"args": args, "path": path, "manifest": manifest}).Debug("New aci")

	fullPath, err := filepath.Abs(path)
	if err != nil {
		return nil, errs.WithEF(err, fields, "Cannot get fullpath of project")
	}

	target := fullPath + PATH_TARGET
	if Home.Config.TargetWorkDir != "" {
		currentAbsDir, err := filepath.Abs(Home.Config.TargetWorkDir + "/" + manifest.NameAndVersion.ShortName())
		if err != nil {
			return nil, errs.WithEF(err, fields.WithField("path", path), "Invalid target path")
		}
		target = currentAbsDir
	}

	aci := &Aci{
		fields:          fields,
		args:            args,
		path:            fullPath,
		manifest:        manifest,
		target:          target,
		FullyResolveDep: true,
	}

	froms, err := manifest.GetFroms()
	if err != nil {
		logs.WithEF(err, aci.fields).Fatal("Invalid from data")
	}
	if len(froms) != 0 {
		if froms[0].String() != "" {
			logs.WithF(aci.fields).Warn("From is deprecated and empty, remove it")
		} else {
			logs.WithF(aci.fields).Warn("From is deprecated and processed as dependency. move from to dependencies")
			aci.manifest.Aci.Dependencies = append(froms, aci.manifest.Aci.Dependencies...)
		}
	}

	go aci.checkCompatibilityVersions()
	go aci.checkLatestVersions()
	return aci, nil
}

func NewAci(path string, args BuildArgs) (*Aci, error) {
	manifest, err := readAciManifest(path + PATH_ACI_MANIFEST)
	if err != nil {
		manifest2, err2 := readAciManifest(path + "/cnt-manifest.yml")
		if err2 != nil {
			return nil, errs.WithEF(err, data.WithField("path", path+PATH_ACI_MANIFEST).WithField("err2", err2), "Cannot read manifest")
		}
		logs.WithField("old", "cnt-manifest.yml").WithField("new", "aci-manifest.yml").Warn("You are using the old aci configuration file")
		manifest = manifest2
	}
	return NewAciWithManifest(path, args, manifest)
}

//////////////////////////////////////////////////////////////////

func readAciManifest(manifestPath string) (*AciManifest, error) {
	manifest := AciManifest{Aci: AciDefinition{}}

	source, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(source), &manifest)
	if err != nil {
		return nil, errs.WithE(err, "Cannot unmarshall manifest")
	}

	return &manifest, nil
}

func (aci *Aci) tarAci(path string, zip bool) error {
	target := PATH_IMAGE_ACI[1:]
	if zip {
		target = PATH_IMAGE_ACI_ZIP[1:]
	}
	dir, _ := os.Getwd()
	logs.WithField("path", path).Debug("chdir")
	os.Chdir(path)
	if err := common.Tar(zip, target, common.PATH_MANIFEST[1:], common.PATH_ROOTFS[1:]); err != nil {
		return errs.WithEF(err, aci.fields.WithField("path", path), "Failed to tar container")
	}
	logs.WithField("path", dir).Debug("chdir")
	os.Chdir(dir)
	return nil
}

func (aci *Aci) checkCompatibilityVersions() {
	for _, dep := range aci.manifest.Aci.Dependencies {
		depFields := aci.fields.WithField("dependency", dep.String())
		common.ExecCmdGetStdoutAndStderr("rkt", "--insecure-options=image", "fetch", dep.String())

		version, err := GetDependencyDgrVersion(dep)
		if err != nil {
			logs.WithEF(err, depFields).Error("Failed to check compatibility version of dependency")
		} else {
			if version < 55 {
				logs.WithF(aci.fields).
					WithField("dependency", dep).
					WithField("require", ">=55").
					Error("dependency was not build with a compatible version of dgr")
			}
		}

	}
}

func GetDependencyDgrVersion(acName common.ACFullname) (int, error) {
	depFields := data.WithField("dependency", acName.String())
	out, err := common.ExecCmdGetOutput("rkt", "image", "cat-manifest", acName.String())
	if err != nil {
		return 0, errs.WithEF(err, depFields, "Dependency not found")
	}

	im := schema.ImageManifest{}
	if err := im.UnmarshalJSON([]byte(out)); err != nil {
		return 0, errs.WithEF(err, depFields.WithField("content", out), "Cannot read manifest cat by rkt image")
	}

	version, ok := im.Annotations.Get(MANIFEST_DRG_VERSION)
	var val int
	if ok {
		val, err = strconv.Atoi(version)
		if err != nil {
			return 0, errs.WithEF(err, depFields.WithField("version", version), "Failed to parse "+MANIFEST_DRG_VERSION+" from manifest")
		}
	}
	return val, nil
}

func (aci *Aci) giveBackUserRightsToTarget() {
	giveBackUserRights(aci.target)
}

func (aci *Aci) checkLatestVersions() {
	for _, dep := range aci.manifest.Aci.Dependencies {
		if dep.Version() == "" {
			continue
		}
		version, _ := dep.LatestVersion()
		if version != "" && Version(dep.Version()).LessThan(Version(version)) {
			logs.WithField("newer", dep.Name()+":"+version).
				WithField("current", dep.String()).
				Warn("Newer 'dependency' version")
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 cainjector

import (
	"context"
	"fmt"
	"io/ioutil"

	logf "github.com/jetstack/cert-manager/pkg/logs"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	admissionreg "k8s.io/api/admissionregistration/v1beta1"
	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	apireg "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

// injectorSet describes a particular setup of the injector controller
type injectorSetup struct {
	resourceName string
	injector     CertInjector
	listType     runtime.Object
}

var (
	MutatingWebhookSetup = injectorSetup{
		resourceName: "mutatingwebhookconfiguration",
		injector:     mutatingWebhookInjector{},
		listType:     &admissionreg.MutatingWebhookConfigurationList{},
	}

	ValidatingWebhookSetup = injectorSetup{
		resourceName: "validatingwebhookconfiguration",
		injector:     validatingWebhookInjector{},
		listType:     &admissionreg.ValidatingWebhookConfigurationList{},
	}

	APIServiceSetup = injectorSetup{
		resourceName: "apiservice",
		injector:     apiServiceInjector{},
		listType:     &apireg.APIServiceList{},
	}

	CRDSetup = injectorSetup{
		resourceName: "customresourcedefinition",
		injector:     crdConversionInjector{},
		listType:     &apiext.CustomResourceDefinitionList{},
	}

	injectorSetups  = []injectorSetup{MutatingWebhookSetup, ValidatingWebhookSetup, APIServiceSetup, CRDSetup}
	ControllerNames []string
)

// registerAllInjectors registers all injectors and based on the
// graduation state of the injector decides how to log no kind/resource match errors
func registerAllInjectors(ctx context.Context, name string, mgr ctrl.Manager, sources []caDataSource, ca cache.Cache) error {
	controllers := map[string]controller.Controller{}
	for _, setup := range injectorSetups {
		controller, err := Register(fmt.Sprintf("%s-injector-%s", name, setup.resourceName), mgr, setup, sources, ca)
		if err != nil {
			if !meta.IsNoMatchError(err) || !setup.injector.IsAlpha() {
				return err
			}
			ctrl.Log.V(logf.WarnLevel).Info("unable to register injector which is still in an alpha phase."+
				" Enable the feature on the API server in order to use this injector",
				"injector", setup.resourceName)
		}
		controllers[setup.resourceName] = controller
	}
	g, gctx := errgroup.WithContext(ctx)

	g.Go(func() (err error) {
		defer func() {
			ctrl.Log.V(logf.TraceLevel).Error(err, "DEBUG: cache routine finished", "name", name)
		}()
		ctrl.Log.V(logf.TraceLevel).Info("DEBUG: cache routine starting", "name", name)
		if err = ca.Start(gctx.Done()); err != nil {
			return errors.WithStack(err)
		}
		return nil
	})
	if ca.WaitForCacheSync(gctx.Done()) {
		for resourceName, controller := range controllers {
			if gctx.Err() != nil {
				continue
			}
			resourceName := resourceName
			controller := controller
			g.Go(func() (err error) {
				defer func() {
					ctrl.Log.V(logf.TraceLevel).Error(err, "DEBUG: controller routine finished", "name", name, "resourceName", resourceName)
				}()
				ctrl.Log.V(logf.TraceLevel).Info("DEBUG: controller routine starting", "name", name, "resourceName", resourceName)
				return controller.Start(gctx.Done())
			})
		}
	}
	return g.Wait()
}

// Register registers an injection controller with the given manager, and adds relevant indicies.
func Register(name string, mgr ctrl.Manager, setup injectorSetup, sources []caDataSource, ca cache.Cache) (controller.Controller, error) {
	typ := setup.injector.NewTarget().AsObject()

	c, err := controller.NewUnmanaged(
		// XXX:  strings.ToLower(typ.GetObjectKind().GroupVersionKind().Kind),
		name,
		mgr,
		controller.Options{
			Reconciler: &genericInjectReconciler{
				Client:       mgr.GetClient(),
				sources:      sources,
				log:          ctrl.Log.WithName("inject-controller"),
				resourceName: setup.resourceName,
				injector:     setup.injector,
			},
		})
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if err := c.Watch(source.NewKindWithCache(typ, ca), &handler.EnqueueRequestForObject{}); err != nil {
		return nil, errors.WithStack(err)
	}

	for _, s := range sources {
		if err := s.ApplyTo(mgr, setup, c, ca); err != nil {
			return nil, err
		}
	}

	return c, nil
}

// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
// or an error if an error occurred reading the file
func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
	if len(data) > 0 {
		return data, nil
	}
	if len(file) > 0 {
		fileData, err := ioutil.ReadFile(file)
		if err != nil {
			return []byte{}, err
		}
		return fileData, nil
	}
	return nil, nil
}

// RegisterCertificateBased registers all known injection controllers that
// target Certificate resources with the  given manager, and adds relevant
// indices.
// The registered controllers require the cert-manager API to be available
// in order to run.
func RegisterCertificateBased(ctx context.Context, mgr ctrl.Manager) error {
	cacheOptions := cache.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	ca, err := cache.New(mgr.GetConfig(), cacheOptions)
	if err != nil {
		return errors.WithStack(err)
	}
	return registerAllInjectors(
		ctx,
		"certificate",
		mgr,
		[]caDataSource{
			&certificateDataSource{client: ca},
		},
		ca,
	)
}

// RegisterSecretBased registers all known injection controllers that
// target Secret resources with the  given manager, and adds relevant
// indices.
// The registered controllers only require the corev1 APi to be available in
// order to run.
func RegisterSecretBased(ctx context.Context, mgr ctrl.Manager) error {
	cacheOptions := cache.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	ca, err := cache.New(mgr.GetConfig(), cacheOptions)
	if err != nil {
		return errors.WithStack(err)
	}
	return registerAllInjectors(
		ctx,
		"secret",
		mgr,
		[]caDataSource{
			&secretDataSource{client: ca},
			&kubeconfigDataSource{},
		},
		ca,
	)
}
<commit_msg>Increase the number of reconciler goroutines<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 cainjector

import (
	"context"
	"fmt"
	"io/ioutil"

	logf "github.com/jetstack/cert-manager/pkg/logs"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	admissionreg "k8s.io/api/admissionregistration/v1beta1"
	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	apireg "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

// injectorSet describes a particular setup of the injector controller
type injectorSetup struct {
	resourceName string
	injector     CertInjector
	listType     runtime.Object
}

var (
	MutatingWebhookSetup = injectorSetup{
		resourceName: "mutatingwebhookconfiguration",
		injector:     mutatingWebhookInjector{},
		listType:     &admissionreg.MutatingWebhookConfigurationList{},
	}

	ValidatingWebhookSetup = injectorSetup{
		resourceName: "validatingwebhookconfiguration",
		injector:     validatingWebhookInjector{},
		listType:     &admissionreg.ValidatingWebhookConfigurationList{},
	}

	APIServiceSetup = injectorSetup{
		resourceName: "apiservice",
		injector:     apiServiceInjector{},
		listType:     &apireg.APIServiceList{},
	}

	CRDSetup = injectorSetup{
		resourceName: "customresourcedefinition",
		injector:     crdConversionInjector{},
		listType:     &apiext.CustomResourceDefinitionList{},
	}

	injectorSetups  = []injectorSetup{MutatingWebhookSetup, ValidatingWebhookSetup, APIServiceSetup, CRDSetup}
	ControllerNames []string
)

// registerAllInjectors registers all injectors and based on the
// graduation state of the injector decides how to log no kind/resource match errors
func registerAllInjectors(ctx context.Context, name string, mgr ctrl.Manager, sources []caDataSource, ca cache.Cache) error {
	controllers := map[string]controller.Controller{}
	for _, setup := range injectorSetups {
		controller, err := Register(fmt.Sprintf("%s-injector-%s", name, setup.resourceName), mgr, setup, sources, ca)
		if err != nil {
			if !meta.IsNoMatchError(err) || !setup.injector.IsAlpha() {
				return err
			}
			ctrl.Log.V(logf.WarnLevel).Info("unable to register injector which is still in an alpha phase."+
				" Enable the feature on the API server in order to use this injector",
				"injector", setup.resourceName)
		}
		controllers[setup.resourceName] = controller
	}
	g, gctx := errgroup.WithContext(ctx)

	g.Go(func() (err error) {
		defer func() {
			ctrl.Log.V(logf.TraceLevel).Error(err, "DEBUG: cache routine finished", "name", name)
		}()
		ctrl.Log.V(logf.TraceLevel).Info("DEBUG: cache routine starting", "name", name)
		if err = ca.Start(gctx.Done()); err != nil {
			return errors.WithStack(err)
		}
		return nil
	})
	if ca.WaitForCacheSync(gctx.Done()) {
		for resourceName, controller := range controllers {
			if gctx.Err() != nil {
				continue
			}
			resourceName := resourceName
			controller := controller
			g.Go(func() (err error) {
				defer func() {
					ctrl.Log.V(logf.TraceLevel).Error(err, "DEBUG: controller routine finished", "name", name, "resourceName", resourceName)
				}()
				ctrl.Log.V(logf.TraceLevel).Info("DEBUG: controller routine starting", "name", name, "resourceName", resourceName)
				return controller.Start(gctx.Done())
			})
		}
	}
	return g.Wait()
}

// Register registers an injection controller with the given manager, and adds relevant indicies.
func Register(name string, mgr ctrl.Manager, setup injectorSetup, sources []caDataSource, ca cache.Cache) (controller.Controller, error) {
	typ := setup.injector.NewTarget().AsObject()

	c, err := controller.NewUnmanaged(
		// XXX:  strings.ToLower(typ.GetObjectKind().GroupVersionKind().Kind),
		name,
		mgr,
		controller.Options{
			Reconciler: &genericInjectReconciler{
				Client:       mgr.GetClient(),
				sources:      sources,
				log:          ctrl.Log.WithName("inject-controller"),
				resourceName: setup.resourceName,
				injector:     setup.injector,
			},
			MaxConcurrentReconciles: 5,
		})
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if err := c.Watch(source.NewKindWithCache(typ, ca), &handler.EnqueueRequestForObject{}); err != nil {
		return nil, errors.WithStack(err)
	}

	for _, s := range sources {
		if err := s.ApplyTo(mgr, setup, c, ca); err != nil {
			return nil, err
		}
	}

	return c, nil
}

// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
// or an error if an error occurred reading the file
func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
	if len(data) > 0 {
		return data, nil
	}
	if len(file) > 0 {
		fileData, err := ioutil.ReadFile(file)
		if err != nil {
			return []byte{}, err
		}
		return fileData, nil
	}
	return nil, nil
}

// RegisterCertificateBased registers all known injection controllers that
// target Certificate resources with the  given manager, and adds relevant
// indices.
// The registered controllers require the cert-manager API to be available
// in order to run.
func RegisterCertificateBased(ctx context.Context, mgr ctrl.Manager) error {
	cacheOptions := cache.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	ca, err := cache.New(mgr.GetConfig(), cacheOptions)
	if err != nil {
		return errors.WithStack(err)
	}
	return registerAllInjectors(
		ctx,
		"certificate",
		mgr,
		[]caDataSource{
			&certificateDataSource{client: ca},
		},
		ca,
	)
}

// RegisterSecretBased registers all known injection controllers that
// target Secret resources with the  given manager, and adds relevant
// indices.
// The registered controllers only require the corev1 APi to be available in
// order to run.
func RegisterSecretBased(ctx context.Context, mgr ctrl.Manager) error {
	cacheOptions := cache.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	ca, err := cache.New(mgr.GetConfig(), cacheOptions)
	if err != nil {
		return errors.WithStack(err)
	}
	return registerAllInjectors(
		ctx,
		"secret",
		mgr,
		[]caDataSource{
			&secretDataSource{client: ca},
			&kubeconfigDataSource{},
		},
		ca,
	)
}
<|endoftext|>


<commit_before>package ground

import (
	"fmt"

	"github.com/pkg/errors"
	rbac "k8s.io/api/rbac/v1beta1"
	storage "k8s.io/api/storage/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"

	v1 "github.com/sapcc/kubernikus/pkg/apis/kubernikus/v1"
	openstack_project "github.com/sapcc/kubernikus/pkg/client/openstack/project"
	"github.com/sapcc/kubernikus/pkg/controller/config"
	"github.com/sapcc/kubernikus/pkg/controller/ground/bootstrap"
	"github.com/sapcc/kubernikus/pkg/controller/ground/bootstrap/dns"
	"github.com/sapcc/kubernikus/pkg/controller/ground/bootstrap/gpu"
	"github.com/sapcc/kubernikus/pkg/util"
)

func SeedKluster(clients config.Clients, factories config.Factories, kluster *v1.Kluster) error {
	kubernetes, err := clients.Satellites.ClientFor(kluster)
	if err != nil {
		return err
	}

	if err := SeedAllowBootstrapTokensToPostCSRs(kubernetes); err != nil {
		return errors.Wrap(err, "seed allow bootstrap tokens to post CSRs")
	}
	if err := SeedAutoApproveNodeBootstrapTokens(kubernetes); err != nil {
		return errors.Wrap(err, "seed auto approve node bootstrap tokens")
	}
	if err := SeedAutoRenewalNodeCertificates(kubernetes); err != nil {
		return errors.Wrap(err, "seed auto renewal node certificates")
	}
	if err := SeedKubernikusAdmin(kubernetes); err != nil {
		return errors.Wrap(err, "seed kubernikus admin")
	}
	if err := SeedKubernikusMember(kubernetes); err != nil {
		return errors.Wrap(err, "seed kubernikus member")
	}
	if !kluster.Spec.NoCloud {
		openstack, err := factories.Openstack.ProjectAdminClientFor(kluster.Account())
		if err != nil {
			return err
		}
		if err := SeedCinderStorageClasses(kubernetes, openstack); err != nil {
			return errors.Wrap(err, "seed cinder storage classes")
		}
	}
	if err := SeedAllowCertificateControllerToDeleteCSRs(kubernetes); err != nil {
		return errors.Wrap(err, "seed allow certificate controller to delete CSRs")
	}
	if err := SeedAllowApiserverToAccessKubeletAPI(kubernetes); err != nil {
		return errors.Wrap(err, "seed allow apiserver access to kubelet api")
	}
	if ok, _ := util.KlusterVersionConstraint(kluster, ">= 1.16"); ok {
		if err := dns.SeedCoreDNS116(kubernetes, "", "", kluster.Spec.DNSDomain, kluster.Spec.DNSAddress); err != nil {
			return errors.Wrap(err, "seed coredns")
		}
	} else if ok, _ := util.KlusterVersionConstraint(kluster, ">= 1.13"); ok {
		if err := dns.SeedCoreDNS(kubernetes, "", "", kluster.Spec.DNSDomain, kluster.Spec.DNSAddress); err != nil {
			return errors.Wrap(err, "seed coredns")
		}
	} else {
		if err := dns.SeedKubeDNS(kubernetes, "", "", kluster.Spec.DNSDomain, kluster.Spec.DNSAddress); err != nil {
			return errors.Wrap(err, "seed kubedns")
		}
	}

	if ok, _ := util.KlusterVersionConstraint(kluster, ">= 1.10"); ok {
		if err := gpu.SeedGPUSupport(kubernetes); err != nil {
			return errors.Wrap(err, "seed GPU support")
		}
	}

	if err := SeedOpenStackClusterRoleBindings(kubernetes); err != nil {
		return errors.Wrap(err, "seed openstack cluster role bindings")
	}

	return nil
}

func SeedCinderStorageClasses(client clientset.Interface, openstack openstack_project.ProjectClient) error {
	if err := createStorageClass(client, "cinder-default", "", true); err != nil {
		return err
	}

	metadata, err := openstack.GetMetadata()
	if err != nil {
		return err
	}

	for _, avz := range metadata.AvailabilityZones {
		name := fmt.Sprintf("cinder-zone-%s", avz.Name[len(avz.Name)-1:])
		if err := createStorageClass(client, name, avz.Name, false); err != nil {
			return err
		}
	}

	return nil
}

func createStorageClass(client clientset.Interface, name, avz string, isDefault bool) error {
	storageClass := storage.StorageClass{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Provisioner: "kubernetes.io/cinder",
	}

	if isDefault {
		storageClass.Annotations = map[string]string{
			"storageclass.kubernetes.io/is-default-class": "true",
		}
	}

	if avz != "" {
		storageClass.Parameters = map[string]string{
			"availability": avz,
		}
	}

	if _, err := client.StorageV1().StorageClasses().Create(&storageClass); err != nil {
		if !apierrors.IsAlreadyExists(err) {
			return fmt.Errorf("unable to create storage class: %v", err)
		}

		if _, err := client.StorageV1().StorageClasses().Update(&storageClass); err != nil {
			return fmt.Errorf("unable to update storage class: %v", err)
		}
	}

	return nil
}

func SeedKubernikusAdmin(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:admin",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "cluster-admin",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: "os:kubernetes_admin",
			},
		},
	})
}

func SeedKubernikusMember(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "kubernikus:member",
			Namespace: "default",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "Role",
			Name:     "edit",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: "os:kubernetes_member",
			},
		},
	})
}

func SeedAllowBootstrapTokensToPostCSRs(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:kubelet-bootstrap",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "system:node-bootstrapper",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: "system:bootstrappers",
			},
		},
	})
}

func SeedAllowApiserverToAccessKubeletAPI(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:apiserver-kubeletapi",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "system:kubelet-api-admin",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.UserKind,
				Name: "apiserver",
			},
		},
	})
}

// addresses https://github.com/kubernetes/kubernetes/issues/59351
func SeedAllowCertificateControllerToDeleteCSRs(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRole(client, &rbac.ClusterRole{
		ObjectMeta: metav1.ObjectMeta{
			Name: "system:controller:certificate-controller",
			Annotations: map[string]string{
				"rbac.authorization.kubernetes.io/autoupdate": "true",
			},
			Labels: map[string]string{
				"kubernetes.io/bootstrapping": "rbac-defaults",
			},
		},
		Rules: []rbac.PolicyRule{
			{
				Verbs:     []string{"delete", "get", "list", "watch"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests"},
			},
			{
				Verbs:     []string{"update"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests/approval", "certificatesigningrequests/status"},
			},
			{
				Verbs:     []string{"create"},
				APIGroups: []string{"authorization.k8s.io"},
				Resources: []string{"subjectaccessreviews"},
			},
			{
				Verbs:     []string{"create", "patch", "update"},
				APIGroups: []string{""}, //looks funny but is in the default rule ...
				Resources: []string{"events"},
			},
		},
	})
}

func SeedAutoApproveNodeBootstrapTokens(client clientset.Interface) error {
	err := bootstrap.CreateOrUpdateClusterRole(client, &rbac.ClusterRole{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:approve-node-client-csr",
		},
		Rules: []rbac.PolicyRule{
			{
				Verbs:     []string{"create"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests/nodeclient"},
			},
		},
	})
	if err != nil {
		return err
	}

	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:node-client-csr-autoapprove",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "kubernikus:approve-node-client-csr",
		},
		Subjects: []rbac.Subject{
			{
				Kind: "Group",
				Name: "system:bootstrappers",
			},
		},
	})
}

func SeedAutoRenewalNodeCertificates(client clientset.Interface) error {
	err := bootstrap.CreateOrUpdateClusterRole(client, &rbac.ClusterRole{
		ObjectMeta: metav1.ObjectMeta{
			Name: "system:certificates.k8s.io:certificatesigningrequests:selfnodeclient",
		},
		Rules: []rbac.PolicyRule{
			{
				Verbs:     []string{"create"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests/selfnodeclient"},
			},
		},
	})
	if err != nil {
		return err
	}

	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:auto-approve-renewals-for-nodes",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "system:certificates.k8s.io:certificatesigningrequests:selfnodeclient",
		},
		Subjects: []rbac.Subject{
			{
				APIGroup: rbac.GroupName,
				Kind:     "Group",
				Name:     "system:nodes",
			},
		},
	})
}

func SeedOpenStackClusterRoleBindings(client clientset.Interface) error {

	err := bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:openstack-kubernetes-admin",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "cluster-admin",
		},
		Subjects: []rbac.Subject{
			{
				Kind: "Group",
				Name: "openstack_role:kubernetes_admin",
			},
			{
				Kind: "User",
				// It is the marshall & b64enc of the protobuf message IDTokenSubject: https://github.com/dexidp/dex/blob/master/server/oauth2.go#L300
				// User ID: 00000000-0000-0000-0000-000000000001 ConnID: local
				Name: "CiQwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDESBWxvY2Fs",
				// For claims, we are using "sub" instead of "email" since some technical users missing emails
				// If we switch to email, we can directly use email as Name field above
			},
		},
	})

	if err != nil {
		return err
	}

	err = bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:openstack-kubernetes-member",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "view",
		},
		Subjects: []rbac.Subject{
			{
				Kind: "Group",
				Name: "openstack_role:kubernetes_member",
			},
		},
	})

	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Use VolumeBindingWaitForFirstConsumer in storage class (#527)<commit_after>package ground

import (
	"fmt"

	"github.com/pkg/errors"
	rbac "k8s.io/api/rbac/v1beta1"
	storage "k8s.io/api/storage/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"

	v1 "github.com/sapcc/kubernikus/pkg/apis/kubernikus/v1"
	openstack_project "github.com/sapcc/kubernikus/pkg/client/openstack/project"
	"github.com/sapcc/kubernikus/pkg/controller/config"
	"github.com/sapcc/kubernikus/pkg/controller/ground/bootstrap"
	"github.com/sapcc/kubernikus/pkg/controller/ground/bootstrap/dns"
	"github.com/sapcc/kubernikus/pkg/controller/ground/bootstrap/gpu"
	"github.com/sapcc/kubernikus/pkg/util"
)

func SeedKluster(clients config.Clients, factories config.Factories, kluster *v1.Kluster) error {
	kubernetes, err := clients.Satellites.ClientFor(kluster)
	if err != nil {
		return err
	}

	if err := SeedAllowBootstrapTokensToPostCSRs(kubernetes); err != nil {
		return errors.Wrap(err, "seed allow bootstrap tokens to post CSRs")
	}
	if err := SeedAutoApproveNodeBootstrapTokens(kubernetes); err != nil {
		return errors.Wrap(err, "seed auto approve node bootstrap tokens")
	}
	if err := SeedAutoRenewalNodeCertificates(kubernetes); err != nil {
		return errors.Wrap(err, "seed auto renewal node certificates")
	}
	if err := SeedKubernikusAdmin(kubernetes); err != nil {
		return errors.Wrap(err, "seed kubernikus admin")
	}
	if err := SeedKubernikusMember(kubernetes); err != nil {
		return errors.Wrap(err, "seed kubernikus member")
	}
	if !kluster.Spec.NoCloud {
		openstack, err := factories.Openstack.ProjectAdminClientFor(kluster.Account())
		if err != nil {
			return err
		}
		if err := SeedCinderStorageClasses(kubernetes, openstack); err != nil {
			return errors.Wrap(err, "seed cinder storage classes")
		}
	}
	if err := SeedAllowCertificateControllerToDeleteCSRs(kubernetes); err != nil {
		return errors.Wrap(err, "seed allow certificate controller to delete CSRs")
	}
	if err := SeedAllowApiserverToAccessKubeletAPI(kubernetes); err != nil {
		return errors.Wrap(err, "seed allow apiserver access to kubelet api")
	}
	if ok, _ := util.KlusterVersionConstraint(kluster, ">= 1.16"); ok {
		if err := dns.SeedCoreDNS116(kubernetes, "", "", kluster.Spec.DNSDomain, kluster.Spec.DNSAddress); err != nil {
			return errors.Wrap(err, "seed coredns")
		}
	} else if ok, _ := util.KlusterVersionConstraint(kluster, ">= 1.13"); ok {
		if err := dns.SeedCoreDNS(kubernetes, "", "", kluster.Spec.DNSDomain, kluster.Spec.DNSAddress); err != nil {
			return errors.Wrap(err, "seed coredns")
		}
	} else {
		if err := dns.SeedKubeDNS(kubernetes, "", "", kluster.Spec.DNSDomain, kluster.Spec.DNSAddress); err != nil {
			return errors.Wrap(err, "seed kubedns")
		}
	}

	if ok, _ := util.KlusterVersionConstraint(kluster, ">= 1.10"); ok {
		if err := gpu.SeedGPUSupport(kubernetes); err != nil {
			return errors.Wrap(err, "seed GPU support")
		}
	}

	if err := SeedOpenStackClusterRoleBindings(kubernetes); err != nil {
		return errors.Wrap(err, "seed openstack cluster role bindings")
	}

	return nil
}

func SeedCinderStorageClasses(client clientset.Interface, openstack openstack_project.ProjectClient) error {
	if err := createStorageClass(client, "cinder-default", "", true); err != nil {
		return err
	}

	metadata, err := openstack.GetMetadata()
	if err != nil {
		return err
	}

	for _, avz := range metadata.AvailabilityZones {
		name := fmt.Sprintf("cinder-zone-%s", avz.Name[len(avz.Name)-1:])
		if err := createStorageClass(client, name, avz.Name, false); err != nil {
			return err
		}
	}

	return nil
}

func createStorageClass(client clientset.Interface, name, avz string, isDefault bool) error {
	mode := storage.VolumeBindingWaitForFirstConsumer

	storageClass := storage.StorageClass{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Provisioner:       "kubernetes.io/cinder",
		VolumeBindingMode: &mode,
	}

	if isDefault {
		storageClass.Annotations = map[string]string{
			"storageclass.kubernetes.io/is-default-class": "true",
		}
	}

	if avz != "" {
		storageClass.Parameters = map[string]string{
			"availability": avz,
		}
	}

	if _, err := client.StorageV1().StorageClasses().Create(&storageClass); err != nil {
		if !apierrors.IsAlreadyExists(err) {
			return fmt.Errorf("unable to create storage class: %v", err)
		}

		if _, err := client.StorageV1().StorageClasses().Update(&storageClass); err != nil {
			return fmt.Errorf("unable to update storage class: %v", err)
		}
	}

	return nil
}

func SeedKubernikusAdmin(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:admin",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "cluster-admin",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: "os:kubernetes_admin",
			},
		},
	})
}

func SeedKubernikusMember(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "kubernikus:member",
			Namespace: "default",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "Role",
			Name:     "edit",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: "os:kubernetes_member",
			},
		},
	})
}

func SeedAllowBootstrapTokensToPostCSRs(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:kubelet-bootstrap",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "system:node-bootstrapper",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: "system:bootstrappers",
			},
		},
	})
}

func SeedAllowApiserverToAccessKubeletAPI(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:apiserver-kubeletapi",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "system:kubelet-api-admin",
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.UserKind,
				Name: "apiserver",
			},
		},
	})
}

// addresses https://github.com/kubernetes/kubernetes/issues/59351
func SeedAllowCertificateControllerToDeleteCSRs(client clientset.Interface) error {
	return bootstrap.CreateOrUpdateClusterRole(client, &rbac.ClusterRole{
		ObjectMeta: metav1.ObjectMeta{
			Name: "system:controller:certificate-controller",
			Annotations: map[string]string{
				"rbac.authorization.kubernetes.io/autoupdate": "true",
			},
			Labels: map[string]string{
				"kubernetes.io/bootstrapping": "rbac-defaults",
			},
		},
		Rules: []rbac.PolicyRule{
			{
				Verbs:     []string{"delete", "get", "list", "watch"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests"},
			},
			{
				Verbs:     []string{"update"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests/approval", "certificatesigningrequests/status"},
			},
			{
				Verbs:     []string{"create"},
				APIGroups: []string{"authorization.k8s.io"},
				Resources: []string{"subjectaccessreviews"},
			},
			{
				Verbs:     []string{"create", "patch", "update"},
				APIGroups: []string{""}, //looks funny but is in the default rule ...
				Resources: []string{"events"},
			},
		},
	})
}

func SeedAutoApproveNodeBootstrapTokens(client clientset.Interface) error {
	err := bootstrap.CreateOrUpdateClusterRole(client, &rbac.ClusterRole{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:approve-node-client-csr",
		},
		Rules: []rbac.PolicyRule{
			{
				Verbs:     []string{"create"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests/nodeclient"},
			},
		},
	})
	if err != nil {
		return err
	}

	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:node-client-csr-autoapprove",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "kubernikus:approve-node-client-csr",
		},
		Subjects: []rbac.Subject{
			{
				Kind: "Group",
				Name: "system:bootstrappers",
			},
		},
	})
}

func SeedAutoRenewalNodeCertificates(client clientset.Interface) error {
	err := bootstrap.CreateOrUpdateClusterRole(client, &rbac.ClusterRole{
		ObjectMeta: metav1.ObjectMeta{
			Name: "system:certificates.k8s.io:certificatesigningrequests:selfnodeclient",
		},
		Rules: []rbac.PolicyRule{
			{
				Verbs:     []string{"create"},
				APIGroups: []string{"certificates.k8s.io"},
				Resources: []string{"certificatesigningrequests/selfnodeclient"},
			},
		},
	})
	if err != nil {
		return err
	}

	return bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:auto-approve-renewals-for-nodes",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "system:certificates.k8s.io:certificatesigningrequests:selfnodeclient",
		},
		Subjects: []rbac.Subject{
			{
				APIGroup: rbac.GroupName,
				Kind:     "Group",
				Name:     "system:nodes",
			},
		},
	})
}

func SeedOpenStackClusterRoleBindings(client clientset.Interface) error {

	err := bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:openstack-kubernetes-admin",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "cluster-admin",
		},
		Subjects: []rbac.Subject{
			{
				Kind: "Group",
				Name: "openstack_role:kubernetes_admin",
			},
			{
				Kind: "User",
				// It is the marshall & b64enc of the protobuf message IDTokenSubject: https://github.com/dexidp/dex/blob/master/server/oauth2.go#L300
				// User ID: 00000000-0000-0000-0000-000000000001 ConnID: local
				Name: "CiQwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDESBWxvY2Fs",
				// For claims, we are using "sub" instead of "email" since some technical users missing emails
				// If we switch to email, we can directly use email as Name field above
			},
		},
	})

	if err != nil {
		return err
	}

	err = bootstrap.CreateOrUpdateClusterRoleBinding(client, &rbac.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: "kubernikus:openstack-kubernetes-member",
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "ClusterRole",
			Name:     "view",
		},
		Subjects: []rbac.Subject{
			{
				Kind: "Group",
				Name: "openstack_role:kubernetes_member",
			},
		},
	})

	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package credentialprovider

import (
	"os"
	"reflect"
	"sync"
	"time"

	"github.com/golang/glog"
)

// DockerConfigProvider is the interface that registered extensions implement
// to materialize 'dockercfg' credentials.
type DockerConfigProvider interface {
	Enabled() bool
	Provide() DockerConfig
}

// A DockerConfigProvider that simply reads the .dockersfg file
type defaultDockerConfigProvider struct{}

// init registers our default provider, which simply reads the .dockercfg file.
func init() {
	RegisterCredentialProvider(".dockercfg",
		&CachingDockerConfigProvider{
			Provider: &defaultDockerConfigProvider{},
			Lifetime: 5 * time.Minute,
		})
}

// CachingDockerConfigProvider implements DockerConfigProvider by composing
// with another DockerConfigProvider and caching the DockerConfig it provides
// for a pre-specified lifetime.
type CachingDockerConfigProvider struct {
	Provider DockerConfigProvider
	Lifetime time.Duration

	// cache fields
	cacheDockerConfig DockerConfig
	expiration        time.Time
	mu                sync.Mutex
}

// Enabled implements dockerConfigProvider
func (d *defaultDockerConfigProvider) Enabled() bool {
	return true
}

// Provide implements dockerConfigProvider
func (d *defaultDockerConfigProvider) Provide() DockerConfig {
	// Read the standard Docker credentials from .dockercfg
	if cfg, err := ReadDockerConfigFile(); err == nil {
		return cfg
	} else if !os.IsNotExist(err) {
		glog.V(4).Infof("Unable to parse Docker config file: %v", err)
	}
	return DockerConfig{}
}

// Enabled implements dockerConfigProvider
func (d *CachingDockerConfigProvider) Enabled() bool {
	return d.Provider.Enabled()
}

// Provide implements dockerConfigProvider
func (d *CachingDockerConfigProvider) Provide() DockerConfig {
	d.mu.Lock()
	defer d.mu.Unlock()

	// If the cache hasn't expired, return our cache
	if time.Now().Before(d.expiration) {
		return d.cacheDockerConfig
	}

	glog.Infof("Refreshing cache for provider: %v", reflect.TypeOf(d.Provider).String())
	d.cacheDockerConfig = d.Provider.Provide()
	d.expiration = time.Now().Add(d.Lifetime)
	return d.cacheDockerConfig
}
<commit_msg>Fix typo in provider.go<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package credentialprovider

import (
	"os"
	"reflect"
	"sync"
	"time"

	"github.com/golang/glog"
)

// DockerConfigProvider is the interface that registered extensions implement
// to materialize 'dockercfg' credentials.
type DockerConfigProvider interface {
	Enabled() bool
	Provide() DockerConfig
}

// A DockerConfigProvider that simply reads the .dockercfg file
type defaultDockerConfigProvider struct{}

// init registers our default provider, which simply reads the .dockercfg file.
func init() {
	RegisterCredentialProvider(".dockercfg",
		&CachingDockerConfigProvider{
			Provider: &defaultDockerConfigProvider{},
			Lifetime: 5 * time.Minute,
		})
}

// CachingDockerConfigProvider implements DockerConfigProvider by composing
// with another DockerConfigProvider and caching the DockerConfig it provides
// for a pre-specified lifetime.
type CachingDockerConfigProvider struct {
	Provider DockerConfigProvider
	Lifetime time.Duration

	// cache fields
	cacheDockerConfig DockerConfig
	expiration        time.Time
	mu                sync.Mutex
}

// Enabled implements dockerConfigProvider
func (d *defaultDockerConfigProvider) Enabled() bool {
	return true
}

// Provide implements dockerConfigProvider
func (d *defaultDockerConfigProvider) Provide() DockerConfig {
	// Read the standard Docker credentials from .dockercfg
	if cfg, err := ReadDockerConfigFile(); err == nil {
		return cfg
	} else if !os.IsNotExist(err) {
		glog.V(4).Infof("Unable to parse Docker config file: %v", err)
	}
	return DockerConfig{}
}

// Enabled implements dockerConfigProvider
func (d *CachingDockerConfigProvider) Enabled() bool {
	return d.Provider.Enabled()
}

// Provide implements dockerConfigProvider
func (d *CachingDockerConfigProvider) Provide() DockerConfig {
	d.mu.Lock()
	defer d.mu.Unlock()

	// If the cache hasn't expired, return our cache
	if time.Now().Before(d.expiration) {
		return d.cacheDockerConfig
	}

	glog.Infof("Refreshing cache for provider: %v", reflect.TypeOf(d.Provider).String())
	d.cacheDockerConfig = d.Provider.Provide()
	d.expiration = time.Now().Add(d.Lifetime)
	return d.cacheDockerConfig
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Hubble

package drop

import (
	"context"

	"github.com/prometheus/client_golang/prometheus"

	flowpb "github.com/cilium/cilium/api/v1/flow"
	v1 "github.com/cilium/cilium/pkg/hubble/api/v1"
	"github.com/cilium/cilium/pkg/hubble/metrics/api"
	monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
)

type dropHandler struct {
	drops   *prometheus.CounterVec
	context *api.ContextOptions
}

func (d *dropHandler) Init(registry *prometheus.Registry, options api.Options) error {
	c, err := api.ParseContextOptions(options)
	if err != nil {
		return err
	}
	d.context = c

	labels := []string{"reason", "protocol"}
	labels = append(labels, d.context.GetLabelNames()...)

	d.drops = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: api.DefaultPrometheusNamespace,
		Name:      "drop_total",
		Help:      "Number of drops",
	}, labels)

	registry.MustRegister(d.drops)
	return nil
}

func (d *dropHandler) Status() string {
	return d.context.Status()
}

func (d *dropHandler) ProcessFlow(ctx context.Context, flow *flowpb.Flow) error {
	if flow.GetVerdict() != flowpb.Verdict_DROPPED {
		return nil
	}

	labels, err := d.context.GetLabelValues(flow)
	if err != nil {
		return err
	}

	labels = append(labels, monitorAPI.DropReason(uint8(flow.GetDropReason())), v1.FlowProtocol(flow))

	d.drops.WithLabelValues(labels...).Inc()
	return nil
}
<commit_msg>hubble/metrics: Fix drop metric label ordering<commit_after>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Hubble

package drop

import (
	"context"

	"github.com/prometheus/client_golang/prometheus"

	flowpb "github.com/cilium/cilium/api/v1/flow"
	v1 "github.com/cilium/cilium/pkg/hubble/api/v1"
	"github.com/cilium/cilium/pkg/hubble/metrics/api"
	monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
)

type dropHandler struct {
	drops   *prometheus.CounterVec
	context *api.ContextOptions
}

func (d *dropHandler) Init(registry *prometheus.Registry, options api.Options) error {
	c, err := api.ParseContextOptions(options)
	if err != nil {
		return err
	}
	d.context = c

	contextLabels := d.context.GetLabelNames()
	labels := append(contextLabels, "reason", "protocol")

	d.drops = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: api.DefaultPrometheusNamespace,
		Name:      "drop_total",
		Help:      "Number of drops",
	}, labels)

	registry.MustRegister(d.drops)
	return nil
}

func (d *dropHandler) Status() string {
	return d.context.Status()
}

func (d *dropHandler) ProcessFlow(ctx context.Context, flow *flowpb.Flow) error {
	if flow.GetVerdict() != flowpb.Verdict_DROPPED {
		return nil
	}

	contextLabels, err := d.context.GetLabelValues(flow)
	if err != nil {
		return err
	}

	labels := append(contextLabels, monitorAPI.DropReason(uint8(flow.GetDropReason())), v1.FlowProtocol(flow))

	d.drops.WithLabelValues(labels...).Inc()
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Mirantis

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 libvirttools

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

	libvirtxml "github.com/libvirt/libvirt-go-xml"

	"github.com/Mirantis/virtlet/pkg/utils"
)

type rawVolumeOptions struct {
	Path string `json:"path"`
	Uuid string `json:"uuid"`
}

func (vo *rawVolumeOptions) validate() error {
	if !strings.HasPrefix(vo.Path, "/dev/") {
		return fmt.Errorf("raw volume path needs to be prefixed by '/dev/', but it's whole value is: ", vo.Path)
	}
	return nil
}

// rawDeviceVolume denotes a raw device that's made accessible for a VM
type rawDeviceVolume struct {
	volumeBase
	opts *rawVolumeOptions
}

var _ VMVolume = &rawDeviceVolume{}

func newRawDeviceVolume(volumeName, configPath string, config *VMConfig, owner VolumeOwner) (VMVolume, error) {
	var opts rawVolumeOptions
	if err := utils.ReadJson(configPath, &opts); err != nil {
		return nil, fmt.Errorf("failed to parse raw volume config %q: %v", configPath, err)
	}
	if err := opts.validate(); err != nil {
		return nil, err
	}
	return &rawDeviceVolume{
		volumeBase: volumeBase{config, owner},
		opts:       &opts,
	}, nil
}

func (v *rawDeviceVolume) verifyRawDeviceWhitelisted(path string) error {
	for _, deviceTemplate := range v.owner.RawDevices() {
		devicePaths, err := filepath.Glob("/dev/" + deviceTemplate)
		if err != nil {
			return fmt.Errorf("error in raw device whitelist glob pattern '%s': %v", deviceTemplate, err)
		}
		for _, devicePath := range devicePaths {
			if path == devicePath {
				return nil
			}
		}
	}
	return fmt.Errorf("device '%s' not whitelisted on this virtlet node", path)
}

func (v *rawDeviceVolume) Uuid() string {
	return v.opts.Uuid
}

func (v *rawDeviceVolume) Setup() (*libvirtxml.DomainDisk, error) {
	if err := v.verifyRawDeviceWhitelisted(v.opts.Path); err != nil {
		return nil, err
	}

	if err := verifyRawDeviceAccess(v.opts.Path); err != nil {
		return nil, err
	}
	return &libvirtxml.DomainDisk{
		Type:   "block",
		Device: "disk",
		Source: &libvirtxml.DomainDiskSource{Device: v.opts.Path},
		Driver: &libvirtxml.DomainDiskDriver{Name: "qemu", Type: "raw"},
	}, nil
}

func init() {
	AddFlexvolumeSource("raw", newRawDeviceVolume)
}

// TODO: this file needs a test
<commit_msg>Avoid unneeded Linux /dev dep in raw flexvolumes<commit_after>/*
Copyright 2017 Mirantis

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 libvirttools

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

	libvirtxml "github.com/libvirt/libvirt-go-xml"

	"github.com/Mirantis/virtlet/pkg/utils"
)

type rawVolumeOptions struct {
	Path string `json:"path"`
	Uuid string `json:"uuid"`
}

func (vo *rawVolumeOptions) validate() error {
	if !strings.HasPrefix(vo.Path, "/dev/") {
		return fmt.Errorf("raw volume path needs to be prefixed by '/dev/', but it's whole value is: ", vo.Path)
	}
	return nil
}

// rawDeviceVolume denotes a raw device that's made accessible for a VM
type rawDeviceVolume struct {
	volumeBase
	opts *rawVolumeOptions
}

var _ VMVolume = &rawDeviceVolume{}

func newRawDeviceVolume(volumeName, configPath string, config *VMConfig, owner VolumeOwner) (VMVolume, error) {
	var opts rawVolumeOptions
	if err := utils.ReadJson(configPath, &opts); err != nil {
		return nil, fmt.Errorf("failed to parse raw volume config %q: %v", configPath, err)
	}
	if err := opts.validate(); err != nil {
		return nil, err
	}
	return &rawDeviceVolume{
		volumeBase: volumeBase{config, owner},
		opts:       &opts,
	}, nil
}

func (v *rawDeviceVolume) verifyRawDeviceWhitelisted(path string) error {
	for _, deviceTemplate := range v.owner.RawDevices() {
		matches, err := filepath.Match("/dev/"+deviceTemplate, path)
		if err != nil {
			return fmt.Errorf("bad raw device whitelist glob pattern '%s': %v", deviceTemplate, err)
		}
		if matches {
			return nil
		}
	}
	return fmt.Errorf("device '%s' not whitelisted on this virtlet node", path)
}

func (v *rawDeviceVolume) Uuid() string {
	return v.opts.Uuid
}

func (v *rawDeviceVolume) Setup() (*libvirtxml.DomainDisk, error) {
	if err := v.verifyRawDeviceWhitelisted(v.opts.Path); err != nil {
		return nil, err
	}

	if err := verifyRawDeviceAccess(v.opts.Path); err != nil {
		return nil, err
	}
	return &libvirtxml.DomainDisk{
		Type:   "block",
		Device: "disk",
		Source: &libvirtxml.DomainDiskSource{Device: v.opts.Path},
		Driver: &libvirtxml.DomainDiskDriver{Name: "qemu", Type: "raw"},
	}, nil
}

func init() {
	AddFlexvolumeSource("raw", newRawDeviceVolume)
}

// TODO: this file needs a test
<|endoftext|>