<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/net/context"
)

type (
	CommandConfig struct {
		Template []string            `json:"-"`
		Options  map[string][]string `json:"options,omitempty"`
		Dryrun   bool                `json:"dryrun,omitempty"`
	}

	Job struct {
		config *CommandConfig
		// https://godoc.org/google.golang.org/genproto/googleapis/pubsub/v1#ReceivedMessage
		message      *JobMessage
		notification *ProgressNotification
		storage      Storage

		// These are set at at setupWorkspace
		workspace     string
		downloads_dir string
		uploads_dir   string

		// These are set at setupDownloadFiles
		downloadFileMap     map[string]string
		remoteDownloadFiles interface{}
		localDownloadFiles  interface{}

		cmd *exec.Cmd
	}
)

func (job *Job) run(ctx context.Context) error {
	job.notification.notify(PROCESSING, job.message.MessageId(), "info")

	verr := job.message.Validate()
	if verr != nil {
		log.Printf("Invalid Message: MessageId: %v, Message: %v, error: %v\n", job.message.MessageId(), job.message.raw.Message, verr)
		err := job.withNotify(CANCELLING, job.message.Ack)()
		if err != nil {
			return err
		}
		return nil
	}

	err := job.setupWorkspace()
	if err != nil {
		return err
	}

	defer job.clearWorkspace()

	err = job.withNotify(PREPARING, job.setupDownloadFiles)()
	if err != nil {
		return err
	}

	err = job.build()
	if err != nil {
		log.Fatalf("Command build Error template: %v msg: %v cause of %v\n", job.config.Template, job.message, err)
		return err
	}

	go job.message.sendMADPeriodically()
	defer job.message.Done()

	err = job.withNotify(DOWNLOADING, job.downloadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(EXECUTING, job.execute)()
	if err != nil {
		return err
	}

	err = job.withNotify(UPLOADING, job.uploadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(ACKSENDING, job.message.Ack)()
	if err != nil {
		return err
	}

	job.notification.notify(CLEANUP, job.message.MessageId(), "info")
	return err
}

func (job *Job) withNotify(progress int, f func() error) func() error {
	msg_id := job.message.MessageId()
	return func() error {
		job.notification.notify(progress, msg_id, "info")
		err := f()
		if err != nil {
			job.notification.notify(progress+2, msg_id, "error")
			return err
		}
		job.notification.notify(progress+1, msg_id, "info")
		return nil
	}
}

func (job *Job) setupWorkspace() error {
	dir, err := ioutil.TempDir("", "workspace")
	if err != nil {
		log.Fatal(err)
		return err
	}

	subdirs := []string{
		filepath.Join(dir, "downloads"),
		filepath.Join(dir, "uploads"),
	}
	for _, subdir := range subdirs {
		err := os.MkdirAll(subdir, 0700)
		if err != nil {
			return err
		}
	}
	job.workspace = dir
	job.downloads_dir = subdirs[0]
	job.uploads_dir = subdirs[1]
	return nil
}

func (job *Job) clearWorkspace() error {
	return os.RemoveAll(job.workspace)
}

func (job *Job) setupDownloadFiles() error {
	job.downloadFileMap = map[string]string{}
	job.remoteDownloadFiles = job.message.DownloadFiles()
	objects := job.flatten(job.remoteDownloadFiles)
	remoteUrls := []string{}
	for _, obj := range objects {
		switch obj.(type) {
		case string:
			remoteUrls = append(remoteUrls, obj.(string))
		default:
			log.Printf("Invalid download file URL: %v [%T]", obj, obj)
		}
	}
	for _, remote_url := range remoteUrls {
		url, err := url.Parse(remote_url)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remote_url, err)
			return err
		}
		urlstr := fmt.Sprintf("gs://%v%v", url.Host, url.Path)
		destPath := filepath.Join(job.downloads_dir, url.Host, url.Path)
		job.downloadFileMap[urlstr] = destPath
	}
	job.localDownloadFiles = job.copyWithFileMap(job.remoteDownloadFiles)
	return nil
}

func (job *Job) copyWithFileMap(obj interface{}) interface{} {
	switch obj.(type) {
	case map[string]interface{}:
		result := map[string]interface{}{}
		for k, v := range obj.(map[string]interface{}) {
			result[k] = job.copyWithFileMap(v)
		}
		return result
	case []interface{}:
		result := []interface{}{}
		for _, v := range obj.([]interface{}) {
			result = append(result, job.copyWithFileMap(v))
		}
		return result
	case string:
		return job.downloadFileMap[obj.(string)]
	default:
		return obj
	}
}

func (job *Job) buildVariable() *Variable {
	return &Variable{
		data: map[string]interface{}{
			"workspace":             job.workspace,
			"downloads_dir":         job.downloads_dir,
			"uploads_dir":           job.uploads_dir,
			"download_files":        job.localDownloadFiles,
			"local_download_files":  job.localDownloadFiles,
			"remote_download_files": job.remoteDownloadFiles,
			"attrs":                 job.message.raw.Message.Attributes,
			"attributes":            job.message.raw.Message.Attributes,
			"data":                  job.message.raw.Message.Data,
		},
	}
}

func (job *Job) build() error {
	v := job.buildVariable()

	values, err := job.extract(v, job.config.Template)
	if err != nil {
		return err
	}
	if len(job.config.Options) > 0 {
		key := strings.Join(values, " ")
		t := job.config.Options[key]
		if t == nil {
			t = job.config.Options["default"]
		}
		if t != nil {
			values, err = job.extract(v, t)
			if err != nil {
				return err
			}
		}
	}
	job.cmd = exec.Command(values[0], values[1:]...)
	return nil
}

func (job *Job) extract(v *Variable, values []string) ([]string, error) {
	result := []string{}
	for _, src := range values {
		extracted, err := v.expand(src)
		if err != nil {
			return nil, &InvalidJobError{err.Error()}
		}
		vals := strings.Split(extracted, v.separator)
		for _, val := range vals {
			result = append(result, val)
		}
	}
	return result, nil
}

func (job *Job) downloadFiles() error {
	for remoteURL, destPath := range job.downloadFileMap {
		url, err := url.Parse(remoteURL)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remoteURL, err)
			return err
		}

		dir := path.Dir(destPath)
		err = os.MkdirAll(dir, 0700)
		if err != nil {
			return err
		}

		err = job.storage.Download(url.Host, url.Path[1:], destPath)
		if err != nil {
			return err
		}
	}
	return nil
}

func (job *Job) execute() error {
	var out bytes.Buffer
	job.cmd.Stdout = &out
	job.cmd.Stderr = &out
	log.Printf("EXECUTE running: %v\n", job.cmd)
	err := job.cmd.Run()
	if err != nil {
		log.Printf("Command Error: cmd: %v cause of %v\n%v\n", job.cmd, err, out.String())
		return err
	}
	return nil
}

func (job *Job) uploadFiles() error {
	localPaths, err := job.listFiles(job.uploads_dir)
	if err != nil {
		return err
	}
	for _, localPath := range localPaths {
		relPath, err := filepath.Rel(job.uploads_dir, localPath)
		if err != nil {
			log.Fatalf("Error getting relative path of %v: %v\n", localPath, err)
			return err
		}
		sep := string([]rune{os.PathSeparator})
		parts := strings.Split(relPath, sep)
		bucket := parts[0]
		object := strings.Join(parts[1:], sep)
		err = job.storage.Upload(bucket, object, localPath)
		if err != nil {
			log.Fatalf("Error uploading %v to gs://%v/%v: %v\n", localPath, bucket, object, err)
			return err
		}
	}
	return nil
}

func (job *Job) listFiles(dir string) ([]string, error) {
	result := []string{}
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			result = append(result, path)
		}
		return nil
	})
	if err != nil {
		log.Fatalf("Error listing upload files: %v\n", err)
		return nil, err
	}
	return result, nil
}

func (job *Job) flatten(obj interface{}) []interface{} {
	// Support only unmarshalled object from JSON
	// See https://golang.org/pkg/encoding/json/#Unmarshal also
	switch obj.(type) {
	case []interface{}:
		res := []interface{}{}
		for _, i := range obj.([]interface{}) {
			switch i.(type) {
			case bool, float64, string, nil:
				res = append(res, i)
			default:
				for _, j := range job.flatten(i) {
					res = append(res, j)
				}
			}
		}
		return res
	case map[string]interface{}:
		values := []interface{}{}
		for _, val := range obj.(map[string]interface{}) {
			values = append(values, val)
		}
		return job.flatten(values)
	default:
		return []interface{}{obj}
	}
}
<commit_msg>:+1: Call Ack for InvalidJobError<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/net/context"
)

type (
	CommandConfig struct {
		Template []string            `json:"-"`
		Options  map[string][]string `json:"options,omitempty"`
		Dryrun   bool                `json:"dryrun,omitempty"`
	}

	Job struct {
		config *CommandConfig
		// https://godoc.org/google.golang.org/genproto/googleapis/pubsub/v1#ReceivedMessage
		message      *JobMessage
		notification *ProgressNotification
		storage      Storage

		// These are set at at setupWorkspace
		workspace     string
		downloads_dir string
		uploads_dir   string

		// These are set at setupDownloadFiles
		downloadFileMap     map[string]string
		remoteDownloadFiles interface{}
		localDownloadFiles  interface{}

		cmd *exec.Cmd
	}
)

func (job *Job) run(ctx context.Context) error {
	err := job.runImpl(ctx)
	switch err.(type) {
	case InvalidJobError:
		err := job.withNotify(CANCELLING, job.message.Ack)()
		if err != nil {
			return err
		}
	}
	return err
}

func (job *Job) runImpl(ctx context.Context) error {
	job.notification.notify(PROCESSING, job.message.MessageId(), "info")

	verr := job.message.Validate()
	if verr != nil {
		log.Printf("Invalid Message: MessageId: %v, Message: %v, error: %v\n", job.message.MessageId(), job.message.raw.Message, verr)
		return nil
	}

	err := job.setupWorkspace()
	if err != nil {
		return err
	}

	defer job.clearWorkspace()

	err = job.withNotify(PREPARING, job.setupDownloadFiles)()
	if err != nil {
		return err
	}

	err = job.build()
	if err != nil {
		log.Fatalf("Command build Error template: %v msg: %v cause of %v\n", job.config.Template, job.message, err)
		return err
	}

	go job.message.sendMADPeriodically()
	defer job.message.Done()

	err = job.withNotify(DOWNLOADING, job.downloadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(EXECUTING, job.execute)()
	if err != nil {
		return err
	}

	err = job.withNotify(UPLOADING, job.uploadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(ACKSENDING, job.message.Ack)()
	if err != nil {
		return err
	}

	job.notification.notify(CLEANUP, job.message.MessageId(), "info")
	return err
}

func (job *Job) withNotify(progress int, f func() error) func() error {
	msg_id := job.message.MessageId()
	return func() error {
		job.notification.notify(progress, msg_id, "info")
		err := f()
		if err != nil {
			job.notification.notify(progress+2, msg_id, "error")
			return err
		}
		job.notification.notify(progress+1, msg_id, "info")
		return nil
	}
}

func (job *Job) setupWorkspace() error {
	dir, err := ioutil.TempDir("", "workspace")
	if err != nil {
		log.Fatal(err)
		return err
	}

	subdirs := []string{
		filepath.Join(dir, "downloads"),
		filepath.Join(dir, "uploads"),
	}
	for _, subdir := range subdirs {
		err := os.MkdirAll(subdir, 0700)
		if err != nil {
			return err
		}
	}
	job.workspace = dir
	job.downloads_dir = subdirs[0]
	job.uploads_dir = subdirs[1]
	return nil
}

func (job *Job) clearWorkspace() error {
	return os.RemoveAll(job.workspace)
}

func (job *Job) setupDownloadFiles() error {
	job.downloadFileMap = map[string]string{}
	job.remoteDownloadFiles = job.message.DownloadFiles()
	objects := job.flatten(job.remoteDownloadFiles)
	remoteUrls := []string{}
	for _, obj := range objects {
		switch obj.(type) {
		case string:
			remoteUrls = append(remoteUrls, obj.(string))
		default:
			log.Printf("Invalid download file URL: %v [%T]", obj, obj)
		}
	}
	for _, remote_url := range remoteUrls {
		url, err := url.Parse(remote_url)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remote_url, err)
			return err
		}
		urlstr := fmt.Sprintf("gs://%v%v", url.Host, url.Path)
		destPath := filepath.Join(job.downloads_dir, url.Host, url.Path)
		job.downloadFileMap[urlstr] = destPath
	}
	job.localDownloadFiles = job.copyWithFileMap(job.remoteDownloadFiles)
	return nil
}

