<commit_before>package gopush

import (
	"github.com/appleboy/gofight"
	"github.com/buger/jsonparser"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"net/http"
	"os"
	"runtime"
	"testing"
	"time"
)

var go_version = runtime.Version()

func initTest() {
	PushConf = BuildDefaultPushConf()
	PushConf.Core.Mode = "test"
}

func TestPrintGoPushVersion(t *testing.T) {
	PrintGoPushVersion()
}

func TestRunNormalServer(t *testing.T) {
	initTest()

	gin.SetMode(gin.TestMode)

	router := gin.New()

	go func() {
		assert.NoError(t, RunHTTPServer())
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, router.Run(":8088"))
	gofight.TestRequest(t, "http://localhost:8088/api/status")
}

// func TestRunTLSServer(t *testing.T) {
// 	initTest()

// 	PushConf.Core.SSL = true
// 	PushConf.Core.Port = "8087"
// 	PushConf.Core.CertPath = "../certificate/localhost.cert"
// 	PushConf.Core.KeyPath = "../certificate/localhost.key"
// 	router := gin.New()

// 	go func() {
// 		assert.NoError(t, RunHTTPServer())
// 	}()
// 	// have to wait for the goroutine to start and run the server
// 	// otherwise the main thread will complete
// 	time.Sleep(5 * time.Millisecond)

// 	assert.Error(t, router.Run(":8087"))
// 	testRequest(t, "https://localhost:8087/api/status")
// }

