<commit_before>/*
   Copyright 2017 Shlomi Noach, GitHub 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 process

import (
	"sync"
	"sync/atomic"
	"time"

	"github.com/github/orchestrator/go/config"

	"github.com/github/orchestrator/go/raft"
	"github.com/openark/golib/log"
	"github.com/patrickmn/go-cache"
)

var lastHealthCheckUnixNano int64
var lastGoodHealthCheckUnixNano int64
var LastContinousCheckHealthy int64

var lastHealthCheckCache = cache.New(config.HealthPollSeconds*time.Second, time.Second)

type NodeHealth struct {
	Hostname        string
	Token           string
	AppVersion      string
	FirstSeenActive string
	LastSeenActive  string
	ExtraInfo       string
	Command         string
	DBBackend       string

	LastReported time.Time
	onceHistory  sync.Once
	onceUpdate   sync.Once
}

func NewNodeHealth() *NodeHealth {
	return &NodeHealth{
		Hostname:   ThisHostname,
		Token:      ProcessToken.Hash,
		AppVersion: config.RuntimeCLIFlags.ConfiguredVersion,
	}
}

func (nodeHealth *NodeHealth) Update() *NodeHealth {
	nodeHealth.onceUpdate.Do(func() {
		nodeHealth.Hostname = ThisHostname
		nodeHealth.Token = ProcessToken.Hash
		nodeHealth.AppVersion = config.RuntimeCLIFlags.ConfiguredVersion
	})
	nodeHealth.LastReported = time.Now()
	return nodeHealth
}

var ThisNodeHealth = NewNodeHealth()

type HealthStatus struct {
	Healthy        bool
	Hostname       string
	Token          string
	IsActiveNode   bool
	ActiveNode     NodeHealth
	Error          error
	AvailableNodes [](*NodeHealth)
}

type OrchestratorExecutionMode string

const (
	OrchestratorExecutionCliMode  OrchestratorExecutionMode = "CLIMode"
	OrchestratorExecutionHttpMode                           = "HttpMode"
)

var continuousRegistrationOnce sync.Once

func RegisterNode(nodeHealth *NodeHealth) (healthy bool, err error) {
	nodeHealth.Update()
	healthy, err = WriteRegisterNode(nodeHealth)
	atomic.StoreInt64(&lastHealthCheckUnixNano, time.Now().UnixNano())
	if healthy {
		atomic.StoreInt64(&lastGoodHealthCheckUnixNano, time.Now().UnixNano())
	}
	return healthy, err
}

// HealthTest attempts to write to the backend database and get a result
func HealthTest() (health *HealthStatus, err error) {
	log.Debugf(".....................0")
	cacheKey := ProcessToken.Hash
	if healthStatus, found := lastHealthCheckCache.Get(cacheKey); found {
		return healthStatus.(*HealthStatus), nil
	}

	health = &HealthStatus{Healthy: false, Hostname: ThisHostname, Token: ProcessToken.Hash}
	defer lastHealthCheckCache.Set(cacheKey, health, cache.DefaultExpiration)

	if healthy, err := RegisterNode(ThisNodeHealth); err != nil {
		health.Error = err
		return health, log.Errore(err)
	} else {
		health.Healthy = healthy
	}

	if orcraft.IsRaftEnabled() {
		health.ActiveNode.Hostname = orcraft.GetLeader()
		health.IsActiveNode = orcraft.IsLeader()
	} else {
		if health.ActiveNode, health.IsActiveNode, err = ElectedNode(); err != nil {
			health.Error = err
			return health, log.Errore(err)
		}
	}
	health.AvailableNodes, err = ReadAvailableNodes(true)

	return health, nil
}

func SinceLastHealthCheck() time.Duration {
	timeNano := atomic.LoadInt64(&lastHealthCheckUnixNano)
	if timeNano == 0 {
		return 0
	}
	return time.Since(time.Unix(0, timeNano))
}

func SinceLastGoodHealthCheck() time.Duration {
	timeNano := atomic.LoadInt64(&lastGoodHealthCheckUnixNano)
	if timeNano == 0 {
		return 0
	}
	return time.Since(time.Unix(0, timeNano))
}

// ContinuousRegistration will continuously update the node_health
// table showing that the current process is still running.
func ContinuousRegistration(extraInfo string, command string) {
	ThisNodeHealth.ExtraInfo = extraInfo
	ThisNodeHealth.Command = command
	continuousRegistrationOnce.Do(func() {
		tickOperation := func() {
			healthy, err := RegisterNode(ThisNodeHealth)
			if err != nil {
				log.Errorf("ContinuousRegistration: RegisterNode failed: %+v", err)
			}
			if healthy {
				atomic.StoreInt64(&LastContinousCheckHealthy, 1)
			} else {
				atomic.StoreInt64(&LastContinousCheckHealthy, 0)
			}
		}
		// First one is synchronous
		tickOperation()
		go func() {
			registrationTick := time.Tick(config.HealthPollSeconds * time.Second)
			for range registrationTick {
				// We already run inside a go-routine so
				// do not do this asynchronously.  If we
				// get stuck then we don't want to fill up
				// the backend pool with connections running
				// this maintenance operation.
				tickOperation()
			}
		}()
	})
}
<commit_msg>removed debug line<commit_after>/*
   Copyright 2017 Shlomi Noach, GitHub 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 process

import (
	"sync"
	"sync/atomic"
	"time"

	"github.com/github/orchestrator/go/config"

	"github.com/github/orchestrator/go/raft"
	"github.com/openark/golib/log"
	"github.com/patrickmn/go-cache"
)

var lastHealthCheckUnixNano int64
var lastGoodHealthCheckUnixNano int64
var LastContinousCheckHealthy int64

var lastHealthCheckCache = cache.New(config.HealthPollSeconds*time.Second, time.Second)

type NodeHealth struct {
	Hostname        string
	Token           string
	AppVersion      string
	FirstSeenActive string
	LastSeenActive  string
	ExtraInfo       string
	Command         string
	DBBackend       string

	LastReported time.Time
	onceHistory  sync.Once
	onceUpdate   sync.Once
}

func NewNodeHealth() *NodeHealth {
	return &NodeHealth{
		Hostname:   ThisHostname,
		Token:      ProcessToken.Hash,
		AppVersion: config.RuntimeCLIFlags.ConfiguredVersion,
	}
}

func (nodeHealth *NodeHealth) Update() *NodeHealth {
	nodeHealth.onceUpdate.Do(func() {
		nodeHealth.Hostname = ThisHostname
		nodeHealth.Token = ProcessToken.Hash
		nodeHealth.AppVersion = config.RuntimeCLIFlags.ConfiguredVersion
	})
	nodeHealth.LastReported = time.Now()
	return nodeHealth
}

var ThisNodeHealth = NewNodeHealth()

type HealthStatus struct {
	Healthy        bool
	Hostname       string
	Token          string
	IsActiveNode   bool
	ActiveNode     NodeHealth
	Error          error
	AvailableNodes [](*NodeHealth)
}

type OrchestratorExecutionMode string

const (
	OrchestratorExecutionCliMode  OrchestratorExecutionMode = "CLIMode"
	OrchestratorExecutionHttpMode                           = "HttpMode"
)

var continuousRegistrationOnce sync.Once

func RegisterNode(nodeHealth *NodeHealth) (healthy bool, err error) {
	nodeHealth.Update()
	healthy, err = WriteRegisterNode(nodeHealth)
	atomic.StoreInt64(&lastHealthCheckUnixNano, time.Now().UnixNano())
	if healthy {
		atomic.StoreInt64(&lastGoodHealthCheckUnixNano, time.Now().UnixNano())
	}
	return healthy, err
}

// HealthTest attempts to write to the backend database and get a result
func HealthTest() (health *HealthStatus, err error) {
	cacheKey := ProcessToken.Hash
	if healthStatus, found := lastHealthCheckCache.Get(cacheKey); found {
		return healthStatus.(*HealthStatus), nil
	}

	health = &HealthStatus{Healthy: false, Hostname: ThisHostname, Token: ProcessToken.Hash}
	defer lastHealthCheckCache.Set(cacheKey, health, cache.DefaultExpiration)

	if healthy, err := RegisterNode(ThisNodeHealth); err != nil {
		health.Error = err
		return health, log.Errore(err)
	} else {
		health.Healthy = healthy
	}

	if orcraft.IsRaftEnabled() {
		health.ActiveNode.Hostname = orcraft.GetLeader()
		health.IsActiveNode = orcraft.IsLeader()
	} else {
		if health.ActiveNode, health.IsActiveNode, err = ElectedNode(); err != nil {
			health.Error = err
			return health, log.Errore(err)
		}
	}
	health.AvailableNodes, err = ReadAvailableNodes(true)

	return health, nil
}

func SinceLastHealthCheck() time.Duration {
	timeNano := atomic.LoadInt64(&lastHealthCheckUnixNano)
	if timeNano == 0 {
		return 0
	}
	return time.Since(time.Unix(0, timeNano))
}

func SinceLastGoodHealthCheck() time.Duration {
	timeNano := atomic.LoadInt64(&lastGoodHealthCheckUnixNano)
	if timeNano == 0 {
		return 0
	}
	return time.Since(time.Unix(0, timeNano))
}

// ContinuousRegistration will continuously update the node_health
// table showing that the current process is still running.
func ContinuousRegistration(extraInfo string, command string) {
	ThisNodeHealth.ExtraInfo = extraInfo
	ThisNodeHealth.Command = command
	continuousRegistrationOnce.Do(func() {
		tickOperation := func() {
			healthy, err := RegisterNode(ThisNodeHealth)
			if err != nil {
				log.Errorf("ContinuousRegistration: RegisterNode failed: %+v", err)
			}
			if healthy {
				atomic.StoreInt64(&LastContinousCheckHealthy, 1)
			} else {
				atomic.StoreInt64(&LastContinousCheckHealthy, 0)
			}
		}
		// First one is synchronous
		tickOperation()
		go func() {
			registrationTick := time.Tick(config.HealthPollSeconds * time.Second)
			for range registrationTick {
				// We already run inside a go-routine so
				// do not do this asynchronously.  If we
				// get stuck then we don't want to fill up
				// the backend pool with connections running
				// this maintenance operation.
				tickOperation()
			}
		}()
	})
}
<|endoftext|>


<commit_before>package tricorder

import (
	"fmt"
	"github.com/Symantec/tricorder/go/tricorder/types"
	"github.com/Symantec/tricorder/go/tricorder/units"
	"html/template"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

const (
	htmlUrl         = "/metrics"
	htmlTemplateStr = `
	\ {{define "METRIC"}} \
	  \ {{with $top := .}} \
            \ {{if .IsDistribution}} \
	      {{.Metric.AbsPath}} (distribution: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	      \ {{with .Metric.AsDistribution.Snapshot}} \

	        \ {{range .Breakdown}} \
	          \ {{if .Count}} \

                    \ {{if .First}} \
	              <{{$top.ToFloat32 .End}}:	{{.Count}}
	            \ {{else if .Last}} \
	              >={{$top.ToFloat32 .Start}}:	 {{.Count}}
	            \ {{else}} \
	              {{$top.ToFloat32 .Start}}-{{$top.ToFloat32 .End}}:	 {{.Count}}
	            \ {{end}} \

		  \ {{end}} \
		\ {{end}} \

	        \ {{if .Count}} \
		 min: {{$top.ToFloat32 .Min}} max: {{$top.ToFloat32 .Max}} avg: {{$top.ToFloat32 .Average}} ~median: {{$top.ToFloat32 .Median}} sum: {{$top.ToFloat32 .Sum}} count: {{.Count}}

	        \ {{end}} \
	      \ {{end}} \
	    \ {{else}} \
	      {{.Metric.AbsPath}} {{.AsHtmlString}} ({{.Metric.Type}}{{if .Metric.Bits}}{{.Metric.Bits}}{{end}}: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	    \ {{end}} \
	  \ {{end}} \
	\ {{end}} \

	  <link rel="stylesheet" type="text/css" href="/metricsstatic/theme.css">

	\ {{with $top := .}} \
	  \ {{if .Directory}} \
	    \ {{range .Directory.List}} \
	      \ {{if .Directory}} \
	        {{.Directory.AbsPath}}

              \ {{else}} \
	        \ {{template "METRIC" $top.AsMetricView .Metric}} \
	      \ {{end}} \
	    \ {{end}} \
	  \ {{else}} \
	    \ {{template "METRIC" .}} \
	  \ {{end}} \
	\ {{end}} \

	  `

	themeCss = `
	.summary {color:#999999; font-style: italic;}
	.parens {color:#999999;}
	  `
)

var (
	leadingWhitespace = regexp.MustCompile(`\n\s*\\ `)
	htmlTemplate      = template.Must(
		template.New("browser").Parse(
			strings.Replace(
				leadingWhitespace.ReplaceAllString(
					htmlTemplateStr, "\n"),
				" \\\n",
				"",
				-1)))
)

type htmlView struct {
	Directory *directory
	Metric    *metric
	Session   *session
}

func (v *htmlView) AsMetricView(m *metric) *htmlView {
	return &htmlView{Metric: m, Session: v.Session}
}

func (v *htmlView) AsHtmlString() string {
	return v.Metric.AsHtmlString(v.Session)
}

func (v *htmlView) IsDistribution() bool {
	return v.Metric.Type() == types.Dist
}

func (v *htmlView) HasUnit() bool {
	return v.Metric.Unit != units.None
}

func (v *htmlView) Link(d *directory) string {
	return htmlUrl + d.AbsPath()
}

func (v *htmlView) ToFloat32(f float64) float32 {
	return float32(f)
}

func htmlEmitMetric(m *metric, s *session, w io.Writer) error {
	v := &htmlView{Metric: m, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectory(d *directory, s *session, w io.Writer) error {
	v := &htmlView{Directory: d, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "Path does not exist.")
		return nil
	}
	s := newSession()
	defer s.Close()
	if m == nil {
		return htmlEmitDirectory(d, s, w)
	}
	return htmlEmitMetric(m, s, w)
}

type textCollector struct {
	W io.Writer
}

func (c *textCollector) Collect(m *metric, s *session) (err error) {
	if _, err = fmt.Fprintf(c.W, "%s ", m.AbsPath()); err != nil {
		return
	}
	return textEmitMetric(m, s, c.W)
}

func textEmitDistribution(s *snapshot, w io.Writer) error {
	_, err := fmt.Fprintf(
		w,
		"{min:%s;max:%s;avg:%s;median:%s;sum:%s;count:%d",
		strconv.FormatFloat(s.Min, 'f', -1, 32),
		strconv.FormatFloat(s.Max, 'f', -1, 32),
		strconv.FormatFloat(s.Average, 'f', -1, 32),
		strconv.FormatFloat(s.Median, 'f', -1, 32),
		strconv.FormatFloat(s.Sum, 'f', -1, 32),
		s.Count)
	if err != nil {
		return err
	}
	for _, piece := range s.Breakdown {
		if piece.Count == 0 {
			continue
		}
		if piece.First {
			_, err := fmt.Fprintf(
				w,
				";[-inf,%s):%d",
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else if piece.Last {
			_, err := fmt.Fprintf(
				w,
				";[%s,inf):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else {
			_, err := fmt.Fprintf(
				w,
				";[%s,%s):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		}
	}
	_, err = fmt.Fprintf(w, "}\n")
	return err
}

func textEmitMetric(m *metric, s *session, w io.Writer) error {
	if m.Type() == types.Dist {
		return textEmitDistribution(m.AsDistribution().Snapshot(), w)
	}
	_, err := fmt.Fprintf(w, "%s\n", m.AsTextString(s))
	return err
}

func textEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "*Path does not exist.*")
		return nil
	}
	if m == nil {
		return d.GetAllMetrics(&textCollector{W: w}, nil)
	}
	return textEmitMetric(m, nil, w)
}

func htmlAndTextHandlerFunc(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	path := r.URL.Path
	var err error
	if r.Form.Get("format") == "text" {
		err = textEmitDirectoryOrMetric(path, w)
	} else {
		err = htmlEmitDirectoryOrMetric(path, w)
	}
	if err != nil {
		handleError(w, err)
	}
}

func newStatic() http.Handler {
	result := http.NewServeMux()
	addStatic(result, "/theme.css", themeCss)
	return result
}

func initHtmlHandlers() {
	http.Handle(
		htmlUrl+"/",
		http.StripPrefix(
			htmlUrl, http.HandlerFunc(htmlAndTextHandlerFunc)))
	http.Handle(
		"/metricsstatic/",
		http.StripPrefix("/metricsstatic", newStatic()))
}
<commit_msg>Git rid of leading tab in html lines.<commit_after>package tricorder

import (
	"fmt"
	"github.com/Symantec/tricorder/go/tricorder/types"
	"github.com/Symantec/tricorder/go/tricorder/units"
	"html/template"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

const (
	htmlUrl         = "/metrics"
	htmlTemplateStr = ` \
	\ {{define "METRIC"}} \
	  \ {{with $top := .}} \
            \ {{if .IsDistribution}} \
	      {{.Metric.AbsPath}} (distribution: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	      \ {{with .Metric.AsDistribution.Snapshot}} \

	        \ {{range .Breakdown}} \
	          \ {{if .Count}} \

                    \ {{if .First}} \
	              <{{$top.ToFloat32 .End}}:	{{.Count}}
	            \ {{else if .Last}} \
	              >={{$top.ToFloat32 .Start}}:	 {{.Count}}
	            \ {{else}} \
	              {{$top.ToFloat32 .Start}}-{{$top.ToFloat32 .End}}:	 {{.Count}}
	            \ {{end}} \

		  \ {{end}} \
		\ {{end}} \

	        \ {{if .Count}} \
		 min: {{$top.ToFloat32 .Min}} max: {{$top.ToFloat32 .Max}} avg: {{$top.ToFloat32 .Average}} ~median: {{$top.ToFloat32 .Median}} sum: {{$top.ToFloat32 .Sum}} count: {{.Count}}

	        \ {{end}} \
	      \ {{end}} \
	    \ {{else}} \
	      {{.Metric.AbsPath}} {{.AsHtmlString}} ({{.Metric.Type}}{{if .Metric.Bits}}{{.Metric.Bits}}{{end}}: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	    \ {{end}} \
	  \ {{end}} \
	\ {{end}} \

	  <link rel="stylesheet" type="text/css" href="/metricsstatic/theme.css">

	\ {{with $top := .}} \
	  \ {{if .Directory}} \
	    \ {{range .Directory.List}} \
	      \ {{if .Directory}} \
	        {{.Directory.AbsPath}}

              \ {{else}} \
	        \ {{template "METRIC" $top.AsMetricView .Metric}} \
	      \ {{end}} \
	    \ {{end}} \
	  \ {{else}} \
	    \ {{template "METRIC" .}} \
	  \ {{end}} \
	\ {{end}} \

	  `

	themeCss = `
	.summary {color:#999999; font-style: italic;}
	.parens {color:#999999;}
	  `
)

var (
	leadingWhitespace = regexp.MustCompile(`\n\s*\\ `)
	htmlTemplate      = template.Must(
		template.New("browser").Parse(
			strings.Replace(
				leadingWhitespace.ReplaceAllString(
					strings.Replace(
						htmlTemplateStr,
						"\n\t",
						"\n",
						-1),
					"\n"),
				" \\\n",
				"",
				-1)))
)

type htmlView struct {
	Directory *directory
	Metric    *metric
	Session   *session
}

func (v *htmlView) AsMetricView(m *metric) *htmlView {
	return &htmlView{Metric: m, Session: v.Session}
}

func (v *htmlView) AsHtmlString() string {
	return v.Metric.AsHtmlString(v.Session)
}

func (v *htmlView) IsDistribution() bool {
	return v.Metric.Type() == types.Dist
}

func (v *htmlView) HasUnit() bool {
	return v.Metric.Unit != units.None
}

func (v *htmlView) Link(d *directory) string {
	return htmlUrl + d.AbsPath()
}

func (v *htmlView) ToFloat32(f float64) float32 {
	return float32(f)
}

func htmlEmitMetric(m *metric, s *session, w io.Writer) error {
	v := &htmlView{Metric: m, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectory(d *directory, s *session, w io.Writer) error {
	v := &htmlView{Directory: d, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "Path does not exist.")
		return nil
	}
	s := newSession()
	defer s.Close()
	if m == nil {
		return htmlEmitDirectory(d, s, w)
	}
	return htmlEmitMetric(m, s, w)
}

type textCollector struct {
	W io.Writer
}

func (c *textCollector) Collect(m *metric, s *session) (err error) {
	if _, err = fmt.Fprintf(c.W, "%s ", m.AbsPath()); err != nil {
		return
	}
	return textEmitMetric(m, s, c.W)
}

func textEmitDistribution(s *snapshot, w io.Writer) error {
	_, err := fmt.Fprintf(
		w,
		"{min:%s;max:%s;avg:%s;median:%s;sum:%s;count:%d",
		strconv.FormatFloat(s.Min, 'f', -1, 32),
		strconv.FormatFloat(s.Max, 'f', -1, 32),
		strconv.FormatFloat(s.Average, 'f', -1, 32),
		strconv.FormatFloat(s.Median, 'f', -1, 32),
		strconv.FormatFloat(s.Sum, 'f', -1, 32),
		s.Count)
	if err != nil {
		return err
	}
	for _, piece := range s.Breakdown {
		if piece.Count == 0 {
			continue
		}
		if piece.First {
			_, err := fmt.Fprintf(
				w,
				";[-inf,%s):%d",
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else if piece.Last {
			_, err := fmt.Fprintf(
				w,
				";[%s,inf):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else {
			_, err := fmt.Fprintf(
				w,
				";[%s,%s):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		}
	}
	_, err = fmt.Fprintf(w, "}\n")
	return err
}

func textEmitMetric(m *metric, s *session, w io.Writer) error {
	if m.Type() == types.Dist {
		return textEmitDistribution(m.AsDistribution().Snapshot(), w)
	}
	_, err := fmt.Fprintf(w, "%s\n", m.AsTextString(s))
	return err
}

func textEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "*Path does not exist.*")
		return nil
	}
	if m == nil {
		return d.GetAllMetrics(&textCollector{W: w}, nil)
	}
	return textEmitMetric(m, nil, w)
}

func htmlAndTextHandlerFunc(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	path := r.URL.Path
	var err error
	if r.Form.Get("format") == "text" {
		err = textEmitDirectoryOrMetric(path, w)
	} else {
		err = htmlEmitDirectoryOrMetric(path, w)
	}
	if err != nil {
		handleError(w, err)
	}
}

func newStatic() http.Handler {
	result := http.NewServeMux()
	addStatic(result, "/theme.css", themeCss)
	return result
}

func initHtmlHandlers() {
	http.Handle(
		htmlUrl+"/",
		http.StripPrefix(
			htmlUrl, http.HandlerFunc(htmlAndTextHandlerFunc)))
	http.Handle(
		"/metricsstatic/",
		http.StripPrefix("/metricsstatic", newStatic()))
}
<|endoftext|>


<commit_before>package list

import "github.com/qlova/ilang/src"

var Type = ilang.NewType("list", "SHARE", "GRAB")

func ScanStatement(ic *ilang.Compiler) {
	var name = ic.Scan(ilang.Name)
	var t  = ic.GetVariable(name)
	var token = ic.Scan(0)

	//TODO CLEAN THIS UP!
	switch token {
		case "-":
			ic.Scan('-')
			ic.Assembly("PLACE ", name)
			ic.Assembly("POP ", ic.Tmp("cut"))

		case "+":
			ic.Scan('=')

			value := ic.ScanExpression()

			if t.SubType == nil {
				t.SubType = &ic.ExpressionType
				ic.UpdateVariable(name, t)
			}

			if ic.ExpressionType != *t.SubType {
				ic.RaiseError("Cannot add value of type '",ic.ExpressionType.Name,"' to a list of '",t.SubType.Name,"'")
			}

			ic.Assembly("PLACE ", name)
			ic.Assembly("PUT ", ic.GetPointerTo(value))

		case "[":

			index := ic.ScanExpression()
			ic.Scan(']')

			token = ic.Scan(0)
			if token == "=" {

				value := ic.ScanExpression()
				ic.Assembly("PUSH ", index)
				ic.Assembly("PLACE ", name)
				ic.Assembly("SET ", ic.GetPointerTo(value))

			} else {
				var pointer = ic.Tmp("pointer")
				ic.Assembly("PUSH ", index)
				ic.Assembly("PLACE ", name)
				ic.Assembly("GET ", pointer)

				ic.NextToken = pointer
				ic.NextNextToken = token
				ic.ScanExpression()
			}

		case "=":

		default:
			ic.ExpressionType = t
			ic.NextToken = token
			ic.Shunt(name)
			if ic.ExpressionType != ilang.Undefined {
				ic.RaiseError("blank expression!")
			}
	}
}

func ScanSymbol(ic *ilang.Compiler) ilang.Type {
	var ListType = Type
	ListType.SubType = new(ilang.Type)
	*ListType.SubType = ic.ScanSymbolicType()
	return ListType
}

func ScanExpression(ic *ilang.Compiler) string {
	var token = ic.LastToken
	//Types.
	if token == "[" {

		var tmp = ic.Tmp("newlist")
		ic.Assembly("ARRAY ", tmp)

		var ListType = ilang.Undefined

		if tok := ic.Scan(0); tok == "]" {
			ic.ExpressionType = Type
			return tmp
		} else {
			ic.NextToken = tok
		}

		for {
			value := ic.ScanExpression()
			if (ListType == ilang.Undefined) {
				ListType = ic.ExpressionType
			}

			//Oh great, this needs to become a something list... #TODO
			if ic.ExpressionType != ListType {
				ic.RaiseError("Consistency error! There is a ", ic.ExpressionType.Name,
				" value in the list.\nThis is inconsistant with the previous elements which are ",ListType.Name," values.")
			}

			ic.Assembly("PLACE ", tmp)
			ic.Assembly("PUT ", ic.GetPointerTo(value))

			token = ic.Scan(0)
			if token != "," {
				if token == "]" {
					ic.ExpressionType = Type
					ic.ExpressionType.SubType = &ListType
					break
				}
				ic.RaiseError("Expecting ,")
			}
		}

		return tmp
	}

	return ""
}

func Shunt(ic *ilang.Compiler, name string) string {
	if ic.ExpressionType.Name == "list" {
		var list = ic.ExpressionType

		index := ic.ScanExpression()
		ic.Scan(']')
		if ic.ExpressionType != ilang.Number {
			ic.RaiseError("Index must be a number.")
		}

		if list.SubType == nil {
			ic.RaiseError("List elements are undefined!")
		}

		var pointer = ic.Tmp("index")
		ic.Assembly("PUSH ", index)
		ic.Assembly("PLACE ", name)
		ic.Assembly("GET ", pointer)

		ic.ExpressionType = *list.SubType

		return ic.Dereference(pointer)
	}
	return ""
}

var Number = Type

func init() {
	Number.SubType = new(ilang.Type)
	*Number.SubType = ilang.Number

	ilang.RegisterStatement(Type, ScanStatement)
	ilang.RegisterSymbol("..", ScanSymbol)
	ilang.RegisterShunt("[", Shunt)
	ilang.RegisterExpression(ScanExpression)

	ilang.RegisterFunction("table", ilang.Method(Type, true, "PUSH 64\nMAKE\nPUSH 0\nHEAP\n"))
	ilang.RegisterFunction("text_m_numberlist", ilang.BlankMethod(ilang.Text))

	ilang.RegisterFunction("copy_m_numberlist", ilang.Function{Exists:true, Returns:[]ilang.Type{Number}, Data: `
	#Compiled with IC.
	FUNCTION copy_m_numberlist
		GRAB array
		ARRAY c

		VAR i
		LOOP
			VAR i+shunt+1
			SGE i+shunt+1 i #array
			IF i+shunt+1
				SHARE c
				RETURN
			END
			PLACE array
				PUSH i
				GET i+shunt+3
			VAR v
			ADD v 0 i+shunt+3
			PLACE c
				PUT v
			ADD i i 1
		REPEAT
	RETURN
	`})
}

<commit_msg>Fix unusual bug.<commit_after>package list

import "github.com/qlova/ilang/src"

var Type = ilang.NewType("list", "SHARE", "GRAB")

func ScanStatement(ic *ilang.Compiler) {
	var name = ic.Scan(ilang.Name)
	var t  = ic.GetVariable(name)
	var token = ic.Scan(0)

	//TODO CLEAN THIS UP!
	switch token {
		case "-":
			ic.Scan('-')
			ic.Assembly("PLACE ", name)
			ic.Assembly("POP ", ic.Tmp("cut"))

		case "+":
			ic.Scan('=')

			value := ic.ScanExpression()

			if t.SubType == nil {
				t.SubType = new(ilang.Type)
				*t.SubType = ic.ExpressionType
				ic.UpdateVariable(name, t)
			}

			if ic.ExpressionType != *t.SubType {
				ic.RaiseError("Cannot add value of type '",ic.ExpressionType.Name,"' to a list of '",t.SubType.Name,"'")
			}

			ic.Assembly("PLACE ", name)
			ic.Assembly("PUT ", ic.GetPointerTo(value))

		case "[":

			index := ic.ScanExpression()
			ic.Scan(']')

			token = ic.Scan(0)
			if token == "=" {

				value := ic.ScanExpression()
				ic.Assembly("PUSH ", index)
				ic.Assembly("PLACE ", name)
				ic.Assembly("SET ", ic.GetPointerTo(value))

			} else {
				var pointer = ic.Tmp("pointer")
				ic.Assembly("PUSH ", index)
				ic.Assembly("PLACE ", name)
				ic.Assembly("GET ", pointer)

				ic.NextToken = pointer
				ic.NextNextToken = token
				ic.ScanExpression()
			}

		case "=":

		default:
			ic.ExpressionType = t
			ic.NextToken = token
			ic.Shunt(name)
			if ic.ExpressionType != ilang.Undefined {
				ic.RaiseError("blank expression!")
			}
	}
}

func ScanSymbol(ic *ilang.Compiler) ilang.Type {
	var ListType = Type
	ListType.SubType = new(ilang.Type)
	*ListType.SubType = ic.ScanSymbolicType()
	return ListType
}

func ScanExpression(ic *ilang.Compiler) string {
	var token = ic.LastToken
	//Types.
	if token == "[" {

		var tmp = ic.Tmp("newlist")
		ic.Assembly("ARRAY ", tmp)

		var ListType = ilang.Undefined

		if tok := ic.Scan(0); tok == "]" {
			ic.ExpressionType = Type
			return tmp
		} else {
			ic.NextToken = tok
		}

		for {
			value := ic.ScanExpression()
			if (ListType == ilang.Undefined) {
				ListType = ic.ExpressionType
			}

			//Oh great, this needs to become a something list... #TODO
			if ic.ExpressionType != ListType {
				ic.RaiseError("Consistency error! There is a ", ic.ExpressionType.Name,
				" value in the list.\nThis is inconsistant with the previous elements which are ",ListType.Name," values.")
			}

			ic.Assembly("PLACE ", tmp)
			ic.Assembly("PUT ", ic.GetPointerTo(value))

			token = ic.Scan(0)
			if token != "," {
				if token == "]" {
					ic.ExpressionType = Type
					ic.ExpressionType.SubType = &ListType
					break
				}
				ic.RaiseError("Expecting ,")
			}
		}

		return tmp
	}

	return ""
}

func Shunt(ic *ilang.Compiler, name string) string {
	if ic.ExpressionType.Name == "list" {
		var list = ic.ExpressionType

		index := ic.ScanExpression()
		ic.Scan(']')
		if ic.ExpressionType != ilang.Number {
			ic.RaiseError("Index must be a number.")
		}

		if list.SubType == nil {
			ic.RaiseError("List elements are undefined!")
		}

		var pointer = ic.Tmp("index")
		ic.Assembly("PUSH ", index)
		ic.Assembly("PLACE ", name)
		ic.Assembly("GET ", pointer)

		ic.ExpressionType = *list.SubType

		return ic.Dereference(pointer)
	}
	return ""
}

var Number = Type

func init() {
	Number.SubType = new(ilang.Type)
	*Number.SubType = ilang.Number

	ilang.RegisterStatement(Type, ScanStatement)
	ilang.RegisterSymbol("..", ScanSymbol)
	ilang.RegisterShunt("[", Shunt)
	ilang.RegisterExpression(ScanExpression)

	ilang.RegisterFunction("table", ilang.Method(Type, true, "PUSH 64\nMAKE\nPUSH 0\nHEAP\n"))
	ilang.RegisterFunction("text_m_numberlist", ilang.BlankMethod(ilang.Text))

	ilang.RegisterFunction("copy_m_numberlist", ilang.Function{Exists:true, Returns:[]ilang.Type{Number}, Data: `
	#Compiled with IC.
	FUNCTION copy_m_numberlist
		GRAB array
		ARRAY c

		VAR i
		LOOP
			VAR i+shunt+1
			SGE i+shunt+1 i #array
			IF i+shunt+1
				SHARE c
				RETURN
			END
			PLACE array
				PUSH i
				GET i+shunt+3
			VAR v
			ADD v 0 i+shunt+3
			PLACE c
				PUT v
			ADD i i 1
		REPEAT
	RETURN
	`})
}

<|endoftext|>


<commit_before>package transformer

import (
	"math"

	rpb "github.com/ampproject/amppackager/transformer/request"
	"github.com/pkg/errors"
)

// SupportedVersions is a set of all transform versions supported by this
// snapshot of the library. This should not include transforms not yet
// snapshotted to a finalized version.
// The ranges should be non-overlapping and in descending order.
// Visible for test.
var SupportedVersions = []*rpb.VersionRange{{Min: 1, Max: 4}}

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

// intervalsOverlap returns true if there exists at least one value in both `a`
// and `b`. This assumes `a` and `b` are not malformed.
func intervalsOverlap(a, b *rpb.VersionRange) bool {
	return a.Max >= b.Min && a.Min <= b.Max
}

// isGreater returns true if all of the values in `a` are greater than all of
// the values in `b`. This assumes `a` and `b` are not malformed.
func isGreater(a, b *rpb.VersionRange) bool {
	return a.Min > b.Max
}

// validateRequest verifies the request is properly formed.
func validateRequest(rs []*rpb.VersionRange) error {
	var lastMin int64 = math.MaxInt64
	for i, r := range rs {
		if r.Min > r.Max {
			return errors.Errorf("malformed range %v at index %d", r, i)
		}
		if r.Min < 1 || r.Max < 1 {
			return errors.Errorf("non-positive value in range %v at index %d", r, i)
		}
		if r.Max >= lastMin {
			return errors.Errorf("overlapping or out-of-order range %v at index %d", r, i)
		}
		lastMin = r.Min
	}
	return nil
}

func selectVersion(requested, supported []*rpb.VersionRange) (int64, error) {
	// If request is invalid, then error.
	if err := validateRequest(requested); err != nil {
		return 0, err
	}
	// If no versions are supported, then huh.
	if len(supported) == 0 {
		return 0, errors.New("no version at all is supported by this transformer")
	}
	// If no requested versions are specified, then return the highest
	// support version.
	if len(requested) == 0 {
		return supported[0].Max, nil
	}
	// Otherwise, search for the highest number in both sets.
	for r, s := 0, 0; r < len(requested) && s < len(supported); {
		if intervalsOverlap(requested[r], supported[s]) {
			return min(requested[r].Max, supported[s].Max), nil
		} else if isGreater(requested[r], supported[s]) {
			r++
		} else {
			s++
		}
	}
	return 0, errors.New("no requested version is supported by this transformer")
}

// SelectVersion returns the highest requested version number that the
// transformer supports, or an error if no such version exists. The requested
// list must consist of non-overlapping ranges in descending order.
//
// The transfomer will select the highest version from requested that it
// supports. If requested is nil or empty, the transfomer will select the
// highest version it supports. In both cases, it shouldn't include
// in-development versions.
func SelectVersion(requested []*rpb.VersionRange) (int64, error) {
	return selectVersion(requested, SupportedVersions)
}
<commit_msg>Release version 5 of the AMP transforms.<commit_after>package transformer

import (
	"math"

	rpb "github.com/ampproject/amppackager/transformer/request"
	"github.com/pkg/errors"
)

// SupportedVersions is a set of all transform versions supported by this
// snapshot of the library. This should not include transforms not yet
// snapshotted to a finalized version.
// The ranges should be non-overlapping and in descending order.
// Visible for test.
var SupportedVersions = []*rpb.VersionRange{{Min: 1, Max: 5}}

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

// intervalsOverlap returns true if there exists at least one value in both `a`
// and `b`. This assumes `a` and `b` are not malformed.
func intervalsOverlap(a, b *rpb.VersionRange) bool {
	return a.Max >= b.Min && a.Min <= b.Max
}

// isGreater returns true if all of the values in `a` are greater than all of
// the values in `b`. This assumes `a` and `b` are not malformed.
func isGreater(a, b *rpb.VersionRange) bool {
	return a.Min > b.Max
}

// validateRequest verifies the request is properly formed.
func validateRequest(rs []*rpb.VersionRange) error {
	var lastMin int64 = math.MaxInt64
	for i, r := range rs {
		if r.Min > r.Max {
			return errors.Errorf("malformed range %v at index %d", r, i)
		}
		if r.Min < 1 || r.Max < 1 {
			return errors.Errorf("non-positive value in range %v at index %d", r, i)
		}
		if r.Max >= lastMin {
			return errors.Errorf("overlapping or out-of-order range %v at index %d", r, i)
		}
		lastMin = r.Min
	}
	return nil
}

func selectVersion(requested, supported []*rpb.VersionRange) (int64, error) {
	// If request is invalid, then error.
	if err := validateRequest(requested); err != nil {
		return 0, err
	}
	// If no versions are supported, then huh.
	if len(supported) == 0 {
		return 0, errors.New("no version at all is supported by this transformer")
	}
	// If no requested versions are specified, then return the highest
	// support version.
	if len(requested) == 0 {
		return supported[0].Max, nil
	}
	// Otherwise, search for the highest number in both sets.
	for r, s := 0, 0; r < len(requested) && s < len(supported); {
		if intervalsOverlap(requested[r], supported[s]) {
			return min(requested[r].Max, supported[s].Max), nil
		} else if isGreater(requested[r], supported[s]) {
			r++
		} else {
			s++
		}
	}
	return 0, errors.New("no requested version is supported by this transformer")
}

// SelectVersion returns the highest requested version number that the
// transformer supports, or an error if no such version exists. The requested
// list must consist of non-overlapping ranges in descending order.
//
// The transfomer will select the highest version from requested that it
// supports. If requested is nil or empty, the transfomer will select the
// highest version it supports. In both cases, it shouldn't include
// in-development versions.
func SelectVersion(requested []*rpb.VersionRange) (int64, error) {
	return selectVersion(requested, SupportedVersions)
}
<|endoftext|>


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

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

var (
	localUpTimeout = flag.Duration("local-up-timeout", 2*time.Minute, "(local only) Time limit between 'local-up-cluster.sh' and a response from the Kubernetes API.")
)

func removeAllContainers(cli *client.Client) {
	// list all containers
	listOptions := types.ContainerListOptions{
		Quiet: true,
		All:   true,
	}
	containers, err := cli.ContainerList(context.Background(), listOptions)
	if err != nil {
		log.Printf("Failed to list containers: %v\n", err)
		return
	}

	// reverse sort by Creation time so we delete newest containers first
	sort.Slice(containers, func(i, j int) bool {
		return containers[i].Created > containers[j].Created
	})

	// stop then remove (which implicitly kills) each container
	duration := time.Second * 1
	removeOptions := types.ContainerRemoveOptions{
		RemoveVolumes: true,
		Force:         true,
	}
	for _, container := range containers {
		log.Printf("Stopping container: %v %s with ID: %s\n",
			container.Names, container.Image, container.ID)
		err = cli.ContainerStop(context.Background(), container.ID, &duration)
		if err != nil {
			log.Printf("Error stopping container: %v\n", err)
		}

		log.Printf("Removing container: %v %s with ID: %s\n",
			container.Names, container.Image, container.ID)
		err = cli.ContainerRemove(context.Background(), container.ID, removeOptions)
		if err != nil {
			log.Printf("Error removing container: %v\n", err)
		}
	}
}

type localCluster struct {
	tempDir    string
	kubeConfig string
}

var _ deployer = localCluster{}

func newLocalCluster() *localCluster {
	tempDir, err := ioutil.TempDir("", "kubetest-local")
	if err != nil {
		log.Fatal("unable to create temp directory")
	}
	err = os.Chmod(tempDir, 0755)
	if err != nil {
		log.Fatal("unable to change temp directory permissions")
	}
	return &localCluster{
		tempDir: tempDir,
	}
}

func (n localCluster) getScript(scriptPath string) (string, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	path := filepath.Join(cwd, scriptPath)
	if _, err := os.Stat(path); err == nil {
		return path, nil
	}
	return "", fmt.Errorf("unable to find script %v in directory %v", scriptPath, cwd)
}

func (n localCluster) Up() error {
	script, err := n.getScript("hack/local-up-cluster.sh")
	if err != nil {
		return err
	}

	cmd := exec.Command(script)
	cmd.Env = os.Environ()

	cmd.Env = append(cmd.Env, "ENABLE_DAEMON=true")
	cmd.Env = append(cmd.Env, fmt.Sprintf("LOG_DIR=%s", n.tempDir))

	// Needed for at least one conformance e2e test. Please see issue #59978
	cmd.Env = append(cmd.Env, "ALLOW_PRIVILEGED=true")

	// when we are running in a DIND scenario, we should use the ip address of
	// the docker0 network interface, This ensures that when the pods come up
	// the health checks (for example for kubedns) succeed. If there is no
	// docker0, just use the defaults in local-up-cluster.sh
	dockerIP := ""
	docker0, err := net.InterfaceByName("docker0")
	if err == nil {
		addresses, err := docker0.Addrs()
		if err == nil {
			for _, address := range addresses {
				if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
					if ipnet.IP.To4() != nil {
						dockerIP = ipnet.IP.String()
						break
					}
				}
			}
		} else {
			log.Printf("unable to get addresses from docker0 interface : %v", err)
		}
	} else {
		log.Printf("unable to find docker0 interface : %v", err)
	}
	if dockerIP != "" {
		log.Printf("using %v for API_HOST_IP, HOSTNAME_OVERRIDE, KUBELET_HOST", dockerIP)
		cmd.Env = append(cmd.Env, fmt.Sprintf("API_HOST_IP=%s", dockerIP))
		cmd.Env = append(cmd.Env, fmt.Sprintf("HOSTNAME_OVERRIDE=%s", dockerIP))
		cmd.Env = append(cmd.Env, fmt.Sprintf("KUBELET_HOST=%s", dockerIP))
	} else {
		log.Println("using local-up-cluster.sh's defaults for API_HOST_IP, HOSTNAME_OVERRIDE, KUBELET_HOST")
	}

	err = control.FinishRunning(cmd)
	if err != nil {
		return err
	}
	n.kubeConfig = "/var/run/kubernetes/admin.kubeconfig"
	_, err = os.Stat(n.kubeConfig)
	return err
}

func (n localCluster) IsUp() error {
	if n.kubeConfig != "" {
		if err := os.Setenv("KUBECONFIG", n.kubeConfig); err != nil {
			return err
		}
	}
	if err := os.Setenv("KUBERNETES_CONFORMANCE_TEST", "yes"); err != nil {
		return err
	}
	if err := os.Setenv("KUBERNETES_PROVIDER", "local"); err != nil {
		return err
	}

	stop := time.Now().Add(*localUpTimeout)
	for {
		script, err := n.getScript("cluster/kubectl.sh")
		if err != nil {
			return err
		}
		nodes, err := kubectlGetNodes(script)
		if err != nil {
			return err
		}
		readyNodes := countReadyNodes(nodes)
		if readyNodes > 0 {
			return nil
		}
		if time.Now().After(stop) {
			break
		} else {
			time.Sleep(5 * time.Second)
		}
	}
	return errors.New("local-up-cluster.sh is not ready")
}

func (n localCluster) DumpClusterLogs(localPath, gcsPath string) error {
	cmd := exec.Command("sudo", "cp", "-r", n.tempDir, localPath)
	return control.FinishRunning(cmd)
}

func (n localCluster) TestSetup() error {
	return nil
}

func (n localCluster) Down() error {
	// create docker client
	cli, err := client.NewEnvClient()
	if err != nil {
		log.Printf("Docker containers cleanup, unable to create Docker client: %v", err)
	}
	// make sure all containers are removed
	removeAllContainers(cli)
	err = control.FinishRunning(exec.Command("pkill", "hyperkube"))
	if err != nil {
		log.Printf("unable to kill hyperkube processes: %v", err)
	}
	err = control.FinishRunning(exec.Command("pkill", "etcd"))
	if err != nil {
		log.Printf("unable to kill etcd: %v", err)
	}
	return nil
}

func (n localCluster) GetClusterCreated(gcpProject string) (time.Time, error) {
	return time.Time{}, errors.New("GetClusterCreated not implemented in localCluster")
}

func (_ localCluster) KubectlCommand() (*exec.Cmd, error) { return nil, nil }
<commit_msg>Drop sudo from local-e2e DumpClusterLogs<commit_after>/*
Copyright 2018 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 main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

var (
	localUpTimeout = flag.Duration("local-up-timeout", 2*time.Minute, "(local only) Time limit between 'local-up-cluster.sh' and a response from the Kubernetes API.")
)

func removeAllContainers(cli *client.Client) {
	// list all containers
	listOptions := types.ContainerListOptions{
		Quiet: true,
		All:   true,
	}
	containers, err := cli.ContainerList(context.Background(), listOptions)
	if err != nil {
		log.Printf("Failed to list containers: %v\n", err)
		return
	}

	// reverse sort by Creation time so we delete newest containers first
	sort.Slice(containers, func(i, j int) bool {
		return containers[i].Created > containers[j].Created
	})

	// stop then remove (which implicitly kills) each container
	duration := time.Second * 1
	removeOptions := types.ContainerRemoveOptions{
		RemoveVolumes: true,
		Force:         true,
	}
	for _, container := range containers {
		log.Printf("Stopping container: %v %s with ID: %s\n",
			container.Names, container.Image, container.ID)
		err = cli.ContainerStop(context.Background(), container.ID, &duration)
		if err != nil {
			log.Printf("Error stopping container: %v\n", err)
		}

		log.Printf("Removing container: %v %s with ID: %s\n",
			container.Names, container.Image, container.ID)
		err = cli.ContainerRemove(context.Background(), container.ID, removeOptions)
		if err != nil {
			log.Printf("Error removing container: %v\n", err)
		}
	}
}

type localCluster struct {
	tempDir    string
	kubeConfig string
}

var _ deployer = localCluster{}

func newLocalCluster() *localCluster {
	tempDir, err := ioutil.TempDir("", "kubetest-local")
	if err != nil {
		log.Fatal("unable to create temp directory")
	}
	err = os.Chmod(tempDir, 0755)
	if err != nil {
		log.Fatal("unable to change temp directory permissions")
	}
	return &localCluster{
		tempDir: tempDir,
	}
}

func (n localCluster) getScript(scriptPath string) (string, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	path := filepath.Join(cwd, scriptPath)
	if _, err := os.Stat(path); err == nil {
		return path, nil
	}
	return "", fmt.Errorf("unable to find script %v in directory %v", scriptPath, cwd)
}

func (n localCluster) Up() error {
	script, err := n.getScript("hack/local-up-cluster.sh")
	if err != nil {
		return err
	}

	cmd := exec.Command(script)
	cmd.Env = os.Environ()

	cmd.Env = append(cmd.Env, "ENABLE_DAEMON=true")
	cmd.Env = append(cmd.Env, fmt.Sprintf("LOG_DIR=%s", n.tempDir))

	// Needed for at least one conformance e2e test. Please see issue #59978
	cmd.Env = append(cmd.Env, "ALLOW_PRIVILEGED=true")

	// when we are running in a DIND scenario, we should use the ip address of
	// the docker0 network interface, This ensures that when the pods come up
	// the health checks (for example for kubedns) succeed. If there is no
	// docker0, just use the defaults in local-up-cluster.sh
	dockerIP := ""
	docker0, err := net.InterfaceByName("docker0")
	if err == nil {
		addresses, err := docker0.Addrs()
		if err == nil {
			for _, address := range addresses {
				if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
					if ipnet.IP.To4() != nil {
						dockerIP = ipnet.IP.String()
						break
					}
				}
			}
		} else {
			log.Printf("unable to get addresses from docker0 interface : %v", err)
		}
	} else {
		log.Printf("unable to find docker0 interface : %v", err)
	}
	if dockerIP != "" {
		log.Printf("using %v for API_HOST_IP, HOSTNAME_OVERRIDE, KUBELET_HOST", dockerIP)
		cmd.Env = append(cmd.Env, fmt.Sprintf("API_HOST_IP=%s", dockerIP))
		cmd.Env = append(cmd.Env, fmt.Sprintf("HOSTNAME_OVERRIDE=%s", dockerIP))
		cmd.Env = append(cmd.Env, fmt.Sprintf("KUBELET_HOST=%s", dockerIP))
	} else {
		log.Println("using local-up-cluster.sh's defaults for API_HOST_IP, HOSTNAME_OVERRIDE, KUBELET_HOST")
	}

	err = control.FinishRunning(cmd)
	if err != nil {
		return err
	}
	n.kubeConfig = "/var/run/kubernetes/admin.kubeconfig"
	_, err = os.Stat(n.kubeConfig)
	return err
}

func (n localCluster) IsUp() error {
	if n.kubeConfig != "" {
		if err := os.Setenv("KUBECONFIG", n.kubeConfig); err != nil {
			return err
		}
	}
	if err := os.Setenv("KUBERNETES_CONFORMANCE_TEST", "yes"); err != nil {
		return err
	}
	if err := os.Setenv("KUBERNETES_PROVIDER", "local"); err != nil {
		return err
	}

	stop := time.Now().Add(*localUpTimeout)
	for {
		script, err := n.getScript("cluster/kubectl.sh")
		if err != nil {
			return err
		}
		nodes, err := kubectlGetNodes(script)
		if err != nil {
			return err
		}
		readyNodes := countReadyNodes(nodes)
		if readyNodes > 0 {
			return nil
		}
		if time.Now().After(stop) {
			break
		} else {
			time.Sleep(5 * time.Second)
		}
	}
	return errors.New("local-up-cluster.sh is not ready")
}

func (n localCluster) DumpClusterLogs(localPath, gcsPath string) error {
	cmd := exec.Command("cp", "-r", n.tempDir, localPath)
	return control.FinishRunning(cmd)
}

func (n localCluster) TestSetup() error {
	return nil
}

func (n localCluster) Down() error {
	// create docker client
	cli, err := client.NewEnvClient()
	if err != nil {
		log.Printf("Docker containers cleanup, unable to create Docker client: %v", err)
	}
	// make sure all containers are removed
	removeAllContainers(cli)
	err = control.FinishRunning(exec.Command("pkill", "hyperkube"))
	if err != nil {
		log.Printf("unable to kill hyperkube processes: %v", err)
	}
	err = control.FinishRunning(exec.Command("pkill", "etcd"))
	if err != nil {
		log.Printf("unable to kill etcd: %v", err)
	}
	return nil
}

func (n localCluster) GetClusterCreated(gcpProject string) (time.Time, error) {
	return time.Time{}, errors.New("GetClusterCreated not implemented in localCluster")
}

func (_ localCluster) KubectlCommand() (*exec.Cmd, error) { return nil, nil }
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package kv

// UnionStore is a store that wraps a snapshot for read and a BufferStore for buffered write.
// Also, it provides some transaction related utilities.
type UnionStore interface {
	MemBuffer
	// Returns related condition pair
	LookupConditionPair(k Key) *conditionPair
	// DeleteConditionPair deletes a condition pair.
	DeleteConditionPair(k Key)
	// WalkBuffer iterates all buffered kv pairs.
	WalkBuffer(f func(k Key, v []byte) error) error
	// SetOption sets an option with a value, when val is nil, uses the default
	// value of this option.
	SetOption(opt Option, val interface{})
	// DelOption deletes an option.
	DelOption(opt Option)
	// GetOption gets an option.
	GetOption(opt Option) interface{}
	// GetMemBuffer return the MemBuffer binding to this UnionStore.
	GetMemBuffer() MemBuffer
}

// AssertionType is the type of a assertion.
type AssertionType int

// The AssertionType constants.
const (
	None AssertionType = iota
	Exist
	NotExist
)

// Option is used for customizing kv store's behaviors during a transaction.
type Option int

// Options is an interface of a set of options. Each option is associated with a value.
type Options interface {
	// Get gets an option value.
	Get(opt Option) (v interface{}, ok bool)
}

// conditionPair is used to store lazy check condition.
// If condition not match (value is not equal as expected one), returns err.
type conditionPair struct {
	key   Key
	value []byte
	err   error
}

func (c *conditionPair) ShouldNotExist() bool {
	return len(c.value) == 0
}

func (c *conditionPair) Err() error {
	return c.err
}

// unionStore is an in-memory Store which contains a buffer for write and a
// snapshot for read.
type unionStore struct {
	*BufferStore
	lazyConditionPairs map[string]*conditionPair // for delay check
	opts               options
}

// NewUnionStore builds a new UnionStore.
func NewUnionStore(snapshot Snapshot) UnionStore {
	return &unionStore{
		BufferStore:        NewBufferStore(snapshot, DefaultTxnMembufCap),
		lazyConditionPairs: make(map[string]*conditionPair),
		opts:               make(map[Option]interface{}),
	}
}

// invalidIterator implements Iterator interface.
// It is used for read-only transaction which has no data written, the iterator is always invalid.
type invalidIterator struct{}

func (it invalidIterator) Valid() bool {
	return false
}

func (it invalidIterator) Next() error {
	return nil
}

func (it invalidIterator) Key() Key {
	return nil
}

func (it invalidIterator) Value() []byte {
	return nil
}

func (it invalidIterator) Close() {}

// lazyMemBuffer wraps a MemBuffer which is to be initialized when it is modified.
type lazyMemBuffer struct {
	mb  MemBuffer
	cap int
}

func (lmb *lazyMemBuffer) Get(k Key) ([]byte, error) {
	if lmb.mb == nil {
		return nil, ErrNotExist
	}

	return lmb.mb.Get(k)
}

func (lmb *lazyMemBuffer) Set(key Key, value []byte) error {
	if lmb.mb == nil {
		lmb.mb = NewMemDbBuffer(lmb.cap)
	}

	return lmb.mb.Set(key, value)
}

func (lmb *lazyMemBuffer) Delete(k Key) error {
	if lmb.mb == nil {
		lmb.mb = NewMemDbBuffer(lmb.cap)
	}

	return lmb.mb.Delete(k)
}

func (lmb *lazyMemBuffer) Iter(k Key, upperBound Key) (Iterator, error) {
	if lmb.mb == nil {
		return invalidIterator{}, nil
	}
	return lmb.mb.Iter(k, upperBound)
}

func (lmb *lazyMemBuffer) IterReverse(k Key) (Iterator, error) {
	if lmb.mb == nil {
		return invalidIterator{}, nil
	}
	return lmb.mb.IterReverse(k)
}

func (lmb *lazyMemBuffer) Size() int {
	if lmb.mb == nil {
		return 0
	}
	return lmb.mb.Size()
}

func (lmb *lazyMemBuffer) Len() int {
	if lmb.mb == nil {
		return 0
	}
	return lmb.mb.Len()
}

func (lmb *lazyMemBuffer) Reset() {
	if lmb.mb != nil {
		lmb.mb.Reset()
	}
}

func (lmb *lazyMemBuffer) SetCap(cap int) {
	lmb.cap = cap
}

// Get implements the Retriever interface.
func (us *unionStore) Get(k Key) ([]byte, error) {
	v, err := us.MemBuffer.Get(k)
	if IsErrNotFound(err) {
		if _, ok := us.opts.Get(PresumeKeyNotExists); ok {
			e, ok := us.opts.Get(PresumeKeyNotExistsError)
			if ok && e != nil {
				us.markLazyConditionPair(k, nil, e.(error))
			} else {
				us.markLazyConditionPair(k, nil, ErrKeyExists)
			}
			return nil, ErrNotExist
		}
	}
	if IsErrNotFound(err) {
		v, err = us.BufferStore.r.Get(k)
	}
	if err != nil {
		return v, err
	}
	if len(v) == 0 {
		return nil, ErrNotExist
	}
	return v, nil
}

// markLazyConditionPair marks a kv pair for later check.
// If condition not match, should return e as error.
func (us *unionStore) markLazyConditionPair(k Key, v []byte, e error) {
	us.lazyConditionPairs[string(k)] = &conditionPair{
		key:   k.Clone(),
		value: v,
		err:   e,
	}
}

func (us *unionStore) LookupConditionPair(k Key) *conditionPair {
	if c, ok := us.lazyConditionPairs[string(k)]; ok {
		return c
	}
	return nil
}

func (us *unionStore) DeleteConditionPair(k Key) {
	delete(us.lazyConditionPairs, string(k))
}

// SetOption implements the UnionStore SetOption interface.
func (us *unionStore) SetOption(opt Option, val interface{}) {
	us.opts[opt] = val
}

// DelOption implements the UnionStore DelOption interface.
func (us *unionStore) DelOption(opt Option) {
	delete(us.opts, opt)
}

// GetOption implements the UnionStore GetOption interface.
func (us *unionStore) GetOption(opt Option) interface{} {
	return us.opts[opt]
}

// GetMemBuffer return the MemBuffer binding to this UnionStore.
func (us *unionStore) GetMemBuffer() MemBuffer {
	return us.BufferStore.MemBuffer
}

// SetCap sets membuffer capability.
func (us *unionStore) SetCap(cap int) {
	us.BufferStore.SetCap(cap)
}

func (us *unionStore) Reset() {
	us.BufferStore.Reset()
}

type options map[Option]interface{}

func (opts options) Get(opt Option) (interface{}, bool) {
	v, ok := opts[opt]
	return v, ok
}
<commit_msg>kv: tiny cleanup (#10961)<commit_after>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package kv

// UnionStore is a store that wraps a snapshot for read and a BufferStore for buffered write.
// Also, it provides some transaction related utilities.
type UnionStore interface {
	MemBuffer
	// Returns related condition pair
	LookupConditionPair(k Key) *conditionPair
	// DeleteConditionPair deletes a condition pair.
	DeleteConditionPair(k Key)
	// WalkBuffer iterates all buffered kv pairs.
	WalkBuffer(f func(k Key, v []byte) error) error
	// SetOption sets an option with a value, when val is nil, uses the default
	// value of this option.
	SetOption(opt Option, val interface{})
	// DelOption deletes an option.
	DelOption(opt Option)
	// GetOption gets an option.
	GetOption(opt Option) interface{}
	// GetMemBuffer return the MemBuffer binding to this UnionStore.
	GetMemBuffer() MemBuffer
}

// AssertionType is the type of a assertion.
type AssertionType int

// The AssertionType constants.
const (
	None AssertionType = iota
	Exist
	NotExist
)

// Option is used for customizing kv store's behaviors during a transaction.
type Option int

// Options is an interface of a set of options. Each option is associated with a value.
type Options interface {
	// Get gets an option value.
	Get(opt Option) (v interface{}, ok bool)
}

// conditionPair is used to store lazy check condition.
// If condition not match (value is not equal as expected one), returns err.
type conditionPair struct {
	key   Key
	value []byte
	err   error
}

func (c *conditionPair) ShouldNotExist() bool {
	return len(c.value) == 0
}

func (c *conditionPair) Err() error {
	return c.err
}

// unionStore is an in-memory Store which contains a buffer for write and a
// snapshot for read.
type unionStore struct {
	*BufferStore
	lazyConditionPairs map[string]*conditionPair // for delay check
	opts               options
}

// NewUnionStore builds a new UnionStore.
func NewUnionStore(snapshot Snapshot) UnionStore {
	return &unionStore{
		BufferStore:        NewBufferStore(snapshot, DefaultTxnMembufCap),
		lazyConditionPairs: make(map[string]*conditionPair),
		opts:               make(map[Option]interface{}),
	}
}

// invalidIterator implements Iterator interface.
// It is used for read-only transaction which has no data written, the iterator is always invalid.
type invalidIterator struct{}

func (it invalidIterator) Valid() bool {
	return false
}

func (it invalidIterator) Next() error {
	return nil
}

func (it invalidIterator) Key() Key {
	return nil
}

func (it invalidIterator) Value() []byte {
	return nil
}

func (it invalidIterator) Close() {}

// lazyMemBuffer wraps a MemBuffer which is to be initialized when it is modified.
type lazyMemBuffer struct {
	mb  MemBuffer
	cap int
}

func (lmb *lazyMemBuffer) Get(k Key) ([]byte, error) {
	if lmb.mb == nil {
		return nil, ErrNotExist
	}

	return lmb.mb.Get(k)
}

func (lmb *lazyMemBuffer) Set(key Key, value []byte) error {
	if lmb.mb == nil {
		lmb.mb = NewMemDbBuffer(lmb.cap)
	}

	return lmb.mb.Set(key, value)
}

func (lmb *lazyMemBuffer) Delete(k Key) error {
	if lmb.mb == nil {
		lmb.mb = NewMemDbBuffer(lmb.cap)
	}

	return lmb.mb.Delete(k)
}

func (lmb *lazyMemBuffer) Iter(k Key, upperBound Key) (Iterator, error) {
	if lmb.mb == nil {
		return invalidIterator{}, nil
	}
	return lmb.mb.Iter(k, upperBound)
}

func (lmb *lazyMemBuffer) IterReverse(k Key) (Iterator, error) {
	if lmb.mb == nil {
		return invalidIterator{}, nil
	}
	return lmb.mb.IterReverse(k)
}

func (lmb *lazyMemBuffer) Size() int {
	if lmb.mb == nil {
		return 0
	}
	return lmb.mb.Size()
}

func (lmb *lazyMemBuffer) Len() int {
	if lmb.mb == nil {
		return 0
	}
	return lmb.mb.Len()
}

func (lmb *lazyMemBuffer) Reset() {
	if lmb.mb != nil {
		lmb.mb.Reset()
	}
}

func (lmb *lazyMemBuffer) SetCap(cap int) {
	lmb.cap = cap
}

// Get implements the Retriever interface.
func (us *unionStore) Get(k Key) ([]byte, error) {
	v, err := us.MemBuffer.Get(k)
	if IsErrNotFound(err) {
		if _, ok := us.opts.Get(PresumeKeyNotExists); ok {
			e, ok := us.opts.Get(PresumeKeyNotExistsError)
			if ok && e != nil {
				us.markLazyConditionPair(k, nil, e.(error))
			} else {
				us.markLazyConditionPair(k, nil, ErrKeyExists)
			}
			return nil, ErrNotExist
		}
		v, err = us.BufferStore.r.Get(k)
	}
	if err != nil {
		return v, err
	}
	if len(v) == 0 {
		return nil, ErrNotExist
	}
	return v, nil
}

// markLazyConditionPair marks a kv pair for later check.
// If condition not match, should return e as error.
func (us *unionStore) markLazyConditionPair(k Key, v []byte, e error) {
	us.lazyConditionPairs[string(k)] = &conditionPair{
		key:   k.Clone(),
		value: v,
		err:   e,
	}
}

func (us *unionStore) LookupConditionPair(k Key) *conditionPair {
	if c, ok := us.lazyConditionPairs[string(k)]; ok {
		return c
	}
	return nil
}

func (us *unionStore) DeleteConditionPair(k Key) {
	delete(us.lazyConditionPairs, string(k))
}

// SetOption implements the UnionStore SetOption interface.
func (us *unionStore) SetOption(opt Option, val interface{}) {
	us.opts[opt] = val
}

// DelOption implements the UnionStore DelOption interface.
func (us *unionStore) DelOption(opt Option) {
	delete(us.opts, opt)
}

// GetOption implements the UnionStore GetOption interface.
func (us *unionStore) GetOption(opt Option) interface{} {
	return us.opts[opt]
}

// GetMemBuffer return the MemBuffer binding to this UnionStore.
func (us *unionStore) GetMemBuffer() MemBuffer {
	return us.BufferStore.MemBuffer
}

// SetCap sets membuffer capability.
func (us *unionStore) SetCap(cap int) {
	us.BufferStore.SetCap(cap)
}

func (us *unionStore) Reset() {
	us.BufferStore.Reset()
}

type options map[Option]interface{}

func (opts options) Get(opt Option) (interface{}, bool) {
	v, ok := opts[opt]
	return v, ok
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"flag"
	"log"

	//_ "github.com/mattn/go-sqlite3"

	_ "github.com/lib/pq"
	"github.com/shopspring/decimal"
)

const DebitCreditPrecision int32 = 2

var accounts map[int64]*Account

var shares map[string]*Share

var netWorth decimal.Decimal

var db *sql.DB
var err error

func main() {
	log.SetFlags(log.LstdFlags | log.Llongfile)
	// Data
	accounts = make(map[int64]*Account)
	shares = make(map[string]*Share)

	setupConfig()

	setupDB()

	loadData()

	r := setupRouting()

	// Bind to a port and pass our router in
	listen := ":8000"
	log.Printf("Starting server on %s\n", listen)
	r.Run(listen)
}

func setupDB() {
	// db, err = sql.Open("sqlite3", "./lunchmoney.db")
	db, err = sql.Open("postgres", "")
	if err != nil {
		log.Printf("Error connect to the db: %s\n", err)
	}

	err = db.Ping()
	if err != nil {
		log.Fatal("Error connecting to the db: %s\n", err)
	}
}

func setupConfig() {
	flag.Parse()
}

func loadData() {
	query := `SELECT
		id,
		name,
		currency_code,
		currency_symbol_left,
		currency_symbol_right,
		decimal_places,
		icon,
		is_active,
		cleared_total,
		total
	FROM accounts`

	var id int64
	var cleared_total, total decimal.Decimal
	var decimal_places int32
	var name, currency_code, currency_symbol_left, currency_symbol_right, icon string
	var is_active bool

	rows, err := db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&id,
			&name,
			&currency_code,
			&currency_symbol_left,
			&currency_symbol_right,
			&decimal_places,
			&icon,
			&is_active,
			&cleared_total,
			&total,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		acc := &Account{
			ID:                  id,
			Name:                name,
			CurrencyCode:        currency_code,
			CurrencySymbolLeft:  currency_symbol_left,
			CurrencySymbolRight: currency_symbol_right,
			DecimalPlaces:       decimal_places,
			Icon:                icon,
			IsActive:            is_active,
			clearedTotal:        cleared_total,
			Total:               total,
		}

		acc.LoadTransactions()

		netWorth = netWorth.Add(acc.GetTotal())
		// log.Printf("%v\n", acc)
		accounts[acc.ID] = acc
	}
	err = rows.Err()
	if err != nil {
		log.Printf("%s\n", err)
		return
	}

	query = `SELECT stockcode, qty FROM shares`

	var stockcode string
	var qty int64

	rows, err = db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&stockcode,
			&qty,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		share := &Share{
			Code: stockcode,
			Qty:  qty,
		}
		share.GetValue()
		// log.Println(share)

		shares[stockcode] = share

		netWorth = netWorth.Add(share.Value)
	}

}
<commit_msg>Support for a config file<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"os"

	//_ "github.com/mattn/go-sqlite3"

	_ "github.com/lib/pq"
	"github.com/shopspring/decimal"
)

const DebitCreditPrecision int32 = 2

var accounts map[int64]*Account

var shares map[string]*Share

var netWorth decimal.Decimal

var db *sql.DB
var err error

var cfg Config

type Config struct {
	Listen string
	DSN    string
}

func main() {
	log.SetFlags(log.LstdFlags | log.Llongfile)
	// Data
	accounts = make(map[int64]*Account)
	shares = make(map[string]*Share)

	parseConfig()

	setupDB()

	loadData()

	r := setupRouting()

	// Bind to a port and pass our router in
	listen := cfg.Listen
	log.Printf("Starting server on %s\n", listen)
	r.Run(listen)
}

func parseConfig() {
	file, _ := os.Open("lunchmoney.json")
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&cfg)
	if err != nil {
		fmt.Println("error:", err)
	}
}

func setupDB() {
	// db, err = sql.Open("sqlite3", "./lunchmoney.db")
	db, err = sql.Open("postgres", cfg.DSN)
	if err != nil {
		log.Printf("Error connect to the db: %s\n", err)
	}

	err = db.Ping()
	if err != nil {
		log.Fatal("Error connecting to the db: %s\n", err)
	}
}

func loadData() {
	query := `SELECT
		id,
		name,
		currency_code,
		currency_symbol_left,
		currency_symbol_right,
		decimal_places,
		icon,
		is_active,
		cleared_total,
		total
	FROM accounts`

	var id int64
	var cleared_total, total decimal.Decimal
	var decimal_places int32
	var name, currency_code, currency_symbol_left, currency_symbol_right, icon string
	var is_active bool

	rows, err := db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&id,
			&name,
			&currency_code,
			&currency_symbol_left,
			&currency_symbol_right,
			&decimal_places,
			&icon,
			&is_active,
			&cleared_total,
			&total,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		acc := &Account{
			ID:                  id,
			Name:                name,
			CurrencyCode:        currency_code,
			CurrencySymbolLeft:  currency_symbol_left,
			CurrencySymbolRight: currency_symbol_right,
			DecimalPlaces:       decimal_places,
			Icon:                icon,
			IsActive:            is_active,
			clearedTotal:        cleared_total,
			Total:               total,
		}

		acc.LoadTransactions()

		netWorth = netWorth.Add(acc.GetTotal())
		// log.Printf("%v\n", acc)
		accounts[acc.ID] = acc
	}
	err = rows.Err()
	if err != nil {
		log.Printf("%s\n", err)
		return
	}

	query = `SELECT stockcode, qty FROM shares`

	var stockcode string
	var qty int64

	rows, err = db.Query(query)
	defer rows.Close()
	for rows.Next() {
		err := rows.Scan(
			&stockcode,
			&qty,
		)
		if err != nil {
			log.Printf("%s\n", err)
			return
		}

		share := &Share{
			Code: stockcode,
			Qty:  qty,
		}
		share.GetValue()
		// log.Println(share)

		shares[stockcode] = share

		netWorth = netWorth.Add(share.Value)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"unsafe"

	"github.com/gorilla/mux"

	"github.com/lxc/lxd/shared"
)

func socketPath() string {
	return shared.VarPath("devlxd")
}

type devLxdResponse struct {
	content interface{}
	code    int
	ctype   string
}

func okResponse(ct interface{}, ctype string) *devLxdResponse {
	return &devLxdResponse{ct, http.StatusOK, ctype}
}

type devLxdHandler struct {
	path string

	/*
	 * This API will have to be changed slightly when we decide to support
	 * websocket events upgrading, but since we don't have events on the
	 * server side right now either, I went the simple route to avoid
	 * needless noise.
	 */
	f func(c container, r *http.Request) *devLxdResponse
}