func (job *Job) copyWithFileMap(obj interface{}) interface{} {
	switch obj.(type) {
	case map[string]interface{}:
		result := map[string]interface{}{}
		for k, v := range obj.(map[string]interface{}) {
			result[k] = job.copyWithFileMap(v)
		}
		return result
	case []interface{}:
		result := []interface{}{}
		for _, v := range obj.([]interface{}) {
			result = append(result, job.copyWithFileMap(v))
		}
		return result
	case string:
		return job.downloadFileMap[obj.(string)]
	default:
		return obj
	}
}

func (job *Job) buildVariable() *Variable {
	return &Variable{
		data: map[string]interface{}{
			"workspace":             job.workspace,
			"downloads_dir":         job.downloads_dir,
			"uploads_dir":           job.uploads_dir,
			"download_files":        job.localDownloadFiles,
			"local_download_files":  job.localDownloadFiles,
			"remote_download_files": job.remoteDownloadFiles,
			"attrs":                 job.message.raw.Message.Attributes,
			"attributes":            job.message.raw.Message.Attributes,
			"data":                  job.message.raw.Message.Data,
		},
	}
}

func (job *Job) build() error {
	v := job.buildVariable()

	values, err := job.extract(v, job.config.Template)
	if err != nil {
		return err
	}
	if len(job.config.Options) > 0 {
		key := strings.Join(values, " ")
		t := job.config.Options[key]
		if t == nil {
			t = job.config.Options["default"]
		}
		if t != nil {
			values, err = job.extract(v, t)
			if err != nil {
				return err
			}
		}
	}
	job.cmd = exec.Command(values[0], values[1:]...)
	return nil
}

func (job *Job) extract(v *Variable, values []string) ([]string, error) {
	result := []string{}
	for _, src := range values {
		extracted, err := v.expand(src)
		if err != nil {
			return nil, &InvalidJobError{err.Error()}
		}
		vals := strings.Split(extracted, v.separator)
		for _, val := range vals {
			result = append(result, val)
		}
	}
	return result, nil
}

func (job *Job) downloadFiles() error {
	for remoteURL, destPath := range job.downloadFileMap {
		url, err := url.Parse(remoteURL)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remoteURL, err)
			return err
		}

		dir := path.Dir(destPath)
		err = os.MkdirAll(dir, 0700)
		if err != nil {
			return err
		}

		err = job.storage.Download(url.Host, url.Path[1:], destPath)
		if err != nil {
			return err
		}
	}
	return nil
}

func (job *Job) execute() error {
	var out bytes.Buffer
	job.cmd.Stdout = &out
	job.cmd.Stderr = &out
	log.Printf("EXECUTE running: %v\n", job.cmd)
	err := job.cmd.Run()
	if err != nil {
		log.Printf("Command Error: cmd: %v cause of %v\n%v\n", job.cmd, err, out.String())
		return err
	}
	return nil
}

func (job *Job) uploadFiles() error {
	localPaths, err := job.listFiles(job.uploads_dir)
	if err != nil {
		return err
	}
	for _, localPath := range localPaths {
		relPath, err := filepath.Rel(job.uploads_dir, localPath)
		if err != nil {
			log.Fatalf("Error getting relative path of %v: %v\n", localPath, err)
			return err
		}
		sep := string([]rune{os.PathSeparator})
		parts := strings.Split(relPath, sep)
		bucket := parts[0]
		object := strings.Join(parts[1:], sep)
		err = job.storage.Upload(bucket, object, localPath)
		if err != nil {
			log.Fatalf("Error uploading %v to gs://%v/%v: %v\n", localPath, bucket, object, err)
			return err
		}
	}
	return nil
}

func (job *Job) listFiles(dir string) ([]string, error) {
	result := []string{}
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			result = append(result, path)
		}
		return nil
	})
	if err != nil {
		log.Fatalf("Error listing upload files: %v\n", err)
		return nil, err
	}
	return result, nil
}

func (job *Job) flatten(obj interface{}) []interface{} {
	// Support only unmarshalled object from JSON
	// See https://golang.org/pkg/encoding/json/#Unmarshal also
	switch obj.(type) {
	case []interface{}:
		res := []interface{}{}
		for _, i := range obj.([]interface{}) {
			switch i.(type) {
			case bool, float64, string, nil:
				res = append(res, i)
			default:
				for _, j := range job.flatten(i) {
					res = append(res, j)
				}
			}
		}
		return res
	case map[string]interface{}:
		values := []interface{}{}
		for _, val := range obj.(map[string]interface{}) {
			values = append(values, val)
		}
		return job.flatten(values)
	default:
		return []interface{}{obj}
	}
}
<|endoftext|>


<commit_before>package rdbtools

import (
	"fmt"
	"time"
)

type KeyObject struct {
	ExpiryTime time.Time
	Key        interface{}
}

func NewKeyObject(key interface{}, expiryTime int64) KeyObject {
	k := KeyObject{
		Key: key,
	}
	if expiryTime >= 0 {
		k.ExpiryTime = time.Unix(expiryTime/1000, 0)
	}

	return k
}

func (k KeyObject) Expired() bool {
	return k.ExpiryTime.Before(time.Now())
}

func (k KeyObject) String() string {
	if !k.ExpiryTime.IsZero() {
		return fmt.Sprintf("KeyObject{ExpiryTime: %s, Key: %s}", k.ExpiryTime, DataToString(k.Key))
	}

	return fmt.Sprintf("%s", DataToString(k.Key))
}
<commit_msg>Use UTC for the ExpiryTime in String()<commit_after>package rdbtools

import (
	"fmt"
	"time"
)

type KeyObject struct {
	ExpiryTime time.Time
	Key        interface{}
}

func NewKeyObject(key interface{}, expiryTime int64) KeyObject {
	k := KeyObject{
		Key: key,
	}
	if expiryTime >= 0 {
		k.ExpiryTime = time.Unix(expiryTime/1000, 0)
	}

	return k
}

func (k KeyObject) Expired() bool {
	return k.ExpiryTime.Before(time.Now())
}

func (k KeyObject) String() string {
	if !k.ExpiryTime.IsZero() {
		return fmt.Sprintf("KeyObject{ExpiryTime: %s, Key: %s}", k.ExpiryTime.UTC(), DataToString(k.Key))
	}

	return fmt.Sprintf("%s", DataToString(k.Key))
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httptest

import (
	"io/ioutil"
	"net/http"
	"testing"
	"time"
)

func TestServer(t *testing.T) {
	ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello"))
	}))
	defer ts.Close()
	res, err := http.Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	got, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != "hello" {
		t.Errorf("got %q, want hello", string(got))
	}
}

func TestIssue7264(t *testing.T) {
	for i := 0; i < 1000; i++ {
		func() {
			inHandler := make(chan bool, 1)
			ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				inHandler <- true
			}))
			defer ts.Close()
			tr := &http.Transport{
				ResponseHeaderTimeout: time.Nanosecond,
			}
			defer tr.CloseIdleConnections()
			c := &http.Client{Transport: tr}
			res, err := c.Get(ts.URL)
			<-inHandler
			if err == nil {
				res.Body.Close()
			}
		}()
	}
}
<commit_msg>net/http/httptest: fix deadlock in TestIssue7264<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httptest

import (
	"io/ioutil"
	"net/http"
	"testing"
	"time"
)

func TestServer(t *testing.T) {
	ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello"))
	}))
	defer ts.Close()
	res, err := http.Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	got, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != "hello" {
		t.Errorf("got %q, want hello", string(got))
	}
}

func TestIssue7264(t *testing.T) {
	for i := 0; i < 1000; i++ {
		func() {
			ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
			defer ts.Close()
			tr := &http.Transport{
				ResponseHeaderTimeout: time.Nanosecond,
			}
			defer tr.CloseIdleConnections()
			c := &http.Client{Transport: tr}
			res, err := c.Get(ts.URL)
			// err can be non-nil here.
			// If the client writes the header and then immediately observes
			// the timeout and closes the connection, the server might never
			// have gotten a chance to send a response. That's okay.
			if err == nil {
				res.Body.Close()
			}
		}()
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"v.io/jiri/collect"
	"v.io/jiri/project"
	"v.io/jiri/runutil"
	"v.io/jiri/tool"
	"v.io/x/devtools/internal/test"
)

const (
	scriptEnvVar        = "CREATE_INSTANCE_SCRIPT"
	testInstancePrefix  = "create-instance-test"
	testInstanceProject = "vanadium-internal"
	testInstanceZone    = "us-central1-c"
)

var (
	defaultCreateInstanceTimeout = time.Minute * 10
	defaultCheckInstanceTimeout  = time.Minute * 5
)

type instance struct {
	Name              string
	Zone              string
	NetworkInterfaces []struct {
		AccessConfigs []struct {
			NatIP string
		}
	}
}

// vanadiumCreateInstanceTest creates a test instance using the
// create_instance.sh script (specified in the CREATE_INSTANCE_SCRIPT
// environment variable) and run prod service test and load test againest it.
func vanadiumCreateInstanceTest(ctx *tool.Context, testName string, opts ...Opt) (_ *test.Result, e error) {
	root, err := project.JiriRoot()
	if err != nil {
		return nil, err
	}

	// Check CREATE_INSTANCE_SCRIPT environment variable.
	script := os.Getenv(scriptEnvVar)
	if script == "" {
		return nil, internalTestError{fmt.Errorf("script not defined in %s environment variable", scriptEnvVar), "Env"}
	}

	cleanup, err := initTest(ctx, testName, []string{"base"})
	if err != nil {
		return nil, internalTestError{err, "Init"}
	}
	defer collect.Error(func() error { return cleanup() }, &e)

	// Clean up test instances possibly left by previous test runs.
	if err := cleanupTestInstances(ctx); err != nil {
		return nil, internalTestError{err, "Delete old test instances"}
	}

	// Run script.
	printBanner(ctx, fmt.Sprintf("Running instance creation script: %s", script))
	instanceName := fmt.Sprintf("%s-%s", testInstancePrefix, time.Now().Format("20060102150405"))
	defer collect.Error(func() error {
		// TODO(caprita): Commenting this out so we can debug failures.
		// return cleanupTestInstances(ctx)
		return nil
	}, &e)
	go func() {
		sigchan := make(chan os.Signal, 1)
		signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
		<-sigchan
		if err := cleanupTestInstances(ctx); err != nil {
			fmt.Fprintf(os.Stderr, "%v\n", err)
		}
		os.Exit(0)
	}()
	if err := runScript(ctx, script, instanceName); err != nil {
		if err == runutil.CommandTimedOutErr {
			return &test.Result{
				Status:       test.TimedOut,
				TimeoutValue: defaultCreateInstanceTimeout,
			}, nil
		}
		return nil, internalTestError{err, err.Error()}
	}

	// Check the test instance.
	printBanner(ctx, "Checking test instance")
	if err := checkTestInstance(ctx, root, instanceName); err != nil {
		if err == runutil.CommandTimedOutErr {
			return &test.Result{
				Status:       test.TimedOut,
				TimeoutValue: defaultCheckInstanceTimeout,
			}, nil
		}
		return nil, internalTestError{err, err.Error()}
	}

	return &test.Result{Status: test.Passed}, nil
}

func cleanupTestInstances(ctx *tool.Context) error {
	printBanner(ctx, "Cleaning up test instances")

	// List all test instances.
	instances, err := listInstances(ctx, testInstancePrefix+".*")
	if err != nil {
		return err
	}

	// Delete them.
	for _, instance := range instances {
		if err := deleteInstance(ctx, instance.Name, instance.Zone); err != nil {
			fmt.Fprintf(ctx.Stderr(), "%v", err)
		}
	}
	return nil
}

func listInstances(ctx *tool.Context, instanceRegEx string) ([]instance, error) {
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	args := []string{
		"-q",
		"compute",
		"instances",
		"list",
		"--project",
		testInstanceProject,
		fmt.Sprintf("--regexp=%s", instanceRegEx),
		"--format=json",
	}
	if err := ctx.Run().CommandWithOpts(opts, "gcloud", args...); err != nil {
		return nil, err
	}
	instances := []instance{}
	if err := json.Unmarshal(out.Bytes(), &instances); err != nil {
		return nil, fmt.Errorf("Unmarshal() failed: %v", err)
	}
	return instances, nil
}

func deleteInstance(ctx *tool.Context, instanceName, instanceZone string) error {
	args := []string{
		"-q",
		"compute",
		"instances",
		"delete",
		"--project",
		testInstanceProject,
		"--zone",
		instanceZone,
		instanceName,
	}
	if err := ctx.Run().Command("gcloud", args...); err != nil {
		return err
	}
	return nil
}

func runScript(ctx *tool.Context, script, instanceName string) error {
	// Build all binaries.
	args := []string{"go", "install", "v.io/..."}
	if err := ctx.Run().Command("jiri", args...); err != nil {
		return err
	}

	// Run script.
	args = []string{instanceName}
	if err := ctx.Run().TimedCommand(defaultCreateInstanceTimeout, script, args...); err != nil {
		return err
	}

	return nil
}

func checkTestInstance(ctx *tool.Context, root, instanceName string) error {
	instances, err := listInstances(ctx, instanceName)
	if err != nil {
		return err
	}
	if len(instances) == 0 {
		return fmt.Errorf("no matching instance for %q", instanceName)
	}
	externalIP := instances[0].NetworkInterfaces[0].AccessConfigs[0].NatIP
	suites := testAllProdServices(ctx, root, "", fmt.Sprintf("/%s:8101", externalIP))
	allPassed := true
	for _, suite := range suites {
		allPassed = allPassed && (suite.Failures == 0)
	}
	if !allPassed {
		return fmt.Errorf("some checks failed")
	}
	return nil
}

func printBanner(ctx *tool.Context, msg string) {
	fmt.Fprintf(ctx.Stdout(), "##### %s #####\n", msg)
}
<commit_msg>TBR: jiri-test/internal/test/create_instance.go: Add Env Var for project.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"v.io/jiri/collect"
	"v.io/jiri/project"
	"v.io/jiri/runutil"
	"v.io/jiri/tool"
	"v.io/x/devtools/internal/test"
)