func TestRootHandler(t *testing.T) {
	initTest()

	r := gofight.New()

	r.GET("/").
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			data := []byte(r.Body.String())

			value, _ := jsonparser.GetString(data, "text")

			assert.Equal(t, "Welcome to notification server.", value)
			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestAPIStatusHandler(t *testing.T) {
	initTest()

	r := gofight.New()

	r.GET("/api/status").
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			data := []byte(r.Body.String())

			value, _ := jsonparser.GetString(data, "go_version")

			assert.Equal(t, go_version, value)
			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestMissingParameterPushHandler(t *testing.T) {
	initTest()

	r := gofight.New()

	// missing some parameter.
	r.POST("/api/push").
		SetJSON(gofight.D{
			"platform": 1,
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusBadRequest, r.Code)
		})
}

func TestDisabledIosPushHandler(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = false
	InitAPNSClient()

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
			"platform": 1,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestMissingIosCertificate(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = true
	PushConf.Ios.PemKeyPath = "test"
	err := InitAPNSClient()

	assert.Error(t, err)
}

func TestIosPushDevelopment(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = true
	PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem"
	InitAPNSClient()

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
			"platform": 1,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestIosPushProduction(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = true
	PushConf.Ios.Production = true
	PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem"
	InitAPNSClient()

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
			"platform": 1,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestDisabledAndroidPushHandler(t *testing.T) {
	initTest()

	PushConf.Android.Enabled = false

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"aaaaaa", "bbbbb"},
			"platform": 2,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestAndroidPushHandler(t *testing.T) {
	initTest()

	PushConf.Android.Enabled = true
	PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY")

	android_token := os.Getenv("ANDROID_TEST_TOKEN")

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{android_token, "bbbbb"},
			"platform": 2,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}
<commit_msg>update test server listen on same port.<commit_after>package gopush

import (
	"github.com/appleboy/gofight"
	"github.com/buger/jsonparser"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"net/http"
	"os"
	"runtime"
	"testing"
	"time"
)

var go_version = runtime.Version()

func initTest() {
	PushConf = BuildDefaultPushConf()
	PushConf.Core.Mode = "test"
}

func TestPrintGoPushVersion(t *testing.T) {
	PrintGoPushVersion()
}

func TestRunNormalServer(t *testing.T) {
	initTest()

	gin.SetMode(gin.TestMode)

	go func() {
		assert.NoError(t, RunHTTPServer())
	}()
	// have to wait for the goroutine to start and run the server
	// otherwise the main thread will complete
	time.Sleep(5 * time.Millisecond)

	assert.Error(t, RunHTTPServer())
	gofight.TestRequest(t, "http://localhost:8088/api/status")
}

// func TestRunTLSServer(t *testing.T) {
// 	initTest()

// 	PushConf.Core.SSL = true
// 	PushConf.Core.Port = "8087"
// 	PushConf.Core.CertPath = "../certificate/localhost.cert"
// 	PushConf.Core.KeyPath = "../certificate/localhost.key"
// 	router := gin.New()

// 	go func() {
// 		assert.NoError(t, RunHTTPServer())
// 	}()
// 	// have to wait for the goroutine to start and run the server
// 	// otherwise the main thread will complete
// 	time.Sleep(5 * time.Millisecond)

// 	assert.Error(t, router.Run(":8087"))
// 	testRequest(t, "https://localhost:8087/api/status")
// }

func TestRootHandler(t *testing.T) {
	initTest()

	r := gofight.New()

	r.GET("/").
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			data := []byte(r.Body.String())

			value, _ := jsonparser.GetString(data, "text")

			assert.Equal(t, "Welcome to notification server.", value)
			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestAPIStatusHandler(t *testing.T) {
	initTest()

	r := gofight.New()

	r.GET("/api/status").
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
			data := []byte(r.Body.String())

			value, _ := jsonparser.GetString(data, "go_version")

			assert.Equal(t, go_version, value)
			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestMissingParameterPushHandler(t *testing.T) {
	initTest()

	r := gofight.New()

	// missing some parameter.
	r.POST("/api/push").
		SetJSON(gofight.D{
			"platform": 1,
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusBadRequest, r.Code)
		})
}

func TestDisabledIosPushHandler(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = false
	InitAPNSClient()

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
			"platform": 1,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestMissingIosCertificate(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = true
	PushConf.Ios.PemKeyPath = "test"
	err := InitAPNSClient()

	assert.Error(t, err)
}

func TestIosPushDevelopment(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = true
	PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem"
	InitAPNSClient()

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
			"platform": 1,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestIosPushProduction(t *testing.T) {
	initTest()

	PushConf.Ios.Enabled = true
	PushConf.Ios.Production = true
	PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem"
	InitAPNSClient()

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
			"platform": 1,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestDisabledAndroidPushHandler(t *testing.T) {
	initTest()

	PushConf.Android.Enabled = false

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{"aaaaaa", "bbbbb"},
			"platform": 2,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}

func TestAndroidPushHandler(t *testing.T) {
	initTest()

	PushConf.Android.Enabled = true
	PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY")

	android_token := os.Getenv("ANDROID_TEST_TOKEN")

	r := gofight.New()

	r.POST("/api/push").
		SetJSON(gofight.D{
			"tokens":   []string{android_token, "bbbbb"},
			"platform": 2,
			"message":  "Welcome",
		}).
		Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {

			assert.Equal(t, http.StatusOK, r.Code)
		})
}
<|endoftext|>


<commit_before>//
package gnuplot

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
    "exec"
)

var g_gnuplot_cmd string
var g_gnuplot_prefix string = "go-gnuplot-"

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func init() {
	var err os.Error
	g_gnuplot_cmd, err = exec.LookPath("gnuplot")
	if err != nil {
		fmt.Printf("** could not find path to 'gnuplot':\n%v\n", err)
		panic("could not find 'gnuplot'")
	}
	fmt.Printf("-- found gnuplot command: %s\n", g_gnuplot_cmd)
}

type gnuplot_error struct {
	err string
}

func (e *gnuplot_error) String() string {
	return e.err
}

type plotter_process struct {
	handle *exec.Cmd
	stdin  io.WriteCloser
}

func new_plotter_proc(persist bool) (*plotter_process, os.Error) {
	proc_args := []string{}
	if persist {
		proc_args = append(proc_args, "-persist")
	}
	fmt.Printf("--> [%v] %v\n", g_gnuplot_cmd, proc_args)
	cmd := exec.Command(g_gnuplot_cmd, proc_args...)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return nil, err
	}
	return &plotter_process{handle: cmd, stdin: stdin}, cmd.Start()
}

type tmpfiles_db map[string]*os.File

type Plotter struct {
	proc     *plotter_process
	debug    bool
	plotcmd  string
	nplots   int    // number of currently active plots
	style    string // current plotting style
	tmpfiles tmpfiles_db
}

func (self *Plotter) Cmd(format string, a ...interface{}) os.Error {
	cmd := fmt.Sprintf(format, a...) + "\n"
	n, err := io.WriteString(self.proc.stdin, cmd)

	if self.debug {
		//buf := new(bytes.Buffer)
		//io.Copy(buf, self.proc.handle.Stdout)
		fmt.Printf("cmd> %v", cmd)
		fmt.Printf("res> %v\n", n)
	}

	return err
}

func (self *Plotter) CheckedCmd(format string, a ...interface{}) {
	err := self.Cmd(format, a...)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
}

func (self *Plotter) Close() (err os.Error) {
	if self.proc != nil && self.proc.handle != nil {
		self.proc.stdin.Close()
		err = self.proc.handle.Wait()
	}
	self.ResetPlot()
	return err
}

func (self *Plotter) PlotNd(title string, data ...[]float64) os.Error {
	ndims := len(data)

	switch ndims {
	case 1:
		return self.PlotX(data[0], title)
	case 2:
		return self.PlotXY(data[0], data[1], title)
	case 3:
		return self.PlotXYZ(data[0], data[1], data[2], title)
	}

	return &gnuplot_error{fmt.Sprintf("invalid number of dims '%v'", ndims)}
}

func (self *Plotter) PlotX(data []float64, title string) os.Error {
	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f
	for _, d := range data {
		f.WriteString(fmt.Sprintf("%v\n", d))
	}
	f.Close()
	cmd := self.plotcmd
	if self.nplots > 0 {
		cmd = "replot"
	}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

func (self *Plotter) PlotXY(x, y []float64, title string) os.Error {
	npoints := min(len(x), len(y))

	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f

	for i := 0; i < npoints; i++ {
		f.WriteString(fmt.Sprintf("%v %v\n", x[i], y[i]))
	}

	f.Close()
	cmd := self.plotcmd
	if self.nplots > 0 {
		cmd = "replot"
	}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

func (self *Plotter) PlotXYZ(x, y, z []float64, title string) os.Error {
	npoints := min(len(x), len(y))
	npoints = min(npoints, len(z))
	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f

	for i := 0; i < npoints; i++ {
		f.WriteString(fmt.Sprintf("%v %v %v\n", x[i], y[i], z[i]))
	}

	f.Close()
	cmd := "splot" // Force 3D plot
	if self.nplots > 0 {
		cmd = "replot"
	}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

type Func func(x float64) float64

func (self *Plotter) PlotFunc(data []float64, fct Func, title string) os.Error {

	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f

	for _, x := range data {
		f.WriteString(fmt.Sprintf("%v %v\n", x, fct(x)))
	}

	f.Close()
	cmd := self.plotcmd
	if self.nplots > 0 {
		cmd = "replot"
	}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

func (self *Plotter) SetPlotCmd(cmd string) (err os.Error) {
	switch cmd {
	case "plot", "splot":
		self.plotcmd = cmd
	default:
		err = os.NewError("invalid plot cmd [" + cmd + "]")
	}
	return err
}

func (self *Plotter) SetStyle(style string) (err os.Error) {
	allowed := []string{
		"lines", "points", "linepoints",
		"impulses", "dots",
		"steps",
		"errorbars",
		"boxes",
		"boxerrorbars",
		"pm3d"}

	for _, s := range allowed {
		if s == style {
			self.style = style
			err = nil
			return err
		}
	}

	fmt.Printf("** style '%v' not in allowed list %v\n", style, allowed)
	fmt.Printf("** default to 'points'\n")
	self.style = "points"
	err = &gnuplot_error{fmt.Sprintf("invalid style '%s'", style)}

	return err
}

func (self *Plotter) SetXLabel(label string) os.Error {
	return self.Cmd(fmt.Sprintf("set xlabel '%s'", label))
}

func (self *Plotter) SetYLabel(label string) os.Error {
	return self.Cmd(fmt.Sprintf("set ylabel '%s'", label))
}

func (self *Plotter) SetZLabel(label string) os.Error {
	return self.Cmd(fmt.Sprintf("set zlabel '%s'", label))
}

func (self *Plotter) SetLabels(labels ...string) os.Error {
	ndims := len(labels)
	if ndims > 3 || ndims <= 0 {
		return &gnuplot_error{fmt.Sprintf("invalid number of dims '%v'", ndims)}
	}
	var err os.Error = nil

	for i, label := range labels {
		switch i {
		case 0:
			ierr := self.SetXLabel(label)
			if ierr != nil {
				err = ierr
				return err
			}
		case 1:
			ierr := self.SetYLabel(label)
			if ierr != nil {
				err = ierr
				return err
			}
		case 2:
			ierr := self.SetZLabel(label)
			if ierr != nil {
				err = ierr
				return err
			}
		}
	}
	return nil
}

func (self *Plotter) ResetPlot() (err os.Error) {
	for fname, fhandle := range self.tmpfiles {
		ferr := fhandle.Close()
		if ferr != nil {
			err = ferr
		}
		os.Remove(fname)
	}
	self.nplots = 0
	return err
}

func NewPlotter(fname string, persist, debug bool) (*Plotter, os.Error) {
	p := &Plotter{proc: nil, debug: debug, plotcmd: "plot",
		nplots: 0, style: "points"}
	p.tmpfiles = make(tmpfiles_db)

	if fname != "" {
		panic("NewPlotter with fname is not yet supported")
	} else {
		proc, err := new_plotter_proc(persist)
		if err != nil {
			return nil, err
		}
		p.proc = proc
	}
	return p, nil
}

/* EOF */
<commit_msg>Hacked gnuplot for realtime publishing.<commit_after>//
package gnuplot

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
    "exec"
)

var g_gnuplot_cmd string
var g_gnuplot_prefix string = "go-gnuplot-"

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func init() {
	var err os.Error
	g_gnuplot_cmd, err = exec.LookPath("gnuplot")
	if err != nil {
		fmt.Printf("** could not find path to 'gnuplot':\n%v\n", err)
		panic("could not find 'gnuplot'")
	}
	fmt.Printf("-- found gnuplot command: %s\n", g_gnuplot_cmd)
}

type gnuplot_error struct {
	err string
}

func (e *gnuplot_error) String() string {
	return e.err
}

type plotter_process struct {
	handle *exec.Cmd
	stdin  io.WriteCloser
}

func new_plotter_proc(persist bool) (*plotter_process, os.Error) {
	proc_args := []string{}
	if persist {
		proc_args = append(proc_args, "-persist")
	}
	fmt.Printf("--> [%v] %v\n", g_gnuplot_cmd, proc_args)
	cmd := exec.Command(g_gnuplot_cmd, proc_args...)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return nil, err
	}
	return &plotter_process{handle: cmd, stdin: stdin}, cmd.Start()
}

type tmpfiles_db map[string]*os.File

type Plotter struct {
	proc     *plotter_process
	debug    bool
	plotcmd  string
	nplots   int    // number of currently active plots
	style    string // current plotting style
	tmpfiles tmpfiles_db
}

func (self *Plotter) Cmd(format string, a ...interface{}) os.Error {
	cmd := fmt.Sprintf(format, a...) + "\n"
	n, err := io.WriteString(self.proc.stdin, cmd)

	if self.debug {
		//buf := new(bytes.Buffer)
		//io.Copy(buf, self.proc.handle.Stdout)
		fmt.Printf("cmd> %v", cmd)
		fmt.Printf("res> %v\n", n)
	}

	return err
}

func (self *Plotter) CheckedCmd(format string, a ...interface{}) {
	err := self.Cmd(format, a...)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
}

func (self *Plotter) Close() (err os.Error) {
	if self.proc != nil && self.proc.handle != nil {
		self.proc.stdin.Close()
		err = self.proc.handle.Wait()
	}
	self.ResetPlot()
	return err
}

func (self *Plotter) PlotNd(title string, data ...[]float64) os.Error {
	ndims := len(data)

	switch ndims {
	case 1:
		return self.PlotX(data[0], title)
	case 2:
		return self.PlotXY(data[0], data[1], title)
	case 3:
		return self.PlotXYZ(data[0], data[1], data[2], title)
	}

	return &gnuplot_error{fmt.Sprintf("invalid number of dims '%v'", ndims)}
}

func (self *Plotter) PlotX(data []float64, title string) os.Error {
	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f
	for _, d := range data {
		f.WriteString(fmt.Sprintf("%v\n", d))
	}
	f.Close()
	cmd := self.plotcmd
	//if self.nplots > 0 {
	//	cmd = "replot"
	//}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s lw .7",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

func (self *Plotter) PlotXY(x, y []float64, title string) os.Error {
	npoints := min(len(x), len(y))

	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f

	for i := 0; i < npoints; i++ {
		f.WriteString(fmt.Sprintf("%v %v\n", x[i], y[i]))
	}

	f.Close()
	cmd := self.plotcmd
	if self.nplots > 0 {
		cmd = "replot"
	}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

func (self *Plotter) PlotXYZ(x, y, z []float64, title string) os.Error {
	npoints := min(len(x), len(y))
	npoints = min(npoints, len(z))
	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f

	for i := 0; i < npoints; i++ {
		f.WriteString(fmt.Sprintf("%v %v %v\n", x[i], y[i], z[i]))
	}

	f.Close()
	cmd := "splot" // Force 3D plot
	if self.nplots > 0 {
		cmd = "replot"
	}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

type Func func(x float64) float64

func (self *Plotter) PlotFunc(data []float64, fct Func, title string) os.Error {

	f, err := ioutil.TempFile(os.TempDir(), g_gnuplot_prefix)
	if err != nil {
		return err
	}
	fname := f.Name()
	self.tmpfiles[fname] = f

	for _, x := range data {
		f.WriteString(fmt.Sprintf("%v %v\n", x, fct(x)))
	}

	f.Close()
	cmd := self.plotcmd
	if self.nplots > 0 {
		cmd = "replot"
	}

	var line string
	if title == "" {
		line = fmt.Sprintf("%s \"%s\" with %s", cmd, fname, self.style)
	} else {
		line = fmt.Sprintf("%s \"%s\" title \"%s\" with %s",
			cmd, fname, title, self.style)
	}
	self.nplots += 1
	return self.Cmd(line)
}

func (self *Plotter) SetPlotCmd(cmd string) (err os.Error) {
	switch cmd {
	case "plot", "splot":
		self.plotcmd = cmd
	default:
		err = os.NewError("invalid plot cmd [" + cmd + "]")
	}
	return err
}

func (self *Plotter) SetStyle(style string) (err os.Error) {
	allowed := []string{
		"lines", "points", "linepoints",
		"impulses", "dots",
		"steps",
		"errorbars",
		"boxes",
		"boxerrorbars",
		"pm3d"}

	for _, s := range allowed {
		if s == style {
			self.style = style
			err = nil
			return err
		}
	}

	fmt.Printf("** style '%v' not in allowed list %v\n", style, allowed)
	fmt.Printf("** default to 'points'\n")
	self.style = "points"
	err = &gnuplot_error{fmt.Sprintf("invalid style '%s'", style)}

	return err
}

func (self *Plotter) SetXLabel(label string) os.Error {
	return self.Cmd(fmt.Sprintf("set xlabel '%s'", label))
}

func (self *Plotter) SetYLabel(label string) os.Error {
	return self.Cmd(fmt.Sprintf("set ylabel '%s'", label))
}

func (self *Plotter) SetZLabel(label string) os.Error {
	return self.Cmd(fmt.Sprintf("set zlabel '%s'", label))
}

func (self *Plotter) SetLabels(labels ...string) os.Error {
	ndims := len(labels)
	if ndims > 3 || ndims <= 0 {
		return &gnuplot_error{fmt.Sprintf("invalid number of dims '%v'", ndims)}
	}
	var err os.Error = nil

	for i, label := range labels {
		switch i {
		case 0:
			ierr := self.SetXLabel(label)
			if ierr != nil {
				err = ierr
				return err
			}
		case 1:
			ierr := self.SetYLabel(label)
			if ierr != nil {
				err = ierr
				return err
			}
		case 2:
			ierr := self.SetZLabel(label)
			if ierr != nil {
				err = ierr
				return err
			}
		}
	}
	return nil
}

func (self *Plotter) ResetPlot() (err os.Error) {
	for fname, fhandle := range self.tmpfiles {
		ferr := fhandle.Close()
		if ferr != nil {
			err = ferr
		}
		os.Remove(fname)
	}
	self.nplots = 0
	return err
}

func NewPlotter(fname string, persist, debug bool) (*Plotter, os.Error) {
	p := &Plotter{proc: nil, debug: debug, plotcmd: "plot",
		nplots: 0, style: "points"}
	p.tmpfiles = make(tmpfiles_db)

	if fname != "" {
		panic("NewPlotter with fname is not yet supported")
	} else {
		proc, err := new_plotter_proc(persist)
		if err != nil {
			return nil, err
		}
		p.proc = proc
	}
	return p, nil
}

/* EOF */
<|endoftext|>


<commit_before>// Copyright 2017 Cisco Systems, 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.

// Handlers for node updates.

package hostagent

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strings"
	"time"

	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/kubernetes/pkg/controller"

	"context"
	"github.com/noironetworks/aci-containers/pkg/metadata"
)

const (
	hostVethEP   = "veth_host_ac.ep"
	hostVethName = "veth_host"
)

func (agent *HostAgent) initNodeInformerFromClient(
	kubeClient *kubernetes.Clientset) {

	agent.initNodeInformerBase(
		&cache.ListWatch{
			ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
				options.FieldSelector =
					fields.Set{"metadata.name": agent.config.NodeName}.String()
				return kubeClient.CoreV1().Nodes().List(context.TODO(), options)
			},
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				options.FieldSelector =
					fields.Set{"metadata.name": agent.config.NodeName}.String()
				return kubeClient.CoreV1().Nodes().Watch(context.TODO(), options)
			},
		})
}

func (agent *HostAgent) initNodeInformerBase(listWatch *cache.ListWatch) {
	agent.nodeInformer = cache.NewSharedIndexInformer(
		listWatch,
		&v1.Node{},
		controller.NoResyncPeriodFunc(),
		cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
	)
	agent.nodeInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			agent.nodeChanged(obj)
		},
		UpdateFunc: func(_ interface{}, obj interface{}) {
			agent.nodeChanged(obj)
		},
		DeleteFunc: func(obj interface{}) {
			agent.nodeDeleted(obj)
		},
	})
}

func (agent *HostAgent) nodeChanged(obj interface{}) {
	updateServices := false

	node := obj.(*v1.Node)
	if node.ObjectMeta.Name != agent.config.NodeName {
		agent.log.Error("Got incorrect node update for ", node.ObjectMeta.Name)
		return
	}

	agent.indexMutex.Lock()

	pnet, ok := node.ObjectMeta.Annotations[metadata.PodNetworkRangeAnnotation]
	if ok {
		agent.updateIpamAnnotation(pnet)
	}

	{
		var newServiceEp metadata.ServiceEndpoint
		epval, ok := node.ObjectMeta.Annotations[metadata.ServiceEpAnnotation]
		if ok {
			err := json.Unmarshal([]byte(epval), &newServiceEp)
			if err != nil {
				agent.log.WithFields(logrus.Fields{
					"epval": epval,
				}).Warn("Could not parse node ",
					"service endpoint annotation: ", err)
			}
		}
		if !reflect.DeepEqual(newServiceEp, agent.serviceEp) {
			agent.log.WithFields(logrus.Fields{
				"epval": epval,
			}).Info("Updated service endpoint")
			agent.serviceEp = newServiceEp
			updateServices = true
		}
	}

	gotVtep := false
	if agent.vtepIP == "" {
		for _, a := range node.Status.Addresses {
			if a.Type == v1.NodeInternalIP {
				agent.vtepIP = a.Address
				agent.log.Infof("vtepIP: %s", agent.vtepIP)
				gotVtep = true
			}
		}
	}

	agent.indexMutex.Unlock()
	if gotVtep {
		agent.routeInit()
		if agent.crdClient != nil {
			agent.registerHostVeth()
		}
	}

	if updateServices {
		agent.updateAllServices()
	}
}

func (agent *HostAgent) registerHostVeth() {
	go func() {
		for {
			ep := &opflexEndpoint{}
			epfile := filepath.Join(agent.config.OpFlexEndpointDir, hostVethEP)
			datacont, err := ioutil.ReadFile(epfile)
			if err != nil {
				agent.log.Errorf("Unable to read %s - %v", epfile, err)
				return
			}

			err = json.Unmarshal(datacont, ep)
			if err != nil {
				agent.log.Errorf("Unable to read %s - %v", epfile, err)
				return
			}

			vmName := ep.Attributes["vm-name"]
			if !strings.Contains(vmName, agent.vtepIP) {
				vmName = fmt.Sprintf("%s.%s", vmName, agent.vtepIP)
				ep.Attributes["vm-name"] = vmName
			}
			agent.log.Infof("-- Adding %+v to registry", ep)
			agent.EPRegAdd(ep)
			if ep.registered {
				return
			}
			time.Sleep(5 * time.Second)
		}
	}()
}

func (agent *HostAgent) nodeDeleted(obj interface{}) {
	agent.indexMutex.Lock()
	defer agent.indexMutex.Unlock()

}

func (agent *HostAgent) routeInit() {
	for _, nc := range agent.config.NetConfig {
		err := addPodRoute(nc.Subnet, hostVethName, agent.vtepIP)
		if err != nil {
			agent.log.Errorf("### Could not add route for subnet %+v reason: %s", nc.Subnet, err)
			continue
		}
		agent.log.Infof("VtepIP: %s, subnet: %+v, interface: %s", agent.vtepIP, nc.Subnet, hostVethName)
	}
}
<commit_msg>Service interfaceIP is not udated properly if the default snatpolicy is present and  node gets added  and the node is still not annonted with ServiceEP data. then we are setting the Snat external file with nil IP. to handle the above scenario we are setting the explicitly if we see node annotation changes<commit_after>// Copyright 2017 Cisco Systems, 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.

// Handlers for node updates.

package hostagent

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strings"
	"time"

	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/kubernetes/pkg/controller"

	"context"
	"github.com/noironetworks/aci-containers/pkg/metadata"
)

const (
	hostVethEP   = "veth_host_ac.ep"
	hostVethName = "veth_host"
)

func (agent *HostAgent) initNodeInformerFromClient(
	kubeClient *kubernetes.Clientset) {

	agent.initNodeInformerBase(
		&cache.ListWatch{
			ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
				options.FieldSelector =
					fields.Set{"metadata.name": agent.config.NodeName}.String()
				return kubeClient.CoreV1().Nodes().List(context.TODO(), options)
			},
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				options.FieldSelector =
					fields.Set{"metadata.name": agent.config.NodeName}.String()
				return kubeClient.CoreV1().Nodes().Watch(context.TODO(), options)
			},
		})
}

func (agent *HostAgent) initNodeInformerBase(listWatch *cache.ListWatch) {
	agent.nodeInformer = cache.NewSharedIndexInformer(
		listWatch,
		&v1.Node{},
		controller.NoResyncPeriodFunc(),
		cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
	)
	agent.nodeInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			agent.nodeChanged(obj)
		},
		UpdateFunc: func(_ interface{}, obj interface{}) {
			agent.nodeChanged(obj)
		},
		DeleteFunc: func(obj interface{}) {
			agent.nodeDeleted(obj)
		},
	})
}