var configGet = devLxdHandler{"/1.0/config", func(c container, r *http.Request) *devLxdResponse {
	filtered := []string{}
	for k, _ := range c.ConfigGet() {
		if strings.HasPrefix(k, "user.") {
			filtered = append(filtered, fmt.Sprintf("/1.0/config/%s", k))
		}
	}
	return okResponse(filtered, "json")
}}

var configKeyGet = devLxdHandler{"/1.0/config/{key}", func(c container, r *http.Request) *devLxdResponse {
	key := mux.Vars(r)["key"]
	if !strings.HasPrefix(key, "user.") {
		return &devLxdResponse{"not authorized", http.StatusForbidden, "raw"}
	}

	value, ok := c.ConfigGet()[key]
	if !ok {
		return &devLxdResponse{"not found", http.StatusNotFound, "raw"}
	}

	return okResponse(value, "raw")
}}

var metadataGet = devLxdHandler{"/1.0/meta-data", func(c container, r *http.Request) *devLxdResponse {
	value := c.ConfigGet()["user.meta-data"]
	return okResponse(fmt.Sprintf("#cloud-config\ninstance-id: %s\nlocal-hostname: %s\n%s", c.NameGet(), c.NameGet(), value), "raw")
}}

var handlers = []devLxdHandler{
	devLxdHandler{"/", func(c container, r *http.Request) *devLxdResponse {
		return okResponse([]string{"/1.0"}, "json")
	}},
	devLxdHandler{"/1.0", func(c container, r *http.Request) *devLxdResponse {
		return okResponse(shared.Jmap{"api_compat": 0}, "json")
	}},
	configGet,
	configKeyGet,
	metadataGet,
	/* TODO: events */
}