const (
	scriptEnvVar       = "CREATE_INSTANCE_SCRIPT"
	projectEnvVar      = "CREATE_INSTANCE_PROJECT_ID"
	testInstancePrefix = "create-instance-test"
	testInstanceZone   = "us-central1-c"
)

var (
	defaultCreateInstanceTimeout = time.Minute * 10
	defaultCheckInstanceTimeout  = time.Minute * 5
	testInstanceProject          = os.Getenv(projectEnvVar)
)

type instance struct {
	Name              string
	Zone              string
	NetworkInterfaces []struct {
		AccessConfigs []struct {
			NatIP string
		}
	}
}

// vanadiumCreateInstanceTest creates a test instance using the
// create_instance.sh script (specified in the CREATE_INSTANCE_SCRIPT
// environment variable) and run prod service test and load test againest it.
func vanadiumCreateInstanceTest(ctx *tool.Context, testName string, opts ...Opt) (_ *test.Result, e error) {
	root, err := project.JiriRoot()
	if err != nil {
		return nil, err
	}

	if testInstanceProject == "" {
		return nil, internalTestError{fmt.Errorf("project not defined in %s environment variable", projectEnvVar), "Env"}
	}

	// Check CREATE_INSTANCE_SCRIPT environment variable.
	script := os.Getenv(scriptEnvVar)
	if script == "" {
		return nil, internalTestError{fmt.Errorf("script not defined in %s environment variable", scriptEnvVar), "Env"}
	}

	cleanup, err := initTest(ctx, testName, []string{"base"})
	if err != nil {
		return nil, internalTestError{err, "Init"}
	}
	defer collect.Error(func() error { return cleanup() }, &e)

	// Clean up test instances possibly left by previous test runs.
	if err := cleanupTestInstances(ctx); err != nil {
		return nil, internalTestError{err, "Delete old test instances"}
	}

	// Run script.
	printBanner(ctx, fmt.Sprintf("Running instance creation script: %s", script))
	instanceName := fmt.Sprintf("%s-%s", testInstancePrefix, time.Now().Format("20060102150405"))
	defer collect.Error(func() error {
		// TODO(caprita): Commenting this out so we can debug failures.
		// return cleanupTestInstances(ctx)
		return nil
	}, &e)
	go func() {
		sigchan := make(chan os.Signal, 1)
		signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
		<-sigchan
		if err := cleanupTestInstances(ctx); err != nil {
			fmt.Fprintf(os.Stderr, "%v\n", err)
		}
		os.Exit(0)
	}()
	if err := runScript(ctx, script, instanceName); err != nil {
		if err == runutil.CommandTimedOutErr {
			return &test.Result{
				Status:       test.TimedOut,
				TimeoutValue: defaultCreateInstanceTimeout,
			}, nil
		}
		return nil, internalTestError{err, err.Error()}
	}

	// Check the test instance.
	printBanner(ctx, "Checking test instance")
	if err := checkTestInstance(ctx, root, instanceName); err != nil {
		if err == runutil.CommandTimedOutErr {
			return &test.Result{
				Status:       test.TimedOut,
				TimeoutValue: defaultCheckInstanceTimeout,
			}, nil
		}
		return nil, internalTestError{err, err.Error()}
	}

	return &test.Result{Status: test.Passed}, nil
}

func cleanupTestInstances(ctx *tool.Context) error {
	printBanner(ctx, "Cleaning up test instances")

	// List all test instances.
	instances, err := listInstances(ctx, testInstancePrefix+".*")
	if err != nil {
		return err
	}

	// Delete them.
	for _, instance := range instances {
		if err := deleteInstance(ctx, instance.Name, instance.Zone); err != nil {
			fmt.Fprintf(ctx.Stderr(), "%v", err)
		}
	}
	return nil
}

func listInstances(ctx *tool.Context, instanceRegEx string) ([]instance, error) {
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	args := []string{
		"-q",
		"compute",
		"instances",
		"list",
		"--project",
		testInstanceProject,
		fmt.Sprintf("--regexp=%s", instanceRegEx),
		"--format=json",
	}
	if err := ctx.Run().CommandWithOpts(opts, "gcloud", args...); err != nil {
		return nil, err
	}
	instances := []instance{}
	if err := json.Unmarshal(out.Bytes(), &instances); err != nil {
		return nil, fmt.Errorf("Unmarshal() failed: %v", err)
	}
	return instances, nil
}

func deleteInstance(ctx *tool.Context, instanceName, instanceZone string) error {
	args := []string{
		"-q",
		"compute",
		"instances",
		"delete",
		"--project",
		testInstanceProject,
		"--zone",
		instanceZone,
		instanceName,
	}
	if err := ctx.Run().Command("gcloud", args...); err != nil {
		return err
	}
	return nil
}

func runScript(ctx *tool.Context, script, instanceName string) error {
	// Build all binaries.
	args := []string{"go", "install", "v.io/..."}
	if err := ctx.Run().Command("jiri", args...); err != nil {
		return err
	}

	// Run script.
	args = []string{instanceName}
	if err := ctx.Run().TimedCommand(defaultCreateInstanceTimeout, script, args...); err != nil {
		return err
	}

	return nil
}

func checkTestInstance(ctx *tool.Context, root, instanceName string) error {
	instances, err := listInstances(ctx, instanceName)
	if err != nil {
		return err
	}
	if len(instances) == 0 {
		return fmt.Errorf("no matching instance for %q", instanceName)
	}
	externalIP := instances[0].NetworkInterfaces[0].AccessConfigs[0].NatIP
	suites := testAllProdServices(ctx, root, "", fmt.Sprintf("/%s:8101", externalIP))
	allPassed := true
	for _, suite := range suites {
		allPassed = allPassed && (suite.Failures == 0)
	}
	if !allPassed {
		return fmt.Errorf("some checks failed")
	}
	return nil
}

func printBanner(ctx *tool.Context, msg string) {
	fmt.Fprintf(ctx.Stdout(), "##### %s #####\n", msg)
}
<|endoftext|>


<commit_before>package gohm

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

const apacheLogFormat = "%s [%s] \"%s\" %d %d %f\n"
const timeFormat = "02/Jan/2006:15:04:05 MST"

type loggedResponseWriter struct {
	http.ResponseWriter
	responseBytes int64
	status        int
}

func (r *loggedResponseWriter) Write(p []byte) (int, error) {
	written, err := r.ResponseWriter.Write(p)
	r.responseBytes += int64(written)
	return written, err
}

func (r *loggedResponseWriter) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

// LogAll returns a new http.Handler that logs HTTP requests and responses in common log format
// to the specified io.Writer.
//
// 	mux := http.NewServeMux()
// 	mux.Handle("/example/path", gohm.LogAll(os.Stderr, decodeURI(expand(querier))))
func LogAll(out io.Writer, next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lrw := &loggedResponseWriter{
			ResponseWriter: w,
			status:         http.StatusOK,
		}

		begin := time.Now()
		next.ServeHTTP(lrw, r)
		end := time.Now()

		clientIP := r.RemoteAddr
		if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
			clientIP = clientIP[:colon]
		}
		request := fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto)

		duration := end.Sub(begin).Seconds()
		formattedTime := end.UTC().Format(timeFormat)
		fmt.Fprintf(out, apacheLogFormat, clientIP, formattedTime, request, lrw.status, lrw.responseBytes, duration)
	})
}

// LogErrors returns a new http.Handler that logs HTTP requests that result in response errors, or
// more specifically, HTTP status codes that are either 4xx or 5xx.  The handler will output lines
// in common log format to the specified io.Writer.
//
// 	mux := http.NewServeMux()
// 	mux.Handle("/example/path", gohm.LogErrors(os.Stderr, decodeURI(expand(querier))))
func LogErrors(out io.Writer, next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lrw := &loggedResponseWriter{
			ResponseWriter: w,
			status:         http.StatusOK,
		}

		begin := time.Now()
		next.ServeHTTP(lrw, r)

		// NOTE: Also need to check for zero-value of status variable, because when omitted
		// by handler, it's filled in later in http stack.
		if lrw.status != 0 && !member(lrw.status, 100) && !member(lrw.status, 200) && !member(lrw.status, 300) {
			end := time.Now()
			clientIP := r.RemoteAddr
			if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
				clientIP = clientIP[:colon]
			}
			request := fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto)
			duration := end.Sub(begin).Seconds()
			formattedTime := end.UTC().Format(timeFormat)
			fmt.Fprintf(out, apacheLogFormat, clientIP, formattedTime, request, lrw.status, lrw.responseBytes, duration)
		}
	})
}
<commit_msg>no longer needlessly checks for unset status because it was set at beginning of handler<commit_after>package gohm

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

const apacheLogFormat = "%s [%s] \"%s\" %d %d %f\n"
const timeFormat = "02/Jan/2006:15:04:05 MST"

type loggedResponseWriter struct {
	http.ResponseWriter
	responseBytes int64
	status        int
}

func (r *loggedResponseWriter) Write(p []byte) (int, error) {
	written, err := r.ResponseWriter.Write(p)
	r.responseBytes += int64(written)
	return written, err
}

func (r *loggedResponseWriter) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

// LogAll returns a new http.Handler that logs HTTP requests and responses in common log format
// to the specified io.Writer.
//
// 	mux := http.NewServeMux()
// 	mux.Handle("/example/path", gohm.LogAll(os.Stderr, decodeURI(expand(querier))))
func LogAll(out io.Writer, next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lrw := &loggedResponseWriter{
			ResponseWriter: w,
			status:         http.StatusOK,
		}

		begin := time.Now()
		next.ServeHTTP(lrw, r)
		end := time.Now()

		clientIP := r.RemoteAddr
		if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
			clientIP = clientIP[:colon]
		}
		request := fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto)

		duration := end.Sub(begin).Seconds()
		formattedTime := end.UTC().Format(timeFormat)
		fmt.Fprintf(out, apacheLogFormat, clientIP, formattedTime, request, lrw.status, lrw.responseBytes, duration)
	})
}