func (agent *HostAgent) nodeChanged(obj interface{}) {
	updateServices := false

	node := obj.(*v1.Node)
	if node.ObjectMeta.Name != agent.config.NodeName {
		agent.log.Error("Got incorrect node update for ", node.ObjectMeta.Name)
		return
	}

	agent.indexMutex.Lock()

	pnet, ok := node.ObjectMeta.Annotations[metadata.PodNetworkRangeAnnotation]
	if ok {
		agent.updateIpamAnnotation(pnet)
	}

	{
		var newServiceEp metadata.ServiceEndpoint
		epval, ok := node.ObjectMeta.Annotations[metadata.ServiceEpAnnotation]
		if ok {
			err := json.Unmarshal([]byte(epval), &newServiceEp)
			if err != nil {
				agent.log.WithFields(logrus.Fields{
					"epval": epval,
				}).Warn("Could not parse node ",
					"service endpoint annotation: ", err)
			}
		}
		if !reflect.DeepEqual(newServiceEp, agent.serviceEp) {
			agent.log.WithFields(logrus.Fields{
				"epval": epval,
			}).Info("Updated service endpoint")
			agent.serviceEp = newServiceEp
			// this case can be posible when there is a default snatpolicy present
			// And nodeinfo service EP is not annotated
			if _, ok := agent.opflexServices[SnatService]; ok {
				agent.opflexServices[SnatService].InterfaceIp = agent.serviceEp.Ipv4.String()
				agent.log.Infof("Updated Snat service-ext file: %s", agent.serviceEp.Ipv4.String())
			}
			updateServices = true
		}
	}

	gotVtep := false
	if agent.vtepIP == "" {
		for _, a := range node.Status.Addresses {
			if a.Type == v1.NodeInternalIP {
				agent.vtepIP = a.Address
				agent.log.Infof("vtepIP: %s", agent.vtepIP)
				gotVtep = true
			}
		}
	}

	agent.indexMutex.Unlock()
	if gotVtep {
		agent.routeInit()
		if agent.crdClient != nil {
			agent.registerHostVeth()
		}
	}

	if updateServices {
		agent.updateAllServices()
	}
}

func (agent *HostAgent) registerHostVeth() {
	go func() {
		for {
			ep := &opflexEndpoint{}
			epfile := filepath.Join(agent.config.OpFlexEndpointDir, hostVethEP)
			datacont, err := ioutil.ReadFile(epfile)
			if err != nil {
				agent.log.Errorf("Unable to read %s - %v", epfile, err)
				return
			}

			err = json.Unmarshal(datacont, ep)
			if err != nil {
				agent.log.Errorf("Unable to read %s - %v", epfile, err)
				return
			}

			vmName := ep.Attributes["vm-name"]
			if !strings.Contains(vmName, agent.vtepIP) {
				vmName = fmt.Sprintf("%s.%s", vmName, agent.vtepIP)
				ep.Attributes["vm-name"] = vmName
			}
			agent.log.Infof("-- Adding %+v to registry", ep)
			agent.EPRegAdd(ep)
			if ep.registered {
				return
			}
			time.Sleep(5 * time.Second)
		}
	}()
}

func (agent *HostAgent) nodeDeleted(obj interface{}) {
	agent.indexMutex.Lock()
	defer agent.indexMutex.Unlock()

}