func hoistReq(f func(container, *http.Request) *devLxdResponse, d *Daemon) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		conn := extractUnderlyingConn(w)
		pid, ok := pidMapper.m[conn]
		if !ok {
			http.Error(w, pidNotInContainerErr.Error(), 500)
			return
		}

		c, err := findContainerForPid(pid, d)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		resp := f(c, r)
		if resp.code != http.StatusOK {
			w.Header().Set("Content-Type", "application/octet-stream")
			http.Error(w, fmt.Sprintf("%s", resp.content), resp.code)
		} else if resp.ctype == "json" {
			w.Header().Set("Content-Type", "application/json")
			WriteJSON(w, resp.content)
		} else {
			w.Header().Set("Content-Type", "application/octet-stream")
			fmt.Fprintf(w, resp.content.(string))
		}
	}
}

func createAndBindDevLxd() (*net.UnixListener, error) {
	if err := os.MkdirAll(socketPath(), 0777); err != nil {
		return nil, err
	}

	sockFile := path.Join(socketPath(), "sock")

	/*
	 * If this socket exists, that means a previous lxd died and didn't
	 * clean up after itself. We assume that the LXD is actually dead if we
	 * get this far, since StartDaemon() tries to connect to the actual lxd
	 * socket to make sure that it is actually dead. So, it is safe to
	 * remove it here without any checks.
	 *
	 * Also, it would be nice to SO_REUSEADDR here so we don't have to
	 * delete the socket, but we can't:
	 *   http://stackoverflow.com/questions/15716302/so-reuseaddr-and-af-unix
	 *
	 * Note that this will force clients to reconnect when LXD is restarted.
	 */
	if err := os.Remove(sockFile); err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	unixAddr, err := net.ResolveUnixAddr("unix", sockFile)
	if err != nil {
		return nil, err
	}

	unixl, err := net.ListenUnix("unix", unixAddr)
	if err != nil {
		return nil, err
	}

	if err := os.Chmod(sockFile, 0666); err != nil {
		return nil, err
	}

	return unixl, nil
}