// LogErrors returns a new http.Handler that logs HTTP requests that result in response errors, or
// more specifically, HTTP status codes that are either 4xx or 5xx.  The handler will output lines
// in common log format to the specified io.Writer.
//
// 	mux := http.NewServeMux()
// 	mux.Handle("/example/path", gohm.LogErrors(os.Stderr, decodeURI(expand(querier))))
func LogErrors(out io.Writer, next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lrw := &loggedResponseWriter{
			ResponseWriter: w,
			status:         http.StatusOK,
		}

		begin := time.Now()
		next.ServeHTTP(lrw, r)

		if !member(lrw.status, 100) && !member(lrw.status, 200) && !member(lrw.status, 300) {
			end := time.Now()
			clientIP := r.RemoteAddr
			if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
				clientIP = clientIP[:colon]
			}
			request := fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto)
			duration := end.Sub(begin).Seconds()
			formattedTime := end.UTC().Format(timeFormat)
			fmt.Fprintf(out, apacheLogFormat, clientIP, formattedTime, request, lrw.status, lrw.responseBytes, duration)
		}
	})
}
<|endoftext|>


<commit_before>package colog

import (
	"encoding/json"
	"log"

	"github.com/keks/go-ipfs-colog/immutabledb"
)

var joinpass int

// hash is the base58 string representation of a multihash
type Hash string

func (h Hash) String() string {
	if h == "" {
		return "null"
	}
	return string(h)
}

// CoLog is a concurrent log
type CoLog struct {
	Id string
	db immutabledb.ImmutableDB

	next, prev Index

	heads HashSet
}

// New returns a concurrent log
func New(id string, db immutabledb.ImmutableDB) *CoLog {
	// TODO: iterate over db to build index
	// TODO: make index persistent

	return &CoLog{
		Id: id,
		db: db,

		next: make(Index),
		prev: make(Index),

		heads: make(HashSet),
	}
}

// Add adds data to the colog and returns the resulting entry
func (l *CoLog) Add(data interface{}) (*Entry, error) {
	// prepare entry
	e := &Entry{
		Prev: l.heads.Copy(),
	}

	// set value
	err := e.set(data)
	if err != nil {
		return nil, err
	}

	// use empty string to mark root entry
	if len(e.Prev) == 0 {
		e.Prev.Set("")
	}

	eBytes, err := json.Marshal(e)
	if err != nil {
		return nil, err
	}

	// store entry
	hStr, err := l.db.Put(eBytes)
	if err != nil {
		return nil, err
	}

	// set hash
	e.Hash = Hash(hStr)

	// update index
	for h := range e.Prev {
		l.next.Add(h, e.Hash)
		l.prev.Add(e.Hash, h)
	}

	// update local heads
	l.heads = make(HashSet)
	l.heads.Set(e.Hash)

	return e, err
}

// Get returns an entry from the db.
func (l *CoLog) Get(h Hash) (*Entry, error) {
	e := NewEntry()

	eBytes, err := l.db.Get(string(h))
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(eBytes, e)
	if err != nil {
		return nil, err
	}

	e.Hash = h

	return e, nil
}

// Contains returns whether an Entry with Hash h is stored
func (l *CoLog) Contains(h Hash) bool {
	hs, ok := l.prev[h]

	delete(hs, "")

	return ok && len(h) > 0
}

// Join merges colog `other' into `l'
func (l *CoLog) Join(other *CoLog) error {
	defer func() { joinpass++ }()

	newHeads := make(HashSet)

	for h := range other.prev {
		// skip known hashes
		if l.Contains(h) {
			//	log.Printf("join#%d %v <- %v - entry %v already there - continuing\n", joinpass, l.Id, other.Id, h)
			continue
		}

		e, err := other.Get(h)
		if err != nil {
			return err
		}

		eBytes, err := json.Marshal(e)
		if err != nil {
			return err
		}

		// add to db
		_, err = l.db.Put(eBytes)
		if err != nil {
			return err
		}

		// fix heads
		for head := range l.heads {

			// case 1: hash is head in both logs => remains head
			if other.heads.IsSet(head) {
				newHeads.Set(head)
				continue
			}

			// case 2: hash is head in l1, but not in l2 and is not part of l2
			//  => remains head
			if !other.Contains(head) {
				newHeads.Set(head)
				continue
			}

			// case 3: hash is head in l1, but not in l2 and is part of l2
			//  => not head anymore
			// do nothing
		}

		for head := range other.heads {
			// we had those already
			if l.heads.IsSet(head) {
				continue
			}

			// case 4: hash is head in l2, but not in l1 and is not part of l1
			//  => remains head
			if !l.Contains(head) {
				newHeads.Set(head)
				continue
			}

			// case 5: hash is head in l2, but not in l1 and is part of l1
			//  => not head anymore
			// do nothing
		}

		// fix up index
		for hPrev := range e.Prev {
			l.next.Add(hPrev, e.Hash)
			l.prev.Add(e.Hash, hPrev)
		}

	}

	l.heads = newHeads

	return nil
}

// Items returns the Entries in canonical order
func (l *CoLog) Items() []*Entry {
	// output Entry slice
	out := make([]*Entry, 0, len(l.prev))

	// keeps track how many of the revious pointers have been added to out already
	addedPrevs := map[Hash]int{}

	// set up hash stack to track concurrentness
	var stack = []Hash{}

	// push to stack
	push := func(hs ...Hash) {
		stack = append(stack, hs...)
	}

	//pop from stack
	pop := func() Hash {
		h := stack[len(stack)-1]
		stack = stack[:len(stack)-1]

		return h
	}

	// start with root nodes: nodes with prev=[""]
	push(l.next[""].Sorted()...)

	for len(stack) > 0 {
		// pop hash from stack
		h := pop()

		//ignore root
		if h == "" {
			continue
		}

		// get Entry
		e, err := l.Get(h)
		if err != nil {
			log.Printf("error fetching item with hash %#s. continuing.\n", h)
			continue
		}

		// append Entry
		out = append(out, e)

		// mark that an Entry was added in all next hashes
		for hNext := range l.next[h] {
			addedPrevs[hNext]++
		}

		// push next hashes, but only if all past hashes have been added
		for _, hNext := range l.next[h].Sorted() {
			if addedPrevs[hNext] == len(l.prev[hNext]) {
				push(hNext)
			}
		}
	}

	return out
}

func (l *CoLog) Print() {
	log.Println("next:", l.next)
	log.Println("prev:", l.prev)

	for _, e := range l.Items() {
		log.Println("Entry:", e.Hash)

		data, err := l.db.Get(string(e.Hash))
		if err != nil {
			log.Panic(e.Hash, err)
		}

		log.Println("Data:", string(data))

		if len(e.Prev) > 0 {
			for p := range e.Prev {
				log.Println("Prev:", p)
			}
		}

		log.Println()
	}
}

func (l *CoLog) Heads() []Hash {
	return l.heads.Sorted()
}

func (l *CoLog) FetchFromHead(head Hash) error {
	if _, ok := l.prev[head]; ok {
		return nil
	}

	// set up hash stack to track concurrentness
	var stack = []Hash{}

	// push to stack
	push := func(hs ...Hash) {
		stack = append(stack, hs...)
	}

	//pop from stack
	pop := func() Hash {
		h := stack[len(stack)-1]
		stack = stack[:len(stack)-1]

		return h
	}

	// start with root nodes: nodes with prev=[""]
	push(head)

	for len(stack) > 0 {
		// pop hash from stack
		h := pop()

		//ignore root
		if h == "" {
			continue
		}

		// check if already known
		if _, ok := l.prev[head]; ok {
			continue
		}

		// get Entry
		e, err := l.Get(h)
		if err != nil {
			log.Printf("error fetching item with hash %#s. continuing.\n", h)
			continue
		}

		for hPrev := range e.Prev {
			// add to index
			l.prev[h].Set(hPrev)
			l.next[hPrev].Set(h)

			// mark for recursion
			push(hPrev)
		}
	}

	return nil
}
<commit_msg>minor fixes<commit_after>package colog

import (
	"encoding/json"
	"log"

	"github.com/keks/go-ipfs-colog/immutabledb"
)

var joinpass int

// hash is the base58 string representation of a multihash
type Hash string

func (h Hash) String() string {
	if h == "" {
		return "null"
	}
	return string(h)
}

// CoLog is a concurrent log
type CoLog struct {
	Id string
	db immutabledb.ImmutableDB

	next, prev Index

	heads HashSet
}

// New returns a concurrent log
func New(id string, db immutabledb.ImmutableDB) *CoLog {
	// TODO: iterate over db to build index
	// TODO: make index persistent

	return &CoLog{
		Id: id,
		db: db,

		next: make(Index),
		prev: make(Index),

		heads: make(HashSet),
	}
}

// Add adds data to the colog and returns the resulting entry
func (l *CoLog) Add(data interface{}) (*Entry, error) {
	// prepare entry
	e := &Entry{
		Prev: l.heads.Copy(),
	}

	// set value
	err := e.set(data)
	if err != nil {
		return nil, err
	}

	// use empty string to mark root entry
	if len(e.Prev) == 0 {
		e.Prev.Set("")
	}

	eBytes, err := json.Marshal(e)
	if err != nil {
		return nil, err
	}

	// store entry
	hStr, err := l.db.Put(eBytes)
	if err != nil {
		return nil, err
	}

	// set hash
	e.Hash = Hash(hStr)

	// update index
	for h := range e.Prev {
		l.next.Add(h, e.Hash)
		l.prev.Add(e.Hash, h)
	}

	// update local heads
	l.heads = make(HashSet)
	l.heads.Set(e.Hash)

	return e, err
}

// Get returns an entry from the db.
func (l *CoLog) Get(h Hash) (*Entry, error) {
	e := NewEntry()

	eBytes, err := l.db.Get(string(h))
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(eBytes, e)
	if err != nil {
		return nil, err
	}

	e.Hash = h

	return e, nil
}

// Contains returns whether an Entry with Hash h is stored
func (l *CoLog) Contains(h Hash) bool {
	hs, ok := l.prev[h]

	delete(hs, "")

	return ok && len(h) > 0
}

// Join merges colog `other' into `l'
func (l *CoLog) Join(other *CoLog) error {
	defer func() { joinpass++ }()

	newHeads := make(HashSet)

	for h := range other.prev {
		// skip known hashes
		if l.Contains(h) {
			//	log.Printf("join#%d %v <- %v - entry %v already there - continuing\n", joinpass, l.Id, other.Id, h)
			continue
		}

		e, err := other.Get(h)
		if err != nil {
			return err
		}

		eBytes, err := json.Marshal(e)
		if err != nil {
			return err
		}

		// add to db
		_, err = l.db.Put(eBytes)
		if err != nil {
			return err
		}

		// fix heads
		for head := range l.heads {

			// case 1: hash is head in both logs => remains head
			if other.heads.IsSet(head) {
				newHeads.Set(head)
				continue
			}

			// case 2: hash is head in l1, but not in l2 and is not part of l2
			//  => remains head
			if !other.Contains(head) {
				newHeads.Set(head)
				continue
			}

			// case 3: hash is head in l1, but not in l2 and is part of l2
			//  => not head anymore
			// do nothing
		}

		for head := range other.heads {
			// we had those already
			if l.heads.IsSet(head) {
				continue
			}

			// case 4: hash is head in l2, but not in l1 and is not part of l1
			//  => remains head
			if !l.Contains(head) {
				newHeads.Set(head)
				continue
			}

			// case 5: hash is head in l2, but not in l1 and is part of l1
			//  => not head anymore
			// do nothing
		}

		// fix up index
		for hPrev := range e.Prev {
			l.next.Add(hPrev, e.Hash)
			l.prev.Add(e.Hash, hPrev)
		}

	}

	l.heads = newHeads

	return nil
}