func (agent *HostAgent) routeInit() {
	for _, nc := range agent.config.NetConfig {
		err := addPodRoute(nc.Subnet, hostVethName, agent.vtepIP)
		if err != nil {
			agent.log.Errorf("### Could not add route for subnet %+v reason: %s", nc.Subnet, err)
			continue
		}
		agent.log.Infof("VtepIP: %s, subnet: %+v, interface: %s", agent.vtepIP, nc.Subnet, hostVethName)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package hyper

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

	"github.com/golang/glog"

	"k8s.io/frakti/pkg/hyper/types"
	kubeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)

const (
	volDriver = "vfs"
)

// CreateContainer creates a new container in specified PodSandbox
func (h *Runtime) CreateContainer(podSandboxID string, config *kubeapi.ContainerConfig, sandboxConfig *kubeapi.PodSandboxConfig) (string, error) {
	containerSpec, err := buildUserContainer(config, sandboxConfig)
	if err != nil {
		glog.Errorf("Build UserContainer for container %q failed: %v", config.String(), err)
		return "", err
	}

	containerID, err := h.client.CreateContainer(podSandboxID, containerSpec)
	if err != nil {
		glog.Errorf("Create container %s in pod %s failed: %v", config.Metadata.Name, podSandboxID, err)
		return "", err
	}

	return containerID, nil
}

// buildUserContainer builds hyperd's UserContainer based kubelet ContainerConfig.
func buildUserContainer(config *kubeapi.ContainerConfig, sandboxConfig *kubeapi.PodSandboxConfig) (*types.UserContainer, error) {
	var privilege bool
	if securityContext := config.GetLinux().GetSecurityContext(); securityContext != nil {
		privilege = securityContext.Privileged
	}

	if privilege {
		return nil, fmt.Errorf("Privileged containers are not supported in hyper")
	}

	logPath := filepath.Join(sandboxConfig.LogDirectory, config.LogPath)
	if config.Labels == nil {
		config.Labels = make(map[string]string)
	}
	config.Labels[containerLogPathLabelKey] = logPath
	containerSpec := &types.UserContainer{
		Name:       buildContainerName(sandboxConfig, config),
		Image:      config.GetImage().Image,
		Workdir:    config.WorkingDir,
		Tty:        config.Tty,
		Command:    config.Args,
		Entrypoint: config.Command,
		Labels:     buildLabelsWithAnnotations(config.Labels, config.Annotations),
		LogPath:    logPath,
	}

	// make volumes
	// TODO: support adding device in upstream hyperd when creating container.
	volumes := make([]*types.UserVolumeReference, len(config.Mounts))
	for i, m := range config.Mounts {
		hostPath := m.HostPath
		_, volName := filepath.Split(hostPath)
		volDetail := &types.UserVolume{
			Name: volName + fmt.Sprintf("_%08x", rand.Uint32()),
			// kuberuntime will set HostPath to the abs path of volume directory on host
			Source: hostPath,
			Format: volDriver,
		}
		volumes[i] = &types.UserVolumeReference{
			// use the generated volume name above
			Volume:   volDetail.Name,
			Path:     m.ContainerPath,
			ReadOnly: m.Readonly,
			Detail:   volDetail,
		}
	}

	containerSpec.Volumes = volumes

	// make environments
	environments := make([]*types.EnvironmentVar, len(config.Envs))
	for idx, env := range config.Envs {
		environments[idx] = &types.EnvironmentVar{
			Env:   env.Key,
			Value: env.Value,
		}
	}
	containerSpec.Envs = environments

	return containerSpec, nil
}

// StartContainer starts the container.
func (h *Runtime) StartContainer(rawContainerID string) error {
	err := h.client.StartContainer(rawContainerID)
	if err != nil {
		glog.Errorf("Start container %q failed: %v", rawContainerID, err)
		return err
	}

	return nil
}

// StopContainer stops a running container with a grace period (i.e. timeout).
func (h *Runtime) StopContainer(rawContainerID string, timeout int64) error {
	err := h.client.StopContainer(rawContainerID, timeout)
	if err != nil {
		glog.Errorf("Stop container %s failed: %v", rawContainerID, err)
		return err
	}

	return nil
}

// RemoveContainer removes the container. If the container is running, the container
// should be force removed.
func (h *Runtime) RemoveContainer(rawContainerID string) error {
	err := h.client.RemoveContainer(rawContainerID)
	if err != nil {
		glog.Errorf("Remove container %q failed: %v", rawContainerID, err)
		return err
	}

	return nil
}

// ListContainers lists all containers by filters.
func (h *Runtime) ListContainers(filter *kubeapi.ContainerFilter) ([]*kubeapi.Container, error) {
	containerList, err := h.client.GetContainerList()
	if err != nil {
		glog.Errorf("Get container list failed: %v", err)
		return nil, err
	}

	containers := make([]*kubeapi.Container, 0, len(containerList))

	for _, c := range containerList {
		state := toKubeContainerState(c.Status)
		_, _, _, containerName, attempt, err := parseContainerName(strings.Replace(c.ContainerName, "/", "", -1))

		if err != nil {
			glog.V(3).Infof("ParseContainerName for %q failed (%v), assuming it is not managed by frakti", c.ContainerName, err)
			continue
		}

		if filter != nil {
			if filter.Id != "" && c.ContainerID != filter.Id {
				continue
			}

			if filter.PodSandboxId != "" && c.PodID != filter.PodSandboxId {
				continue
			}

			if filter.State != nil && state != filter.GetState().State {
				continue
			}
		}

		info, err := h.client.GetContainerInfo(c.ContainerID)
		if err != nil {
			glog.Errorf("Get container info for %s failed: %v", c.ContainerID, err)
			return nil, err
		}

		annotations := getAnnotationsFromLabels(info.Container.Labels)
		kubeletLabels := getKubeletLabels(info.Container.Labels)

		if filter != nil {
			if filter.LabelSelector != nil && !inMap(filter.LabelSelector, kubeletLabels) {
				continue
			}
		}

		containerMetadata := &kubeapi.ContainerMetadata{
			Name:    containerName,
			Attempt: attempt,
		}

		createdAtNano := info.CreatedAt * secondToNano
		containers = append(containers, &kubeapi.Container{
			Id:           c.ContainerID,
			PodSandboxId: c.PodID,
			CreatedAt:    createdAtNano,
			Metadata:     containerMetadata,
			Image:        &kubeapi.ImageSpec{Image: info.Container.Image},
			ImageRef:     info.Container.ImageID,
			State:        state,
			Labels:       kubeletLabels,
			Annotations:  annotations,
		})
	}

	return containers, nil
}

// ContainerStatus returns the container status.
func (h *Runtime) ContainerStatus(containerID string) (*kubeapi.ContainerStatus, error) {
	status, err := h.client.GetContainerInfo(containerID)
	if err != nil {
		glog.Errorf("Get container info for %s failed: %v", containerID, err)
		return nil, err
	}

	podInfo, err := h.client.GetPodInfo(status.PodID)
	if err != nil {
		glog.Errorf("Get pod info for %s failed: %v", status.PodID, err)
		return nil, err
	}

	logPath := status.Container.Labels[containerLogPathLabelKey]
	state := toKubeContainerState(status.Status.Phase)
	annotations := getAnnotationsFromLabels(status.Container.Labels)
	kubeletLabels := getKubeletLabels(status.Container.Labels)

	_, _, _, containerName, attempt, err := parseContainerName(strings.Replace(status.Container.Name, "/", "", -1))
	if err != nil {
		glog.Errorf("ParseContainerName for %s failed: %v", status.Container.Name, err)
		return nil, err
	}

	containerMetadata := &kubeapi.ContainerMetadata{
		Name:    containerName,
		Attempt: attempt,
	}

	createdAtNano := status.CreatedAt * secondToNano
	kubeStatus := &kubeapi.ContainerStatus{
		Id:          status.Container.ContainerID,
		Image:       &kubeapi.ImageSpec{Image: status.Container.Image},
		ImageRef:    status.Container.ImageID,
		Metadata:    containerMetadata,
		State:       state,
		Labels:      kubeletLabels,
		Annotations: annotations,
		CreatedAt:   createdAtNano,
		LogPath:     logPath,
	}

	mounts := make([]*kubeapi.Mount, len(status.Container.VolumeMounts))
	for idx, mnt := range status.Container.VolumeMounts {
		mounts[idx] = &kubeapi.Mount{
			ContainerPath: mnt.MountPath,
			Readonly:      mnt.ReadOnly,
		}

		for _, v := range podInfo.Spec.Volumes {
			if v.Name == mnt.Name {
				mounts[idx].HostPath = v.Source
			}
		}
	}
	kubeStatus.Mounts = mounts

	switch status.Status.Phase {
	case "running":
		startedAt, err := parseTimeString(status.Status.Running.StartedAt)
		if err != nil {
			glog.Errorf("Hyper: can't parse startedAt %s", status.Status.Running.StartedAt)
			return nil, err
		}
		kubeStatus.StartedAt = startedAt
	case "failed", "succeeded":
		startedAt, err := parseTimeString(status.Status.Terminated.StartedAt)
		if err != nil {
			glog.Errorf("Hyper: can't parse startedAt %s", status.Status.Terminated.StartedAt)
			return nil, err
		}
		finishedAt, err := parseTimeString(status.Status.Terminated.FinishedAt)
		if err != nil {
			glog.Errorf("Hyper: can't parse finishedAt %s", status.Status.Terminated.FinishedAt)
			return nil, err
		}

		kubeStatus.StartedAt = startedAt
		kubeStatus.FinishedAt = finishedAt
		kubeStatus.Reason = status.Status.Terminated.Reason
		kubeStatus.ExitCode = status.Status.Terminated.ExitCode
	default:
		kubeStatus.Reason = status.Status.Waiting.Reason
	}

	return kubeStatus, nil
}
<commit_msg>Set readonly rootfs for container<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package hyper

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

	"github.com/golang/glog"

	"k8s.io/frakti/pkg/hyper/types"
	kubeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)

const (
	volDriver = "vfs"
)

// CreateContainer creates a new container in specified PodSandbox
func (h *Runtime) CreateContainer(podSandboxID string, config *kubeapi.ContainerConfig, sandboxConfig *kubeapi.PodSandboxConfig) (string, error) {
	containerSpec, err := buildUserContainer(config, sandboxConfig)
	if err != nil {
		glog.Errorf("Build UserContainer for container %q failed: %v", config.String(), err)
		return "", err
	}

	containerID, err := h.client.CreateContainer(podSandboxID, containerSpec)
	if err != nil {
		glog.Errorf("Create container %s in pod %s failed: %v", config.Metadata.Name, podSandboxID, err)
		return "", err
	}

	return containerID, nil
}

// buildUserContainer builds hyperd's UserContainer based kubelet ContainerConfig.
func buildUserContainer(config *kubeapi.ContainerConfig, sandboxConfig *kubeapi.PodSandboxConfig) (*types.UserContainer, error) {
	privilege := false
	readonlyRootfs := false
	if securityContext := config.GetLinux().GetSecurityContext(); securityContext != nil {
		privilege = securityContext.Privileged
		readonlyRootfs = securityContext.ReadonlyRootfs
	}

	if privilege {
		return nil, fmt.Errorf("Privileged containers are not supported in hyper")
	}

	logPath := filepath.Join(sandboxConfig.LogDirectory, config.LogPath)
	if config.Labels == nil {
		config.Labels = make(map[string]string)
	}
	config.Labels[containerLogPathLabelKey] = logPath
	containerSpec := &types.UserContainer{
		Name:       buildContainerName(sandboxConfig, config),
		Image:      config.GetImage().Image,
		Workdir:    config.WorkingDir,
		Tty:        config.Tty,
		Command:    config.Args,
		Entrypoint: config.Command,
		Labels:     buildLabelsWithAnnotations(config.Labels, config.Annotations),
		LogPath:    logPath,
		ReadOnly:   readonlyRootfs,
	}

	// make volumes
	// TODO: support adding device in upstream hyperd when creating container.
	volumes := make([]*types.UserVolumeReference, len(config.Mounts))
	for i, m := range config.Mounts {
		hostPath := m.HostPath
		_, volName := filepath.Split(hostPath)
		volDetail := &types.UserVolume{
			Name: volName + fmt.Sprintf("_%08x", rand.Uint32()),
			// kuberuntime will set HostPath to the abs path of volume directory on host
			Source: hostPath,
			Format: volDriver,
		}
		volumes[i] = &types.UserVolumeReference{
			// use the generated volume name above
			Volume:   volDetail.Name,
			Path:     m.ContainerPath,
			ReadOnly: m.Readonly,
			Detail:   volDetail,
		}
	}

	containerSpec.Volumes = volumes

	// make environments
	environments := make([]*types.EnvironmentVar, len(config.Envs))
	for idx, env := range config.Envs {
		environments[idx] = &types.EnvironmentVar{
			Env:   env.Key,
			Value: env.Value,
		}
	}
	containerSpec.Envs = environments

	return containerSpec, nil
}

// StartContainer starts the container.
func (h *Runtime) StartContainer(rawContainerID string) error {
	err := h.client.StartContainer(rawContainerID)
	if err != nil {
		glog.Errorf("Start container %q failed: %v", rawContainerID, err)
		return err
	}

	return nil
}

// StopContainer stops a running container with a grace period (i.e. timeout).
func (h *Runtime) StopContainer(rawContainerID string, timeout int64) error {
	err := h.client.StopContainer(rawContainerID, timeout)
	if err != nil {
		glog.Errorf("Stop container %s failed: %v", rawContainerID, err)
		return err
	}

	return nil
}

// RemoveContainer removes the container. If the container is running, the container
// should be force removed.
func (h *Runtime) RemoveContainer(rawContainerID string) error {
	err := h.client.RemoveContainer(rawContainerID)
	if err != nil {
		glog.Errorf("Remove container %q failed: %v", rawContainerID, err)
		return err
	}

	return nil
}