func setupDevLxdMount(c *containerLXD) error {
	mtab := fmt.Sprintf("%s dev/lxd none bind,create=dir 0 0", socketPath())
	return setConfigItem(c, "lxc.mount.entry", mtab)
}

func devLxdServer(d *Daemon) http.Server {
	m := mux.NewRouter()

	for _, handler := range handlers {
		m.HandleFunc(handler.path, hoistReq(handler.f, d))
	}

	return http.Server{
		Handler:   m,
		ConnState: pidMapper.ConnStateHandler,
	}
}

/*
 * Everything below here is the guts of the unix socket bits. Unfortunately,
 * golang's API does not make this easy. What happens is:
 *
 * 1. We install a ConnState listener on the http.Server, which does the
 *    initial unix socket credential exchange. When we get a connection started
 *    event, we use SO_PEERCRED to extract the creds for the socket.
 *
 * 2. We store a map from the connection pointer to the pid for that
 *    connection, so that once the HTTP negotiation occurrs and we get a
 *    ResponseWriter, we know (because we negotiated on the first byte) which
 *    pid the connection belogs to.
 *
 * 3. Regular HTTP negotiation and dispatch occurs via net/http.
 *
 * 4. When rendering the response via ResponseWriter, we match its underlying
 *    connection against what we stored in step (2) to figure out which container
 *    it came from.
 */