// Items returns the Entries in canonical order
func (l *CoLog) Items() []*Entry {
	// output Entry slice
	out := make([]*Entry, 0, len(l.prev))

	// keeps track how many of the revious pointers have been added to out already
	addedPrevs := map[Hash]int{}

	// set up hash stack to track concurrentness
	var stack = []Hash{}

	// push to stack
	push := func(hs ...Hash) {
		stack = append(stack, hs...)
	}

	//pop from stack
	pop := func() Hash {
		h := stack[len(stack)-1]
		stack = stack[:len(stack)-1]

		return h
	}

	// start with root nodes: nodes with prev=[""]
	push(l.next[""].Sorted()...)

	for len(stack) > 0 {
		// pop hash from stack
		h := pop()

		//ignore root
		if h == "" {
			continue
		}

		// get Entry
		e, err := l.Get(h)
		if err != nil {
			log.Printf("error fetching item with hash %#s. continuing.\n", h)
			continue
		}

		// append Entry
		out = append(out, e)

		// mark that an Entry was added in all next hashes
		for hNext := range l.next[h] {
			addedPrevs[hNext]++
		}

		// push next hashes, but only if all past hashes have been added
		for _, hNext := range l.next[h].Sorted() {
			if addedPrevs[hNext] == len(l.prev[hNext]) {
				push(hNext)
			}
		}
	}

	return out
}

func (l *CoLog) Print() {
	log.Println("next:", l.next)
	log.Println("prev:", l.prev)

	for _, e := range l.Items() {
		log.Println("Entry:", e.Hash)

		data, err := l.db.Get(string(e.Hash))
		if err != nil {
			log.Panic(e.Hash, err)
		}

		log.Println("Data:", string(data))

		if len(e.Prev) > 0 {
			for p := range e.Prev {
				log.Println("Prev:", p)
			}
		}

		log.Println()
	}
}

func (l *CoLog) Heads() []Hash {
	return l.heads.Sorted()
}

func (l *CoLog) FetchFromHead(head Hash) error {
	if _, ok := l.prev[head]; ok {
		return nil
	}

	// set up hash stack to track concurrentness
	var stack = []Hash{}

	// push to stack
	push := func(hs ...Hash) {
		stack = append(stack, hs...)
	}

	//pop from stack
	pop := func() Hash {
		h := stack[len(stack)-1]
		stack = stack[:len(stack)-1]

		return h
	}

	// walk colog from head
	push(head)

	for len(stack) > 0 {
		// pop hash from stack
		h := pop()

		//ignore root
		if h == "" {
			continue
		}

		// check if already known
		if _, ok := l.prev[h]; ok {
			continue
		}

		// set as head if no followups known
		if nexts := l.next[h]; len(nexts) == 0 {
			l.heads.Set(h)
		}

		// get Entry
		e, err := l.Get(h)
		if err != nil {
			log.Printf("error fetching item with hash %#x. continuing.\n", h)
			continue
		}

		for hPrev := range e.Prev {
			// remove from heads in case it was there
			l.heads.Unset(hPrev)

			// add to index
			l.prev.Add(h, hPrev)
			l.next.Add(hPrev, h)

			// mark for recursion
			push(hPrev)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
)

const (
	script1 = `set 0 dst mac %s
set 1 dst mac %s
set 0 size 1500
set 1 size 1500
`
	script2 = `range 0 dst mac start %s
range 1 dst mac start %s
range 0 size start 1500
range 0 size min 1500
range 0 size max 1500
range 0 dst port start 50
range 0 dst port min 50
range 0 dst port max 60
range 0 dst port inc 1
enable 0 range
`
	script3 = `range 0 dst mac start %s
range 1 dst mac start %s
range 0 size start 1500
range 0 size min 1500
range 0 size max 1500
range 0 src ip start 111.2.0.0
range 0 src ip min 111.2.0.0
range 0 src ip max 111.2.0.3
range 0 src ip inc 0.0.0.1
enable 0 range
`
	scriptNat = `range 0 dst mac start %s
range 1 dst mac start %s
range 0 size start 1500
range 0 size min 1500
range 0 size max 1500
range 1 size start 1500
range 1 size min 1500
range 1 size max 1500
range 0 src ip start 192.168.1.2
range 0 src ip min 192.168.1.2
range 0 src ip max 192.168.1.12
range 0 src ip inc 0.0.0.1
range 0 dst ip start 10.1.1.2
range 0 dst ip inc 0.0.0.0
range 0 src port start 1234
range 0 src port inc 0
range 1 src ip start 10.1.1.2
range 1 src ip inc 0.0.0.0
range 1 dst ip start 10.1.1.1
range 1 dst ip inc 0.0.0.0
range 1 dst port start 1024
range 1 dst port inc 0
enable 0 range
enable 1 range
`
	jsonNat = `{
    "port-pairs": [
        {
            "private-port": {
                "index": 0,
                "dst_mac": "%s",
                "subnet": "192.168.1.1/24"
            },
            "public-port": {
                "index": 1,
                "dst_mac": "%s",
                "subnet": "10.1.1.1"
            }
        }
    ]
}
`
	workaroundScript = `
start 1
sleep 1
stop 1
`
)

var workaroundTargets = map[string]struct{}{
	"dbdw14": {},
	"dbdw15": {},
	"dbdw16": {},
	"dbdw17": {},
}

func genScript(hostdir string, hosts []string, format, mac0, mac1 string, workaround bool) {
	for _, hostname := range hosts {
		if hostdir != "" {
			hostname = hostdir + string(os.PathSeparator) + hostname
		}
		file, err := os.Create(hostname)
		if err != nil {
			log.Fatal(err)
		} else {
			defer file.Close()
		}

		fmt.Fprintf(file, format, mac0, mac1)
		if workaround {
			fmt.Fprintf(file, workaroundScript)
		}
	}
}

func main() {
	// Parse arguments
	pktgenDir := flag.String("pgdir", "../../dpdk", "Specify directory where to put pktgen script files")
	configFile := flag.String("config", "config.json", "Specify config file name")
	target := flag.String("target", "", "Target host name from config file")
	pktgen := flag.String("pktgen", "", "Pktgen host name from config file")
	flag.Parse()

	// Read config
	err := readConfig(*configFile)
	if err != nil {
		log.Fatal(err)
	}

	if *target == "" && *pktgen == "" {
		target = &direct
		println("Generating scripts for -target direct")
	}

	_, needWO := workaroundTargets[*target]

	if *target != "" {
		genScript(*pktgenDir, []string{"step2.pg", "step3.pg"}, script1, config[*target][0], config[*target][1], needWO)
		genScript(*pktgenDir, []string{"step4.pg"}, script2, config[*target][0], config[*target][1], needWO)
		genScript(*pktgenDir, []string{"step5.pg", "step6.pg", "step7.pg", "step8.pg", "step9.pg", "step10.pg", "step11.pg"},
			script3, config[*target][0], config[*target][1], needWO)
		genScript(*pktgenDir, []string{"nat.pg"}, scriptNat, config[*target][0], config[*target][1], needWO)
	}

	if *pktgen != "" {
		// Write NAT config file
		genScript("", []string{"nat.json"}, jsonNat, config[*pktgen][0], config[*pktgen][1], false)
	}
}
<commit_msg>Added workaround for strange pktgen behavior in VMs when packet size is not initialized<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
)

const (
	script1 = `set 0 dst mac %s
set 1 dst mac %s
set 0 size 1500
set 1 size 1500
`
	script2 = `set 0 size 1500
set 1 size 1500
range 0 dst mac start %s
range 1 dst mac start %s
range 0 size start 1500
range 0 size min 1500
range 0 size max 1500
range 0 dst port start 50
range 0 dst port min 50
range 0 dst port max 60
range 0 dst port inc 1
enable 0 range
`
	script3 = `set 0 size 1500
set 1 size 1500
range 0 dst mac start %s
range 1 dst mac start %s
range 0 size start 1500
range 0 size min 1500
range 0 size max 1500
range 0 src ip start 111.2.0.0
range 0 src ip min 111.2.0.0
range 0 src ip max 111.2.0.3
range 0 src ip inc 0.0.0.1
enable 0 range
`
	scriptNat = `set 0 size 1500
set 1 size 1500
range 0 dst mac start %s
range 1 dst mac start %s
range 0 size start 1500
range 0 size min 1500
range 0 size max 1500
range 1 size start 1500
range 1 size min 1500
range 1 size max 1500
range 0 src ip start 192.168.1.2
range 0 src ip min 192.168.1.2
range 0 src ip max 192.168.1.12
range 0 src ip inc 0.0.0.1
range 0 dst ip start 10.1.1.2
range 0 dst ip inc 0.0.0.0
range 0 src port start 1234
range 0 src port inc 0
range 1 src ip start 10.1.1.2
range 1 src ip inc 0.0.0.0
range 1 dst ip start 10.1.1.1
range 1 dst ip inc 0.0.0.0
range 1 dst port start 1024
range 1 dst port inc 0
enable 0 range
enable 1 range
`
	jsonNat = `{
    "port-pairs": [
        {
            "private-port": {
                "index": 0,
                "dst_mac": "%s",
                "subnet": "192.168.1.1/24"
            },
            "public-port": {
                "index": 1,
                "dst_mac": "%s",
                "subnet": "10.1.1.1"
            }
        }
    ]
}
`
	workaroundScript = `
start 1
sleep 1
stop 1
`
)

var workaroundTargets = map[string]struct{}{
	"dbdw14": {},
	"dbdw15": {},
	"dbdw16": {},
	"dbdw17": {},
}

func genScript(hostdir string, hosts []string, format, mac0, mac1 string, workaround bool) {
	for _, hostname := range hosts {
		if hostdir != "" {
			hostname = hostdir + string(os.PathSeparator) + hostname
		}
		file, err := os.Create(hostname)
		if err != nil {
			log.Fatal(err)
		} else {
			defer file.Close()
		}

		fmt.Fprintf(file, format, mac0, mac1)
		if workaround {
			fmt.Fprintf(file, workaroundScript)
		}
	}
}

func main() {
	// Parse arguments
	pktgenDir := flag.String("pgdir", "../../dpdk", "Specify directory where to put pktgen script files")
	configFile := flag.String("config", "config.json", "Specify config file name")
	target := flag.String("target", "", "Target host name from config file")
	pktgen := flag.String("pktgen", "", "Pktgen host name from config file")
	flag.Parse()

	// Read config
	err := readConfig(*configFile)
	if err != nil {
		log.Fatal(err)
	}

	if *target == "" && *pktgen == "" {
		target = &direct
		println("Generating scripts for -target direct")
	}

	_, needWO := workaroundTargets[*target]

	if *target != "" {
		genScript(*pktgenDir, []string{"step2.pg", "step3.pg"}, script1, config[*target][0], config[*target][1], needWO)
		genScript(*pktgenDir, []string{"step4.pg"}, script2, config[*target][0], config[*target][1], needWO)
		genScript(*pktgenDir, []string{"step5.pg", "step6.pg", "step7.pg", "step8.pg", "step9.pg", "step10.pg", "step11.pg"},
			script3, config[*target][0], config[*target][1], needWO)
		genScript(*pktgenDir, []string{"nat.pg"}, scriptNat, config[*target][0], config[*target][1], needWO)
	}

	if *pktgen != "" {
		// Write NAT config file
		genScript("", []string{"nat.json"}, jsonNat, config[*pktgen][0], config[*pktgen][1], false)
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"time"
)

type badWriter struct{}

func (_ badWriter) Write(p []byte) (int, error) { return 0, fmt.Errorf("no write set") }
func (_ badWriter) Close() error                { return fmt.Errorf("no write set") }

// LogFile is a persistent file.
type LogFile struct {
	path string // the path to the file
	mode os.FileMode
	mu   *sync.Mutex
	file io.WriteCloser
}

func NewLogFile(path string, mode os.FileMode) (*LogFile, error) {
	lf := &LogFile{path, mode, &sync.Mutex{}, badWriter{}}
	if err := lf.Create(); err != nil {
		return nil, fmt.Errorf("could not create log file: %v", err)
	}
	return lf, nil
}

type nopCloser struct {
	io.Writer
}

var Foo = "bar"

func (nopCloser) Close() error { return nil }

func (lf *LogFile) Close() (err error) {
	lf.mu.Lock()
	err = lf.file.Close()
	lf.file = nopCloser{ioutil.Discard}
	lf.mu.Unlock()
	return
}

func (lf *LogFile) Write(p []byte) (n int, err error) {
	lf.mu.Lock()
	defer lf.mu.Unlock()
	n, err = lf.file.Write(p)
	if err != nil {
		if err := lf.Create(); err != nil {
			log.Printf("MIDDLEWARE: could not create log file: %v", err)
		}
	}
	n, err = lf.file.Write(p)
	return
}

func (lf *LogFile) Create() error {
	flags := os.O_WRONLY | os.O_APPEND | os.O_CREATE
	file, err := os.OpenFile(lf.path, flags, lf.mode)
	if err != nil {
		lf.file = badWriter{}
	} else {
		lf.file = file
	}
	return err
}

const defaultStatus int = -1

type statusWrapper struct {
	wr     http.ResponseWriter
	status int
	nbytes int
}

func (w *statusWrapper) Header() http.Header { return w.wr.Header() }

func (w *statusWrapper) WriteHeader(status int) {
	w.wr.WriteHeader(status)
	w.status = status
}

func (w *statusWrapper) Write(p []byte) (n int, err error) {
	if w.status == defaultStatus {
		w.status = http.StatusOK
	}
	n, err = w.wr.Write(p)
	w.nbytes += n
	return
}

type statusHijacker struct {
	*statusWrapper
	hijacker http.Hijacker
}

func (w *statusHijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	// if the ResponseWriter is hijacked we'll assume the request was a success
	if w.statusWrapper.status == defaultStatus {
		w.statusWrapper.status = http.StatusOK
	}
	return w.hijacker.Hijack()
}

func Log(log io.Writer, h http.Handler) http.Handler {
	hf := func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		path := r.URL.String()
		method := r.Method
		origin := r.Header.Get("X-Forwarded-For")
		if origin == "" {
			origin = r.RemoteAddr
		}
		wrapper := &statusWrapper{w, defaultStatus, 0}
		hijacker, ok := w.(http.Hijacker)
		if ok {
			w = &statusHijacker{wrapper, hijacker}
		} else {
			w = wrapper
		}

		h.ServeHTTP(w, r)

		diff := time.Since(start)
		args := []interface{}{
			start.Format("2006/01/02 15:04:05"),
			method,
			path,
			wrapper.status,
			origin,
			wrapper.nbytes,
			diff.String(),
		}
		fmt.Fprintf(log, "%s %s %s %d %d %s %s\n", args...)
	}
	return http.HandlerFunc(hf)
}
<commit_msg>added user agent<commit_after>package middleware

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"sync"
	"time"
)