// ListContainers lists all containers by filters.
func (h *Runtime) ListContainers(filter *kubeapi.ContainerFilter) ([]*kubeapi.Container, error) {
	containerList, err := h.client.GetContainerList()
	if err != nil {
		glog.Errorf("Get container list failed: %v", err)
		return nil, err
	}

	containers := make([]*kubeapi.Container, 0, len(containerList))

	for _, c := range containerList {
		state := toKubeContainerState(c.Status)
		_, _, _, containerName, attempt, err := parseContainerName(strings.Replace(c.ContainerName, "/", "", -1))

		if err != nil {
			glog.V(3).Infof("ParseContainerName for %q failed (%v), assuming it is not managed by frakti", c.ContainerName, err)
			continue
		}

		if filter != nil {
			if filter.Id != "" && c.ContainerID != filter.Id {
				continue
			}

			if filter.PodSandboxId != "" && c.PodID != filter.PodSandboxId {
				continue
			}

			if filter.State != nil && state != filter.GetState().State {
				continue
			}
		}

		info, err := h.client.GetContainerInfo(c.ContainerID)
		if err != nil {
			glog.Errorf("Get container info for %s failed: %v", c.ContainerID, err)
			return nil, err
		}

		annotations := getAnnotationsFromLabels(info.Container.Labels)
		kubeletLabels := getKubeletLabels(info.Container.Labels)

		if filter != nil {
			if filter.LabelSelector != nil && !inMap(filter.LabelSelector, kubeletLabels) {
				continue
			}
		}

		containerMetadata := &kubeapi.ContainerMetadata{
			Name:    containerName,
			Attempt: attempt,
		}

		createdAtNano := info.CreatedAt * secondToNano
		containers = append(containers, &kubeapi.Container{
			Id:           c.ContainerID,
			PodSandboxId: c.PodID,
			CreatedAt:    createdAtNano,
			Metadata:     containerMetadata,
			Image:        &kubeapi.ImageSpec{Image: info.Container.Image},
			ImageRef:     info.Container.ImageID,
			State:        state,
			Labels:       kubeletLabels,
			Annotations:  annotations,
		})
	}

	return containers, nil
}

// ContainerStatus returns the container status.
func (h *Runtime) ContainerStatus(containerID string) (*kubeapi.ContainerStatus, error) {
	status, err := h.client.GetContainerInfo(containerID)
	if err != nil {
		glog.Errorf("Get container info for %s failed: %v", containerID, err)
		return nil, err
	}

	podInfo, err := h.client.GetPodInfo(status.PodID)
	if err != nil {
		glog.Errorf("Get pod info for %s failed: %v", status.PodID, err)
		return nil, err
	}

	logPath := status.Container.Labels[containerLogPathLabelKey]
	state := toKubeContainerState(status.Status.Phase)
	annotations := getAnnotationsFromLabels(status.Container.Labels)
	kubeletLabels := getKubeletLabels(status.Container.Labels)

	_, _, _, containerName, attempt, err := parseContainerName(strings.Replace(status.Container.Name, "/", "", -1))
	if err != nil {
		glog.Errorf("ParseContainerName for %s failed: %v", status.Container.Name, err)
		return nil, err
	}

	containerMetadata := &kubeapi.ContainerMetadata{
		Name:    containerName,
		Attempt: attempt,
	}

	createdAtNano := status.CreatedAt * secondToNano
	kubeStatus := &kubeapi.ContainerStatus{
		Id:          status.Container.ContainerID,
		Image:       &kubeapi.ImageSpec{Image: status.Container.Image},
		ImageRef:    status.Container.ImageID,
		Metadata:    containerMetadata,
		State:       state,
		Labels:      kubeletLabels,
		Annotations: annotations,
		CreatedAt:   createdAtNano,
		LogPath:     logPath,
	}

	mounts := make([]*kubeapi.Mount, len(status.Container.VolumeMounts))
	for idx, mnt := range status.Container.VolumeMounts {
		mounts[idx] = &kubeapi.Mount{
			ContainerPath: mnt.MountPath,
			Readonly:      mnt.ReadOnly,
		}

		for _, v := range podInfo.Spec.Volumes {
			if v.Name == mnt.Name {
				mounts[idx].HostPath = v.Source
			}
		}
	}
	kubeStatus.Mounts = mounts

	switch status.Status.Phase {
	case "running":
		startedAt, err := parseTimeString(status.Status.Running.StartedAt)
		if err != nil {
			glog.Errorf("Hyper: can't parse startedAt %s", status.Status.Running.StartedAt)
			return nil, err
		}
		kubeStatus.StartedAt = startedAt
	case "failed", "succeeded":
		startedAt, err := parseTimeString(status.Status.Terminated.StartedAt)
		if err != nil {
			glog.Errorf("Hyper: can't parse startedAt %s", status.Status.Terminated.StartedAt)
			return nil, err
		}
		finishedAt, err := parseTimeString(status.Status.Terminated.FinishedAt)
		if err != nil {
			glog.Errorf("Hyper: can't parse finishedAt %s", status.Status.Terminated.FinishedAt)
			return nil, err
		}

		kubeStatus.StartedAt = startedAt
		kubeStatus.FinishedAt = finishedAt
		kubeStatus.Reason = status.Status.Terminated.Reason
		kubeStatus.ExitCode = status.Status.Terminated.ExitCode
	default:
		kubeStatus.Reason = status.Status.Waiting.Reason
	}

	return kubeStatus, nil
}
<|endoftext|>


<commit_before>// Package pidfile provides structure and helper functions to create and remove
// PID file. A PID file is usually a file used to store the process ID of a
// running process.
package pidfile

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
)

// PIDFile is a file used to store the process ID of a running process.
type PIDFile struct {
	path string
}

func checkPIDFileAlreadyExists(path string) error {
	if pidString, err := ioutil.ReadFile(path); err == nil {
		if pid, err := strconv.Atoi(string(pidString)); err == nil {
			if _, err := os.Stat(filepath.Join("/proc", string(pid))); err == nil {
				return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path)
			}
		}
	}
	return nil
}

// New creates a PIDfile using the specified path.
func New(path string) (*PIDFile, error) {
	if err := checkPIDFileAlreadyExists(path); err != nil {
		return nil, err
	}
	if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
		return nil, err
	}

	return &PIDFile{path: path}, nil
}

// Remove removes the PIDFile.
func (file PIDFile) Remove() error {
	if err := os.Remove(file.path); err != nil {
		return err
	}
	return nil
}
<commit_msg>fix pidfile, pid is num use '/proc + string(pid)' can't found it<commit_after>// Package pidfile provides structure and helper functions to create and remove
// PID file. A PID file is usually a file used to store the process ID of a
// running process.
package pidfile

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

// PIDFile is a file used to store the process ID of a running process.
type PIDFile struct {
	path string
}

func checkPIDFileAlreadyExists(path string) error {
	if pidByte, err := ioutil.ReadFile(path); err == nil {
		pidString := strings.TrimSpace(string(pidByte))
		if pid, err := strconv.Atoi(pidString); err == nil {
			if _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))); err == nil {
				return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path)
			}
		}
	}
	return nil
}

// New creates a PIDfile using the specified path.
func New(path string) (*PIDFile, error) {
	if err := checkPIDFileAlreadyExists(path); err != nil {
		return nil, err
	}
	if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
		return nil, err
	}

	return &PIDFile{path: path}, nil
}