/*
 * We keep this in a global so that we can reference it from the server and
 * from our http handlers, since there appears to be no way to pass information
 * around here.
 */
var pidMapper = ConnPidMapper{m: map[*net.UnixConn]int32{}}

type ConnPidMapper struct {
	m map[*net.UnixConn]int32
}

func (m *ConnPidMapper) ConnStateHandler(conn net.Conn, state http.ConnState) {
	unixConn := conn.(*net.UnixConn)
	switch state {
	case http.StateNew:
		pid, err := getPid(unixConn)
		if err != nil {
			shared.Debugf("Error getting pid for conn %s", err)
		} else {
			m.m[unixConn] = pid
		}
	case http.StateActive:
		return
	case http.StateIdle:
		return
	case http.StateHijacked:
		/*
		 * The "Hijacked" state indicates that the connection has been
		 * taken over from net/http. This is useful for things like
		 * developing websocket libraries, who want to upgrade the
		 * connection to a websocket one, and not use net/http any
		 * more. Whatever the case, we want to forget about it since we
		 * won't see it either.
		 */
		delete(m.m, unixConn)
	case http.StateClosed:
		delete(m.m, unixConn)
	default:
		shared.Debugf("Unknown state for connection %s", state)
	}
}

/*
 * I also don't see that golang exports an API to get at the underlying FD, but
 * we need it to get at SO_PEERCRED, so let's grab it.
 */