type badWriter struct{}

func (_ badWriter) Write(p []byte) (int, error) { return 0, fmt.Errorf("no write set") }
func (_ badWriter) Close() error                { return fmt.Errorf("no write set") }

// LogFile is a persistent file.
type LogFile struct {
	path string // the path to the file
	mode os.FileMode
	mu   *sync.Mutex
	file io.WriteCloser
}

func NewLogFile(path string, mode os.FileMode) (*LogFile, error) {
	lf := &LogFile{path, mode, &sync.Mutex{}, badWriter{}}
	if err := lf.Create(); err != nil {
		return nil, fmt.Errorf("could not create log file: %v", err)
	}
	return lf, nil
}

type nopCloser struct {
	io.Writer
}

var Foo = "bar"

func (nopCloser) Close() error { return nil }

func (lf *LogFile) Close() (err error) {
	lf.mu.Lock()
	err = lf.file.Close()
	lf.file = nopCloser{ioutil.Discard}
	lf.mu.Unlock()
	return
}

func (lf *LogFile) Write(p []byte) (n int, err error) {
	lf.mu.Lock()
	defer lf.mu.Unlock()
	n, err = lf.file.Write(p)
	if err != nil {
		if err := lf.Create(); err != nil {
			log.Printf("MIDDLEWARE: could not create log file: %v", err)
		}
	}
	n, err = lf.file.Write(p)
	return
}

func (lf *LogFile) Create() error {
	flags := os.O_WRONLY | os.O_APPEND | os.O_CREATE
	file, err := os.OpenFile(lf.path, flags, lf.mode)
	if err != nil {
		lf.file = badWriter{}
	} else {
		lf.file = file
	}
	return err
}

const defaultStatus int = -1

type statusWrapper struct {
	wr     http.ResponseWriter
	status int
	nbytes int
}

func (w *statusWrapper) Header() http.Header { return w.wr.Header() }

func (w *statusWrapper) WriteHeader(status int) {
	w.wr.WriteHeader(status)
	w.status = status
}

func (w *statusWrapper) Write(p []byte) (n int, err error) {
	if w.status == defaultStatus {
		w.status = http.StatusOK
	}
	n, err = w.wr.Write(p)
	w.nbytes += n
	return
}

type statusHijacker struct {
	*statusWrapper
	hijacker http.Hijacker
}

func (w *statusHijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	// if the ResponseWriter is hijacked we'll assume the request was a success
	if w.statusWrapper.status == defaultStatus {
		w.statusWrapper.status = http.StatusOK
	}
	return w.hijacker.Hijack()
}

func Log(log io.Writer, h http.Handler) http.Handler {
	hf := func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		path := r.URL.String()
		method := r.Method
		origin := r.Header.Get("X-Forwarded-For")
		if origin == "" {
			origin = r.RemoteAddr
		}
		userAgent := r.UserAgent()
		wrapper := &statusWrapper{w, defaultStatus, 0}
		hijacker, ok := w.(http.Hijacker)
		if ok {
			w = &statusHijacker{wrapper, hijacker}
		} else {
			w = wrapper
		}

		h.ServeHTTP(w, r)

		diff := time.Since(start)
		args := []interface{}{
			start.Format("2006/01/02 15:04:05"),
			method,
			wrapper.status,
			path,
			origin,
			wrapper.nbytes,
			diff.String(),
			userAgent,
		}
		fmt.Fprintf(log, "%s %s %d %s %s %d %s '%s'\n", args...)
	}
	return http.HandlerFunc(hf)
}
<|endoftext|>


<commit_before>package cfutil

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/Sirupsen/logrus"
)

type Logger interface {
	Debug(c context.Context, format string, args ...interface{})
	Info(c context.Context, format string, args ...interface{})
	Warning(c context.Context, format string, args ...interface{})
	Error(c context.Context, format string, args ...interface{})
	Critical(c context.Context, format string, args ...interface{})
	Raw(c context.Context, rawMessage string)
}

func NewLogger() Logger {
	newLogger := HSDPLogger{}
	appName, _ := GetApplicationName()
	newLogger.Init(appName, "", "", "")
	return newLogger
}

var log = NewLogger()

type HSDPLogger struct {
	logger   *logrus.Logger
	template logMessage
}

type Value struct {
	Message string `json:"message"`
}

type logMessage struct {
	App         string        `json:"app"`
	Value       Value         `json:"val"`
	Version     string        `json:"ver,omitempty"`
	Event       string        `json:"evt,omitempty"`
	Severity    string        `json:"sev,omitempty"`
	Transaction string        `json:"trns,omitempty"`
	User        string        `json:"usr,omitempty"`
	Server      string        `json:"srv,omitempty"`
	Service     string        `json:"service,omitempty"`
	Instance    string        `json:"inst,omitempty"`
	Category    string        `json:"cat,omitempty"`
	Component   string        `json:"cmp,omitempty"`
	Time        string        `json:"time,omitempty"`
	Fields      logrus.Fields `json:"fields,omitempty"`
}

func (f *HSDPLogger) Init(app, version, instance, component string) {
	f.logger = logrus.New()
	f.logger.Formatter = f
	f.template.App = app
	f.template.Version = version
	f.template.Instance = instance
	f.template.Component = component
}

func (f HSDPLogger) Raw(c context.Context, rawString string) {
	fmt.Print(rawString)
}

func (f HSDPLogger) Debug(c context.Context, format string, args ...interface{}) {
	f.logger.Debugf(format, args...)
}

func (f HSDPLogger) Info(c context.Context, format string, args ...interface{}) {
	f.logger.Infof(format, args...)
}

func (f HSDPLogger) Warning(c context.Context, format string, args ...interface{}) {
	f.logger.Warningf(format, args...)
}

func (f HSDPLogger) Error(c context.Context, format string, args ...interface{}) {
	f.logger.Errorf(format, args...)
}

func (f HSDPLogger) Critical(c context.Context, format string, args ...interface{}) {
	f.logger.Fatalf(format, args...)
}

func (f *HSDPLogger) Format(entry *logrus.Entry) ([]byte, error) {
	data := f.template
	data.Time = entry.Time.Format(time.RFC3339)
	data.Value.Message = entry.Message
	data.Severity = entry.Level.String()

	data.Fields = make(logrus.Fields, len(entry.Data))
	for k, v := range entry.Data {
		switch k {
		case "transaction":
			data.Transaction = v.(string)
			continue
		case "user":
			data.User = v.(string)
			continue
		}
		switch v := v.(type) {
		case error:
			data.Fields[k] = v.Error()
		default:
			data.Fields[k] = v
		}
	}
	serialized, err := json.Marshal(data)
	if err != nil {
		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
	}
	return append(serialized, '\n'), nil
}
<commit_msg>Output to STDOUT instead of STDERR<commit_after>package cfutil

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"time"

	"github.com/Sirupsen/logrus"
)

type Logger interface {
	Debug(c context.Context, format string, args ...interface{})
	Info(c context.Context, format string, args ...interface{})
	Warning(c context.Context, format string, args ...interface{})
	Error(c context.Context, format string, args ...interface{})
	Critical(c context.Context, format string, args ...interface{})
	Raw(c context.Context, rawMessage string)
}

func NewLogger() Logger {
	newLogger := HSDPLogger{}
	appName, _ := GetApplicationName()
	newLogger.Init(appName, "", "", "")
	return newLogger
}

var log = NewLogger()

type HSDPLogger struct {
	logger   *logrus.Logger
	template logMessage
}

type Value struct {
	Message string `json:"message"`
}

type logMessage struct {
	App         string        `json:"app"`
	Value       Value         `json:"val"`
	Version     string        `json:"ver,omitempty"`
	Event       string        `json:"evt,omitempty"`
	Severity    string        `json:"sev,omitempty"`
	Transaction string        `json:"trns,omitempty"`
	User        string        `json:"usr,omitempty"`
	Server      string        `json:"srv,omitempty"`
	Service     string        `json:"service,omitempty"`
	Instance    string        `json:"inst,omitempty"`
	Category    string        `json:"cat,omitempty"`
	Component   string        `json:"cmp,omitempty"`
	Time        string        `json:"time,omitempty"`
	Fields      logrus.Fields `json:"fields,omitempty"`
}

func (f *HSDPLogger) Init(app, version, instance, component string) {
	f.logger = logrus.New()
	logrus.SetOutput(os.Stdout)
	f.logger.Formatter = f

	f.template.App = app
	f.template.Version = version
	f.template.Instance = instance
	f.template.Component = component
}

func (f HSDPLogger) Raw(c context.Context, rawString string) {
	fmt.Print(rawString)
}

func (f HSDPLogger) Debug(c context.Context, format string, args ...interface{}) {
	f.logger.Debugf(format, args...)
}

func (f HSDPLogger) Info(c context.Context, format string, args ...interface{}) {
	f.logger.Infof(format, args...)
}

func (f HSDPLogger) Warning(c context.Context, format string, args ...interface{}) {
	f.logger.Warningf(format, args...)
}

func (f HSDPLogger) Error(c context.Context, format string, args ...interface{}) {
	f.logger.Errorf(format, args...)
}

func (f HSDPLogger) Critical(c context.Context, format string, args ...interface{}) {
	f.logger.Fatalf(format, args...)
}