// Remove removes the PIDFile.
func (file PIDFile) Remove() error {
	if err := os.Remove(file.path); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package rangedb // import "a4.io/blobstash/pkg/rangedb"

import (
	"io"
	"os"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/util"
)

type RangeDB struct {
	db   *leveldb.DB
	path string
}

// New creates a new database.
func New(path string) (*RangeDB, error) {
	var err error
	db, err := leveldb.OpenFile(path, nil)
	if err != nil {
		return nil, err
	}
	return &RangeDB{
		db:   db,
		path: path,
	}, nil
}

func (db *RangeDB) Close() error {
	return db.db.Close()
}

func (db *RangeDB) Destroy() error {
	if db.path != "" {
		db.Close()
		return os.RemoveAll(db.path)
	}
	return nil
}

func (db *RangeDB) Set(k, v []byte) error {
	return db.db.Put(k, v, nil)
}

func (db *RangeDB) Get(k []byte) ([]byte, error) {
	v, err := db.db.Get(k, nil)
	if err != nil {
		if err == errors.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}
	return v, nil
}

func (db *RangeDB) Has(k []byte) (bool, error) {
	e, err := db.db.Has(k, nil)
	if err != nil {
		return nil, err
	}
	return e, nil
}

// NextKey returns the next key for lexigraphical (key = NextKey(lastkey))
func NextKey(bkey []byte) []byte {
	i := len(bkey)
	for i > 0 {
		i--
		bkey[i]++
		if bkey[i] != 0 {
			break
		}
	}
	return bkey
}

type Range struct {
	Reverse  bool
	Min, Max []byte
	db       *RangeDB
	it       iterator.Iterator
	first    bool
}

func (db *RangeDB) PrefixRange(prefix []byte, reverse bool) *Range {
	iter := db.db.NewIterator(util.BytesPrefix(prefix), nil)
	return &Range{
		it:      iter,
		Reverse: reverse,
		db:      db,
		first:   true,
	}
}

func (db *RangeDB) Range(min, max []byte, reverse bool) *Range {
	iter := db.db.NewIterator(&util.Range{Start: min, Limit: NextKey(max)}, nil)
	return &Range{
		it:      iter,
		Min:     min,
		Max:     max,
		Reverse: reverse,
		db:      db,
		first:   true,
	}
}

func buildKv(it iterator.Iterator) ([]byte, []byte, error) {
	k := make([]byte, len(it.Key()))
	copy(k[:], it.Key())
	v := make([]byte, len(it.Value()))
	copy(v[:], it.Value())
	return k, v, nil
}

func (r *Range) Seek(k []byte) ([]byte, []byte, error) {
	if r.it.Seek(k) {
		return buildKv(r.it)
	}
	return nil, nil, io.EOF
}

func (r *Range) Next() ([]byte, []byte, error) {
	if !r.Reverse {
		if r.it.Next() {
			return buildKv(r.it)
		}

	} else {
		if r.first {
			if r.it.Last() {
				r.first = false
				return buildKv(r.it)
			}
		} else {
			if r.it.Prev() {
				return buildKv(r.it)
			}
		}
	}
	r.it.Release()
	if err := r.it.Error(); err != nil {
		return nil, nil, err
	}
	return nil, nil, io.EOF
}

func (r *Range) Close() error {
	r.it.Release()
	return r.it.Error()
}
<commit_msg>rangedb: bugfix<commit_after>package rangedb // import "a4.io/blobstash/pkg/rangedb"

import (
	"io"
	"os"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/util"
)

type RangeDB struct {
	db   *leveldb.DB
	path string
}

// New creates a new database.
func New(path string) (*RangeDB, error) {
	var err error
	db, err := leveldb.OpenFile(path, nil)
	if err != nil {
		return nil, err
	}
	return &RangeDB{
		db:   db,
		path: path,
	}, nil
}

func (db *RangeDB) Close() error {
	return db.db.Close()
}

func (db *RangeDB) Destroy() error {
	if db.path != "" {
		db.Close()
		return os.RemoveAll(db.path)
	}
	return nil
}

func (db *RangeDB) Set(k, v []byte) error {
	return db.db.Put(k, v, nil)
}

func (db *RangeDB) Get(k []byte) ([]byte, error) {
	v, err := db.db.Get(k, nil)
	if err != nil {
		if err == errors.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}
	return v, nil
}

func (db *RangeDB) Has(k []byte) (bool, error) {
	e, err := db.db.Has(k, nil)
	if err != nil {
		return false, err
	}
	return e, nil
}

// NextKey returns the next key for lexigraphical (key = NextKey(lastkey))
func NextKey(bkey []byte) []byte {
	i := len(bkey)
	for i > 0 {
		i--
		bkey[i]++
		if bkey[i] != 0 {
			break
		}
	}
	return bkey
}

type Range struct {
	Reverse  bool
	Min, Max []byte
	db       *RangeDB
	it       iterator.Iterator
	first    bool
}

func (db *RangeDB) PrefixRange(prefix []byte, reverse bool) *Range {
	iter := db.db.NewIterator(util.BytesPrefix(prefix), nil)
	return &Range{
		it:      iter,
		Reverse: reverse,
		db:      db,
		first:   true,
	}
}

func (db *RangeDB) Range(min, max []byte, reverse bool) *Range {
	iter := db.db.NewIterator(&util.Range{Start: min, Limit: NextKey(max)}, nil)
	return &Range{
		it:      iter,
		Min:     min,
		Max:     max,
		Reverse: reverse,
		db:      db,
		first:   true,
	}
}

func buildKv(it iterator.Iterator) ([]byte, []byte, error) {
	k := make([]byte, len(it.Key()))
	copy(k[:], it.Key())
	v := make([]byte, len(it.Value()))
	copy(v[:], it.Value())
	return k, v, nil
}

func (r *Range) Seek(k []byte) ([]byte, []byte, error) {
	if r.it.Seek(k) {
		return buildKv(r.it)
	}
	return nil, nil, io.EOF
}

func (r *Range) Next() ([]byte, []byte, error) {
	if !r.Reverse {
		if r.it.Next() {
			return buildKv(r.it)
		}

	} else {
		if r.first {
			if r.it.Last() {
				r.first = false
				return buildKv(r.it)
			}
		} else {
			if r.it.Prev() {
				return buildKv(r.it)
			}
		}
	}
	r.it.Release()
	if err := r.it.Error(); err != nil {
		return nil, nil, err
	}
	return nil, nil, io.EOF
}

func (r *Range) Close() error {
	r.it.Release()
	return r.it.Error()
}
<|endoftext|>


<commit_before>package registry

import (
	"context"
	"encoding/json"

	"github.com/estesp/manifest-tool/pkg/store"
	"github.com/estesp/manifest-tool/pkg/types"

	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/remotes"
	"github.com/docker/distribution/manifest/manifestlist"
	"github.com/docker/distribution/reference"
	"github.com/opencontainers/go-digest"
	specs "github.com/opencontainers/image-spec/specs-go"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// Push performs the actions required to push content to the specified registry endpoint
func Push(m types.ManifestList, addedTags []string, ms *store.MemoryStore) (string, int, error) {
	// push manifest references to target ref (if required)
	baseRef := reference.TrimNamed(m.Reference)
	for _, man := range m.Manifests {
		if man.PushRef {
			ref, err := reference.WithDigest(baseRef, man.Descriptor.Digest)
			if err != nil {
				return "", 0, errors.Wrapf(err, "Error parsing reference for target manifest component push: %s", m.Reference.String())
			}
			err = push(ref, man.Descriptor, m.Resolver, ms)
			if err != nil {
				return "", 0, errors.Wrapf(err, "Error pushing target manifest component reference: %s", ref.String())
			}
			logrus.Infof("pushed manifest component reference (%s) to target namespace: %s", man.Descriptor.Digest.String(), ref.String())
		}
	}
	// build the manifest list/index entry to be pushed and save it in the content store
	desc, indexJSON, err := buildManifest(m)
	if err != nil {
		return "", 0, errors.Wrap(err, "Error creating manifest list/index JSON")
	}
	ms.Set(desc, indexJSON)

	if err := push(m.Reference, desc, m.Resolver, ms); err != nil {
		return "", 0, errors.Wrapf(err, "Error pushing manifest list/index to registry: %s", desc.Digest.String())
	}
	for _, tag := range addedTags {
		taggedRef, err := reference.WithTag(baseRef, tag)
		if err != nil {
			return "", 0, errors.Wrapf(err, "Error creating additional tag reference: %s", tag)
		}
		if err = push(taggedRef, desc, m.Resolver, ms); err != nil {
			return "", 0, errors.Wrapf(err, "Error pushing additional tag reference: %s", tag)
		}
	}
	return desc.Digest.String(), int(desc.Size), nil
}

func buildManifest(m types.ManifestList) (ocispec.Descriptor, []byte, error) {
	var (
		index     interface{}
		mediaType string
	)
	switch m.Type {
	case types.Docker:
		index = dockerManifestList(m.Manifests)
		mediaType = types.MediaTypeDockerSchema2ManifestList

	case types.OCI:
		index = ociIndex(m.Manifests)
		mediaType = ocispec.MediaTypeImageIndex
	}
	bytes, err := json.MarshalIndent(index, "", "  ")
	if err != nil {
		return ocispec.Descriptor{}, []byte{}, err
	}
	desc := ocispec.Descriptor{
		Digest:    digest.FromBytes(bytes),
		MediaType: mediaType,
		Size:      int64(len(bytes)),
	}
	return desc, bytes, nil
}

func push(ref reference.Reference, desc ocispec.Descriptor, resolver remotes.Resolver, ms *store.MemoryStore) error {
	ctx := context.Background()
	pusher, err := resolver.Pusher(ctx, ref.String())
	if err != nil {
		return err
	}
	wrapper := func(f images.Handler) images.Handler {
		return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
			children, err := f.Handle(ctx, desc)
			if err != nil {
				return nil, err
			}
			filtered := children[:0]
			for _, c := range children {
				if !nonDistributable(c.MediaType) {
					filtered = append(filtered, c)
				}
			}
			return filtered, nil
		})
	}
	return remotes.PushContent(ctx, pusher, desc, ms, nil, wrapper)
}

func ociIndex(m []types.Manifest) ocispec.Index {
	index := ocispec.Index{
		Versioned: specs.Versioned{
			SchemaVersion: 2,
		},
	}
	for _, man := range m {
		index.Manifests = append(index.Manifests, man.Descriptor)
	}
	return index
}

func dockerManifestList(m []types.Manifest) manifestlist.ManifestList {
	ml := manifestlist.ManifestList{
		Versioned: manifestlist.SchemaVersion,
	}
	for _, man := range m {
		ml.Manifests = append(ml.Manifests, dockerConvert(man.Descriptor))
	}
	return ml
}

func dockerConvert(m ocispec.Descriptor) manifestlist.ManifestDescriptor {
	var md manifestlist.ManifestDescriptor
	md.Digest = m.Digest
	md.Size = m.Size
	md.MediaType = m.MediaType
	md.Platform.Architecture = m.Platform.Architecture
	md.Platform.OS = m.Platform.OS
	md.Platform.Variant = m.Platform.Variant
	md.Platform.OSFeatures = m.Platform.OSFeatures
	md.Platform.OSVersion = m.Platform.OSVersion
	return md
}
<commit_msg>Properly support pushing additional tags on a manifest list<commit_after>package registry

import (
	"context"
	"encoding/json"

	"github.com/estesp/manifest-tool/pkg/store"
	"github.com/estesp/manifest-tool/pkg/types"

	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/remotes"
	"github.com/docker/distribution/manifest/manifestlist"
	"github.com/docker/distribution/reference"
	"github.com/opencontainers/go-digest"
	specs "github.com/opencontainers/image-spec/specs-go"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// Push performs the actions required to push content to the specified registry endpoint
func Push(m types.ManifestList, addedTags []string, ms *store.MemoryStore) (string, int, error) {
	// push manifest references to target ref (if required)
	baseRef := reference.TrimNamed(m.Reference)
	for _, man := range m.Manifests {
		if man.PushRef {
			ref, err := reference.WithDigest(baseRef, man.Descriptor.Digest)
			if err != nil {
				return "", 0, errors.Wrapf(err, "Error parsing reference for target manifest component push: %s", m.Reference.String())
			}
			err = push(ref, man.Descriptor, m.Resolver, ms)
			if err != nil {
				return "", 0, errors.Wrapf(err, "Error pushing target manifest component reference: %s", ref.String())
			}
			logrus.Infof("pushed manifest component reference (%s) to target namespace: %s", man.Descriptor.Digest.String(), ref.String())
		}
	}
	// build the manifest list/index entry to be pushed and save it in the content store
	desc, indexJSON, err := buildManifest(m)
	if err != nil {
		return "", 0, errors.Wrap(err, "Error creating manifest list/index JSON")
	}
	ms.Set(desc, indexJSON)

	if err := push(m.Reference, desc, m.Resolver, ms); err != nil {
		return "", 0, errors.Wrapf(err, "Error pushing manifest list/index to registry: %s", desc.Digest.String())
	}
	for _, tag := range addedTags {
		taggedRef, err := reference.WithTag(baseRef, tag)
		logrus.Infof("pushing extra tag '%s' to manifest list/index: %s", tag, desc.Digest.String())
		if err != nil {
			return "", 0, errors.Wrapf(err, "Error creating additional tag reference: %s", tag)
		}
		if err = pushTagOnly(taggedRef, desc, m.Resolver, ms); err != nil {
			return "", 0, errors.Wrapf(err, "Error pushing additional tag reference: %s", tag)
		}
	}
	return desc.Digest.String(), int(desc.Size), nil
}

func buildManifest(m types.ManifestList) (ocispec.Descriptor, []byte, error) {
	var (
		index     interface{}
		mediaType string
	)
	switch m.Type {
	case types.Docker:
		index = dockerManifestList(m.Manifests)
		mediaType = types.MediaTypeDockerSchema2ManifestList

	case types.OCI:
		index = ociIndex(m.Manifests)
		mediaType = ocispec.MediaTypeImageIndex
	}
	bytes, err := json.MarshalIndent(index, "", "  ")
	if err != nil {
		return ocispec.Descriptor{}, []byte{}, err
	}
	desc := ocispec.Descriptor{
		Digest:      digest.FromBytes(bytes),
		MediaType:   mediaType,
		Size:        int64(len(bytes)),
		Annotations: map[string]string{},
	}
	desc.Annotations[ocispec.AnnotationRefName] = m.Name
	return desc, bytes, nil
}

func push(ref reference.Reference, desc ocispec.Descriptor, resolver remotes.Resolver, ms *store.MemoryStore) error {
	ctx := context.Background()
	pusher, err := resolver.Pusher(ctx, ref.String())
	if err != nil {
		return err
	}
	wrapper := func(f images.Handler) images.Handler {
		return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
			children, err := f.Handle(ctx, desc)
			if err != nil {
				return nil, err
			}
			filtered := children[:0]
			for _, c := range children {
				if !nonDistributable(c.MediaType) {
					filtered = append(filtered, c)
				}
			}
			return filtered, nil
		})
	}
	return remotes.PushContent(ctx, pusher, desc, ms, nil, nil, wrapper)
}