func extractUnderlyingFd(unixConnPtr *net.UnixConn) int {
	conn := reflect.Indirect(reflect.ValueOf(unixConnPtr))
	netFdPtr := conn.FieldByName("fd")
	netFd := reflect.Indirect(netFdPtr)
	fd := netFd.FieldByName("sysfd")
	return int(fd.Int())
}

func getPid(conn *net.UnixConn) (int32, error) {
	fd := extractUnderlyingFd(conn)

	_, _, pid, err := getUcred(fd)
	if err != nil {
		return 0, err
	}

	return pid, nil
}

/*
 * As near as I can tell, there is no nice way of extracting an underlying
 * net.Conn (or in our case, net.UnixConn) from an http.Request or
 * ResponseWriter without hijacking it [1]. Since we want to send and recieve
 * unix creds to figure out which container this request came from, we need to
 * do this.
 *
 * [1]: https://groups.google.com/forum/#!topic/golang-nuts/_FWdFXJa6QA
 */
func extractUnderlyingConn(w http.ResponseWriter) *net.UnixConn {
	v := reflect.Indirect(reflect.ValueOf(w))
	connPtr := v.FieldByName("conn")
	conn := reflect.Indirect(connPtr)
	rwc := conn.FieldByName("rwc")

	netConnPtr := (*net.Conn)(unsafe.Pointer(rwc.UnsafeAddr()))
	unixConnPtr := (*netConnPtr).(*net.UnixConn)

	return unixConnPtr
}