func (f *HSDPLogger) Format(entry *logrus.Entry) ([]byte, error) {
	data := f.template
	data.Time = entry.Time.Format(time.RFC3339)
	data.Value.Message = entry.Message
	data.Severity = entry.Level.String()

	data.Fields = make(logrus.Fields, len(entry.Data))
	for k, v := range entry.Data {
		switch k {
		case "transaction":
			data.Transaction = v.(string)
			continue
		case "user":
			data.User = v.(string)
			continue
		}
		switch v := v.(type) {
		case error:
			data.Fields[k] = v.Error()
		default:
			data.Fields[k] = v
		}
	}
	serialized, err := json.Marshal(data)
	if err != nil {
		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
	}
	return append(serialized, '\n'), nil
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/Sirupsen/logrus"
)

type Logger struct {
	*logrus.Logger
}

func (l *Logger) GetRequestEntry(r *http.Request) *logrus.Entry {
	return l.WithFields(logrus.Fields{
		"Method":        r.Method,
		"RequestUri":    r.RequestURI,
		"RemoteAddr":    r.RemoteAddr,
		"ContentLength": r.ContentLength,
		"UserAgent":     r.UserAgent(),
	})
}
<commit_msg>add log runtime version & gusher version<commit_after>package main

import (
	"net/http"
	"runtime"

	"github.com/Sirupsen/logrus"
)

func GetLogger() *Logger {
	l := logrus.New()
	e := l.WithFields(logrus.Fields{
		"Version":        version,
		"RuntimeVersion": runtime.Version(),
	})
	return &Logger{
		e,
	}

}

type Logger struct {
	*logrus.Entry
}

func (l *Logger) GetRequestEntry(r *http.Request) *logrus.Entry {
	return l.WithFields(logrus.Fields{
		"Method":        r.Method,
		"RequestUri":    r.RequestURI,
		"RemoteAddr":    r.RemoteAddr,
		"ContentLength": r.ContentLength,
		"UserAgent":     r.UserAgent(),
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"fmt"
	"os"
)

// Currently hard-coded limit on message size.
const MESSAGE_SIZE_LIMIT = 4 * 1024 * 1024

type MessageSet interface {
	Read(start uint64, messages uint) ([]*Message, error)
	Append(message *Message) error
	Close() error
}

type FileMessageSet struct {
	MessageSet
	f *os.File
}

func (fms *FileMessageSet) Read(start uint64, maxMessages uint) ([]*Message, error) {
	var offset = int64(start)
	var messageCount = uint(0)

	fileStat, err := fms.f.Stat()
	if err != nil {
		return nil, err
	}

	messages := make([]*Message, 0)
	for offset < fileStat.Size() && messageCount < maxMessages {
		messageSizeBuf := make([]byte, 4)
		fms.f.ReadAt(messageSizeBuf, offset)

		messageSize := int64(binary.BigEndian.Uint32(messageSizeBuf))
		if messageSize > MESSAGE_SIZE_LIMIT {
			return nil, fmt.Errorf("Message larger than message size limit: %d > %d",
				messageSize, MESSAGE_SIZE_LIMIT)
		}

		crc32bytes := make([]byte, 4)
		fms.f.ReadAt(crc32bytes, offset+4)
		crc := uint32(binary.BigEndian.Uint32(crc32bytes))

		messageBuf := make([]byte, messageSize) // 4mb limit
		fms.f.ReadAt(messageBuf, offset+8)

		newMessage, err := hydrateMessage(messageBuf, crc)
		if err != nil {
			return nil, err
		}

		messages = append(messages, newMessage)

		offset += messageSize + 4 + 4
		messageCount += 1
	}

	return messages, nil
}

func (fms *FileMessageSet) Append(message *Message) error {
	if err := fms.writeData(message.size()); err != nil {
		return err
	}

	if err := fms.writeData(message.Checksum()); err != nil {
		return err
	}

	if err := fms.writeData(message.Offset); err != nil {
		return err
	}

	if err := fms.writeData(message.Payload); err != nil {
		return err
	}

	return nil
}

func (fms *FileMessageSet) Close() error {
	return fms.f.Close()
}

func (fms *FileMessageSet) writeData(data interface{}) error {
	// TODO: more efficient writes, but this is convenient
	return binary.Write(fms.f, binary.BigEndian, data)
}

func int32bytes(num uint32) []byte {
	slice := make([]byte, 4)
	binary.BigEndian.PutUint32(slice, num)

	return slice
}
<commit_msg>log: refactored int32 reads from disk<commit_after>package main

import (
	"encoding/binary"
	"fmt"
	"os"
)

// Currently hard-coded limit on message size.
const MESSAGE_SIZE_LIMIT = 4 * 1024 * 1024

type MessageSet interface {
	Read(start uint64, messages uint) ([]*Message, error)
	Append(message *Message) error
	Close() error
}

type FileMessageSet struct {
	MessageSet
	f *os.File
}

func (fms *FileMessageSet) Read(start uint64, maxMessages uint) ([]*Message, error) {
	var offset = int64(start)
	var messageCount = uint(0)

	fileStat, err := fms.f.Stat()
	if err != nil {
		return nil, err
	}

	messages := make([]*Message, 0)
	for offset < fileStat.Size() && messageCount < maxMessages {
		messageSize, err := fms.readUint32(offset)
		if err != nil {
			return nil, err
		}

		if messageSize > MESSAGE_SIZE_LIMIT {
			return nil, fmt.Errorf("Message larger than message size limit: %d > %d",
				messageSize, MESSAGE_SIZE_LIMIT)
		}

		crc, err := fms.readUint32(offset + 4)
		if err != nil {
			return nil, err
		}

		messageBuf := make([]byte, messageSize) // 4mb limit
		fms.f.ReadAt(messageBuf, offset+8)

		newMessage, err := hydrateMessage(messageBuf, crc)
		if err != nil {
			return nil, err
		}

		messages = append(messages, newMessage)

		offset += int64(messageSize) + 4 + 4
		messageCount += 1
	}

	return messages, nil
}

func (fms *FileMessageSet) Append(message *Message) error {
	if err := fms.writeData(message.size()); err != nil {
		return err
	}

	if err := fms.writeData(message.Checksum()); err != nil {
		return err
	}

	if err := fms.writeData(message.Offset); err != nil {
		return err
	}

	if err := fms.writeData(message.Payload); err != nil {
		return err
	}

	return nil
}

func (fms *FileMessageSet) Close() error {
	return fms.f.Close()
}

func (fms *FileMessageSet) readUint32(offset int64) (uint32, error) {
	buffer := make([]byte, 4)
	if _, err := fms.f.ReadAt(buffer, offset); err != nil {
		return 0, err
	}
	return uint32(binary.BigEndian.Uint32(buffer)), nil
}

func (fms *FileMessageSet) writeData(data interface{}) error {
	// TODO: more efficient writes, but this is convenient
	return binary.Write(fms.f, binary.BigEndian, data)
}
<|endoftext|>


<commit_before>package turnpike

import (
	"fmt"
	"net/http"

	"github.com/gorilla/websocket"
)

const (
	jsonWebsocketProtocol    = "wamp.2.json"
	msgpackWebsocketProtocol = "wamp.2.msgpack"
)

type invalidPayload byte

func (e invalidPayload) Error() string {
	return fmt.Sprintf("Invalid payloadType: %d", e)
}

type protocolExists string

func (e protocolExists) Error() string {
	return "This protocol has already been registered: " + string(e)
}

type protocol struct {
	payloadType int
	serializer  Serializer
}

// WebsocketServer handles websocket connections.
type WebsocketServer struct {
	Router
	Upgrader *websocket.Upgrader

	protocols map[string]protocol

	// The serializer to use for text frames. Defaults to JSONSerializer.
	TextSerializer Serializer
	// The serializer to use for binary frames. Defaults to JSONSerializer.
	BinarySerializer Serializer
}

// NewWebsocketServer creates a new WebsocketServer from a map of realms
func NewWebsocketServer(realms map[string]Realm) (*WebsocketServer, error) {
	log.Println("NewWebsocketServer")
	r := NewDefaultRouter()
	for uri, realm := range realms {
		if err := r.RegisterRealm(URI(uri), realm); err != nil {
			return nil, err
		}
	}
	s := newWebsocketServer(r)
	return s, nil
}

// NewBasicWebsocketServer creates a new WebsocketServer with a single basic realm
func NewBasicWebsocketServer(uri string) *WebsocketServer {
	log.Println("NewBasicWebsocketServer")
	s, _ := NewWebsocketServer(map[string]Realm{uri: {}})
	return s
}

func newWebsocketServer(r Router) *WebsocketServer {
	s := &WebsocketServer{
		Router:    r,
		protocols: make(map[string]protocol),
	}
	s.Upgrader = &websocket.Upgrader{}
	s.RegisterProtocol(jsonWebsocketProtocol, websocket.TextMessage, new(JSONSerializer))
	s.RegisterProtocol(msgpackWebsocketProtocol, websocket.BinaryMessage, new(MessagePackSerializer))
	return s
}

// RegisterProtocol registers a serializer that should be used for a given protocol string and payload type.
func (s *WebsocketServer) RegisterProtocol(proto string, payloadType int, serializer Serializer) error {
	log.Println("RegisterProtocol:", proto)
	if payloadType != websocket.TextMessage && payloadType != websocket.BinaryMessage {
		return invalidPayload(payloadType)
	}
	if _, ok := s.protocols[proto]; ok {
		return protocolExists(proto)
	}
	s.protocols[proto] = protocol{payloadType, serializer}
	s.Upgrader.Subprotocols = append(s.Upgrader.Subprotocols, proto)
	return nil
}

// GetLocalClient returns a client connected to the specified realm
func (s *WebsocketServer) GetLocalClient(realm string, details map[string]interface{}) (*Client, error) {
	peer, err := s.Router.GetLocalPeer(URI(realm), details)
	if err != nil {
		return nil, err
	}
	c := NewClient(peer)
	go c.Receive()
	go c.run()
	return c, nil
}

// ServeHTTP handles a new HTTP connection.
func (s *WebsocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("WebsocketServer.ServeHTTP", r.Method, r.RequestURI)
	// TODO: subprotocol?
	conn, err := s.Upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Error upgrading to websocket connection:", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	s.handleWebsocket(conn)
}

func (s *WebsocketServer) handleWebsocket(conn *websocket.Conn) {
	var serializer Serializer
	var payloadType int
	if proto, ok := s.protocols[conn.Subprotocol()]; ok {
		serializer = proto.serializer
		payloadType = proto.payloadType
	} else {
		// TODO: this will not currently ever be hit because
		//       gorilla/websocket will reject the conncetion
		//       if the subprotocol isn't registered
		switch conn.Subprotocol() {
		case jsonWebsocketProtocol:
			serializer = new(JSONSerializer)
			payloadType = websocket.TextMessage
		case msgpackWebsocketProtocol:
			serializer = new(MessagePackSerializer)
			payloadType = websocket.BinaryMessage
		default:
			conn.Close()
			return
		}
	}

	peer := websocketPeer{
		conn:        conn,
		serializer:  serializer,
		messages:    make(chan Message, 10),
		payloadType: payloadType,
	}
	go peer.run()

	logErr(s.Router.Accept(&peer))
}
<commit_msg>NewClient already calls run(), do not call it again in the GetLocalClient case<commit_after>package turnpike

import (
	"fmt"
	"net/http"

	"github.com/gorilla/websocket"
)

const (
	jsonWebsocketProtocol    = "wamp.2.json"
	msgpackWebsocketProtocol = "wamp.2.msgpack"
)

type invalidPayload byte

func (e invalidPayload) Error() string {
	return fmt.Sprintf("Invalid payloadType: %d", e)
}

type protocolExists string

func (e protocolExists) Error() string {
	return "This protocol has already been registered: " + string(e)
}

type protocol struct {
	payloadType int
	serializer  Serializer
}

// WebsocketServer handles websocket connections.
type WebsocketServer struct {
	Router
	Upgrader *websocket.Upgrader

	protocols map[string]protocol

	// The serializer to use for text frames. Defaults to JSONSerializer.
	TextSerializer Serializer
	// The serializer to use for binary frames. Defaults to JSONSerializer.
	BinarySerializer Serializer
}

// NewWebsocketServer creates a new WebsocketServer from a map of realms
func NewWebsocketServer(realms map[string]Realm) (*WebsocketServer, error) {
	log.Println("NewWebsocketServer")
	r := NewDefaultRouter()
	for uri, realm := range realms {
		if err := r.RegisterRealm(URI(uri), realm); err != nil {
			return nil, err
		}
	}
	s := newWebsocketServer(r)
	return s, nil
}

// NewBasicWebsocketServer creates a new WebsocketServer with a single basic realm
func NewBasicWebsocketServer(uri string) *WebsocketServer {
	log.Println("NewBasicWebsocketServer")
	s, _ := NewWebsocketServer(map[string]Realm{uri: {}})
	return s
}

func newWebsocketServer(r Router) *WebsocketServer {
	s := &WebsocketServer{
		Router:    r,
		protocols: make(map[string]protocol),
	}
	s.Upgrader = &websocket.Upgrader{}
	s.RegisterProtocol(jsonWebsocketProtocol, websocket.TextMessage, new(JSONSerializer))
	s.RegisterProtocol(msgpackWebsocketProtocol, websocket.BinaryMessage, new(MessagePackSerializer))
	return s
}

// RegisterProtocol registers a serializer that should be used for a given protocol string and payload type.
func (s *WebsocketServer) RegisterProtocol(proto string, payloadType int, serializer Serializer) error {
	log.Println("RegisterProtocol:", proto)
	if payloadType != websocket.TextMessage && payloadType != websocket.BinaryMessage {
		return invalidPayload(payloadType)
	}
	if _, ok := s.protocols[proto]; ok {
		return protocolExists(proto)
	}
	s.protocols[proto] = protocol{payloadType, serializer}
	s.Upgrader.Subprotocols = append(s.Upgrader.Subprotocols, proto)
	return nil
}

// GetLocalClient returns a client connected to the specified realm
func (s *WebsocketServer) GetLocalClient(realm string, details map[string]interface{}) (*Client, error) {
	peer, err := s.Router.GetLocalPeer(URI(realm), details)
	if err != nil {
		return nil, err
	}
	c := NewClient(peer)
	go c.Receive()
	return c, nil
}

// ServeHTTP handles a new HTTP connection.
func (s *WebsocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("WebsocketServer.ServeHTTP", r.Method, r.RequestURI)
	// TODO: subprotocol?
	conn, err := s.Upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Error upgrading to websocket connection:", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	s.handleWebsocket(conn)
}

func (s *WebsocketServer) handleWebsocket(conn *websocket.Conn) {
	var serializer Serializer
	var payloadType int
	if proto, ok := s.protocols[conn.Subprotocol()]; ok {
		serializer = proto.serializer
		payloadType = proto.payloadType
	} else {
		// TODO: this will not currently ever be hit because
		//       gorilla/websocket will reject the conncetion
		//       if the subprotocol isn't registered
		switch conn.Subprotocol() {
		case jsonWebsocketProtocol:
			serializer = new(JSONSerializer)
			payloadType = websocket.TextMessage
		case msgpackWebsocketProtocol:
			serializer = new(MessagePackSerializer)
			payloadType = websocket.BinaryMessage
		default:
			conn.Close()
			return
		}
	}

	peer := websocketPeer{
		conn:        conn,
		serializer:  serializer,
		messages:    make(chan Message, 10),
		payloadType: payloadType,
	}
	go peer.run()

	logErr(s.Router.Accept(&peer))
}
<|endoftext|>


<commit_before>// Copyright © 2013, S.Çağlar Onur
// Use of this source code is governed by a LGPLv2.1
// license that can be found in the LICENSE file.
//
// Authors:
// S.Çağlar Onur <caglar@10ur.org>

// +build linux

// Package lxc provides Go (golang) Bindings for LXC (Linux Containers) C API.
package lxc

// #cgo pkg-config: lxc
// #include <lxc/lxccontainer.h>
// #include "lxc.h"
import "C"

import (
	"fmt"
	"os"
	"unsafe"
)

func init() {
	if os.Geteuid() != 0 {
		panic("Running as non-root.")
	}
}

// NewContainer returns a new container struct
func NewContainer(name string, lxcpath ...string) (*Container, error) {
	var container *C.struct_lxc_container

	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		container = C.lxc_container_new(cname, clxcpath)
	} else {
		container = C.lxc_container_new(cname, nil)
	}

	if container == nil {
		return nil, fmt.Errorf(errNewFailed, name)
	}
	return &Container{container: container, verbosity: Quiet}, nil
}

// GetContainer increments reference counter of the container object
func GetContainer(lxc *Container) bool {
	return C.lxc_container_get(lxc.container) == 1
}

// PutContainer decrements reference counter of the container object
func PutContainer(lxc *Container) bool {
	return C.lxc_container_put(lxc.container) == 1
}

// Version returns LXC version
func Version() string {
	return C.GoString(C.lxc_get_version())
}

// GlobalConfigItem returns the value of the given global config key
func GlobalConfigItem(name string) string {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	return C.GoString(C.lxc_get_global_config_item(cname))
}

// DefaultConfigPath returns default config path
func DefaultConfigPath() string {
	return GlobalConfigItem("lxc.lxcpath")
}

// DefaultLvmVg returns default LVM volume group
func DefaultLvmVg() string {
	return GlobalConfigItem("lxc.lvm_vg")
}

// DefaultZfsRoot returns default ZFS root
func DefaultZfsRoot() string {
	return GlobalConfigItem("lxc.zfsroot")
}

// ContainerNames returns the names of defined and active containers on the system.
func ContainerNames(lxcpath ...string) []string {
	var size int
	var cnames **C.char

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		size = int(C.list_all_containers(clxcpath, &cnames, nil))
	} else {

		size = int(C.list_all_containers(nil, &cnames, nil))
	}

	if size < 1 {
		return nil
	}
	return convertNArgs(cnames, size)
}