// used to push only a tag for the "additional tags" feature of manifest-tool
func pushTagOnly(ref reference.Reference, desc ocispec.Descriptor, resolver remotes.Resolver, ms *store.MemoryStore) error {
	ctx := context.Background()
	pusher, err := resolver.Pusher(ctx, ref.String())
	if err != nil {
		return err
	}
	// wrapper will not descend to children; all components have already been pushed and we only want an additional
	// tag on the root descriptor (e.g. pushing a "4.2", "4", and "latest" tags after pushing a full "4.2.2" image)
	wrapper := func(f images.Handler) images.Handler {
		return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
			_, err := f.Handle(ctx, desc)
			if err != nil {
				return nil, err
			}
			return nil, nil
		})
	}
	desc.Annotations[ocispec.AnnotationRefName] = ref.String()
	return remotes.PushContent(ctx, pusher, desc, ms, nil, nil, wrapper)
}

func ociIndex(m []types.Manifest) ocispec.Index {
	index := ocispec.Index{
		Versioned: specs.Versioned{
			SchemaVersion: 2,
		},
	}
	for _, man := range m {
		index.Manifests = append(index.Manifests, man.Descriptor)
	}
	return index
}

func dockerManifestList(m []types.Manifest) manifestlist.ManifestList {
	ml := manifestlist.ManifestList{
		Versioned: manifestlist.SchemaVersion,
	}
	for _, man := range m {
		ml.Manifests = append(ml.Manifests, dockerConvert(man.Descriptor))
	}
	return ml
}

func dockerConvert(m ocispec.Descriptor) manifestlist.ManifestDescriptor {
	var md manifestlist.ManifestDescriptor
	md.Digest = m.Digest
	md.Size = m.Size
	md.MediaType = m.MediaType
	md.Platform.Architecture = m.Platform.Architecture
	md.Platform.OS = m.Platform.OS
	md.Platform.Variant = m.Platform.Variant
	md.Platform.OSFeatures = m.Platform.OSFeatures
	md.Platform.OSVersion = m.Platform.OSVersion
	return md
}
<|endoftext|>


<commit_before>package selinux

import (
	"bufio"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"github.com/dotcloud/docker/pkg/mount"
	"github.com/dotcloud/docker/pkg/system"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
	"syscall"
)

const (
	Enforcing        = 1
	Permissive       = 0
	Disabled         = -1
	selinuxDir       = "/etc/selinux/"
	selinuxConfig    = selinuxDir + "config"
	selinuxTypeTag   = "SELINUXTYPE"
	selinuxTag       = "SELINUX"
	selinuxPath      = "/sys/fs/selinux"
	xattrNameSelinux = "security.selinux"
	stRdOnly         = 0x01
)

var (
	assignRegex           = regexp.MustCompile(`^([^=]+)=(.*)$`)
	spaceRegex            = regexp.MustCompile(`^([^=]+) (.*)$`)
	mcsList               = make(map[string]bool)
	selinuxfs             = "unknown"
	selinuxEnabled        = false
	selinuxEnabledChecked = false
)

type SELinuxContext map[string]string

func GetSelinuxMountPoint() string {
	if selinuxfs != "unknown" {
		return selinuxfs
	}
	selinuxfs = ""

	mounts, err := mount.GetMounts()
	if err != nil {
		return selinuxfs
	}
	for _, mount := range mounts {
		if mount.Fstype == "selinuxfs" {
			selinuxfs = mount.Mountpoint
			break
		}
	}
	if selinuxfs != "" {
		var buf syscall.Statfs_t
		syscall.Statfs(selinuxfs, &buf)
		if (buf.Flags & stRdOnly) == 1 {
			selinuxfs = ""
		}
	}
	return selinuxfs
}

func SelinuxEnabled() bool {
	if selinuxEnabledChecked {
		return selinuxEnabled
	}
	selinuxEnabledChecked = true
	if fs := GetSelinuxMountPoint(); fs != "" {
		if con, _ := Getcon(); con != "kernel" {
			selinuxEnabled = true
		}
	}
	return selinuxEnabled
}

func ReadConfig(target string) (value string) {
	var (
		val, key string
		bufin    *bufio.Reader
	)

	in, err := os.Open(selinuxConfig)
	if err != nil {
		return ""
	}
	defer in.Close()

	bufin = bufio.NewReader(in)

	for done := false; !done; {
		var line string
		if line, err = bufin.ReadString('\n'); err != nil {
			if err != io.EOF {
				return ""
			}
			done = true
		}
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			// Skip blank lines
			continue
		}
		if line[0] == ';' || line[0] == '#' {
			// Skip comments
			continue
		}
		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
			if key == target {
				return strings.Trim(val, "\"")
			}
		}
	}
	return ""
}

func GetSELinuxPolicyRoot() string {
	return selinuxDir + ReadConfig(selinuxTypeTag)
}

func readCon(name string) (string, error) {
	var val string

	in, err := os.Open(name)
	if err != nil {
		return "", err
	}
	defer in.Close()

	_, err = fmt.Fscanf(in, "%s", &val)
	return val, err
}

func Setfilecon(path string, scon string) error {
	return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0)
}

func Getfilecon(path string) (string, error) {
	var scon []byte

	cnt, err := syscall.Getxattr(path, xattrNameSelinux, scon)
	scon = make([]byte, cnt)
	cnt, err = syscall.Getxattr(path, xattrNameSelinux, scon)
	return string(scon), err
}

func Setfscreatecon(scon string) error {
	return writeCon("/proc/self/attr/fscreate", scon)
}

func Getfscreatecon() (string, error) {
	return readCon("/proc/self/attr/fscreate")
}

func Getcon() (string, error) {
	return readCon("/proc/self/attr/current")
}

func Getpidcon(pid int) (string, error) {
	return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
}

func Getexeccon() (string, error) {
	return readCon("/proc/self/attr/exec")
}

func writeCon(name string, val string) error {
	if !SelinuxEnabled() {
		return nil
	}
	out, err := os.OpenFile(name, os.O_WRONLY, 0)
	if err != nil {
		return err
	}
	defer out.Close()

	if val != "" {
		_, err = out.Write([]byte(val))
	} else {
		_, err = out.Write(nil)
	}
	return err
}

func Setexeccon(scon string) error {
	return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon)
}

func (c SELinuxContext) Get() string {
	return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
}

func NewContext(scon string) SELinuxContext {
	c := make(SELinuxContext)

	if len(scon) != 0 {
		con := strings.SplitN(scon, ":", 4)
		c["user"] = con[0]
		c["role"] = con[1]
		c["type"] = con[2]
		c["level"] = con[3]
	}
	return c
}

func SelinuxGetEnforce() int {
	var enforce int

	enforceS, err := readCon(fmt.Sprintf("%s/enforce", selinuxPath))
	if err != nil {
		return -1
	}

	enforce, err = strconv.Atoi(string(enforceS))
	if err != nil {
		return -1
	}
	return enforce
}

func SelinuxGetEnforceMode() int {
	switch ReadConfig(selinuxTag) {
	case "enforcing":
		return Enforcing
	case "permissive":
		return Permissive
	}
	return Disabled
}

func mcsAdd(mcs string) {
	mcsList[mcs] = true
}

func mcsDelete(mcs string) {
	mcsList[mcs] = false
}

func mcsExists(mcs string) bool {
	return mcsList[mcs]
}

func IntToMcs(id int, catRange uint32) string {
	var (
		SETSIZE = int(catRange)
		TIER    = SETSIZE
		ORD     = id
	)

	if id < 1 || id > 523776 {
		return ""
	}

	for ORD > TIER {
		ORD = ORD - TIER
		TIER -= 1
	}
	TIER = SETSIZE - TIER
	ORD = ORD + TIER
	return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
}

func uniqMcs(catRange uint32) string {
	var (
		n      uint32
		c1, c2 uint32
		mcs    string
	)

	for {
		binary.Read(rand.Reader, binary.LittleEndian, &n)
		c1 = n % catRange
		binary.Read(rand.Reader, binary.LittleEndian, &n)
		c2 = n % catRange
		if c1 == c2 {
			continue
		} else {
			if c1 > c2 {
				t := c1
				c1 = c2
				c2 = t
			}
		}
		mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
		if mcsExists(mcs) {
			continue
		}
		mcsAdd(mcs)
		break
	}
	return mcs
}

func FreeContext(con string) {
	if con != "" {
		scon := NewContext(con)
		mcsDelete(scon["level"])
	}
}

func GetLxcContexts() (processLabel string, fileLabel string) {
	var (
		val, key string
		bufin    *bufio.Reader
	)

	if !SelinuxEnabled() {
		return "", ""
	}
	lxcPath := fmt.Sprintf("%s/content/lxc_contexts", GetSELinuxPolicyRoot())
	fileLabel = "system_u:object_r:svirt_sandbox_file_t:s0"
	processLabel = "system_u:system_r:svirt_lxc_net_t:s0"

	in, err := os.Open(lxcPath)
	if err != nil {
		goto exit
	}
	defer in.Close()

	bufin = bufio.NewReader(in)

	for done := false; !done; {
		var line string
		if line, err = bufin.ReadString('\n'); err != nil {
			if err == io.EOF {
				done = true
			} else {
				goto exit
			}
		}
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			// Skip blank lines
			continue
		}
		if line[0] == ';' || line[0] == '#' {
			// Skip comments
			continue
		}
		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
			if key == "process" {
				processLabel = strings.Trim(val, "\"")
			}
			if key == "file" {
				fileLabel = strings.Trim(val, "\"")
			}
		}
	}
exit:
	mcs := IntToMcs(os.Getpid(), 1024)
	scon := NewContext(processLabel)
	scon["level"] = mcs
	processLabel = scon.Get()
	scon = NewContext(fileLabel)
	scon["level"] = mcs
	fileLabel = scon.Get()
	return processLabel, fileLabel
}

func SecurityCheckContext(val string) error {
	return writeCon(fmt.Sprintf("%s.context", selinuxPath), val)
}

func CopyLevel(src, dest string) (string, error) {
	if !SelinuxEnabled() {
		return "", nil
	}
	if src == "" {
		return "", nil
	}
	if err := SecurityCheckContext(src); err != nil {
		return "", err
	}
	if err := SecurityCheckContext(dest); err != nil {
		return "", err
	}
	scon := NewContext(src)
	tcon := NewContext(dest)
	tcon["level"] = scon["level"]
	return tcon.Get(), nil
}
<commit_msg>Remove hard coding of SELinux labels on systems without proper selinux policy.<commit_after>package selinux

import (
	"bufio"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"github.com/dotcloud/docker/pkg/mount"
	"github.com/dotcloud/docker/pkg/system"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
	"syscall"
)

const (
	Enforcing        = 1
	Permissive       = 0
	Disabled         = -1
	selinuxDir       = "/etc/selinux/"
	selinuxConfig    = selinuxDir + "config"
	selinuxTypeTag   = "SELINUXTYPE"
	selinuxTag       = "SELINUX"
	selinuxPath      = "/sys/fs/selinux"
	xattrNameSelinux = "security.selinux"
	stRdOnly         = 0x01
)

var (
	assignRegex           = regexp.MustCompile(`^([^=]+)=(.*)$`)
	spaceRegex            = regexp.MustCompile(`^([^=]+) (.*)$`)
	mcsList               = make(map[string]bool)
	selinuxfs             = "unknown"
	selinuxEnabled        = false
	selinuxEnabledChecked = false
)

type SELinuxContext map[string]string