var pidNotInContainerErr = fmt.Errorf("pid not in container?")

func findContainerForPid(pid int32, d *Daemon) (container, error) {
	/*
	 * Try and figure out which container a pid is in. There is probably a
	 * better way to do this. Based on rharper's initial performance
	 * metrics, looping over every container and calling newLxdContainer is
	 * expensive, so I wanted to avoid that if possible, so this happens in
	 * a two step process:
	 *
	 * 1. Walk up the process tree until you see something that looks like
	 *    an lxc monitor process and extract its name from there.
	 *
	 * 2. If this fails, it may be that someone did an `lxc exec foo bash`,
	 *    so the process isn't actually a decendant of the container's
	 *    init. In this case we just look through all the containers until
	 *    we find an init with a matching pid namespace. This is probably
	 *    uncommon, so hopefully the slowness won't hurt us.
	 */

	origpid := pid

	for pid > 1 {
		cmdline, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
		if err != nil {
			return nil, err
		}

		if strings.HasPrefix(string(cmdline), "[lxc monitor]") {
			// container names can't have spaces
			parts := strings.Split(string(cmdline), " ")
			name := parts[len(parts)-1]

			return containerLXDLoad(d, name)
		}

		status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
		if err != nil {
			return nil, err
		}

		re := regexp.MustCompile("PPid:\\s*([0-9]*)")
		for _, line := range strings.Split(string(status), "\n") {
			m := re.FindStringSubmatch(line)
			if m != nil && len(m) > 1 {
				result, err := strconv.Atoi(m[1])
				if err != nil {
					return nil, err
				}

				pid = int32(result)
				break
			}
		}
	}

	origPidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", origpid))
	if err != nil {
		return nil, err
	}

	containers, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		c, err := containerLXDLoad(d, container)
		if err != nil {
			return nil, err
		}

		initpid := c.InitPidGet()
		pidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", initpid))
		if err != nil {
			return nil, err
		}

		if origPidNs == pidNs {
			return c, nil
		}
	}

	return nil, pidNotInContainerErr
}
<commit_msg>don't pass lock by value<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"unsafe"

	"github.com/gorilla/mux"

	"github.com/lxc/lxd/shared"
)