// Containers returns the defined and active containers on the system.
func Containers(lxcpath ...string) []Container {
	var containers []Container

	for _, v := range ContainerNames(lxcpath...) {
		container, err := NewContainer(v, lxcpath...)
		if err != nil {
			return nil
		}
		containers = append(containers, *container)
	}
	return containers
}

// DefinedContainerNames returns the names of the defined containers on the system.
func DefinedContainerNames(lxcpath ...string) []string {
	var size int
	var cnames **C.char

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		size = int(C.list_defined_containers(clxcpath, &cnames, nil))
	} else {

		size = int(C.list_defined_containers(nil, &cnames, nil))
	}

	if size < 1 {
		return nil
	}
	return convertNArgs(cnames, size)
}

// DefinedContainers returns the defined containers on the system.
func DefinedContainers(lxcpath ...string) []Container {
	var containers []Container

	for _, v := range DefinedContainerNames(lxcpath...) {
		container, err := NewContainer(v, lxcpath...)
		if err != nil {
			return nil
		}
		containers = append(containers, *container)
	}
	return containers
}

// ActiveContainerNames returns the names of the active containers on the system.
func ActiveContainerNames(lxcpath ...string) []string {
	var size int
	var cnames **C.char

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		size = int(C.list_active_containers(clxcpath, &cnames, nil))
	} else {

		size = int(C.list_active_containers(nil, &cnames, nil))
	}

	if size < 1 {
		return nil
	}
	return convertNArgs(cnames, size)
}

// ActiveContainers returns the active containers on the system.
func ActiveContainers(lxcpath ...string) []Container {
	var containers []Container

	for _, v := range ActiveContainerNames(lxcpath...) {
		container, err := NewContainer(v, lxcpath...)
		if err != nil {
			return nil
		}
		containers = append(containers, *container)
	}
	return containers
}
<commit_msg>some enums renamed again so adjust them<commit_after>// Copyright © 2013, S.Çağlar Onur
// Use of this source code is governed by a LGPLv2.1
// license that can be found in the LICENSE file.
//
// Authors:
// S.Çağlar Onur <caglar@10ur.org>

// +build linux

// Package lxc provides Go (golang) Bindings for LXC (Linux Containers) C API.
package lxc

// #cgo pkg-config: lxc
// #include <lxc/lxccontainer.h>
// #include "lxc.h"
import "C"

import (
	"fmt"
	"os"
	"unsafe"
)

func init() {
	if os.Geteuid() != 0 {
		panic("Running as non-root.")
	}
}

// NewContainer returns a new container struct
func NewContainer(name string, lxcpath ...string) (*Container, error) {
	var container *C.struct_lxc_container

	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		container = C.lxc_container_new(cname, clxcpath)
	} else {
		container = C.lxc_container_new(cname, nil)
	}

	if container == nil {
		return nil, fmt.Errorf(errNewFailed, name)
	}
	return &Container{container: container, verbosity: Quiet}, nil
}

// GetContainer increments reference counter of the container object
func GetContainer(lxc *Container) bool {
	return C.lxc_container_get(lxc.container) == 1
}

// PutContainer decrements reference counter of the container object
func PutContainer(lxc *Container) bool {
	return C.lxc_container_put(lxc.container) == 1
}

// Version returns LXC version
func Version() string {
	return C.GoString(C.lxc_get_version())
}

// GlobalConfigItem returns the value of the given global config key
func GlobalConfigItem(name string) string {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	return C.GoString(C.lxc_get_global_config_item(cname))
}

// DefaultConfigPath returns default config path
func DefaultConfigPath() string {
	return GlobalConfigItem("lxc.lxcpath")
}

// DefaultLvmVg returns default LVM volume group
func DefaultLvmVg() string {
	return GlobalConfigItem("lxc.bdev.lvm.vg")
}

// DefaultZfsRoot returns default ZFS root
func DefaultZfsRoot() string {
	return GlobalConfigItem("lxc.bdec.zfs.root")
}

// ContainerNames returns the names of defined and active containers on the system.
func ContainerNames(lxcpath ...string) []string {
	var size int
	var cnames **C.char

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		size = int(C.list_all_containers(clxcpath, &cnames, nil))
	} else {

		size = int(C.list_all_containers(nil, &cnames, nil))
	}

	if size < 1 {
		return nil
	}
	return convertNArgs(cnames, size)
}

// Containers returns the defined and active containers on the system.
func Containers(lxcpath ...string) []Container {
	var containers []Container

	for _, v := range ContainerNames(lxcpath...) {
		container, err := NewContainer(v, lxcpath...)
		if err != nil {
			return nil
		}
		containers = append(containers, *container)
	}
	return containers
}

// DefinedContainerNames returns the names of the defined containers on the system.
func DefinedContainerNames(lxcpath ...string) []string {
	var size int
	var cnames **C.char

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		size = int(C.list_defined_containers(clxcpath, &cnames, nil))
	} else {

		size = int(C.list_defined_containers(nil, &cnames, nil))
	}

	if size < 1 {
		return nil
	}
	return convertNArgs(cnames, size)
}

// DefinedContainers returns the defined containers on the system.
func DefinedContainers(lxcpath ...string) []Container {
	var containers []Container

	for _, v := range DefinedContainerNames(lxcpath...) {
		container, err := NewContainer(v, lxcpath...)
		if err != nil {
			return nil
		}
		containers = append(containers, *container)
	}
	return containers
}

// ActiveContainerNames returns the names of the active containers on the system.
func ActiveContainerNames(lxcpath ...string) []string {
	var size int
	var cnames **C.char

	if lxcpath != nil && len(lxcpath) == 1 {
		clxcpath := C.CString(lxcpath[0])
		defer C.free(unsafe.Pointer(clxcpath))

		size = int(C.list_active_containers(clxcpath, &cnames, nil))
	} else {

		size = int(C.list_active_containers(nil, &cnames, nil))
	}

	if size < 1 {
		return nil
	}
	return convertNArgs(cnames, size)
}

// ActiveContainers returns the active containers on the system.
func ActiveContainers(lxcpath ...string) []Container {
	var containers []Container

	for _, v := range ActiveContainerNames(lxcpath...) {
		container, err := NewContainer(v, lxcpath...)
		if err != nil {
			return nil
		}
		containers = append(containers, *container)
	}
	return containers
}
<|endoftext|>