func GetSelinuxMountPoint() string {
	if selinuxfs != "unknown" {
		return selinuxfs
	}
	selinuxfs = ""

	mounts, err := mount.GetMounts()
	if err != nil {
		return selinuxfs
	}
	for _, mount := range mounts {
		if mount.Fstype == "selinuxfs" {
			selinuxfs = mount.Mountpoint
			break
		}
	}
	if selinuxfs != "" {
		var buf syscall.Statfs_t
		syscall.Statfs(selinuxfs, &buf)
		if (buf.Flags & stRdOnly) == 1 {
			selinuxfs = ""
		}
	}
	return selinuxfs
}

func SelinuxEnabled() bool {
	if selinuxEnabledChecked {
		return selinuxEnabled
	}
	selinuxEnabledChecked = true
	if fs := GetSelinuxMountPoint(); fs != "" {
		if con, _ := Getcon(); con != "kernel" {
			selinuxEnabled = true
		}
	}
	return selinuxEnabled
}

func ReadConfig(target string) (value string) {
	var (
		val, key string
		bufin    *bufio.Reader
	)

	in, err := os.Open(selinuxConfig)
	if err != nil {
		return ""
	}
	defer in.Close()

	bufin = bufio.NewReader(in)

	for done := false; !done; {
		var line string
		if line, err = bufin.ReadString('\n'); err != nil {
			if err != io.EOF {
				return ""
			}
			done = true
		}
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			// Skip blank lines
			continue
		}
		if line[0] == ';' || line[0] == '#' {
			// Skip comments
			continue
		}
		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
			if key == target {
				return strings.Trim(val, "\"")
			}
		}
	}
	return ""
}

func GetSELinuxPolicyRoot() string {
	return selinuxDir + ReadConfig(selinuxTypeTag)
}

func readCon(name string) (string, error) {
	var val string

	in, err := os.Open(name)
	if err != nil {
		return "", err
	}
	defer in.Close()

	_, err = fmt.Fscanf(in, "%s", &val)
	return val, err
}

func Setfilecon(path string, scon string) error {
	return system.Lsetxattr(path, xattrNameSelinux, []byte(scon), 0)
}

func Getfilecon(path string) (string, error) {
	var scon []byte

	cnt, err := syscall.Getxattr(path, xattrNameSelinux, scon)
	scon = make([]byte, cnt)
	cnt, err = syscall.Getxattr(path, xattrNameSelinux, scon)
	return string(scon), err
}

func Setfscreatecon(scon string) error {
	return writeCon("/proc/self/attr/fscreate", scon)
}

func Getfscreatecon() (string, error) {
	return readCon("/proc/self/attr/fscreate")
}

func Getcon() (string, error) {
	return readCon("/proc/self/attr/current")
}

func Getpidcon(pid int) (string, error) {
	return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
}

func Getexeccon() (string, error) {
	return readCon("/proc/self/attr/exec")
}

func writeCon(name string, val string) error {
	if !SelinuxEnabled() {
		return nil
	}
	out, err := os.OpenFile(name, os.O_WRONLY, 0)
	if err != nil {
		return err
	}
	defer out.Close()

	if val != "" {
		_, err = out.Write([]byte(val))
	} else {
		_, err = out.Write(nil)
	}
	return err
}

func Setexeccon(scon string) error {
	return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), scon)
}

func (c SELinuxContext) Get() string {
	return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
}

func NewContext(scon string) SELinuxContext {
	c := make(SELinuxContext)

	if len(scon) != 0 {
		con := strings.SplitN(scon, ":", 4)
		c["user"] = con[0]
		c["role"] = con[1]
		c["type"] = con[2]
		c["level"] = con[3]
	}
	return c
}

func SelinuxGetEnforce() int {
	var enforce int

	enforceS, err := readCon(fmt.Sprintf("%s/enforce", selinuxPath))
	if err != nil {
		return -1
	}

	enforce, err = strconv.Atoi(string(enforceS))
	if err != nil {
		return -1
	}
	return enforce
}

func SelinuxGetEnforceMode() int {
	switch ReadConfig(selinuxTag) {
	case "enforcing":
		return Enforcing
	case "permissive":
		return Permissive
	}
	return Disabled
}

func mcsAdd(mcs string) {
	mcsList[mcs] = true
}

func mcsDelete(mcs string) {
	mcsList[mcs] = false
}

func mcsExists(mcs string) bool {
	return mcsList[mcs]
}

func IntToMcs(id int, catRange uint32) string {
	var (
		SETSIZE = int(catRange)
		TIER    = SETSIZE
		ORD     = id
	)

	if id < 1 || id > 523776 {
		return ""
	}

	for ORD > TIER {
		ORD = ORD - TIER
		TIER -= 1
	}
	TIER = SETSIZE - TIER
	ORD = ORD + TIER
	return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
}

func uniqMcs(catRange uint32) string {
	var (
		n      uint32
		c1, c2 uint32
		mcs    string
	)

	for {
		binary.Read(rand.Reader, binary.LittleEndian, &n)
		c1 = n % catRange
		binary.Read(rand.Reader, binary.LittleEndian, &n)
		c2 = n % catRange
		if c1 == c2 {
			continue
		} else {
			if c1 > c2 {
				t := c1
				c1 = c2
				c2 = t
			}
		}
		mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
		if mcsExists(mcs) {
			continue
		}
		mcsAdd(mcs)
		break
	}
	return mcs
}

func FreeContext(con string) {
	if con != "" {
		scon := NewContext(con)
		mcsDelete(scon["level"])
	}
}

func GetLxcContexts() (processLabel string, fileLabel string) {
	var (
		val, key string
		bufin    *bufio.Reader
	)

	if !SelinuxEnabled() {
		return "", ""
	}
	lxcPath := fmt.Sprintf("%s/content/lxc_contexts", GetSELinuxPolicyRoot())
	in, err := os.Open(lxcPath)
	if err != nil {
		return "", ""
	}
	defer in.Close()

	bufin = bufio.NewReader(in)

	for done := false; !done; {
		var line string
		if line, err = bufin.ReadString('\n'); err != nil {
			if err == io.EOF {
				done = true
			} else {
				goto exit
			}
		}
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			// Skip blank lines
			continue
		}
		if line[0] == ';' || line[0] == '#' {
			// Skip comments
			continue
		}
		if groups := assignRegex.FindStringSubmatch(line); groups != nil {
			key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
			if key == "process" {
				processLabel = strings.Trim(val, "\"")
			}
			if key == "file" {
				fileLabel = strings.Trim(val, "\"")
			}
		}
	}

	if processLabel == "" || fileLabel == "" {
		return "", ""
	}

exit:
	mcs := IntToMcs(os.Getpid(), 1024)
	scon := NewContext(processLabel)
	scon["level"] = mcs
	processLabel = scon.Get()
	scon = NewContext(fileLabel)
	scon["level"] = mcs
	fileLabel = scon.Get()
	return processLabel, fileLabel
}

func SecurityCheckContext(val string) error {
	return writeCon(fmt.Sprintf("%s.context", selinuxPath), val)
}

func CopyLevel(src, dest string) (string, error) {
	if !SelinuxEnabled() {
		return "", nil
	}
	if src == "" {
		return "", nil
	}
	if err := SecurityCheckContext(src); err != nil {
		return "", err
	}
	if err := SecurityCheckContext(dest); err != nil {
		return "", err
	}
	scon := NewContext(src)
	tcon := NewContext(dest)
	tcon["level"] = scon["level"]
	return tcon.Get(), nil
}
<|endoftext|>


<commit_before>package slinga

func (state *ServiceUsageState) Endpoints() map[string]map[string]string {
	result := make(map[string]map[string]string)

	for _, key := range state.ProcessingOrder {
		if _, ok := result[key]; ok {
			continue
		}

		serviceName, _ /*contextName*/, _ /*allocationName*/, componentName := ParseServiceUsageKey(key)
		component := state.Policy.Services[serviceName].getComponentsMap()[componentName]
		if component != nil  && component.Code != nil {
			codeExecutor, err := component.Code.GetCodeExecutor(key, component.Code.Metadata, state.ResolvedLinks[key].CalculatedCodeParams, state.Policy.Clusters)
			if err != nil {
				panic(err)
			}
			endpoints, err := codeExecutor.Endpoints()
			if err != nil {
				panic(err)
			}

			if len(endpoints) > 0 {
				result[key] = endpoints
			}
		}
	}

	return result
}
<commit_msg>Replace panics with fatals<commit_after>package slinga

import (
	log "github.com/Sirupsen/logrus"
)

func (state *ServiceUsageState) Endpoints() map[string]map[string]string {
	result := make(map[string]map[string]string)

	for _, key := range state.ProcessingOrder {
		if _, ok := result[key]; ok {
			continue
		}

		serviceName, _ /*contextName*/, _ /*allocationName*/, componentName := ParseServiceUsageKey(key)
		component := state.Policy.Services[serviceName].getComponentsMap()[componentName]
		if component != nil  && component.Code != nil {
			codeExecutor, err := component.Code.GetCodeExecutor(key, component.Code.Metadata, state.ResolvedLinks[key].CalculatedCodeParams, state.Policy.Clusters)
			if err != nil {
				debug.WithFields(log.Fields{
					"key":  key,
					"error": err,
				}).Fatal("Unable to get CodeExecutor")
			}
			endpoints, err := codeExecutor.Endpoints()
			if err != nil {
				debug.WithFields(log.Fields{
					"key":  key,
					"error": err,
				}).Fatal("Error while getting endpoints")
			}

			if len(endpoints) > 0 {
				result[key] = endpoints
			}
		}
	}

	return result
}
<|endoftext|>


<commit_before>package cmd

import (
	"log"

	"github.com/lileio/account_service"
	"github.com/lileio/account_service/database"
	"github.com/lileio/account_service/server"
	"github.com/lileio/lile"
	"github.com/spf13/cobra"
	"google.golang.org/grpc"
)

var serverCmd = &cobra.Command{
	Use:   "server",
	Short: "Run the gRPC server",
	Run: func(cmd *cobra.Command, args []string) {
		db := database.DatabaseFromEnv()
		defer db.Close()

		as := server.AccountServer{DB: db}

		impl := func(g *grpc.Server) {
			account_service.RegisterAccountServiceServer(g, as)
		}

		err := lile.NewServer(
			lile.Name("account_service"),
			lile.Implementation(impl),
		).ListenAndServe()

		log.Fatal(err)
	},
}

func init() {
	RootCmd.AddCommand(serverCmd)
}
<commit_msg>Add migrations to server command<commit_after>package cmd

import (
	"log"

	"github.com/lileio/account_service"
	"github.com/lileio/account_service/database"
	"github.com/lileio/account_service/server"
	"github.com/lileio/lile"
	"github.com/spf13/cobra"
	"google.golang.org/grpc"
)

var serverCmd = &cobra.Command{
	Use:   "server",
	Short: "Run the gRPC server",
	Run: func(cmd *cobra.Command, args []string) {
		db := database.DatabaseFromEnv()
		err := db.Migrate()
		if err != nil {
			log.Fatal(err)
		}

		defer db.Close()

		as := server.AccountServer{DB: db}

		impl := func(g *grpc.Server) {
			account_service.RegisterAccountServiceServer(g, as)
		}

		err = lile.NewServer(
			lile.Name("account_service"),
			lile.Implementation(impl),
		).ListenAndServe()

		log.Fatal(err)
	},
}

func init() {
	RootCmd.AddCommand(serverCmd)
}
<|endoftext|>