func socketPath() string {
	return shared.VarPath("devlxd")
}

type devLxdResponse struct {
	content interface{}
	code    int
	ctype   string
}

func okResponse(ct interface{}, ctype string) *devLxdResponse {
	return &devLxdResponse{ct, http.StatusOK, ctype}
}

type devLxdHandler struct {
	path string

	/*
	 * This API will have to be changed slightly when we decide to support
	 * websocket events upgrading, but since we don't have events on the
	 * server side right now either, I went the simple route to avoid
	 * needless noise.
	 */
	f func(c container, r *http.Request) *devLxdResponse
}

var configGet = devLxdHandler{"/1.0/config", func(c container, r *http.Request) *devLxdResponse {
	filtered := []string{}
	for k, _ := range c.ConfigGet() {
		if strings.HasPrefix(k, "user.") {
			filtered = append(filtered, fmt.Sprintf("/1.0/config/%s", k))
		}
	}
	return okResponse(filtered, "json")
}}

var configKeyGet = devLxdHandler{"/1.0/config/{key}", func(c container, r *http.Request) *devLxdResponse {
	key := mux.Vars(r)["key"]
	if !strings.HasPrefix(key, "user.") {
		return &devLxdResponse{"not authorized", http.StatusForbidden, "raw"}
	}

	value, ok := c.ConfigGet()[key]
	if !ok {
		return &devLxdResponse{"not found", http.StatusNotFound, "raw"}
	}

	return okResponse(value, "raw")
}}

var metadataGet = devLxdHandler{"/1.0/meta-data", func(c container, r *http.Request) *devLxdResponse {
	value := c.ConfigGet()["user.meta-data"]
	return okResponse(fmt.Sprintf("#cloud-config\ninstance-id: %s\nlocal-hostname: %s\n%s", c.NameGet(), c.NameGet(), value), "raw")
}}

var handlers = []devLxdHandler{
	devLxdHandler{"/", func(c container, r *http.Request) *devLxdResponse {
		return okResponse([]string{"/1.0"}, "json")
	}},
	devLxdHandler{"/1.0", func(c container, r *http.Request) *devLxdResponse {
		return okResponse(shared.Jmap{"api_compat": 0}, "json")
	}},
	configGet,
	configKeyGet,
	metadataGet,
	/* TODO: events */
}

func hoistReq(f func(container, *http.Request) *devLxdResponse, d *Daemon) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		conn := extractUnderlyingConn(w)
		pid, ok := pidMapper.m[conn]
		if !ok {
			http.Error(w, pidNotInContainerErr.Error(), 500)
			return
		}

		c, err := findContainerForPid(pid, d)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		resp := f(c, r)
		if resp.code != http.StatusOK {
			w.Header().Set("Content-Type", "application/octet-stream")
			http.Error(w, fmt.Sprintf("%s", resp.content), resp.code)
		} else if resp.ctype == "json" {
			w.Header().Set("Content-Type", "application/json")
			WriteJSON(w, resp.content)
		} else {
			w.Header().Set("Content-Type", "application/octet-stream")
			fmt.Fprintf(w, resp.content.(string))
		}
	}
}

func createAndBindDevLxd() (*net.UnixListener, error) {
	if err := os.MkdirAll(socketPath(), 0777); err != nil {
		return nil, err
	}

	sockFile := path.Join(socketPath(), "sock")

	/*
	 * If this socket exists, that means a previous lxd died and didn't
	 * clean up after itself. We assume that the LXD is actually dead if we
	 * get this far, since StartDaemon() tries to connect to the actual lxd
	 * socket to make sure that it is actually dead. So, it is safe to
	 * remove it here without any checks.
	 *
	 * Also, it would be nice to SO_REUSEADDR here so we don't have to
	 * delete the socket, but we can't:
	 *   http://stackoverflow.com/questions/15716302/so-reuseaddr-and-af-unix
	 *
	 * Note that this will force clients to reconnect when LXD is restarted.
	 */
	if err := os.Remove(sockFile); err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	unixAddr, err := net.ResolveUnixAddr("unix", sockFile)
	if err != nil {
		return nil, err
	}

	unixl, err := net.ListenUnix("unix", unixAddr)
	if err != nil {
		return nil, err
	}

	if err := os.Chmod(sockFile, 0666); err != nil {
		return nil, err
	}

	return unixl, nil
}

func setupDevLxdMount(c *containerLXD) error {
	mtab := fmt.Sprintf("%s dev/lxd none bind,create=dir 0 0", socketPath())
	return setConfigItem(c, "lxc.mount.entry", mtab)
}

func devLxdServer(d *Daemon) *http.Server {
	m := mux.NewRouter()

	for _, handler := range handlers {
		m.HandleFunc(handler.path, hoistReq(handler.f, d))
	}

	return &http.Server{
		Handler:   m,
		ConnState: pidMapper.ConnStateHandler,
	}
}

/*
 * Everything below here is the guts of the unix socket bits. Unfortunately,
 * golang's API does not make this easy. What happens is:
 *
 * 1. We install a ConnState listener on the http.Server, which does the
 *    initial unix socket credential exchange. When we get a connection started
 *    event, we use SO_PEERCRED to extract the creds for the socket.
 *
 * 2. We store a map from the connection pointer to the pid for that
 *    connection, so that once the HTTP negotiation occurrs and we get a
 *    ResponseWriter, we know (because we negotiated on the first byte) which
 *    pid the connection belogs to.
 *
 * 3. Regular HTTP negotiation and dispatch occurs via net/http.
 *
 * 4. When rendering the response via ResponseWriter, we match its underlying
 *    connection against what we stored in step (2) to figure out which container
 *    it came from.
 */

/*
 * We keep this in a global so that we can reference it from the server and
 * from our http handlers, since there appears to be no way to pass information
 * around here.
 */
var pidMapper = ConnPidMapper{m: map[*net.UnixConn]int32{}}

type ConnPidMapper struct {
	m map[*net.UnixConn]int32
}

func (m *ConnPidMapper) ConnStateHandler(conn net.Conn, state http.ConnState) {
	unixConn := conn.(*net.UnixConn)
	switch state {
	case http.StateNew:
		pid, err := getPid(unixConn)
		if err != nil {
			shared.Debugf("Error getting pid for conn %s", err)
		} else {
			m.m[unixConn] = pid
		}
	case http.StateActive:
		return
	case http.StateIdle:
		return
	case http.StateHijacked:
		/*
		 * The "Hijacked" state indicates that the connection has been
		 * taken over from net/http. This is useful for things like
		 * developing websocket libraries, who want to upgrade the
		 * connection to a websocket one, and not use net/http any
		 * more. Whatever the case, we want to forget about it since we
		 * won't see it either.
		 */
		delete(m.m, unixConn)
	case http.StateClosed:
		delete(m.m, unixConn)
	default:
		shared.Debugf("Unknown state for connection %s", state)
	}
}

/*
 * I also don't see that golang exports an API to get at the underlying FD, but
 * we need it to get at SO_PEERCRED, so let's grab it.
 */
func extractUnderlyingFd(unixConnPtr *net.UnixConn) int {
	conn := reflect.Indirect(reflect.ValueOf(unixConnPtr))
	netFdPtr := conn.FieldByName("fd")
	netFd := reflect.Indirect(netFdPtr)
	fd := netFd.FieldByName("sysfd")
	return int(fd.Int())
}

func getPid(conn *net.UnixConn) (int32, error) {
	fd := extractUnderlyingFd(conn)

	_, _, pid, err := getUcred(fd)
	if err != nil {
		return 0, err
	}

	return pid, nil
}

/*
 * As near as I can tell, there is no nice way of extracting an underlying
 * net.Conn (or in our case, net.UnixConn) from an http.Request or
 * ResponseWriter without hijacking it [1]. Since we want to send and recieve
 * unix creds to figure out which container this request came from, we need to
 * do this.
 *
 * [1]: https://groups.google.com/forum/#!topic/golang-nuts/_FWdFXJa6QA
 */
func extractUnderlyingConn(w http.ResponseWriter) *net.UnixConn {
	v := reflect.Indirect(reflect.ValueOf(w))
	connPtr := v.FieldByName("conn")
	conn := reflect.Indirect(connPtr)
	rwc := conn.FieldByName("rwc")

	netConnPtr := (*net.Conn)(unsafe.Pointer(rwc.UnsafeAddr()))
	unixConnPtr := (*netConnPtr).(*net.UnixConn)

	return unixConnPtr
}

var pidNotInContainerErr = fmt.Errorf("pid not in container?")

func findContainerForPid(pid int32, d *Daemon) (container, error) {
	/*
	 * Try and figure out which container a pid is in. There is probably a
	 * better way to do this. Based on rharper's initial performance
	 * metrics, looping over every container and calling newLxdContainer is
	 * expensive, so I wanted to avoid that if possible, so this happens in
	 * a two step process:
	 *
	 * 1. Walk up the process tree until you see something that looks like
	 *    an lxc monitor process and extract its name from there.
	 *
	 * 2. If this fails, it may be that someone did an `lxc exec foo bash`,
	 *    so the process isn't actually a decendant of the container's
	 *    init. In this case we just look through all the containers until
	 *    we find an init with a matching pid namespace. This is probably
	 *    uncommon, so hopefully the slowness won't hurt us.
	 */

	origpid := pid

	for pid > 1 {
		cmdline, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
		if err != nil {
			return nil, err
		}

		if strings.HasPrefix(string(cmdline), "[lxc monitor]") {
			// container names can't have spaces
			parts := strings.Split(string(cmdline), " ")
			name := parts[len(parts)-1]

			return containerLXDLoad(d, name)
		}

		status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
		if err != nil {
			return nil, err
		}

		re := regexp.MustCompile("PPid:\\s*([0-9]*)")
		for _, line := range strings.Split(string(status), "\n") {
			m := re.FindStringSubmatch(line)
			if m != nil && len(m) > 1 {
				result, err := strconv.Atoi(m[1])
				if err != nil {
					return nil, err
				}

				pid = int32(result)
				break
			}
		}
	}

	origPidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", origpid))
	if err != nil {
		return nil, err
	}

	containers, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		c, err := containerLXDLoad(d, container)
		if err != nil {
			return nil, err
		}

		initpid := c.InitPidGet()
		pidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", initpid))
		if err != nil {
			return nil, err
		}

		if origPidNs == pidNs {
			return c, nil
		}
	}

	return nil, pidNotInContainerErr
}
<|endoftext|>